Database Wrapper Architecture & Specs
A hyper-optimized kernel interceptor featuring a JavaScript Proxy router, 3-Stage Role-Based Access Control (RBAC), and Holographic Temporal time travel.
System & Interception Metrics
Proxy Routing Overhead
<0.001ms latency
Temporal Diffing
Fast RFC 6902 JSON patching
Multi-Tenant Scoping
Mathematically enforced `tenantId`
RBAC Processing
Pre-compiled Filter AST
1. The JS Proxy Router
Developers should not have to context-switch between high-level collection APIs and low-level SQL builders. A native JavaScript Proxy sitting in front of ctx.db solves this.
- Smart Routing: When a developer calls ctx.db.find, the Proxy intercepts the property access. It identifies it as a Collection method and routes it to the security-enforced Collection interface. If they call ctx.db.select(), the proxy falls through directly to the raw Drizzle ORM.
- Type Safety: The TypeScript compiler treats ctx.db as a union of the raw Drizzle client and the Collection API, providing perfect IDE autocomplete for both operational paradigms simultaneously.
2. Holographic Temporal State
Aeion OS moves beyond simple "UpdatedAt" timestamps by treating the database holographically (Event Sourcing Lite).
- RFC 6902 Patching: When temporal tracking is enabled on a collection, every mutation is intercepted before it commits. The engine calculates the diff between the old record and the new payload, generates a strict RFC 6902 JSON patch, and saves it to the temporal event store.
- Time-Travel Queries: Developers can reconstruct a record's exact state at any past moment by asking for it as-of a timestamp — the engine replays the sequence of JSON patches in reverse to rebuild that historical state on demand.
- Why reverse patches, not full snapshots: Storing a complete copy of every row on every write would balloon storage and slow down the hot path. Storing only the minimal RFC 6902 diff keeps writes to a memory-only diff plus a single INSERT, and reconstruction walks patches newest-to-oldest from the current live row — so the common case (querying recent history) touches the fewest patches. The same log powers the .asOf() query modifier, per-document Version History, and admin-driven bulk undo.
3. Structural Multi-Tenant Isolation
Tenant scoping is not a WHERE clause developers have to remember — it is enforced by the Wrapper before a query ever reaches Postgres. The same TypeScript API compiles to one of three physical isolation strategies, chosen per-tenant:
- COLUMN mode (default): All tenants share tables; the
tenantIdpredicate is injected into every WHERE / INSERT / UPDATE / DELETE. Cheapest to operate and efficient for many-tenant SaaS. Because the predicate is added _before_ Drizzle compiles the query, application code cannot construct a cross-tenant read even by mistake. - SCHEMA mode: Each tenant gets a dedicated Postgres schema with a per-tenant search path — stronger physical separation for compliance-sensitive workloads (HIPAA covered entities, EU data residency).
- DATABASE mode: Each tenant gets a dedicated database from a per-tenant connection pool — for white-label deployments that contractually require isolated infrastructure.
Switching modes is a migration, not a code change: the mode is configured per-tenant and applied during schema sync, and the module code above it never changes.
Frequently Asked Questions
No. Module routes receive a `ctx.db` that is the tenant-scoped Wrapper — the `find` / `create` / `update` / `delete` API is the only path, and it auto-injects tenant scope. A raw escape hatch (`sysDb`) exists for the platform's own internal subsystems (the temporal recorder, the migration engine, Aegis), but module code cannot import it and the TypeScript types enforce the boundary.
Stage 1 — Pre-Query: the collection's `access.read()` returns `true`, `false`, or a `Filter` that is intersected into the WHERE clause before Drizzle compiles it. Stage 2 — Post-Read: per-field read guards strip unauthorized fields so a user never even sees the field name. Stage 3 — Pre-Write: `create` / `update` / `delete` guards run, then Zod validation, then `createdBy` / `updatedBy` / `updatedAt` are forcibly injected — overwriting any spoofed values in the request body.
It finds the latest version of the document at-or-before the target timestamp, then replays reverse RFC 6902 patches newest-to-oldest to rebuild that historical state. The modifier works with `.first()`, `.findMany()`, `.count()`, and `.exists()`, and filters apply against the reconstructed historical state.
The reverse-patch capture runs after the primary write commits, as a memory-only diff plus a single INSERT into the temporal event store — negligible against the network + Postgres cost that dominates any write. Very high-write workloads can buffer events asynchronously before flushing.
Fail-closed. A collection with no `access` config resolves to no access until an author explicitly opens it — security is opt-in, not opt-out, so a forgotten policy denies rather than leaks.