Appearance
Architecture overview
Status: slice 34 · October 2026.
Locus is a multi-service platform for arranging, lending, investing in, and legally reviewing debt in the CEMAC zone. The architecture deliberately separates presentation, durable truth, heavy deterministic computation, and immutable document storage. This page gives the topology, ports, request paths, and a reading map into the rest of the site.
Topology
mermaid
flowchart TB
subgraph clients [Clients]
Bank[locus-web :3000]
Ops[locus-ops :3001]
end
subgraph sor [System of record]
API[locus-backend :5000]
PG[(PostgreSQL)]
Redis[(Redis)]
end
Workers[locus-workers :8000]
R2[(Cloudflare R2)]
Bank -->|Bearer AuthSession| API
Ops -->|Bearer AuthSession| API
API --> PG
API --> Redis
API -->|analyze / OCR| Workers
Bank -->|tenant PDFs| R2
Ops -->|vault PDFs| R2
API -.->|artifact meta| R2Additional edges not drawn above:
locus-webalso callslocus-workersdirectly for OCR escalation (POST /api/v1/ocr, viaLOCUS_WORKER_URL) when native text and printable-harvest extraction are insufficient.locus-webuses Redis (BullMQ) forDOCUMENT_OCR,CONTRADICTION_SCAN, andMEMO_COMPILATIONjobs;locus-backenduses Redis forRedisAnalysisJobStore.- The backend can host the Watchtower loop (
LEGAL_VAULT_WATCHTOWER_INTERVAL_MINUTES), which fetches regulator listing pages. - An optional LLM provider (
COPILOT_LLM_PROVIDER) is called fromlocus-webfor prose polish only.
Services and ports
| Service | Role | Default port | Stack |
|---|---|---|---|
locus-web | Bank UI (/workspace/*) + BFF /api/locus/*, auth cookie mint, document upload, copilot, exports proxy | 3000 (Docker image defaults PORT=3002) | Next.js 15 App Router, React 19, TypeScript, Bun tests |
locus-ops | Platform operator UI + regulatory / access-request / market BFF | 3001 | Next.js 15, Bun |
locus-backend | System of record API, EF Core, migrations, seed (off by default), Watchtower host | 5000 | ASP.NET Core 10, EF Core, Npgsql |
locus-workers | OCR (Tesseract fra+eng), SYSCOHADA extract, full analysis, fixed-income math | 8000 | Python 3.12, FastAPI |
| PostgreSQL | Relational state, RLS, FTS | 5432 | Coolify managed in production |
| Redis | Durable queues / job store | 6379 | Coolify managed in production |
| Cloudflare R2 | Immutable PDFs (S3 API) | — | Tenant deal room + platform vault |
Local start: Deploy & environment (./start-services.sh launches workers, backend, and web; start locus-ops separately).
Request paths you should know
Authenticated bank request
text
Browser → middleware (locus_session ticket)
→ /workspace/** SSR or /api/locus/* BFF
→ requireBffSession + enforceRbacGuard (+ Zod validation)
→ Authorization: Bearer <sessionId> + X-Organization-Id (from session)
→ locus-backend InstitutionalAuthMiddleware → claims → controller RequirePermission
→ EF query filters + FORCE RLS GUCs → PostgreSQLDossier → OCR → analysis
text
Deal Room upload → SHA-256 → R2 (encrypted) → POST /api/documents
→ extract pages (native | harvest | Tesseract worker) → ExtractedPages + Citations
→ SYSCOHADA cells / ratios → FinancialStatements, ExtractedCells, RatioSnapshots
Enqueue analysis (POST /api/locus/deals/{id}/analysis → 202 + Location)
→ AnalysisOrchestrator → Python worker /api/v1/analyze
→ Contradictions, Blockers, Alerts; poll /api/locus/analysisjobs/{jobId}Full detail: Dossier → OCR → analysis. Analysis jobs replaced the old synchronous child_process.exec() bridge: long workloads (30 s – 4 min) return 202 Accepted and are tracked QUEUED → PROCESSING → COMPLETED; the worker returns a typed AnalysisResult (metrics, covenants, findings, sources, artifacts). Next.js never spawns OS subprocesses.
Platform operator request
text
locus-ops (locus_ops_session) → requireOpsSession → SoR /api/admin/regulatory/* | /api/access-requests/* | /api/market/ingest
→ PLATFORM_OPERATOR + system:manage → platform legal tables / onboarding / tenant-targeted market ingestTenant read of platform law
text
Bank finding carries vault ids → GET /api/legal-vault/resolve → open-statute BFF
→ hash-verified PDF stream (regulatory:read)Monorepo layout
text
locus/
├── locus-web/ # Next.js bank app (UI + BFF + TS domains + copilot)
├── locus-ops/ # Next.js ops app (vault, onboarding, market ingest)
├── locus-backend/ # ASP.NET Core SoR (controllers, EF, migrations, seed)
├── locus-workers/ # Python FastAPI (OCR, extract, analyze, FI)
├── docs-site/ # This documentation (VitePress)
├── docs/ # Legacy markdown stubs → point here
├── data/regulatory/ # CI vault fixtures (not production law)
├── config/regulatory-sources/
├── scripts/ # attach-vault-fixtures.sh, backup-and-migrations-verify.sh, fixture generator
├── run-all-tests.sh · start-services.sh
└── IMPLEMENTATION_TRACKER.mdDesign principles
- C# SoR owns durable state; Next never opens Postgres directly for product writes.
- Bearer session > spoofable headers (dev headers only when
Auth:AllowDevHeaders). - Fail closed — empty tenant stays empty; no cross-tenant demo injection; production refuses plaintext documents and in-memory queues.
- Zero LLM math — ratios, contradictions, FI pricing are deterministic code; the LLM only polishes prose.
- Human publish gate for legal editions — discovery ≠ in-force law.
- Two libraries, never mixed — platform statutory vault vs tenant deal room.
- One engine, many editions — editions switch modules and home questions; they do not fork business logic.
Design decisions (rationale)
- C# SoR instead of Prisma inside Next — clean UI / durable-truth split,
AuthSessions, tenant filters in EF, institutional migrations. - Bearer session instead of spoofable headers — org and role come from the session at both BFF and SoR.
- R2 instead of local disk — private object vault, checksums, presigned or proxied reads.
- Workers in Python — quant, PDF, curve ecosystem; C# orchestrates and persists.
- Copilot = tools + retrieval + optional LLM — suitable for credit committees; no hallucinated DSCR.
Reading map
| If you are… | Start with | Then |
|---|---|---|
| New to the product | What Locus is | How to read, Glossary |
| Changing a service | The service page: web · ops · backend · workers | The matching flow |
| Touching auth or permissions | Trust boundaries | Auth & sessions, Security |
| Touching persistence | Data stores | locus-backend |
| Working on analysis | Dossier → OCR → analysis | SYSCOHADA & ratios, Contradictions, Citations |
| Working on legal text | Legal vault & Watchtower | Regulatory analyze, Regulatory fixtures, Regulatory admin |
| Operating the platform | Ops overview | Access requests, Market ingest, Deploy |
| Explaining a screen | Workspace route map | Full guide |
| Deploying | Deploy & environment | OCR override SOP, Doc map & deferred work |