docs: add architecture and decisions documentation

This commit is contained in:
2026-08-08 10:26:37 +08:00
commit 405602a943
3 changed files with 423 additions and 0 deletions
+99
View File
@@ -0,0 +1,99 @@
# Architecture & Dependencies
> **Scope:** The system's architecture and dependency graph. For implementation
> details (files, endpoints, build order), see
> [`implementation-plan.md`](./implementation-plan.md). For the rationale behind
> key decisions, see [`decisions.md`](./decisions.md).
## Overview
A lightweight, client-only pnpm monorepo that lets a user search the Tabletop
Simulator Steam Workshop, fetch full TTS save files, and analyze their
contents. It is split into four packages with a strict layering: a thin
HTTP proxy on top, a low-level fetcher, an isomorphic analysis layer, and a
shared types/validation package.
## Design principles
- **Client-only & lightweight** — no caching layer, no shared server state.
- **Fetch vs analyze separation** — `packages/tts` only fetches and parses;
`packages/extract` only analyzes. Neither depends on the other's concerns.
- **Isomorphic analysis** — `packages/extract` runs in browser and Node, using
only `fetch`, `Blob`, and typed arrays (no `Buffer`, no Node-only packages).
- **Thin proxy** — the HTTP layer exposes search and fetch only; traversal is
intentionally not exposed as endpoints.
## Package responsibilities
| Package | Role | Runtime |
| ------------------ | ------------------------------------------- | ------------ |
| `apps/proxy` | Hono HTTP server: search + fetch endpoints | Node |
| `packages/tts` | Fetch save from Steam, BSON-parse to `TTSMod` | Node |
| `packages/extract` | Analyze a `TTSMod`: objects, refs, assets | Isomorphic |
| `packages/shared` | Shared types + zod schemas | Isomorphic |
## Dependency graph
```
apps/proxy ──► packages/tts ──► packages/shared
│ │
│ └──► (fetchMod → TTSMod)
packages/extract ──► packages/tts (traverseMod) ──► packages/shared (types)
```
### Edges
- **`apps/proxy``packages/tts`** — calls `fetchMod` / `getFileName` to serve
item requests.
- **`apps/proxy``packages/shared`** — uses shared types and zod schemas for
request/response validation.
- **`packages/tts``packages/shared`** — consumes `TTSMod` / `TTSObject`
types.
- **`packages/extract``packages/tts`** — reuses `traverseMod` (traversal
logic lives in `extract`; see note below).
- **`packages/extract``packages/shared`** — consumes shared types.
> **Note on `traverseMod`:** traversal is analysis, so it lives in
> `packages/extract`. `packages/tts` is fetch-only. The graph edge
> `extract → tts` reflects that `extract` imports the traversal helper that was
> originally authored alongside the fetcher; `tts` does not depend on `extract`.
### Layering rules
- **No upward dependencies** — `packages/*` never import `apps/*`.
- **No sibling coupling beyond the graph above** — `extract` and `tts` do not
depend on each other's analysis/fetch concerns.
- **`packages/shared` is the leaf** — everything depends on it; it depends on
nothing internal.
## External dependencies
| Package | Purpose | Used by |
| ------------------ | ----------------------------------------- | ------------------ |
| `hono` | HTTP framework | `apps/proxy` |
| `@hono/node-server`| Node adapter for Hono | `apps/proxy` |
| `@hono/cors` | CORS middleware | `apps/proxy` |
| `bson` | BSON deserialization of TTS save files | `packages/tts` |
| `cheerio` | Workshop browse page scraping | `apps/proxy` |
| `zod` | Runtime validation | `apps/proxy`, `packages/shared` |
### Runtime constraints
- **`cheerio` is backend-only** — it never appears in `packages/extract`, which
must stay isomorphic.
- **`bson` is Node-only** — used by the fetcher, not the analysis layer.
- **`packages/extract` has zero external runtime deps** — it relies only on
platform `fetch` / `Blob`, keeping it portable to a future frontend.
## Tooling dependencies
- `typescript` (strict), `tsx` (dev runner), `eslint`, `prettier`.
- `pnpm` workspaces for package management.
## Deployment / runtime shape
- The proxy runs as a single Node process via `@hono/node-server`.
- `packages/extract` is published/consumed as a plain ESM module usable from a
browser bundle or Node.
- No shared state between requests; each request fetches fresh.