Lazy, pooled, per-mode clients
Database exposes core and data(mode). The data clients are instantiated lazily — a process that only ever serves test traffic never opens a connection to the live schema — and each runs with a small connection_limit so a fleet of PM2 workers doesn’t exhaust Postgres.
The mode-to-schema mapping is the only place the words “sandbox” and “live” appear. Everything above it speaks in Mode ('test' | 'live'); the client translates that to a search_path.
Caching without the footguns
Reads are cached in Redis through aCacheStore with three properties that matter:
Single-flight
remember(key, ttl, fn) collapses a stampede: if a thousand requests miss the same key at once, the loader runs once and the rest await it. No cache-miss storm.Null-cacheable
Values are wrapped in an envelope
{ v } so a legitimately-null result is cacheable and distinguishable from a miss. No re-querying for things that don’t exist.Version-bump invalidation
A resource’s list cache lives under a namespace whose version is bumped on write. Invalidation is a single counter increment — never a
SCAN over Redis keyspace.Why version-bump beats key-deletion
The naive approach to “invalidate all the list pages for this tenant’s customers” is toSCAN for matching keys and delete them. SCAN is O(keyspace) and blocks. Instead, every list key embeds a version:
Bumping the version makes every old key instantly unreachable. The stale entries aren’t deleted; they simply age out on their TTL while no one reads them. Invalidation is O(1) and lock-free.
The cache is mode-aware too
Cache keys are namespaced bymode:tenantId:resource. Test-mode writes can never invalidate live-mode reads, and vice versa — the same isolation guarantee as the schemas, carried into Redis.
Next: the Billing Engine — the subscription state machine that everything orbits.