BASG Framework — Full Map

Framework inventory · read from disk, not memory

BASG framework — everything that exists, and what's thin

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.

core-workspace org rules + docs core-template v0.10.0 27 ADRs 11 gates 8 backend domains 10 migrations
Built & verified Thin — exists, not proven or not complete Missing or unresolved

Docker: the product ships in containers, the build does not

settled

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.

LayerWhere it runsWhatStatus
Application runtimeDocker api · frontend · worker · scheduler · postgres · redis · db-backup · adminer containerised
E2E stackDocker api · frontend · worker · postgres · redis · mailpit · mock-oidc · api-unknown-key containerised
Edge proxyDocker traefik · docker-socket-proxy (read-only) containerised
Quality gatesHost uv run ruff · uv run pyright · uv run pytest · pnpm lint host toolchain
Stamping & scriptsHost copier · make · openssl · git · node host toolchain

Settled: this split is the intent

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.

Backend — the 90%

core-template

Eight domains, all infrastructure a project inherits rather than product code it imitates. Ten migrations, linear, single head.

tenancy

15 files · 3,342 lines

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.

auth

15 files · 2,650 lines

Hand-rolled JWT in httpOnly cookies, Argon2 off the event loop, Entra OIDC via PKCE. Admin-created accounts only — no public signup.

apikeys

11 files · 1,659 lines

/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.

storage

20 files · 1,570 lines

Presigned multipart straight to S3 — media never streams through the API. Tenant-prefixed keys, one size budget, hourly reaper.

mail

18 files · 1,256 lines

Transactional outbox: enqueue is a row in the caller's transaction, so a rollback emails nobody. Delivers the tokenised invites.

realtime

5 files · 865 lines

SSE and WebSockets on one engine. A subscription cannot outlive the scope that authorised it — revocation kills an open stream.

theming

7 files · 501 lines

Runtime colour theming per tenant. Colour-only by design — type, spacing and motion are build-time. Worth asking whether this belongs in every project.

health

3 files · 52 lines

Liveness and DB reachability. What make health hits through the edge.

core/rlscore/tenancycore/db core/depscore/config + config_checkscore/security core/workercore/ratelimitcore/revalidation core/storagecore/mailcore/realtime core/exceptionscore/logging

Frontend — rails only

rebuilt at v0.10.0

Rebuilt to ship capability and vocabulary, and compose nothing a user sees. The design belongs to the project.

27 primitives

components/ui

shadcn on Base UI (base-nova) straight from the registry — sidebar, table, dialog, chart, dropdown, tooltip, sheet, tabs, select, skeleton.

token vocabulary

brand.css + globals.css

Colour, type scale, spacing rhythm, motion, elevation, radius. Previously colour-only, which is why nothing composed from it could look designed.

zero composed screens

blocks/ is empty

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.

design guidance

frontend-standards.md

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.

Enforcement

11 gates, in order

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:

check-no-prescription — template-only; fails a real project by design storage-conformance — real S3, credentialed, skips loudly verify-spec / lint-spec check-ledger test-tooling restore-drill

Org layer

core-workspace

docs/reference

7 files

stack · backend-standards · frontend-standards · docker-topology · repository-structure · naming-and-ports · docs-standards

docs/how-to

12 files

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

docs/explanation

3 files

philosophy · architecture · security-model. Thin next to 12 how-tos — the why layer is a third the size of the how.

docs/tutorials

1 file

getting-started only. The quadrant exists but is barely populated.

docs/decisions

27 ADRs

0001→0027. Stack, tenancy, identity, storage, mail, realtime, ingest auth, real-S3-only, hostname decoupling.

scripts

12 files

setup-host · new-project · bootstrap-box · git-remotes · backup-offhost · check-sites · docker-prune · install-timers · traefik-config-check · check_doc_length

What I'd call thin

honest list

Not a bug list — these are places the framework is unproven, unfinished, or resting on an assumption nobody has tested.

  1. Nothing has ever been restored from a backup.

    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.

  2. Portability is claimed, never exercised.

    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.

  3. One server, one Docker daemon, one edge proxy.

    Every project shares them. There's no written analysis of what takes everything down at once.

  4. The orchestration rule doesn't bind.

    Its trigger is /effort ultracode — something the human does, not the session. The project CLAUDE.md never mentions it. Fix in flight.

  5. gga-reports is 9 template versions behind.

    Pinned at v0.1.0 against v0.10.0. The upgrade crosses rollback-only sessions, admin-gated auth, tenancy, and the frontend rebuild.

  6. No project has been built end-to-end by a cold session yet.

    DiMarco is stamped and running but SPEC-001 is untouched. Until that runs, "the spec is the handoff" is a hypothesis.

  7. verify-spec can only score what someone wrote down.

    It is structurally blind to a behaviour with no criterion. Now stated as necessary-not-sufficient, which is honest but not a fix.

  8. Secrets have no rotation path.

    make init-env generates and deliberately never overwrites. Rotating a live SECRET_KEY or DB password is undocumented.

  9. Two design numbers are prose, not tokens.

    16px card padding and 48px topbar sit in a bar doc with nothing enforcing them. They will drift.

Projects on this host

PORTS.md
idxslugpublic hostport basestate
0edge— serves all10000live
1gga-reportsgga-reports.gp.basg.dev10100live · 9 versions behind
2pointandtellpointandtell.gp.basg.dev10200specs only
3dimarcodmarc.basg.dev10300stamped · awaiting build