100 lines
5.0 KiB
Markdown
100 lines
5.0 KiB
Markdown
# STTracker
|
||
|
||
Self-hosted meta media tracker: the user's own permanent record of books, games, film/TV, manga, podcasts
|
||
and music, pulled from Hardcover, Trakt, MangaBaka, ListenBrainz, Last.fm and more. Bun 1.3, TypeScript 5,
|
||
React, Kysely over SQLite (`bun:sqlite`) or Postgres (`Bun.sql`). Bun workspaces.
|
||
|
||
`AGENTS.md` is the single source of truth for agents here. `CLAUDE.md` and `GEMINI.md` only point here.
|
||
Deeper context on demand: `docs/ARCHITECTURE.md`, `docs/DECISIONS.md`, `docs/TODO.md`.
|
||
Product spec: `docs/specs/001-sttracker-v1-design.md`. Read it before any feature work.
|
||
|
||
## Commands
|
||
|
||
Install: `bun install --frozen-lockfile`
|
||
Test: `bun test` | Single test: TODO(maintainer): confirm `bun test <path>` once tests exist
|
||
Typecheck: TODO(maintainer): confirm `bun run typecheck` (fails until source files exist)
|
||
Lint: TODO(maintainer): confirm once a linter is chosen
|
||
Dev / Build: TODO(maintainer): confirm once `apps/server` exists
|
||
|
||
## Workflow
|
||
|
||
Required skills: `superpowers`, `impeccable`. Check at session start; install if missing.
|
||
Specs → `docs/specs/NNN-slug.md` (permanent). Plans → `docs/plans/NNN-slug.md` while in progress;
|
||
`git rm` them before opening a merge request. The spec is the record.
|
||
(Overrides the superpowers default paths.)
|
||
|
||
Anything beyond a trivial fix: brainstorm → spec (sign-off) → plan (sign-off) → TDD → review.
|
||
TDD means failing test first, watch it fail, minimal code, watch it pass, commit.
|
||
Tick plan checkboxes as you go so an interrupted session is resumable.
|
||
Trivial changes (typo, version bump, one-line config): say "trivial, skipping spec" and proceed.
|
||
|
||
Use impeccable for user-facing UI: `craft` for new UI, `audit`/`polish` on existing UI,
|
||
`harden` before shipping. Design context: `PRODUCT.md`, `DESIGN.md`, `docs/design/mockups/`.
|
||
|
||
## Rules
|
||
|
||
- Bun-native only:
|
||
- `Bun.serve()` with HTML imports for the web app. No Express, no Vite.
|
||
- `bun:sqlite` and `Bun.sql`. No `better-sqlite3`, `pg` or `postgres.js`.
|
||
- `bun test`. No Jest or Vitest.
|
||
- `Bun.password`, `Bun.file`.
|
||
- Bun loads `.env` itself. No dotenv.
|
||
- Domain code queries through Kysely from `packages/db`. Dialect-specific SQL lives only in `packages/db`.
|
||
Every DB-touching test must pass on both SQLite and Postgres.
|
||
- Syncs never overwrite or delete user data directly. Source records go through the change engine.
|
||
It applies a value only if `field_sources` says the user never edited the field; anything else
|
||
becomes a Changes-inbox event. Deletes are soft (`deleted_at`).
|
||
- Plugins (`plugins/*`) import only `@sttracker/plugin-sdk`. They never import `packages/db` or core
|
||
internals, and they return `SourceRecord`s instead of writing.
|
||
- `packages/*` and `plugins/*` never import from `apps/*`.
|
||
- IDs are UUIDv7 (`newId()`) generated in app code. Ratings are integers 0–100. Dates carry a precision
|
||
(`day | month | year | unknown`).
|
||
- Tests never call live APIs. Plugin tests use recorded fixtures through the SDK test harness.
|
||
- Write-back (`push`) is opt-in per connection and off by default. No plugin pushes in Phase 1.
|
||
|
||
## Architecture
|
||
|
||
apps/server -> Bun.serve: REST API `/api/v1`, `/ingest/<plugin>`, job worker, serves the web app
|
||
apps/web -> React app via HTML imports
|
||
packages/core -> domain services: entries, matching, change engine, history, export
|
||
packages/db -> Kysely setup, SQLite/Postgres dialects, migrations
|
||
packages/plugin-sdk -> plugin contract, SourceRecord types, http/rate-limit helpers, test harness
|
||
plugins/<id> -> one source integration each
|
||
|
||
Full picture: `docs/ARCHITECTURE.md`. Read it before your first change in a session.
|
||
|
||
## Boundaries
|
||
|
||
Never touch: `docs/design/mockups/` (reference only), `node_modules/`, `data/`.
|
||
Never commit `.env`, secrets, API keys, or recorded fixtures containing real tokens.
|
||
Never force-push, rewrite pushed history, or commit directly to `main`.
|
||
|
||
Ask first: new runtime dependencies · public API, export schema (`sttracker-export/v1`) or
|
||
migration changes after release · auth, token and credential-encryption code · anything destructive
|
||
(`rm -rf`, `git reset --hard`, DB resets) · work the approved plan does not cover.
|
||
|
||
If the task turns out much larger than the plan assumed: stop, report, re-plan.
|
||
|
||
## Docs duties
|
||
|
||
Same commit as the code, not "later":
|
||
- `docs/ARCHITECTURE.md`: when a module, boundary, or data flow changes.
|
||
- `docs/DECISIONS.md`: append-only; any choice a future maintainer would reverse-engineer.
|
||
- `docs/TODO.md`: anything noticed and deliberately not fixed. No `TODO` comments in source.
|
||
- `docs/PERMISSIONS.md`: together with `.claude/settings.json`, `.codex/` and `.gemini/settings.json`, in one commit.
|
||
|
||
## Git
|
||
|
||
Branches: `feat|fix|chore/<slug>`. Commits: Conventional Commits. Keep them small, each leaving tests green.
|
||
|
||
## Done means verified
|
||
|
||
Do not report success on work you have not run. Before saying done, all of these must hold:
|
||
- tests run *in this session* and seen passing, on both databases for DB code;
|
||
- typecheck clean;
|
||
- matches the approved spec;
|
||
- docs duties complete;
|
||
- `git status` clean and the diff is only what you intended.
|
||
|
||
"It should work" is not verification.
|