Kembali ke Studio

Skema Database Enterprise

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.

Modul
18
Tabel
123
Enum
8
Kolom standar
9

Kolom standar global

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).

Rantai relasi inti

Narasi → analisis → storyboard → aset → render → publikasi

UsersOrganizationsProjectsScriptsStoryAnalysisStoryboardsScenesCharactersLocationsImagesVideosVoicesSubtitlesThumbnailsRenderJobsExportsPublishTargets

Katalog tabel per modul

Authentication — JWT, RBAC, OAuth Google, magic link, dan sesi multi-perangkat.

users

Identitas utama pengguna beserta preferensi dan verifikasi.

User
emailStringusernameString?password_hashString?display_nameString?avatar_urlString?localeStringtimezoneStringemail_verified_atDateTime?mfa_secretString?last_login_atDateTime?

@@index([email]) • @@index([username]) • @@index([status, createdAt])

encrypted: password_hash, mfa_secret

sessions

Sesi aktif per perangkat dengan fingerprint dan kedaluwarsa.

Session

FK → User (onDelete: Cascade)

deviceString?ip_addressString?user_agentString?expires_atDateTimerevoked_atDateTime?

@@index([userId, expiresAt])

partition: range(created_at) bulanan

refresh_tokens

Rotating refresh token dengan deteksi reuse.

RefreshToken

FK → User (onDelete: Cascade)

token_hashStringexpires_atDateTimerotated_fromString?

@@index([userId, expiresAt])

encrypted: token_hash

api_keys

Kunci API server-to-server, dienkripsi dan dapat dicabut.

ApiKey

FK → User (onDelete: Cascade)

nameStringprefixStringsecret_hashStringscopesString[]last_used_atDateTime?expires_atDateTime?

@@index([userId, status])

encrypted: secret_hash

oauth_accounts

Tautan penyedia identitas (Google, Apple, SSO).

OAuthAccount

FK → User (onDelete: Cascade)

providerStringprovider_account_idStringaccess_tokenString?refresh_tokenString?expires_atDateTime?

@@unique([provider, providerAccountId])

encrypted: access_token, refresh_token

roles

Definisi peran sistem dan kustom per organisasi.

Role
keyAppRolenameStringdescriptionString?

@@unique([key])

permissions

Izin granular berformat resource:action.

Permission
keyStringresourceStringactionString

@@index([resource, action])

role_permissions

Pemetaan many-to-many peran ke izin.

RolePermission

FK → Role (onDelete: Cascade)

permission_idString

@@unique([roleId, permissionId])

user_roles

Peran pengguna — WAJIB terpisah dari tabel profil untuk mencegah privilege escalation.

UserRole

FK → User (onDelete: Cascade)

roleAppRoleorganization_idString?granted_byString?

@@unique([userId, role, organizationId])

Enum & data lifecycle

Status seragam: draft → processing → ready → published → archived → deleted

DRAFTPROCESSINGREADYPUBLISHEDARCHIVEDDELETED

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

Strategi indexing

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.

Optimasi & skalabilitas

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).

Keamanan data

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.

Backup & retensi

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.

Strategi migrasi & seed

Expand → migrate → contract, tanpa downtime

  1. 1prisma migrate dev untuk pengembangan; prisma migrate deploy pada CI/CD produksi.
  2. 2Expand → migrate → contract: tambah kolom nullable, backfill batch, baru jadikan NOT NULL.
  3. 3Perubahan destruktif selalu dua rilis: hentikan pemakaian dulu, hapus di rilis berikutnya.
  4. 4Index besar dibuat dengan CREATE INDEX CONCURRENTLY di luar transaksi migrasi.
  5. 5Setiap migrasi punya skrip rollback dan diuji pada snapshot produksi terbaru.
  6. 6Seed data: roles, permissions, plans, prompt_templates, project_templates, system_settings, feature_flags.