Skip to content

Orchestrator data model

Audience: backend
Status: specced
Owns: backend
Depends on: Orchestrator backend, Coding standards, Architecture handover

Implementation SoT: elimi-ecosystem/apps/orchestrator/prisma/schema.prisma (migrated). Design seed also exists at ecosystem-root orchestrator-schema.prisma. This page is the human outline. Status fields stay String + CHECK in migration SQL (§23).

Rule Detail
ULID PKs @id @db.Char(26), app-generated
Money BigInt minor units on Payment — never Float
NIN Never store raw NIN — User.ninHash HMAC-only for duplicate block (§17)
Enums Structural: AuthProvider, OtpPurpose, NotificationChannel, IdentityVerificationType, AssetSensitivity
Status fields String + intended CHECK (User, Payment, Notification, …) — sync with @yourorg/common
Audit No audit_logs here — separate Audit service fed from outbox (§14)
Model Notes
User email, phone, passwordHash, authProvider, status (PENDING_VERIFICATION | ACTIVE | SUSPENDED | DEACTIVATED), intents[], optional ninHash, optional notificationPreferences JSON (email / in_app / sms)
Otp purpose (ACCOUNT_VERIFY / PASSWORD_RESET), expiry, consumed
RefreshToken rotation / revoke support
IdentityVerification type (NIN first), provider refs, verified_at — raw ID never persisted
Payment amount minor units, currency, provider refs, referenceType / referenceId, status
StorageAsset sensitivity, provider metadata; resolve via signed URL — not permanent public URLs for sensitive assets
Notification user-scoped inbox rows; channel + template + status — not chat messages
NotificationTemplate per channel / purpose
Conversation kind (direct | group | broadcast), optional title, createdByUserId, platform
ConversationParticipant conversationId + userId; lastReadAt optional
Message conversationId, authorUserId, body, UTC createdAt
OutboxEvent transactional outbox for RabbitMQ publish

Redis remains for OTP TTL, attempt counters, and short-lived rate limits (not in Prisma).

  • CAP references Orchestrator only via CapUser.userIdUser.id.
  • Payment completion is async payment.completed / payment.failed — see Event catalog. Optional provider on payment.completed.
  • POST /auth/delete-account deactivates the User and outbox-publishes user.deleted; CAP anonymizes PII and inactivates memberships.
  • Identity and payment initiation are gRPC (@yourorg/proto); REST covers webhook, storage, auth (incl. delete-account), notifications (inbox + channel preferences), conversations, address. Chat send is client → OL HTTP — no CAP gRPC and no notification.requested on Send. Optional pings use in-process NotificationService.dispatch with a channel allow-list; user prefs skip disabled channels except auth-critical templates.