2.4 KiB
2.4 KiB
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 SourceRecords.
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: entries, matching, change engine, history, export | planned |
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:
- The scheduler enqueues a job.
- The worker loads the plugin and calls
pullorpullChangeswith an SDK context. - The plugin returns
SourceRecord[]. - The core stores a new
source_record_versionsrow for each changed hash and diffs the records intochange_events. - Each event is either auto-applied (new record, or a field never edited by the user) or sent to the inbox.
- Every user-layer write appends to
user_history.
External dependencies
- Database: SQLite file under
DATA_DIR(default) or Postgres viaDATABASE_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.