← Alter Wiki

Architecture

Eleven services, REST-only boundaries, no shared databases, and why the numbers look the way they do.


Alter is eleven TypeScript services with REST-only boundaries and no shared databases. Each service also carries a hard budget of at most fifteen dependencies. A rule that ends up shaping a lot of decisions (it’s why the error-tracking client is hand-rolled and the compilation queue is plain Postgres).

ServiceWhat it does
alter-linkAPI gateway, auth (JWT + Google OAuth), billing
alter-mindAI orchestration: recognition, the five modes, briefing, the provider abstraction
alter-memoCaptures, mode states, artifacts, chat, the Activity read model, SSE proxying
alter-wikiThe wiki substrate, compilation queue, briefing pipeline
alter-vectorsEmbeddings + semantic/hybrid search (pgvector)
alter-dataSchema management, 111 migrations and counting
alter-cryptoStateless AES-256-GCM encryption
alter-traceAudit log, telemetry, privacy guards, the journey read model
alter-vaultS3-compatible file storage with pluggable connectors
alter-portalThe Next.js front-end
alter-service-uiShared dashboard components

The stack, briefly: NestJS 11 and TypeScript 5.9 (strict, no any in new code), Next.js 15 + React 18, PostgreSQL with pgvector, Redis with Bull queues, and SSE for streaming; LLM tokens are piped as NDJSON from alter-mind through alter-memo to the browser, with one shared streaming helper reused across four modes.

Services don’t trust each other by default. Every service-to-service call carries a shared internal credential, added in a security remediation phase after an audit found the boundaries were only conventionally enforced: a REST boundary with no authentication on it is a diagram, not a wall.

Two read models sit beside the write path rather than in it. Activity, the receipt trail, is composed by alter-memo over the content-bearing tables, deliberately not over the telemetry event log, because the privacy invariant forbids content in events and a receipt without content is useless. The journey read model in alter-trace is the mirror image: derived entirely from the event spine, no content, for watching how the system behaves rather than what it holds.

For scale: ~289K lines of TypeScript across 2,171 files, about 40% of it tests, with 750 test files, 29 end-to-end paths, and roughly 1,270 commits over nine months.