Files
STTracker/docs/ARCHITECTURE.md
T

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:

  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.