Files
STTracker/docs/ARCHITECTURE.md
T

45 lines
2.7 KiB
Markdown

# Architecture
How STTracker is built today. Update in the same commit as any structural change.
## Overview
Status 2026-10-30: only the workspace skeleton exists (root `package.json`, `tsconfig.json`).
The target design is in `docs/specs/001-sttracker-v1-design.md` §11. Replace each "planned" marker below as the code lands.
One Bun process serves the REST API, the React web app and plugin ingest endpoints, and runs a
database-backed job worker. Source plugins pull data from platforms and return normalised `SourceRecord`s.
The core snapshots them, diffs against the previous run, matches them to works, and either applies them to the
user layer or files a Changes-inbox event.
## Map
| Path | Responsibility | State |
|---|---|---|
| `apps/server` | `Bun.serve`: `/api/v1`, `/ingest/<plugin>`, job worker, static web | planned |
| `apps/web` | React app (HTML imports) | planned |
| `packages/core` | domain services, one module per area (import by path, no barrel): `auth`, `crypto`, `works`, `matching`, `entries` (entries, library listing, quick add, per-user moves, match suggestions), `engagements`, `history` (`user_history`, restore), `lists`, `copies`, `custom-fields`, `attachments`, `export` (per-user bundle, CSV, restore), `backup` (scheduled bundles + SQLite `VACUUM INTO`). Change engine planned | exists (partial) |
| `packages/db` | Kysely over one Bun.SQL dialect (SQLite + Postgres), ids, JSON helpers, migrations, `forEachDialect` test harness | exists (schema pending) |
| `packages/plugin-sdk` | plugin contract, `SourceRecord`, http/rate-limit helpers, fixture test harness | planned |
| `plugins/<id>` | one source integration each (hardcover, trakt, mangabaka, listenbrainz, lastfm, csv) | planned |
| `docs/design/mockups` | approved UI mockups (reference only) | exists |
## Data flow
Planned sync lifecycle:
1. The scheduler enqueues a job.
2. The worker loads the plugin and calls `pull` or `pullChanges` with an SDK context.
3. The plugin returns `SourceRecord[]`.
4. The core stores a new `source_record_versions` row for each changed hash and diffs the records into `change_events`.
5. Each event is either auto-applied (new record, or a field never edited by the user) or sent to the inbox.
6. Every user-layer write appends to `user_history`.
## External dependencies
- Database: SQLite file under `DATA_DIR` (default) or Postgres via `DATABASE_URL`. If unavailable, nothing works.
- Platform APIs (Hardcover, Trakt, MangaBaka, ListenBrainz, Last.fm). If unavailable, only that source's sync fails; the run is logged and retried.
## Invariants
- A sync never overwrites or hard-deletes user-entered data (spec §8.3).
- Plugins never touch the database.
- All domain behaviour is identical on SQLite and Postgres.
## Known rough edges
None yet. See `docs/TODO.md`.