docs(architecture): add routes_health, logging_config, /healthz to module + route maps
parent
8f3bd78a14
commit
dd3ffd3453
1 changed files with 75 additions and 34 deletions
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
Small FastAPI app rendering Jinja2 templates with HTMX-driven partial
|
||||
updates. SQLite is the only storage. SQLAlchemy 2.x is the ORM; Alembic
|
||||
manages schema. `uv` manages Python deps.
|
||||
manages schema. `uv` manages Python deps. Structured JSON logging to
|
||||
stdout is the runtime-observability contract; see
|
||||
[Operations](Operations).
|
||||
|
||||
## Modules
|
||||
|
||||
|
|
@ -11,12 +13,15 @@ src/quartermaster/
|
|||
main.py FastAPI app factory
|
||||
routes.py Budget configuration HTTP handlers
|
||||
routes_month.py Monthly view HTTP handlers
|
||||
routes_health.py GET /healthz (unauthenticated, separate router)
|
||||
service.py Budget queries, totals, target, zero-amount, group views
|
||||
month_service.py Month snapshot, deviation, per-month CRUD, lifecycle, group views
|
||||
groups.py Group enum, labels, section->group mapping, default open
|
||||
models.py SQLAlchemy models, Section enum, MonthState enum
|
||||
db.py Engine, session, PRAGMA foreign_keys=ON
|
||||
config.py DB URL resolution
|
||||
logging_config.py Loads LOG_CONFIG from logconfig.json; AccessLogFilter
|
||||
logconfig.json dictConfig source-of-truth (tests + uvicorn both consume)
|
||||
templates/ Jinja2 templates (base, index, month, partials)
|
||||
static/
|
||||
app.css Full stylesheet (Barlow Condensed + ledger layout)
|
||||
|
|
@ -195,7 +200,7 @@ Colour tone:
|
|||
GET / index page
|
||||
POST /sections/{section}/entries add entry
|
||||
DELETE /entries/{entry_id} remove entry
|
||||
POST /entries/{entry_id}/notes update entry notes
|
||||
POST /entries/{entry_id}/save update entry (name, amount, notes)
|
||||
POST /debt-target set / clear debt target
|
||||
```
|
||||
|
||||
|
|
@ -229,6 +234,18 @@ All mutation routes return the section partial plus OOB swaps for:
|
|||
OOB is used so section-level changes keep the page-level summary widgets
|
||||
accurate without a reload.
|
||||
|
||||
### Health (`src/quartermaster/routes_health.py`)
|
||||
|
||||
```
|
||||
GET /healthz liveness + DB reachability (unauthenticated)
|
||||
```
|
||||
|
||||
Separate router, zero app-level dependencies. Success: 200
|
||||
`{"status":"ok"}`. Failure: 503
|
||||
`{"status":"error","detail":"<exception-class-name>"}` — class name
|
||||
only, no message or traceback leaked. A failed probe emits a
|
||||
structured warning log with `event=healthz_failed`, `error_class=<cls>`.
|
||||
|
||||
## HTMX conventions
|
||||
|
||||
* Month entry rows carry inline inputs for `name` and `planned` plus a
|
||||
|
|
@ -252,6 +269,23 @@ accurate without a reload.
|
|||
and the server returns 204 + `HX-Redirect: /month/{year_month}` so the
|
||||
page re-renders cleanly in the new state.
|
||||
|
||||
## Observability
|
||||
|
||||
See [Operations](Operations) for the Logs and Health sections. Brief
|
||||
summary:
|
||||
|
||||
* `src/quartermaster/logconfig.json` is the single source of truth for
|
||||
the `logging.config.dictConfig`. Loaded into `LOG_CONFIG` in
|
||||
`logging_config.py` at import time; same file read by uvicorn CLI
|
||||
via `--log-config`.
|
||||
* Formatter: `pythonjsonlogger.json.JsonFormatter` with `rename_fields`
|
||||
mapping `asctime/levelname/name` → `timestamp/level/logger`.
|
||||
* `AccessLogFilter` in `logging_config.py` enriches uvicorn access
|
||||
records with `event="http_request"`, `method`, `path`, `status`,
|
||||
`client_ip`.
|
||||
* Five seed app events at the main mutation sites plus one
|
||||
`healthz_failed` event at the probe.
|
||||
|
||||
## Visual identity
|
||||
|
||||
* **Typography**: Barlow Condensed (300-800 + italic) imported from
|
||||
|
|
@ -276,7 +310,7 @@ accurate without a reload.
|
|||
5-column summary grid (caret / name / planned / applied / actions).
|
||||
The 2px progress bar rides the summary's bottom border.
|
||||
* Budget entry rows use `table.entries` with a 4-column grid.
|
||||
* `.target-section` with a burgundy left bar and `↳` margin glyph
|
||||
* `.target-section` with a burgundy left bar and ↳ margin glyph
|
||||
* `.state-badge` tracked-caps label with bullet separators
|
||||
|
||||
## Testing
|
||||
|
|
@ -286,4 +320,11 @@ accurate without a reload.
|
|||
share the same in-memory engine across threads via `StaticPool`.
|
||||
* Backup script tests shell out and assert on filenames and sqlite
|
||||
round-trips.
|
||||
* Full suite runs in under 4 seconds.
|
||||
* Logging tests instantiate the JSON formatter from `LOG_CONFIG`
|
||||
directly, push a record through a `StringIO` handler, assert on the
|
||||
parsed output. `AccessLogFilter` is tested with a synthetic uvicorn
|
||||
`LogRecord`. Seed events are tested via `caplog`. The dictConfig
|
||||
smoke test saves / restores logger state in a try/finally so it
|
||||
cannot leak `propagate=False` to subsequent tests.
|
||||
* `/healthz` is tested with and without a failing session.
|
||||
* Full suite (148 tests) runs in under 6 seconds.
|
||||
|
|
|
|||
Loading…
Reference in a new issue