CODEX // oaoisme wiki

§ unswayed-backend

Platform infrastructure (Phase 1)

updated 2026-06-04

Phase 1 builds the cross-cutting platform layer every later domain stands on. It ships no business feature of its own except the notifications surface — instead it lands the shared machinery (queue, storage, push, realtime, mailer, audit, seed tooling) behind clean ports, so Phases 2–9 plug into a stable, tested surface instead of each reinventing infrastructure.

What it adds

Module What it is
src/queue/ A durable background-job queue behind QueuePort. BullMQ when Redis is present, a Prisma-backed DB queue otherwise — see Background queue (Redis-optional).
src/storage/ MediaStoragePort + a Cloudinary adapter (resumes, posts, photos, blog).
src/push/ FCM v1 PushPort + a DeviceToken table + the §23 set-token endpoint.
src/notifications/ The §23 read/write surface — see Notifications.
src/realtime/ A Socket.IO gateway with authenticated ralli.* channels.
src/mailer/ A queued transactional email catalogue — one job per mailable.
src/audit/ A real AuditLog + an opt-in interceptor for security events.
src/cli/ Idempotent import:countries / sync:permissions commands.

The one rule that shapes it: Redis is optional

The original plan demanded BullMQ + Redis and "fail fast and loud on missing Redis." The product owner overrode that: if Redis is unset or unreachable, fall back to a database queue — never crash. That single decision (ADR-0020) is why the queue is a port with two interchangeable adapters, and it gives a happy side-effect: the whole test suite (npm run verify) runs with no Redis at all.

How it's wired

Everything follows the repo's ports-and-adapters rule (the same shape as the existing NotificationService): a service depends on an abstract port; an adapter is chosen at boot by a factory from typed config; tests inject a fake. The QueueModule, StorageModule, RealtimeModule, and AuditModule are @Global, so any module injects their ports without re-importing.

The legacy system had three infrastructure bugs that silently broke things; Phase 1 fixes each in the internals while keeping the wire identical:

  • OTP emails never delivered until someone manually ran queue:restart → a managed worker with stale-lock recovery + retries.
  • Every FCM push silently failed (empty body from a non-existent message field; a malformed URL with a literal {env('FCM_PROJECT_ID')}) → body = description, URL built from typed config.
  • Any client could read any user's private realtime stream (return true on every channel) → real per-user / per-participant authorization.

Proof it works

npm run verify is green: 707 unit tests at 99.98% coverage + 44 e2e. The Redis-optional behavior is verified live against the GET /api/health/queue probe in all three modes (Redis up → bullmq; Redis down → database with a warning; explicit database).

See the subpages for the queue internals, the notifications surface, push + realtime, and the storage/mailer/audit/CLI ports.

Subpages