Orchestrator data model
Orchestrator data model
Section titled “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).
Conventions
Section titled “Conventions”| 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) |
Models
Section titled “Models”| 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).
Cross-service links
Section titled “Cross-service links”- CAP references Orchestrator only via
CapUser.userId→User.id. - Payment completion is async
payment.completed/payment.failed— see Event catalog. Optionalprovideronpayment.completed. POST /auth/delete-accountdeactivates the User and outbox-publishesuser.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 nonotification.requestedon Send. Optional pings use in-processNotificationService.dispatchwith a channel allow-list; user prefs skip disabled channels except auth-critical templates.