# 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/web` | React frontend: search + mod pages | Browser | | `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/web ──► apps/proxy ──► packages/tts ──► packages/shared │ │ │ │ │ └──► (fetchMod → TTSMod) │ ▼ └──► packages/extract ──► packages/shared (types) ``` ### Edges - **`apps/web` → `apps/proxy`** — calls `/search`, `/items/:id`, and `/items/:id/file` over HTTP. - **`apps/web` → `packages/extract`** — uses `flattenObjects` / `collectRefs` to analyze a loaded `TTSMod` in the browser. - **`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`. - `vitest` (unit tests), colocated as `*.test.ts` next to sources. - `vite`, `@vitejs/plugin-react`, `tailwindcss`, `@tailwindcss/vite` — frontend build/dev tooling. - `pnpm` workspaces for package management. ## Deployment / runtime shape - The proxy runs as a single Node process via `@hono/node-server`. - `apps/web` is a static Vite build served separately; during development it proxies `/search`, `/items`, and `/health` to the proxy. - `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.