users
Identitas utama pengguna beserta preferensi dan verifikasi.
@@index([email]) • @@index([username]) • @@index([status, createdAt])
PostgreSQL + Prisma untuk jutaan proyek video dan ribuan pengguna serentak. 18 modul, 123 tabel, seluruhnya memakai UUID, soft delete, versioning, metadata JSONB, dan timestamp UTC. Skema Prisma dihasilkan otomatis dari katalog ini ke prisma/schema.prisma.
Wajib ada di seluruh tabel — audit, soft delete, versioning, dan metadata
id
String
Primary key UUID v4.
created_at
DateTime
Waktu pembuatan (UTC).
updated_at
DateTime
Waktu perubahan terakhir (UTC).
deleted_at
DateTime?
Soft delete; NULL = aktif.
created_by
String?
User pembuat baris.
updated_by
String?
User pengubah terakhir.
status
RecordStatus
Siklus hidup data.
version
Int
Optimistic locking / versi konten.
metadata
Json
Ekstensi bebas skema (GIN index).
Narasi → analisis → storyboard → aset → render → publikasi
Authentication — JWT, RBAC, OAuth Google, magic link, dan sesi multi-perangkat.
Identitas utama pengguna beserta preferensi dan verifikasi.
@@index([email]) • @@index([username]) • @@index([status, createdAt])
Sesi aktif per perangkat dengan fingerprint dan kedaluwarsa.
FK → User (onDelete: Cascade)
@@index([userId, expiresAt])
Rotating refresh token dengan deteksi reuse.
FK → User (onDelete: Cascade)
@@index([userId, expiresAt])
Kunci API server-to-server, dienkripsi dan dapat dicabut.
FK → User (onDelete: Cascade)
@@index([userId, status])
Tautan penyedia identitas (Google, Apple, SSO).
FK → User (onDelete: Cascade)
@@unique([provider, providerAccountId])
Definisi peran sistem dan kustom per organisasi.
@@unique([key])
Izin granular berformat resource:action.
@@index([resource, action])
Pemetaan many-to-many peran ke izin.
FK → Role (onDelete: Cascade)
@@unique([roleId, permissionId])
Peran pengguna — WAJIB terpisah dari tabel profil untuk mencegah privilege escalation.
FK → User (onDelete: Cascade)
@@unique([userId, role, organizationId])
Status seragam: draft → processing → ready → published → archived → deleted
RecordStatus
Data lifecycle global untuk semua tabel.
DRAFT | PROCESSING | READY | PUBLISHED | ARCHIVED | DELETED
AppRole
RBAC; disimpan di tabel terpisah (user_roles), tidak pernah di profil.
OWNER | ADMIN | EDITOR | REVIEWER | VIEWER | SERVICE
JobState
State mesin workflow & render.
QUEUED | RUNNING | RETRYING | SUCCEEDED | FAILED | CANCELLED | PAUSED
AssetKind
Klasifikasi aset produksi.
IMAGE | VIDEO | VOICE | MUSIC | SFX | SUBTITLE | THUMBNAIL | EXPORT
Platform
Target publikasi vertikal 9:16.
YOUTUBE | TIKTOK | INSTAGRAM_REELS | FACEBOOK_REELS
Visibility
Kontrol akses proyek (dipakai Row Level Security).
PRIVATE | TEAM | ORGANIZATION | PUBLIC
AgentKind
19 agen produksi; dipakai agent_messages & agent_results.
PROJECT_MANAGER | SCRIPT_ANALYST | STORY_OPTIMIZER | STORYBOARD | CHARACTER | ENVIRONMENT | PROMPT_ENGINEER | IMAGE_GENERATOR | MOTION_DIRECTOR | VIDEO_GENERATOR | VOICE_DIRECTOR | MUSIC_COMPOSER | SFX_DESIGNER | SUBTITLE | VIDEO_EDITOR | QUALITY_CONTROL | THUMBNAIL_DESIGNER | SEO_SPECIALIST | EXPORT_MANAGER
BillingCycle
Siklus penagihan langganan.
MONTHLY | YEARLY | LIFETIME | USAGE_BASED
B-tree, composite, GIN, partial, unique, dan trigram
B-Tree pada FK & status
Setiap kolom FK, status, dan created_at diindeks; query dashboard selalu ter-cover.
Composite index
(owner_id, status), (state, priority, created_at), (project_id, agent) untuk filter + sort satu langkah.
GIN pada JSONB & array
metadata, payload, output, tags, keywords memakai GIN jsonb_path_ops untuk pencarian atribut.
Partial index
WHERE deleted_at IS NULL pada tabel besar; WHERE state IN ('QUEUED','RUNNING') pada antrean.
Unique guard
unique(email), unique(slug), unique(storyboard_id, number), unique(project_id, agent) mencegah duplikasi.
Trigram search
pg_trgm pada title/term untuk pencarian proyek dan trending query.
Materialized view, partisi, pooling, read replica, caching
Materialized View
mv_project_dashboard & mv_render_throughput di-refresh CONCURRENTLY tiap 5 menit.
Partitioning
Tabel log, event, telemetri, dan audit dipartisi per hari/minggu/bulan; partisi lama di-detach ke cold storage.
Connection pooling
PgBouncer transaction pooling; Prisma pakai connection_limit terukur per worker.
Read replica
Query analitik dan dashboard diarahkan ke replica; tulis tetap ke primary.
Query hygiene
Selalu SELECT kolom eksplisit, keyset pagination, hindari N+1 dengan include terukur.
Caching
Redis untuk trending keyword, prompt template, dan feature flag (TTL 60–900 detik).
RLS, RBAC terpisah, enkripsi field, audit trail, rate limiting
Row Level Security
Kebijakan per organisasi/pemilik pada seluruh tabel domain; peran dicek via fungsi SECURITY DEFINER has_role().
RBAC terpisah
Peran hanya di user_roles — tidak pernah pada profil, mencegah privilege escalation.
Encrypted fields
password_hash, mfa_secret, token OAuth, API key, kredensial platform dienkripsi (pgcrypto/KMS envelope).
Ownership validation
Setiap mutasi memverifikasi owner_id/organization_id sebelum menulis.
Rate limiting
Batas per API key & IP dicatat di api_usage; pelanggaran masuk security_logs.
Audit trail
Trigger AFTER INSERT/UPDATE/DELETE menulis before/after ke audit_logs.
7 hari PITR • 30 hari snapshot • 90 hari arsip • 1 tahun kepatuhan
PITR 7 hari
WAL archiving berkelanjutan, RPO < 5 menit, RTO < 30 menit.
Snapshot harian 30 hari
Full snapshot database + metadata aset.
Arsip bulanan 90 hari
Workflow, memory, dan audit diekspor ke object storage terenkripsi.
Retensi 1 tahun
Audit & billing disimpan setahun untuk kepatuhan, lalu dianonimkan.
Expand → migrate → contract, tanpa downtime