quartermaster/CLAUDE.md

130 lines
5.2 KiB
Markdown
Raw Normal View History

# Quartermaster (repo instructions)
## Database safety rule
The SQLite database at `./quartermaster.db` (or whatever path
`QUARTERMASTER_DB_URL` points at) holds real user data. It is
`.gitignored`, so losing it means the data is gone.
**Before any operation that interacts with the database at the schema
or destructive level**, run:
```sh
./scripts/backup-db.sh <reason>
```
That includes:
* `rm`, `mv`, truncate, or otherwise replace `quartermaster.db`
* Ad-hoc `sqlite3` sessions that might `DROP`, `DELETE`, or `UPDATE`
* Any script that does data migration or cleanup outside the running
application
Alembic runs `scripts/backup-db.sh alembic` automatically on every
`alembic upgrade`, `alembic downgrade`, or `alembic revision --autogenerate`
via the hook in `alembic/env.py`, so you do not need to call it
manually for ordinary schema work. The hook is defense in depth, not
a substitute for thinking.
Routine writes through the running web application are NOT covered by
this rule. Those are normal application behaviour, not "interactions"
in the sense meant here.
## Where backups go
Default: `<dir-of-db-file>/backups/quartermaster-YYYYMMDD-HHMMSS-{slug}.db`.
For the standard `./quartermaster.db` that resolves to `./backups/`.
Override with `QUARTERMASTER_BACKUP_DIR=/some/path`.
The `backups/` directory is `.gitignored`. Retention is forever:
backups are small. Prune manually if you need to.
## Restoring
A backup is a complete SQLite file. To restore, stop the app, replace
`quartermaster.db` with the chosen backup (`cp backups/... quartermaster.db`),
then restart.
2026-04-17 17:58:20 -06:00
## Current Project State
* **Phase**: shipped MVP + posting ledger + template-entry edit +
platform-deploy prep (`/healthz`, structured JSON logs). Working
daily-use tool; first production deploy to home-ctr-onyx pending.
* **Last worked on**: 2026-04-19
* **Last commit on main**: `1296258` — chore: silence jsonlogger
deprecation, fix LogQL example (#26, #27)
2026-04-17 17:58:20 -06:00
* **Open PRs**: none
* **Open issues**: #28 Dockerfile, #29 compose.yml, #30 Forgejo
Actions deploy workflow (dependency-chained); #31 small cleanups
(non-blocking polish)
* **Test count**: 148 / 148 passing
* **Migrations**: 5 applied; latest `cc60e7f73a1c` (no schema change
in #26 or #27)
2026-04-17 17:58:20 -06:00
* **Blocking issues**: none
After pulling new work, always:
```sh
uv run alembic upgrade head
```
The backup hook fires before any migration, so this is safe against
the live DB.
## Session Log
Most recent 3 sessions (full history in the [wiki](https://forgejo.labbity.unbiasedgeek.com/archeious/quartermaster/wiki)).
### Session 2 — 2026-04-19
Platform contract intake (#25) filled out and accepted; platform team
provisioned DNS (`quartermaster.unbiasedgeek.com`), Traefik middlewares
(basic-auth + rate-limit), the `/mnt/quartermaster/` bind mount, and
basic-auth creds. Two issues landed on main (#26 `/healthz`, #27
structured JSON logs) via the superpowers brainstorm → spec → plan →
subagent-driven-TDD workflow. Thirteen commits on a single branch
(`feat/platform-deploy-prep`), rebased onto origin/main so history
stays linear despite the unrelated MCP-doc PR that landed alongside.
Key decisions: single-source-of-truth `logconfig.json` (not a Python
dict + YAML shim, which would need `pyyaml` and introduce drift); five
seed app events (`month_created`, `month_closed`,
`template_entry_updated`, `posting_added`, `posting_deleted`) placed
after commit + refresh so they only fire on durable success; `/healthz`
on a dedicated router as a file boundary, with auth living in Traefik
per the platform contract.
Two real misses caught by code review mid-flight: the autouse-fixture
workaround for Task 3's `dictConfig` state leak was wrong (fix: make
the contaminating test save/restore state itself); the third LogQL
example in README used `{{.path}}` on `month_closed` records that
carry `year_month`, not `path`. Both landed as fix commits.
Deploy-pipeline work queued as #28 (Dockerfile), #29 (compose.yml),
#30 (Forgejo Actions), dependency-chained. Polish umbrella at #31.
Full retro: [Session2](https://forgejo.labbity.unbiasedgeek.com/archeious/quartermaster/wiki/Session2).
2026-04-17 17:58:20 -06:00
### Session 1 — 2026-04-17
Greenfield to working ledger. 10 PRs merged in one sitting:
scaffold (#2) → monthly view with snapshot + deviation (#4) →
backups + CLAUDE.md safety rule (#6) → zero amount header (#8) →
gitignore wiki (#10) → section groups + sinking funds (#12) →
notes field (#14) → month lifecycle Planning / Active / Closed
(#16) → UI redesign in Barlow Condensed with logo (#18) →
posting transaction ledger (#20).
Key architectural decisions: snapshot-over-mirror for months;
Primary Debt Target is a pointer, not a pre-allocated amount;
nothing auto-sweeps — close requires applied zero at $0; `applied`
is derived from postings only, no column. UI went through three
mockups before settling on Barlow Condensed + cream paper +
burgundy accent sampled from the logo shield.
One incident: I wiped the live DB several times during early dev
churn before the backup script existed. The script + alembic hook
+ repo-level CLAUDE.md safety rule are the fix.
Full retro: [Session1](https://forgejo.labbity.unbiasedgeek.com/archeious/quartermaster/wiki/Session1).