Files
mangabaka-seeder/docs/ARCHITECTURE.md
T
Lucas WintherandClaude Opus 5.5 17ecebc4a4 feat(web): Obi Shelf design in a console layout, with a timeline view; record DESIGN.md
The user chose the direction over two mockup rounds (samples/mockups, gitignored):
the Obi Shelf's shelf and colours, Graphite Console side panels, the Annotated
Edition timeline as a second view, and warm off-colour grounds in both themes.
Selects look editable; labels are source-neutral. impeccable finish review: ship.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 01:38:00 +02:00

61 lines
4.3 KiB
Markdown

# Architecture
How `mangabaka-seeder` is built today. Update in the same commit as any structural change.
## Overview
The core (`src/core/`) is built and tested: `pipeline.ts` composes the stages of spec §3, `session.ts` holds the review state both front ends share. The server, page and userscript follow. The design is in [`specs/001-webtoons-covers.md`](specs/001-webtoons-covers.md):
one pure TypeScript core (`src/core/`) that turns a MangaBaka series link and a Webtoons series
link into a cover submission, used by three front ends — a static page served by a small
self-hosted Bun server (primary), a userscript, and later a Bun CLI. Replace this section with reality as modules land.
## Map (planned — spec §4)
| Path | Responsibility |
|---|---|
| `src/core/` | Pure pipeline: sources, Wayback history, image inspection, dedupe, seed, MangaBaka client. No DOM, Bun, Node or `GM_*` APIs. |
| `src/core/session.ts` | Review state shared by the page and the userscript: cards, main cover, rehosting, manual text, token flow (preview → confirm → save for review). |
| `src/web/` | Built. The page ("Obi Shelf" design, see `DESIGN.md`): `template.ts` markup shared with the userscript panel, `app.ts` wiring (`mountApp`), `render.ts` shelf and timeline views, `view-model.ts` pure helpers, `transport.ts` (direct to MangaBaka/litterbox, everything else via `/api/fetch`), `styles.css` scoped for a shadow root. |
| `src/server/` | Built. `app.ts`: web-standard handler (`createApp(env)`) — static assets, `/api/config`, `/api/fetch` allowlisted proxy (redirects re-checked, 20 MB cap), `/api/upload` (store or catbox; takes a source URL, never bytes), `/covers/*`. `storage.ts` (interface, in-memory) and `storage-dir.ts` (folder, size cap, 30-day sweep). `config.ts` (env, client IP), `rate-limit.ts`, `assets-path.ts`. `bun.ts`: thin `Bun.serve` entry. Gate and Workers entry deferred. |
| `src/userscript/` | Userscript on mangabaka.org; network via `GM_xmlhttpRequest`. |
| `src/cli/` | Later: Bun CLI. |
| `test/fixtures/` | Saved real responses; tests never hit the network. |
## Data flow
Links → series id + `source.resolve` → current + Wayback candidates → inspect (bytes, size,
sha256) → dedupe against MangaBaka → seed → user reviews → rehost (explicit) → submit or manual entry.
## Running the server
`bun run build` then `bun run start`. Environment:
| Variable | Default | Meaning |
|---|---|---|
| `MBSEED_PORT` | `8787` | Listen port. |
| `MBSEED_HOST` | `127.0.0.1` | Listen address (behind the reverse proxy). |
| `MBSEED_PUBLIC_URL` | — | Public origin, e.g. `https://mbseed.example.org`; required with storage (stored covers are served from it). |
| `MBSEED_STORAGE_DIR` | — | Covers folder; unset = no server storage. |
| `MBSEED_STORAGE_MAX_BYTES` | `1073741824` | Folder size cap; uploads past it get 507. |
| `MBSEED_TRUST_PROXY` | unset | `1` = rate-limit on the last `X-Forwarded-For` entry. |
| `MBSEED_ASSETS_DIR` | `dist/web` | Built page and userscript. |
Put it behind a reverse proxy that terminates TLS and **appends** the client address to
`X-Forwarded-For` (nginx `$proxy_add_x_forwarded_for`, Caddy's default), then set `MBSEED_TRUST_PROXY=1`.
## External dependencies
| Service | Reached via | If unavailable |
|---|---|---|
| `api.mangabaka.org` | direct (CORS open) | Nothing works. |
| Webtoons HTML / `swebtoon-phinf.pstatic.net` | server proxy or `GM_xmlhttpRequest` | Nothing works. |
| Wayback (`web.archive.org`) | same | Warning; current covers only. |
| Server storage (folder on our server) | server | `server` host hidden; litterbox/catbox/direct still work. |
| litterbox / catbox | browser directly (litterbox), server or `GM_xmlhttpRequest` (catbox) | That host fails; others still work. |
## Invariants
- `src/core/` never imports from `web/`, `server/`, `userscript/` or `cli/`.
- The MangaBaka token is only ever sent to `api.mangabaka.org`, never through our server.
- The covers folder never exceeds `MBSEED_STORAGE_MAX_BYTES`; when full, uploads are refused and
no file is deleted before its 30 days.
- Nothing is uploaded or submitted without an explicit user action; saves use `save_mode: "review"`.
- `/api/fetch` only fetches allowlisted hosts; `/api/upload` only takes a source URL, never bytes.
## Known rough edges
See the open questions in spec §7 and [`TODO.md`](TODO.md).