Framework inventory · read from disk, not memory
Two repos. One stamps client projects, the other holds the rules they inherit. Every count below was read off the filesystem at time of writing.
Every service runs in a container; the toolchain that builds and checks them runs on the host. Documented in stack.md as "Task runner (host)" — deliberate, and confirmed as the intent.
| Layer | Where it runs | What | Status |
|---|---|---|---|
| Application runtime | Docker | api · frontend · worker · scheduler · postgres · redis · db-backup · adminer | containerised |
| E2E stack | Docker | api · frontend · worker · postgres · redis · mailpit · mock-oidc · api-unknown-key | containerised |
| Edge proxy | Docker | traefik · docker-socket-proxy (read-only) | containerised |
| Quality gates | Host | uv run ruff · uv run pyright · uv run pytest · pnpm lint | host toolchain |
| Stamping & scripts | Host | copier · make · openssl · git · node | host toolchain |
The shipped product must be containerised; the build does not. Anything that runs in production — every service, every dependency, the e2e stack — is a container with its state bind-mounted under /workspace/data/<slug>/. The toolchain that compiles and checks it (uv, pnpm, node, copier, make) lives on the host and is installed by setup-host.sh. That keeps the test loop fast and the artifact portable, which is the trade worth making.
Eight domains, all infrastructure a project inherits rather than product code it imitates. Ten migrations, linear, single head.
Row-level security on a non-owner NOBYPASSRLS role. Scope set per transaction; a missing scope raises rather than returning everything. Memberships, invites, domain approvals, per-tenant SSO policy.
Hand-rolled JWT in httpOnly cookies, Argon2 off the event loop, Entra OIDC via PKCE. Admin-created accounts only — no public signup.
/ingest as a mounted sub-app with its own CORS, limiter and OpenAPI. A public token resolves to exactly one tenant and sets the scope.
Presigned multipart straight to S3 — media never streams through the API. Tenant-prefixed keys, one size budget, hourly reaper.
Transactional outbox: enqueue is a row in the caller's transaction, so a rollback emails nobody. Delivers the tokenised invites.
SSE and WebSockets on one engine. A subscription cannot outlive the scope that authorised it — revocation kills an open stream.
Runtime colour theming per tenant. Colour-only by design — type, spacing and motion are build-time. Worth asking whether this belongs in every project.
Liveness and DB reachability. What make health hits through the edge.
Rebuilt to ship capability and vocabulary, and compose nothing a user sees. The design belongs to the project.
shadcn on Base UI (base-nova) straight from the registry — sidebar, table, dialog, chart, dropdown, tooltip, sheet, tabs, select, skeleton.
Colour, type scale, spacing rhythm, motion, elevation, radius. Previously colour-only, which is why nothing composed from it could look designed.
No app shell, no dashboard, no admin panels. Auth skeletons carry no className and import no components — raw HTML with test ids, so there's nothing to inherit.
Now states a bar and four required async states. Two numbers in it (16px card padding, 48px topbar) are prose, not tokens, and will drift.
make gates stops at the first failure. Gates constrain values and correctness, never what a project builds.
1 lint-check ruff check + format --check 2 typecheck pyright, strict 3 check-length ≤1000 source · ≤300 docs · ≤150 CLAUDE.md 4 check-env-docs .env.example ≡ configuration.md 5 check-tenancy every tenant table mixed in, migrated with a policy, scoped 6 check-tokens no raw colours in frontend/src 7 lint-frontend eslint — hooks, a11y, token classNames 8 test pytest + testcontainers (532 passing) 9 client-check generated client in sync with the OpenAPI schema 10 typecheck-frontend vite build + tsc --noEmit 11 e2e playwright, 4-way matrix + visual baselines (117 passing)
Outside the chain, run deliberately:
stack · backend-standards · frontend-standards · docker-topology · repository-structure · naming-and-ports · docs-standards
create-new-project · deploy · add-a-backend-domain · write-a-spec · e2e-and-visual-verification · backup-and-restore · host-operations · enable-entra-sso · run-the-edge-proxy · update-from-the-template · delegate-to-grok · git-remotes
philosophy · architecture · security-model. Thin next to 12 how-tos — the why layer is a third the size of the how.
getting-started only. The quadrant exists but is barely populated.
0001→0027. Stack, tenancy, identity, storage, mail, realtime, ingest auth, real-S3-only, hostname decoupling.
setup-host · new-project · bootstrap-box · git-remotes · backup-offhost · check-sites · docker-prune · install-timers · traefik-config-check · check_doc_length
Not a bug list — these are places the framework is unproven, unfinished, or resting on an assumption nobody has tested.
make backup-now, restore and restore-drill exist and the sidecar runs. No drill has been executed on real data. An untested restore is a hope.
Every app is multi-tenant so it can be copied to another server or handed to a client. Nobody has moved one. The port registry, shared edge and TLS story all assume this host.
Every project shares them. There's no written analysis of what takes everything down at once.
Its trigger is /effort ultracode — something the human does, not the session. The project CLAUDE.md never mentions it. Fix in flight.
Pinned at v0.1.0 against v0.10.0. The upgrade crosses rollback-only sessions, admin-gated auth, tenancy, and the frontend rebuild.
DiMarco is stamped and running but SPEC-001 is untouched. Until that runs, "the spec is the handoff" is a hypothesis.
It is structurally blind to a behaviour with no criterion. Now stated as necessary-not-sufficient, which is honest but not a fix.
make init-env generates and deliberately never overwrites. Rotating a live SECRET_KEY or DB password is undocumented.
16px card padding and 48px topbar sit in a bar doc with nothing enforcing them. They will drift.
| idx | slug | public host | port base | state |
|---|---|---|---|---|
| 0 | edge | — serves all | 10000 | live |
| 1 | gga-reports | gga-reports.gp.basg.dev | 10100 | live · 9 versions behind |
| 2 | pointandtell | pointandtell.gp.basg.dev | 10200 | specs only |
| 3 | dimarco | dmarc.basg.dev | 10300 | stamped · awaiting build |