What's built today
This page is the honest inventory of the codebase. architecture/strategy and
architecture/technical-architecture describe the target design — they are product and
architecture documents, and reading them alone will overstate how much exists. Everything on this
page was verified against the source tree, not taken from the other documents.
Legend: Built = implemented and exercised. Partial = some of it is real, the rest is a scaffold or has no caller. Not started = design only.
Foundation (M0 — the base data layer)
This is where the actual engineering investment is, and it is in good shape.
| Area | Status | Where |
|---|---|---|
Postgres 18 with pgvector + Apache AGE, built from source | Built | infra/postgres/, docker-compose.yml |
| 34-table Drizzle schema + 6 migrations | Built | packages/db/src/schema/, packages/db/migrations/ |
| Shared-schema multi-tenancy with Postgres RLS on 19 tables | Built (tested) | packages/db/src/schema/index.ts, client.ts |
| Restricted non-superuser runtime DB role | Built | appRoleSetupSql() in schema/index.ts |
| Better Auth (email/password, organization plugin, 4 roles) | Built | apps/api/src/auth.ts |
| Tenant resolution from session, not a header | Built | apps/api/src/middleware/tenant.ts |
| Role-level RBAC on every write route | Built | apps/api/src/middleware/require-permission.ts |
| Attendance-marking authorization beyond role (faculty assignment) | Built | apps/api/src/routes/attendance.ts |
| Audit trail written atomically with every tenant-scoped write | Built (tested) | packages/db/src/mutation-service.ts |
| Tenant-defined custom fields (no migration needed) | Built | custom_field_definitions + /custom-fields |
| Base-data write APIs (people, org structure, enrollments, employment) | Built | apps/api/src/routes/ |
| Legacy CampusStack import (real org, students, staff, curriculum, attendance) | Built | packages/db/src/import/ |
| Admin UI: org structure, people, curriculum, attendance, settings | Built | apps/web/src/routes/admin.* |
| CI on real Postgres + AGE (typecheck + test + migrations) | Built | .github/workflows/ci.yml |
| Containerised deployment: one app image, production compose, Caddy TLS | Partial — builds and runs; containers verified individually, but TLS/DNS and the full stack have not been run | Dockerfile, docker-compose.prod.yml, Caddyfile, Deploying to a VPS |
| Internal services authenticated (agents, credentials) | Built (tested) | packages/internal-auth/, wired into both services |
| Automated tests | Partial — 4 files, 25 tests | packages/db/src/rls.test.ts, mutation-service.test.ts, apps/api/src/middleware/require-permission.test.ts, packages/internal-auth/src/index.test.ts |
| Lint | Partial — biome.json exists but nothing invokes Biome; only apps/site has a lint script | biome.json |
The module engine is half-built
module_definitions holds the 20 KIOT modules (M1–M20) as JSONB metadata, seeded by
packages/db/src/seed.ts, and /modules serves them. What does not exist yet is the generic
consumer: no route or form renders itself from a module definition, and moduleEntitlements
(which modules a tenant has licensed) has no write UI. Today's endpoints are still hand-written per
entity. So "adding module #21 is a configuration row, not code" is true at the storage layer and
not yet true at the surface layer.
Pillars
| Pillar | Status | Notes |
|---|---|---|
| 1 — Institutional knowledge graph | Partial | Apache AGE is live, runTenantScopedCypher enforces tenant-pre-filtering, and there is a real write path (graph-sync.ts: Person/Department/Branch/Batch/ClassSection/Subject vertices, ENROLLED_IN/TEACHES edges) called inside the same transaction as the relational write. Vector search is not wired: tenantScopedVectorSearch exists but has zero callers and there is no embeddings table in the schema. |
| 2 — Always-audit-ready compliance engine | Not started | No policy-as-code layer, no policy evaluation, no evidence records. The audit_log table is an audit trail, not a compliance engine. |
| 3 — Institutional digital twin | Not started | No simulation layer. |
| 4 — Agent-native operating model | Partial | One Mastra agent (iqac-agent) with one tool that runs a tenant-scoped Cypher query. No A2A, no agent-to-agent delegation, no governance-approval gate, no capability cards. See Agents for a caveat on its memory wiring. |
| 5 — Verifiable credentials | Partial | apps/credentials issues a W3C VC via Veramo with a jwt proof. No DID creation, no key management (the VERAMO_KMS_SECRET env var is declared but unused), no revocation, no storage of issued credentials. |
| M4 workflow engine | Partial (scaffold) | DBOS launches and pg-boss starts, one XState machine and one workflow class exist — but nothing invokes the workflow, and the code says the DBOS decorator API should be re-verified. See Workflow. |
| Real-time / IoT (M13) | Not started | NATS_URL is declared in .env.example; there is no NATS client anywhere in the tree. |
/portal/* self-service surfaces | Not started | apps/web is admin-only, by deliberate scoping. |
| Mobile (Flutter) | Not started | — |
Test coverage in detail
Four test files, and the split matters:
packages/db/src/rls.test.ts— the highest-value test in the repo. Creates two synthetic tenants and proves tenant A cannot read tenant B's row even by exact ID, that tenant B can read its own, and that a query with no tenant context set denies all rows (fails closed). It deliberately usesdepartmentsas a stand-in for all 19 RLS-covered tables, since they share one policy shape.packages/db/src/mutation-service.test.ts— confirms the audit row is written atomically with the data write.apps/api/src/middleware/require-permission.test.ts— confirms each role gets exactly the accessauth.tsdeclares, through a real Better Auth sign-in rather than a mock.packages/internal-auth/src/index.test.ts— the internal-service token and tenant checks, against a real Hono app mounted the same way the services mount it. This is the one file that needs no database, which is the point of keeping that package free of@campus/db.
The first three need Postgres and a loaded .env; they are integration tests by design, because RLS
and Better Auth are enforced outside the application. The test scripts pass --env-file=../../.env
themselves, so bun run test works from the repo root.
There are no route-level or HTTP integration tests for apps/api, which
docs/M0_REMAINING_TASKS.md calls out as a deliberate, lower-priority gap rather than an oversight.
That gap is what let the read-side authorization hole in
API Surface go unnoticed.
What is not claimed anywhere
To be explicit, since these are easy to assume from the architecture docs: there is no compliance
engine, no simulation layer, no real-time dashboard, no mobile app, no NLP/chat interface for
end-users, and no LLM feature reachable from apps/web. The only AI code path in the running
system is an HTTP endpoint on apps/agents that is not called by any other service or UI.