SIKATHREE/Master PRD
Full System
TECHNICAL PRODUCT REQUIREMENTS · VERSION 1.0

Sikathree Master PRD

Dokumentasi lengkap untuk prototipe interaktif, MVP Full System, dan persyaratan Production Go-Live.

HIRADCLaporan BahayaLMSMulti-tenant RBACMobile Responsive
22Bab
175Field specs
53Permission actions
55Acceptance cases
22 bab tersedia
CHAPTER 00Normatif

Ringkasan Eksekutif

Tujuan, lingkup, keputusan yang dibekukan, serta batas kesiapan production.

0.1 Pernyataan produk

Sikathree — Sistem Informasi K3 adalah aplikasi web multi-organisasi untuk mendukung tiga domain yang berdiri sendiri tetapi memakai fondasi bersama: HIRADC, Laporan Bahaya, dan Learning Management System (LMS). Sikathree membantu Operator/Petugas mencatat bahaya dan menjalankan tugas, Pengawas K3 melakukan review dan verifikasi sesuai izin, pengelola organisasi mengatur keanggotaan, dan Admin K3 mengelola materi pembelajaran global.

Pengalaman pengguna menggunakan Modern Operational Dashboard (A), Light Mode, responsif sepenuhnya pada desktop, tablet, dan smartphone. Alur lapangan (Laporan Bahaya dan Control Task) didesain mobile-first. Satu akun dapat mempunyai membership di beberapa organisasi; data tenant tidak otomatis terlihat oleh role global.

0.2 Tujuan dokumen

Master PRD ini adalah spesifikasi end-to-end untuk dua tahap implementasi: (1) Interactive Prototype frontend dengan mock data yang saling terhubung dan simulator workflow; (2) MVP Full System dengan frontend, backend, database, file storage, worker, deployment, serta security controls nyata. Dokumen juga memisahkan go-live gates sebelum pemakaian data operasional sungguhan.

0.3 Keputusan paling utama

  • Frontend: Next.js App Router, TypeScript, Tailwind CSS, shadcn/ui, React Hook Form + Zod, TanStack Query, dan tRPC BFF.
  • Backend: NestJS modular monolith, REST /api/v1, worker terpisah, PostgreSQL + pgvector; transactional outbox untuk email; Garage S3 untuk berkas.
  • Tenant isolation: membership dan Dynamic RBAC diperiksa di backend; PostgreSQL Row Level Security (RLS) dengan konteks transaksi; immutable business versions dan append-only audit.
  • Infrastruktur: 1 VPS per environment (Production 1 dan Staging 1), masing-masing menggunakan 5 Compose project modular. Hanya Nginx mempublikasikan port 80/443; layanan lain memakai Docker network internal. Tidak menggunakan WireGuard antarservice.
  • Capacity assumption: 4.000 akun terdaftar, estimasi 3% aktif bersamaan = 120 peak concurrent users; 8 vCPU/32 GB merupakan kandidat pengujian, bukan kapasitas yang telah dibuktikan.
  • Keamanan produksi: pengujian RLS, otorisasi, konsistensi transaksi, object storage, dan backup/recovery harus selesai sebelum mengelola data nyata.

0.4 Status spesifikasi

Dokumen memakai label [FINAL] untuk keputusan percakapan yang sudah dikunci, [DESIGN] untuk rancangan detail yang didelegasikan pengguna dan direkomendasikan sebagai baseline implementasi, [PROVISIONAL] untuk kebutuhan yang masih perlu disahkan sebelum menjadi konfigurasi production, dan [GATE] untuk kriteria wajib sebelum go-live. Penetapan [DESIGN] bukan berarti klaim sudah terimplementasi atau lolos pengujian.

0.5 Prioritas keberhasilan

  1. Proses bisnis dan histori yang benar, terutama approval, versi, residual risk, dan aturan attempt LMS.
  2. Tidak ada kebocoran data antarorganisasi atau peningkatan hak akses tanpa izin.
  3. Pengalaman mobile yang nyaman untuk pekerjaan lapangan tanpa menghilangkan kemampuan desktop.
  4. Dapat dioperasikan/diobservasi pada staging, lalu dipromosikan ke production melalui release terotorisasi.
  5. Perilaku UI, API, database, audit, dan email saling konsisten; tidak ada hanya-perubahan-badge.
CHAPTER 01Normatif

Status Keputusan, Scope dan Prioritas

Membedakan keputusan final, rancangan delegasi, hal provisional, scope MVP, dan go-live gate.

1.1 Penetapan status dan pengendalian perubahan

  • [FINAL] Keputusan yang telah disepakati dalam diskusi: stack inti, tiga domain, aturan bisnis spesifik, satu VPS per environment, Dynamic RBAC, session, mobile responsive, dan mode penyimpanan draft manual.
  • [DESIGN] Rekomendasi pengisi celah yang pengguna delegasikan: field-level data, validation details, permission/action mapping, state guards, idempotency, edge cases, acceptance test.
  • [PROVISIONAL] Nilai atau batas yang memerlukan kebijakan operator: retention angka final, limit file, durasi grant, provider VPS, domain nyata, detail recovery jawaban tes, dan jalur REST publik.
  • [GATE] Ketentuan yang harus diverifikasi sebelum data nyata: backup/recovery, storage durability, tests security/RLS, secrets, alerting, release process, load testing.

Setiap perubahan keputusan [FINAL] memerlukan catatan Decision Record yang mencantumkan keputusan lama, usulan baru, alasan, dampak pada entitas/API/UX, dan persetujuan pemilik produk. Developer atau AI Agent tidak boleh mengubah rule hanya agar implementasi lebih mudah.

1.2 Tahap deliverable

Tahap Tujuan Data & security Bukti selesai
P0 — Prototipe interaktif Uji seluruh layar dan workflow Fixtures JSON, state lokal, auth/RBAC simulasi 12 scenario utama + negative cases, mobile QA
P1 — MVP fungsional Jalankan operasi tenant dengan persistence NestJS, PostgreSQL/RLS, sessions, Garage, worker, email Integration, e2e, contract, RLS & concurrency tests
P2 — Production go-live Menggunakan data operasional nyata Seluruh go-live gate tuntas Go/no-go checklist dan sign-off

1.3 Termasuk MVP

  • Multi-org users, invitation-only account, organization selection, role/permission dinamis, guarded support access.
  • HIRADC proposal, risk assessment per record dan versi, K×P, review, kontrol, verifikasi, residual risk, audit dan official PDF snapshot.
  • Hazard reporting dari mobile, attachment, approval, penugasan satu PIC aktif, tindakan, verifikasi, revisi substansial, histori dan email penting.
  • LMS course global terbit, pre-test, learn manual complete, post-test, attempt quota, fingerprint/versioning, results dan tenant progress monitoring.
  • Administration tenant/platform/K3, file lifecycle, notification outbox, staging/prod deployment dan basic observability.

1.4 Tidak termasuk MVP

  • AI Learning Companion dan pencarian semantik meskipun pgvector tersedia.
  • Simulasi 3D, native mobile apps, offline/PWA, JSA/LOTO workflows, e-certificate, cross-module task orchestration.
  • Notification Center in-app, video streaming/transcoding platform khusus, advanced BI, microservices/Kubernetes.
  • Multi-node Garage/high availability tidak otomatis masuk scope implementasi MVP awal; tetap menjadi risiko durabilitas yang harus diselesaikan sebelum go-live nyata.

1.5 Asumsi lingkungan

  • Organisasi merupakan tenant dengan empat area K3 global yang sama.
  • Nama domain dan identitas organisasi contoh dalam spesifikasi adalah placeholder, bukan alamat produksi yang telah diputuskan.
  • Semua string locale id-ID, tanggal/jam dipresentasikan WIB (Asia/Jakarta) di UI; event disimpan sebagai UTC timestamp di backend [DESIGN].
  • Status organizationId di browser hanya pilihan konteks, bukan sumber kebenaran authorization.
CHAPTER 02Normatif

Aktor, Organisasi dan Use Cases

Aktor dan batas kewenangannya, katalog empat area, serta alur penggunaan sistem.

2.1 Model identitas dan membership

Satu User merupakan identitas global. Satu user dapat memiliki nol atau lebih Membership organisasi; setiap membership memiliki satu role lokal aktif dan personnel category terpisah. Role Platform Super Admin dan Admin K3 adalah role platform, bukan membership tenant. Organization Admin tidak otomatis memperoleh izin review HIRADC atau laporan. Platform role tidak otomatis membaca tenant data.

2.2 Aktor utama

Aktor Tujuan Lingkup akses default
Operator/Petugas Melaporkan bahaya, mengajukan identifikasi, menjalankan tugas, belajar Tenant tempat menjadi anggota, sesuai permission
Pengawas K3 Review assessment/laporan, verifikasi kontrol, monitoring Tenant dan permission efektif; berlaku guard per transaksi
Organization Admin Administrasi membership, undangan, role, support approval Administrasi tenant, bukan otomatis seluruh proses operasional
Admin K3 Membuat dan menerbitkan konten pembelajaran Course/assessment global, bukan progress individu tenant tanpa grant
Platform Super Admin Mengelola tenant dan platform, mengajukan support grant Metadata platform; data bisnis tenant hanya melalui grant disetujui
Multi-membership User Berpindah antara beberapa tenant Hanya tenant yang aktif dan masih mempunyai membership sah

2.3 Area/lokasi K3 global [FINAL]

Kode stabil [DESIGN] Label tampilan
AREA_DISINFECTION Penyimpanan dan Pembubuhan Desinfektan
AREA_PROCESS_CHEMICAL Penerimaan, Penyimpanan, Penyiapan dan Pembubuhan Bahan Kimia Proses
AREA_MECH_ELECTRIC Pompa, Panel Listrik dan Genset
AREA_RESERVOIR Reservoir Air Bersih

Katalog area berlaku pada HIRADC, Laporan Bahaya, filter, laporan, dan course tagging. Field lokasi spesifik berbentuk teks untuk lokasi lebih rinci. User tidak dapat membuat area global baru dari form tenant.

2.4 Use case end-to-end

  1. Operator menemukan kondisi bahaya dan membuat laporan; status, severity, evidence, email dan audit mengikuti rule; Pengawas/penanggung jawab menindaklanjuti hingga verifikasi.
  2. Operator menyampaikan usulan identifikasi; pihak berizin melakukan assessment satu risiko per record; Pengawas berbeda dari pembuat risiko/versi menyetujui; kontrol dikerjakan dan diverifikasi.
  3. Peserta mengerjakan Pre-Test diagnostik bila aktif, membaca lesson dan menandai selesai manual, kemudian lulus Post-Test sesuai threshold/kuota.
  4. Admin K3 menerbitkan lesson/assessment versi baru; identitas lesson dan fingerprint mempertahankan atau mereset progress sesuai perubahan nyata.
  5. Organization Admin mengundang anggota, mengubah role dalam delegation ceiling, dan menyetujui/menolak permintaan Support Access.
  6. Platform Super Admin mengelola metadata tenant, bukan membaca isi data tenant tanpa izin spesifik.

2.5 Sasaran operasional terukur [DESIGN]

  • Pengguna dapat menemukan tindakan utama (buat laporan, tugas, belajar) dari Dashboard atau mobile navigation.
  • Semua perubahan bisnis signifikan mempunyai actor, timestamp, reason jika diwajibkan, version ID, dan audit event.
  • Seluruh route sensitif mempunyai pemeriksaan permission server-side; tidak bergantung pada hidden UI button.
  • Cross-tenant isolation dan no-self-approval HIRADC diverifikasi oleh automated tests.
CHAPTER 03Normatif

Information Architecture & Screen Inventory

Seluruh route dan pembagian workspace, termasuk perbedaan desktop/mobile.

3.1 Navigasi dan application shells

Aplikasi memiliki satu desain terpusat dengan lima variasi shell: Authentication, Organization, Platform, K3 Content Studio, dan Focused Learning/Assessment. Pada desktop Organization Shell memakai sidebar + topbar; di smartphone memakai topbar, bottom navigation izin-terfilter, dan drawer menu lengkap. Tidak ada fitur berizin yang boleh hilang dari mobile.

3.2 Authentication dan akun

Route Screen Catatan
/login Login Email/password, generic errors, no public sign-up
/invite/[token] Aktivasi undangan Sekali pakai, expired handling
/forgot-password Lupa password Permintaan kode OTP tanpa account enumeration
/reset-password Reset password 6 digit OTP 5 menit [FINAL]
/workspace Pemilihan workspace Membership dan platform role
/account/profile Profil Nama dan informasi akun
/account/security Keamanan Change password, sesi dan logout

3.3 Organization Workspace

Route Screen Tujuan
/app Dashboard Action-oriented dan permission-scoped
/app/my-activity Aktivitas Saya Agregasi baca-only atas pekerjaan dari domain asal
/app/organization Profil Organisasi Metadata tenant
/app/hiradc Risk Register Daftar risiko, filter, skor
/app/hiradc/proposals Daftar Usulan Antrean/riwayat usulan
/app/hiradc/proposals/new Buat Usulan Field bahaya & lokasi
/app/hiradc/proposals/[id] Detail Usulan Review usulan
/app/hiradc/risks/new Penilaian Baru Form assessment bertahap
/app/hiradc/risks/[id] Detail Risiko Versi, kontrol, residual, dokumentasi
/app/hiradc/risks/[id]/versions/new Revisi Risiko Buat kandidat assessment baru
/app/hiradc/risks/[id]/versions/[versionId] Detail Versi Snapshot immutable
/app/hiradc/reviews Review Assessment Antrean approval
/app/hiradc/controls Control Tasks Tugas PIC/verifikasi
/app/hiradc/exports Dokumen Resmi Preview dan immutable PDF
/app/reports Daftar Laporan Case list dan filter
/app/reports/new Buat Laporan Mobile-first 3 langkah
/app/reports/drafts/[id] Edit Draft Manual Save Draft
/app/reports/[id] Detail Laporan Evidence, PIC, timeline
/app/reports/reviews Review Laporan Approval/revision
/app/reports/assignments Penugasan Saya Tugas PIC aktif
/app/reports/[id]/revisions/new Ajukan Revisi Perubahan substansial
/app/reports/[id]/revisions/[revisionId] Riwayat Revisi Snapshot dan diff
/app/learning Katalog Course global terbit
/app/learning/courses/[id] Course Detail Stage/progress
/app/learning/courses/[id]/lessons/[lessonKey] Lesson Focused viewer
/app/learning/courses/[id]/assessments/[type] Mulai Assessment Pre/Post-Test introduction
/app/learning/attempts/[id] Assessment Player Pertanyaan tanpa kunci jawaban
/app/learning/attempts/[id]/result Result Nilai, kuota, status
/app/learning/history Riwayat Saya Historis vs current completion
/app/learning/monitoring Monitoring Peserta Tenant-scoped, permission-protected

3.4 Administrasi organisasi dan platform

Route Screen Catatan
/app/settings/organization Organization Settings Metadata tenant sesuai permission
/app/settings/members Members Daftar anggota
/app/settings/members/[id] Member Detail Membership/role history
/app/settings/invitations Invitations Undang, revoke, resend
/app/settings/roles Roles Custom org role dalam ceiling
/app/settings/roles/[id] Role Editor Permission matrix
/app/settings/support-access Support Approvals Organization Admin approves
/platform Platform Overview Metadata, bukan business dashboard tenant
/platform/organizations Organizations Create/update/activate
/platform/organizations/[id] Organization Detail Admin metadata
/platform/accounts Platform Accounts Global platform role management
/platform/rbac-templates RBAC Templates Versioned default templates
/platform/support-access Support Requests Request/revoke/history
/platform/support-access/[grantId] Support Session Read-only resource/time scoped
/platform/k3 Content Dashboard Global course metadata
/platform/k3/courses Course Management Draft/published
/platform/k3/courses/[id] Course Editor Content structure
/platform/k3/courses/[id]/lessons/[lessonId] Lesson Editor Rich text/media
/platform/k3/assessments Assessment Management Question bank/config
/platform/k3/assessments/[id] Assessment Editor Answer key only privileged
/platform/k3/publications Publication History Version impact

3.5 Route behavior

Semua route mendukung direct link, browser refresh, broken URL, loading/empty/error states, session expiration, dan 403/404. Jangan mengandalkan permission check pada layout saja: page data loader dan action tetap memeriksa izin. URL tenant tidak menyertakan organizationId; konteks dipilih dengan key lokal tepat organizationId dan diteruskan per operasi. Deep link dari email harus mendeteksi tenant mismatch dan menawarkan peralihan hanya jika membership sah.

CHAPTER 04Normatif

UI/UX Design System dan Responsive Behavior

Tokens visual, komponen bersama, interaksi, dan perilaku smartphone yang wajib didukung.

4.1 Identitas visual [FINAL]

  • Modern Operational Dashboard, Light Mode Only, warna primary teal #176B63, accent #249B83, muted #E8F5F0, background #F5F7FA, surface putih #FFFFFF, text #1E293B.
  • Semantic success #15803D, warning #B45309, critical #B91C1C, info #2563EB; kontras harus memenuhi WCAG 2.2 AA.
  • Font Inter direkomendasikan [DESIGN], body 14–16px, form mobile 16px, heading page desktop 24–28px, mobile 20–24px; 4px spacing scale; radius 8–12px.
  • Risiko HIRADC: Low hijau, Moderate biru, High amber, Very High merah. Label selalu tertulis; status workflow tidak disamakan dengan tingkat risiko.

4.2 Breakpoints dan layout [DESIGN]

Viewport Navigasi Perilaku layout
320–639px Topbar + bottom nav + drawer 1 kolom, filter via sheet, fullscreen complex dialog
640–767px Mobile navigation 1 kolom lega
768–1023px Sidebar collapsible 1–2 kolom tergantung isi
1024–1279px Compact sidebar Multi-column form/record
>=1280px Expanded sidebar Table, details, compare side-by-side

4.3 Component specification

Komponen Kontrak visual Kontrak interaksi
AppShell Consistent chrome, workspace indicator Responsive nav, scoped menu
WorkspaceSwitcher Organization/platform/K3 choices Membership verified; protects dirty forms
ResponsiveDataList Desktop table, mobile cards Search, sort/filter, pagination, empty/error
PageHeader Breadcrumb, title, action Mobile action repositioning
PermissionGate Hide/disable unauthorized options Backend remains authoritative
StatusBadge Domain registry mapping Text + color, tooltip only explanatory
FormActions Distinct Save Draft / Submit Loading, success, error, double submit guard
UnsavedChangesGuard Warning modal Back, route, org change
FileUploader Picker/camera, preview, progress Retry, delete temp, attached state
RiskMatrix5x5 K,P picker and grid Preview only; server calculates official
VersionCompare Before/after and changed fields Vertical mobile, immutable snapshots
ActivityTimeline Chronological events Audit source, pagination
AssessmentPlayer One question/group per viewport No answer keys, stable attempt
EmptyState Contextual headline + CTA Permission-scoped CTA
ConfirmationDialog Consequence summary, optional reason Full-screen complex mobile
CourseEditor Outline + editor Drawer outline on mobile, draft version only

4.4 UX behavioral rules

  • Laporan Bahaya dan HIRADC: Simpan Draft manual, tidak autosave. Tindakan Submit terpisah dan konfirmasi final. Saat belum tersimpan, back/navigation/org switch menampilkan dirty form warning.
  • Dashboard: KPI hanya yang berizin; Perlu Tindakan merupakan read-only agregasi dari status modul, bukan Notification Center.
  • Detail records: tampilkan owner, organization context, status terpisah, versi efektif, kandidat revisi, histori, evidence.
  • Permission: menu berdasarkan effective permission; direct URL dan server mutation tetap diperiksa; denied page tidak membocorkan data record.
  • Mobile field operations: form laporan tiga langkah (informasi, evidence/penerima, review); kontrol tugas dan approval mempunyai area sentuh memadai, tidak hanya hover.
  • Assessment: Focused Learning Shell menghilangkan navigasi operasional yang mengganggu; belum ada timer wajib yang ditetapkan.
  • Feedback: setiap mutation menampilkan pending, success, error atau conflict; jangan mengklaim tersimpan ketika jaringan gagal.

4.5 States universal

Loading/skeleton, empty, error/retry, forbidden, not-found, session expired, organization inactive, unsaved changes, version conflict, concurrent modification, upload failed, timeout/unknown submission outcome, offline/network unavailable, assessment changed. Untuk hasil request ambigu, lakukan read-after-write atau status lookup berbasis idempotency key sebelum menampilkan hasil atau mengulangi mutation.

4.6 Accessibility targets

Keyboard navigation, visible focus ring, descriptive field errors, aria labels, semantic headings, screen-reader status feedback, no color-only indicator, text zoom, touch target 44×44 px sebagai target UX; jangan memblokir browser zoom. Uji Chrome Android, Safari iOS, keyboard mobile, landscape/portrait, viewport 320px dan desktop besar.

CHAPTER 05Normatif

Arsitektur Aplikasi dan Boundary Layanan

Boundary browser/BFF/NestJS, database, storage, worker, dan sinkronisasi kontrak API.

5.1 Arsitektur logical [FINAL]

Browser (desktop/mobile)
  | HTTPS + host-only session cookie
  v
Nginx Public Edge :80/:443
  |----> Next.js App Router + tRPC BFF ----> NestJS REST /api/v1 (internal)
  |                                               |--- PostgreSQL + pgvector
  |                                               |--- Garage S3 (internal)
  |                                               `--- Transactional Outbox
  |----> Garage S3 via storage hostname (signed upload/download)
  `----> No other ports exposed

NestJS Worker ----> PostgreSQL outbox, Garage cleanup, SMTP provider
Prometheus/Grafana/Alertmanager/Exporters ----> health metrics + external uptime monitor

5.2 Boundary API [PROVISIONAL DESIGN]

Rekomendasi eksekusi: browser memakai tRPC BFF untuk semua business operations; NestJS REST tetap internal di Docker network; Nginx hanya mempublikasikan web app dan storage signed gateway. Ini mengurangi jalur keamanan ganda. Jika integrasi pihak ketiga membutuhkan public REST kelak, buat keputusan arsitektur terpisah dengan autentikasi dan rate limit sendiri. /api-docs/Scalar harus diproteksi, tidak boleh dipublikasikan secara terbuka.

5.3 Frontend [FINAL]

Next.js App Router, React Hook Form + Zod, TanStack Query untuk query cache, Zustand hanya untuk state lintas-komponen yang tidak lebih tepat dikelola React. Folder fitur: auth, organizations, permissions, dashboard, hazard-reports, hiradc, learning, administration, support-access. dto/handler/service/repository pada frontend bila digunakan merupakan adapter REST ke NestJS, bukan SQL repository. tRPC mengirim organizationId terverifikasi dan cookie session ke backend.

5.4 Backend [FINAL]

NestJS modular monolith; REST controllers -> DTO validation -> guards/policies -> domain service -> database repository dalam transaksi. Worker proses asinkron terpisah; bukan microservice HTTP baru. Gunakan standard error envelope, observability trace correlation ID, idempotency and optimistic concurrency.

5.5 API contract synchronization [DESIGN]

NestJS menghasilkan OpenAPI versioned artifact pada CI; frontend REST adapter dibuat/divalidasi dari kontrak tersebut, disertai contract tests. Perubahan breaking mengikuti /api/v1 policy dan backward-compatible deployment window. Jalur tRPC menyesuaikan schema frontend; browser tidak mengenal kredensial NestJS internal.

5.6 Service responsibility map

Lapisan Berhak memutuskan Tidak boleh diasumsikan
Browser React Presentasi, local validation, preview, optimistic UX terkendali Final permission, official risk score, immutable approval
Next.js tRPC BFF Input normalization, session forwarding, adapter, UX mapping Akses DB tenant langsung, melewati NestJS guards
NestJS API Authorization, workflow, calculations, transaction, outbox Memercayai role/tenant dari body client
PostgreSQL Durable state, FK, unique, RLS, ACID Session context dari koneksi tanpa transaksi
Garage Object storage, signed access Append-only business audit
Worker Outbox, retry, temp file cleanup Menghapus evidence historis atau bypass policy tanpa service account

5.7 Time, error dan replay

Simpan timestamp UTC, presentasi WIB; semua mutation kritis memakai requestId/idempotencyKey yang stabil antar retry. REST/Next tidak boleh mengasumsikan koneksi timeout berarti server gagal: status mutation perlu dicek ulang. Pertahankan HTTP status 400, 401, 403, 404, 409, 422, 429, 5xx sesuai semantik; rahasiakan detail stack trace.

CHAPTER 06Desain Delegasi

Field-Level Specification — Seluruh Form dan Payload

Spesifikasi validasi dan default untuk 175 field dalam 10 grup form.

6.1 Aturan field-level global [DESIGN]

Tabel di bawah merupakan rancangan detail yang didelegasikan oleh pemilik produk. Kolom Draft menentukan apakah field harus terisi saat pengguna menekan Simpan Draft; Submit menentukan apakah field wajib pada aksi final. Auto berarti dihitung/diset oleh server dan tidak dapat diedit klien. Kond. berarti wajib apabila kondisi tertentu terpenuhi. Teks panjang dipangkas whitespace, kosong tidak disamakan dengan 0, datetime disimpan UTC, identifier disimpan sebagai UUID/ULID atau key stabil yang tidak mengandung data pribadi. Semua pilihan katalog berasal dari server dan dipastikan valid saat submit.

  • Identitas/role/organization context diambil dari session atau membership; jangan beri field createdBy yang bebas ditentukan frontend.
  • Semua mutation perubahan dokumen/submission harus membawa expectedLockVersion dan idempotencyKey pada transport, walaupun UI tidak memperlihatkannya sebagai form field.
  • Validasi frontend hanya bantuan UX; NestJS mengulangi validasi dan mengecek rule transaksi.
  • Bila angka batas di bawah memerlukan penyesuaian operasional (misalnya ukuran file), simpan sebagai konfigurasi kebijakan, bukan asumsi yang tersebar di UI.
  • Untuk form Draft HIRADC/Laporan: penyimpanan manual menerima partial fields yang valid; tidak boleh mengeluarkan status Submitted sebelum seluruh persyaratan final terpenuhi. Draft kosong total ditolak sebagai EMPTY_DRAFT [DESIGN].

6.2 Autentikasi dan akun

Objek Field Tipe Draft Final/Submit Validasi, default, dan ketentuan
Login email email N/A Wajib Trim, lowercase canonical; max 254; generic error
Login password secret N/A Wajib Tidak dilog; rate limit; no credential exposure
Invitation inviteToken opaque token N/A Wajib Once-only, hashed at rest, expiry [DESIGN: 72h configurable]
Invitation passwordNew secret N/A Kond. Wajib untuk user baru; password policy centrally configured
Password reset request email email N/A Wajib Generic success message independent of existence
Password reset confirm otp string(6) N/A Wajib 6-digit numeric; 5m validity; limited attempts [FINAL TTL]
Password reset confirm newPassword secret N/A Wajib Policy strong; invalidates sessions as configured
Profile displayName string(2..120) N/A Wajib No unsupported HTML; trim; UTF-8
Session sessionId opaque Auto Auto HttpOnly Secure host-only cookie; never localStorage
Workspace organizationId UUID Auto Kond. Required for tenant operations, verified membership

6.3 Organisasi, membership dan undangan

Objek Field Tipe Draft Final/Submit Validasi, default, dan ketentuan
Organization legalName string(3..200) N/A Wajib Server detects duplicates within policy
Organization shortName string(2..80) N/A Wajib Shown in switcher; non-unique allowed
Organization status enum Auto Auto ACTIVE/INACTIVE; guarded deactivate
Organization contactEmail email N/A Opsional Canonical email
Membership userId UUID Auto Auto Existing user or invite resolution
Membership organizationId UUID Auto Auto Tenant scope
Membership roleId UUID N/A Wajib Assignable within delegation ceiling
Membership personnelCategory enum Auto Auto OPERATOR/SUPERVISOR/OTHER via role/membership policy
Membership status enum Auto Auto ACTIVE/INACTIVE
Invitation email email N/A Wajib Max 254; reject duplicate active membership
Invitation roleId UUID N/A Wajib Active assignable org role
Invitation expiresAt timestamp Auto Auto [DESIGN] 72h invitation default, configurable
Role name string(3..80) N/A Wajib Unique per org; not a source of privilege
Role description string(0..500) N/A Opsional Plain text
Role personnelCategory enum N/A Wajib Controls recipient class independent from role label
Role permissionKeys string[] N/A Wajib Subset of delegation ceiling, never privilege escalation
Role isSystemTemplate boolean Auto Auto Global template flag, cannot be edited by tenant

6.4 HIRADC — Usulan Bahaya

Objek Field Tipe Draft Final/Submit Validasi, default, dan ketentuan
Risk Proposal areaId enum Opsional Wajib One of four global area keys
Risk Proposal specificLocation string(0..200) Opsional Opsional Free text; trim
Risk Proposal activity string(0..240) Opsional Wajib Nama aktivitas/pekerjaan
Risk Proposal hazardDescription text(0..4000) Opsional Wajib Deskripsi bahaya yang teridentifikasi
Risk Proposal potentialConsequence text(0..3000) Opsional Wajib Dampak yang mungkin timbul
Risk Proposal existingControlNotes text(0..3000) Opsional Opsional Pengendalian eksisting dari pengusul
Risk Proposal evidenceIds UUID[] Opsional Opsional Only UPLOADED/ATTACHED tenant files
Risk Proposal submitNote text(0..1000) Opsional Opsional Catatan pengajuan
Risk Proposal reporterId UUID Auto Auto Taken from session, never editable
Risk Proposal state enum Auto Auto DRAFT/SUBMITTED/ACCEPTED/REJECTED/NEEDS_INFO

6.5 HIRADC — Assessment Version

Objek Field Tipe Draft Final/Submit Validasi, default, dan ketentuan
Risk Assessment riskId UUID Auto Auto Risk record identity, one risk per record
Risk Assessment areaId enum Opsional Wajib One of four global areas
Risk Assessment specificLocation string(0..200) Opsional Opsional Free text
Risk Assessment workActivity string(0..240) Opsional Wajib Aktivitas spesifik
Risk Assessment hazardSource text(0..3000) Opsional Wajib Sumber/kondisi bahaya
Risk Assessment riskEvent text(0..3000) Opsional Wajib Peristiwa risiko
Risk Assessment potentialImpact text(0..3000) Opsional Wajib Konsekuensi operasional/K3
Risk Assessment existingControls text(0..3000) Opsional Wajib Existing risk controls
Risk Assessment initialLikelihoodK int 1..5 Opsional Wajib Kali kemungkinan; kriteria global
Risk Assessment initialSeverityP int 1..5 Opsional Wajib Keparahan; kriteria global
Risk Assessment initialScore computed int Auto Auto K×P; level 1–4/5–9/10–14/15–25
Risk Assessment plannedResidualK int 1..5 Opsional Wajib Prospektif setelah kontrol
Risk Assessment plannedResidualP int 1..5 Opsional Wajib Prospektif setelah kontrol
Risk Assessment plannedResidualScore computed int Auto Auto K×P; never treated as verified actual
Risk Assessment assessmentRationale text(0..3000) Opsional Wajib Alasan/justifikasi penilaian
Risk Assessment controlIds UUID[] Opsional Kond. Minimal 1 rencana pengendalian jika diperlukan; at least 1 required control in MVP [DESIGN]
Risk Assessment evidenceIds UUID[] Opsional Opsional Evidence safely scoped
Risk Assessment submitReviewNote text(0..1500) Opsional Opsional Catatan pemohon
Risk Assessment versionNumber int Auto Auto Monotonic per risk; immutable after approval
Risk Assessment assessmentStatus enum Auto Auto DRAFT/PENDING_REVIEW/NEEDS_REVISION/APPROVED/REJECTED
Risk Assessment matrixVersionId UUID Auto Auto Global version pinned to assessment
Risk Assessment verifiedResidualK int 1..5 N/A Kond. Only when all required controls verified
Risk Assessment verifiedResidualP int 1..5 N/A Kond. Only when all required controls verified
Risk Assessment verifiedResidualScore computed int Auto Auto Never auto-copy planned residual

6.6 HIRADC — Control Task dan Review

Objek Field Tipe Draft Final/Submit Validasi, default, dan ketentuan
Control Plan controlDescription text(10..3000) Opsional Wajib Specific actionable mitigation
Control Plan hierarchyLevel enum Opsional Wajib Elimination/substitution/engineering/administrative/PPE [DESIGN catalog]
Control Plan isRequired boolean Opsional Wajib Default true [DESIGN]
Control Plan picMembershipId UUID Opsional Wajib Active membership same org
Control Plan targetDate date Opsional Opsional Cannot be nonsensical; overdue tolerated with reason
Control Task actionNote text(10..3000) N/A Kond. Required to request verification
Control Task executionEvidenceIds UUID[] N/A Kond. Required if control policy demands evidence
Control Verification decision enum N/A Wajib VERIFY / RETURN_FOR_REWORK
Control Verification reviewNote text(0..3000) N/A Kond. Required when returning for rework
HIRADC Review decision enum N/A Wajib APPROVE / REQUEST_REVISION / REJECT
HIRADC Review reason text(0..2000) N/A Kond. Required for reject/request revision
HIRADC Review assessmentVersionId UUID Auto Auto Target immutable candidate
HIRADC Review expectedLockVersion int Auto Auto Optimistic lock
Official Export riskVersionIds UUID[] N/A Wajib Only eligible approved immutable assessment versions
Official Export title string(3..200) N/A Wajib Snapshot manifest title
Official Export purposeNote string(0..500) N/A Opsional Reason for issuance

6.7 Laporan Bahaya — Draft dan Submit

Objek Field Tipe Draft Final/Submit Validasi, default, dan ketentuan
Hazard Report reportTypeId catalog id Opsional Wajib [DESIGN] UNSAFE_CONDITION/UNSAFE_ACTION/NEAR_MISS/INCIDENT, configurable
Hazard Report severityId catalog id Opsional Wajib [DESIGN] LOW/MEDIUM/HIGH/CRITICAL; CRITICAL special acceptance
Hazard Report areaId enum Opsional Wajib Four global K3 areas
Hazard Report specificLocation string(0..240) Opsional Opsional Free text
Hazard Report occurredAt datetime Opsional Wajib Default now editable; reject future > allowed clock skew [DESIGN]
Hazard Report title string(0..180) Opsional Wajib Trim; readable summary
Hazard Report description text(0..5000) Opsional Wajib What was observed; safety language
Hazard Report immediateAction text(0..3000) Opsional Opsional Steps already taken, if any
Hazard Report evidenceIds UUID[] Opsional Opsional Not mandatory for initial report [DESIGN]
Hazard Report extraRecipientMembershipIds UUID[] Opsional Opsional Active same-org members, dedup
Hazard Report reporterId UUID Auto Auto Session actor
Hazard Report reportNumber string Auto Auto Generated on successful submit; not during draft
Hazard Report acceptanceStatus enum Auto Auto PENDING_APPROVAL/ACCEPTED/REJECTED/NEEDS_CORRECTION
Hazard Report handlingStatus enum Auto Auto UNASSIGNED/ASSIGNED/IN_PROGRESS/PENDING_VERIFICATION/COMPLETED/REOPENED

6.8 Laporan Bahaya — Penanganan, Verifikasi, Revisi

Objek Field Tipe Draft Final/Submit Validasi, default, dan ketentuan
Report Review decision enum N/A Wajib APPROVE/REQUEST_CORRECTION/REJECT
Report Review reviewReason text(0..2000) N/A Kond. Required for correction/reject
PIC Assignment picMembershipId UUID N/A Wajib Active membership and suitable permission
PIC Assignment assignmentNote text(0..2000) N/A Opsional Audit event
PIC Assignment expectedLockVersion int N/A Wajib Prevents concurrent active PIC conflict
Report Action actionDescription text(10..5000) N/A Wajib Action performed
Report Action evidenceIds UUID[] N/A Opsional Optional during process, see completion rule
Report Action performedAt datetime Auto Auto Server timestamp; if actual time editable require reason [DESIGN]
Completion Request completionNote text(10..5000) N/A Wajib Required completion statement
Completion Request completionEvidenceIds UUID[] N/A Kond. At least one OR documented evidence exception
Completion Request evidenceExceptionReason text(20..1500) N/A Kond. Required when no completion evidence
Completion Verification decision enum N/A Wajib VERIFY/RETURN_FOR_REWORK
Completion Verification verificationNote text(0..3000) N/A Kond. Required on return
Report Revision revisionReason text(10..2000) N/A Wajib Must explain material change
Report Revision changeSet object Opsional Wajib Field diff against current effective revision
Report Revision newEvidenceIds UUID[] Opsional Opsional Version-scoped evidence
Report Note body text(1..3000) N/A Wajib Append-only, never edit/delete once submitted
Reopen Report reason text(20..2000) N/A Wajib Audited reopening

6.9 LMS — Course, Lesson, Assessment Authoring

Objek Field Tipe Draft Final/Submit Validasi, default, dan ketentuan
Course title string(3..200) Opsional Wajib Unique enough for catalog; global
Course summary text(0..3000) Opsional Wajib Training description
Course targetAreaIds enum[] Opsional Opsional Zero or more of four global areas
Course preTestEnabled boolean Auto Wajib Default true [DESIGN]
Course learnEnabled boolean Auto Wajib Default true [DESIGN]
Course postTestEnabled boolean Auto Wajib Default true [DESIGN]
Course stageOrder array Auto Auto Pre-Test, Learn, Post-Test, skip disabled
Course courseVersion int Auto Auto Immutable published version
Lesson stableLessonKey string Auto Wajib Stable across unchanged lessons; version linked
Lesson title string(3..180) Opsional Wajib Trim
Lesson content rich text JSON Opsional Wajib Sanitize HTML, media whitelist, min meaningful content
Lesson mediaEvidenceIds UUID[] Opsional Opsional Global asset bucket logical scope
Lesson isRequired boolean Auto Wajib Default true [DESIGN]
Lesson sortOrder int Auto Wajib Unique within published course version
Lesson fingerprint hash Auto Auto Deterministic canonical content + meaningful settings
Assessment type enum Auto Wajib PRE_TEST or POST_TEST
Assessment passingThreshold int 0..100 Opsional Kond. Default 80 for Post-Test; Pre-Test no passing gate
Assessment attemptLimit int 1..20 Opsional Wajib Default 3 [PROVISIONAL], versioned; configurable
Assessment shuffleQuestions boolean Auto Wajib Default false [DESIGN]
Assessment shuffleOptions boolean Auto Wajib Default false [DESIGN]
Assessment questionIdList UUID[] Opsional Wajib At least 1 active question
Assessment fingerprint hash Auto Auto Includes questions, options, correct answers, weights, threshold, rules
Question stem text(5..5000) Opsional Wajib Rich content sanitized
Question type enum Auto Wajib MVP SINGLE_CHOICE [DESIGN]
Question options array(2..8) Opsional Wajib At least two options and distinct IDs
Question correctOptionId UUID Opsional Wajib Privileged authoring only; never participant API
Question weight positive number Auto Wajib Default 1 [DESIGN]; normalised to percent
Publication releaseNote text(0..2000) N/A Opsional Recommended for change trace
Publication expectedDraftVersion int N/A Wajib Prevents publish race

6.10 LMS — Participant dan Attempt

Objek Field Tipe Draft Final/Submit Validasi, default, dan ketentuan
Learning Progress courseId UUID Auto Auto Global published course identity
Learning Progress organizationId UUID Auto Auto Tenant progress
Lesson Completion lessonKey string Auto Wajib Exact stable key and fingerprint published
Lesson Completion fingerprint hash Auto Auto Server validates against current lesson
Assessment Start assessmentVersionId UUID Auto Wajib Current published version, quota guarded
Assessment Start idempotencyKey UUID/string Auto Wajib No duplicate start on retry
Assessment Answer questionId UUID N/A Wajib Belongs to attempt snapshot
Assessment Answer selectedOptionId UUID N/A Wajib One valid option of question
Assessment Answer answerRevision int N/A Wajib Sequential update; prevents stale overwrite
Assessment Submit attemptId UUID N/A Wajib One active attempt per config [DESIGN]
Assessment Submit expectedLockVersion int N/A Wajib Prevent double submit
Assessment Result score 0..100 Auto Auto Computed server-side
Assessment Result passed boolean Auto Auto Post-test threshold; Pre-test diagnostic
Assessment Result status enum Auto Auto IN_PROGRESS/SUBMITTED/ABANDONED/INTERRUPTED_BY_UPDATE

6.11 Evidence, Audit, Email dan Support Grant

Objek Field Tipe Draft Final/Submit Validasi, default, dan ketentuan
Upload Init filename string(1..255) N/A Wajib Strip path separators; escaped display
Upload Init mimeType string N/A Wajib Allowlisted mime, server sniff after upload
Upload Init sizeBytes int N/A Wajib [DESIGN] images <=10MB, PDF <=20MB; configurable
Upload Init purpose enum N/A Wajib REPORT/RISK/CONTROL/LESSON; bucket/path policy
Evidence objectKey opaque Auto Auto No user PII in object key; tenant scoped
Evidence state enum Auto Auto PENDING/UPLOADED/ATTACHED
Evidence sha256 hex(64) Auto Auto Integrity/hash validation on finalize [DESIGN]
AuditEvent actorId UUID Auto Auto Authenticated actor
AuditEvent organizationId UUID? Auto Auto Tenant or null global
AuditEvent entityRef string Auto Auto Stable entity ID/version
AuditEvent eventType enum Auto Auto Append-only typed event
Outbox eventType enum Auto Auto Business event trigger
Outbox recipients email[] Auto Auto Snapshot + dedup, enforce policy
Outbox status enum Auto Auto PENDING/PROCESSING/SENT/FAILED
Support Request organizationId UUID N/A Wajib Target tenant
Support Request purpose text(20..2000) N/A Wajib Why support access needed
Support Request resourceScope resource ID[] N/A Wajib Explicit resource list, not wildcard [DESIGN]
Support Request requestedMinutes int N/A Wajib [PROVISIONAL] max 120, default 60
Support Review decision enum N/A Wajib APPROVE/REJECT
Support Review reviewReason text(0..2000) N/A Kond. Mandatory on reject
Support Grant expiresAt timestamp Auto Auto Time bound; server-now check each request
Support Grant mode enum Auto Auto READ_ONLY only
Support Revocation reason text(10..1000) N/A Wajib Audited revoke

6.15 Field dependency dan conditional behavior

Condition UI effect Server rule
Severity == CRITICAL Warning jelas, email urgent flag, confirmation Auto-ACCEPTED; handling belum selesai
Completion tanpa evidence Field evidenceExceptionReason wajib Action ditolak jika kedua evidence dan exception kosong
Review == REJECT/REQUEST_REVISION Kolom alasan wajib Approval event mencatat reason
Semua kontrol wajib VERIFIED Verified residual input dapat dibuka bagi Pengawas berizin Server menghitung required-control set pada assessment version efektif
postTestEnabled=false Stage Post-Test disembunyikan Course completion tidak mengharuskan skor tes
lessonFingerprint berubah Materi tampil perlu dibaca kembali Completion lama disimpan sebagai histori, bukan completion current
assessmentFingerprint berubah Informasi versi baru dan kuota assessment baru Attempt aktif lama interrupted_by_update dan tidak mengurangi quota
Perubahan organisasi saat form dirty Dialog batalkan perubahan atau tinggalkan form Submit dengan konteks lama/wrong tenant ditolak
Support grant expired Keluar dari mode support Semua read, file signed URL issuance, data access ditolak

6.16 Batasan data dan kontrak input

ID pada daftar harus referentially valid; organizationId diperiksa sesudah autentikasi; sensitive strings tidak masuk audit detail/log; HTML dari editor harus disanitasi dan link/file dikendalikan. Tanggal occurredAt dari pengguna memiliki sumber dan timezone eksplisit. Perubahan versi/approval memerlukan expectedLockVersion. Semua field submission yang optional benar-benar diterima sebagai null/absent oleh backend; jangan mengirim string "undefined" atau menyamakan angka nol dengan tidak terisi.

CHAPTER 07Desain Delegasi

Permission Registry, Action Matrix & Delegation Rules

53 aksi dengan permission key, domain, scope, dan guard bisnis.

7.1 Aturan inti otorisasi [FINAL]

  • Akses ditentukan dari effective permission + tenant context + record scope + business guard, bukan hanya string nama role. Contoh default role pada tabel ditandai * sebagai pemetaan rekomendasi, bukan hak yang tidak dapat diubah oleh admin.
  • Satu user dapat mempunyai beberapa organisasi, tetapi satu membership hanya satu role aktif; kategori personel disimpan terpisah. Organization Admin tidak otomatis Pengawas; Admin K3 tidak otomatis tenant reader; Super Admin tidak otomatis tenant reader.
  • Semua endpoint read dan mutation wajib menegakkan policy; frontend PermissionGate hanya aspek UX. Support Access tidak menambah role tenant dan selalu read-only.
  • Untuk setiap perubahan izin, event audit merekam actor, role sebelum/sesudah, organisasi, reason bila relevan, waktu dan lock version.

7.2 Permission registry dan action matrix [DESIGN]

Domain Permission key UI/aksi yang dilindungi Guard tambahan wajib Default contoh / kategori
Navigasi organization.workspace.enter Melihat workspace organisasi Membership aktif pada tenant aktif Operator/Pengawas/Org Admin*
Profil account.profile.read Membaca profil sendiri Subject = actor Semua akun
Profil account.profile.update Mengubah profil sendiri Whitelist field non-privileged Semua akun
HIRADC hiradc.risk.read Melihat Risk Register dan detail risiko Tenant scope, status/visibility Operator/Pengawas*
HIRADC hiradc.proposal.create Membuat usulan bahaya Membership aktif; pembuat dari session Operator/Pengawas*
HIRADC hiradc.proposal.read Melihat usulan Own atau permission org-wide Operator/Pengawas*
HIRADC hiradc.proposal.review Menilai usulan Proposal valid, transaction guard Pengawas*
HIRADC hiradc.assessment.create Membuat draft penilaian formal Domain capability, record scoped Pengawas*
HIRADC hiradc.assessment.update-draft Mengubah assessment draft Owner/authorized editor; lockVersion Pengawas*
HIRADC hiradc.assessment.submit Mengajukan assessment Field lengkap, K×P valid Pengawas*
HIRADC hiradc.assessment.review Setuju/tolak/minta revisi No self-approval terhadap pembuat risiko maupun versi Pengawas*
HIRADC hiradc.control.assign Menugaskan kontrol Satu PIC aktif, target org membership Pengawas*
HIRADC hiradc.control.execute Catat tindakan pengendalian PIC atau delegasi valid Operator/Pengawas*
HIRADC hiradc.control.verify Verifikasi kontrol Pengawas berizin; self-verification PIC diperbolehkan Pengawas*
HIRADC hiradc.residual.verify Tetapkan verified residual Semua kontrol wajib VERIFIED; K/P baru diisi Pengawas*
HIRADC hiradc.version.read Lihat versi assessment Tenant, record visibility Operator/Pengawas*
HIRADC hiradc.export.issue Terbitkan PDF resmi Hanya approved version; snapshot immutable Pengawas*
Laporan Bahaya hazard.report.read Membaca daftar/detail Tenant scope plus record visibility Operator/Pengawas*
Laporan Bahaya hazard.report.create Membuat draft laporan Active membership Operator/Pengawas*
Laporan Bahaya hazard.report.submit Submit draft laporan Validasi final, atomic numbering Operator/Pengawas*
Laporan Bahaya hazard.report.review Menerima, koreksi, menolak Pengawas berizin; self-approval diperbolehkan Pengawas*
Laporan Bahaya hazard.report.assign Menetapkan/mengganti PIC Satu PIC aktif, valid membership Pengawas*
Laporan Bahaya hazard.report.action Catat tindakan PIC berwenang; current effective revision Operator/Pengawas*
Laporan Bahaya hazard.report.request-verification Ajukan hasil penanganan Catatan + evidence atau exception PIC/authorized*
Laporan Bahaya hazard.report.verify Verifikasi penyelesaian Pengawas berizin, guard state Pengawas*
Laporan Bahaya hazard.report.revise Ajukan revisi substantif Accepted report; current effective unchanged Reporter/authorized*
Laporan Bahaya hazard.revision.review Approve/reject revisi Review submission version candidate Pengawas*
Laporan Bahaya hazard.report.note.append Catatan tambahan Append-only termasuk completed Authorized member*
Laporan Bahaya hazard.report.reopen Buka kembali Alasan wajib, history event Pengawas*
LMS Peserta learning.course.read Buka katalog/lesson Global published course; enrolled tenant context Operator/Pengawas/Org Admin*
LMS Peserta learning.lesson.complete Tandai lesson selesai Current course/lesson fingerprint Peserta*
LMS Peserta learning.attempt.start Mulai Pre/Post-Test Prerequisites + quota + version check Peserta*
LMS Peserta learning.attempt.answer Kirim/perbarui jawaban attempt Owner attempt, version, question membership Peserta*
LMS Peserta learning.attempt.submit Submit assessment Owner, quota, idempotent scoring Peserta*
LMS Peserta learning.history.self Lihat histori pribadi Actor = participant Peserta*
LMS Monitoring learning.participant.monitor Monitor progres tenant Only org active + permitted participant set Pengawas/Org Admin*
Org Admin organization.read Lihat profil organisasi Membership current tenant Org Admin*
Org Admin organization.members.manage Kelola membership Delegation ceiling, last org admin guard Org Admin*
Org Admin organization.invitation.manage Undang/cabut/kirim ulang Cannot grant role above ceiling Org Admin*
Org Admin organization.role.read Lihat role lokal Tenant scoped Org Admin*
Org Admin organization.role.manage Ubah permission lokal Cannot escalate own ceiling or manage global template Org Admin*
Support Access support.request.create Request tenant scoped access Global platform role; explicit resources Super Admin
Support Access support.request.review Approve/reject support request Org Admin target tenant; not requester Org Admin*
Support Access support.grant.read Read granted records Approved grant + resource + time + read-only Super Admin via grant
Support Access support.grant.revoke Revoke grant Approving org authority or authorized platform abort Org Admin*/Platform*
Platform platform.organization.manage Kelola metadata tenant No business data read by default Super Admin
Platform platform.account.manage Manage platform role/account No tenant membership escalation Super Admin
Platform platform.role-template.manage Kelola template RBAC global Versioned; org template copy policy Super Admin
K3 Content content.course.manage Create/edit course global draft Global-only resource Admin K3
K3 Content content.lesson.manage Create/edit lesson Stable lesson key/fingerprint Admin K3
K3 Content content.assessment.manage Question/answer authoring Answer keys only privileged endpoints Admin K3
K3 Content content.course.publish Publish course version Compare fingerprints, atomic update Admin K3
Audit audit.business.read Baca event bisnis yang diizinkan Tenant visibility or platform global metadata Authorized auditor*

7.3 Delegation ceiling & non-escalation

Setiap role lokal memiliki permission efektif subset dari role delegation ceiling milik administrator yang menugaskan. Administrator tidak boleh: memberikan hak yang ia tidak boleh delegasikan, mengubah role dirinya untuk memperoleh hak yang melebihi ceiling, menghapus/menonaktifkan Organization Admin aktif terakhir, memberi platform role melalui tenant role editor, atau mengaktifkan grant Support Access tanpa keputusan target Org Admin.

7.4 UI matrix dan navigation

  • Menu ditampilkan apabila setidaknya satu screen/action dalam kategori dapat diakses; tindakan dikontrol terpisah oleh izin spesifik. Jangan tampilkan tombol approval hanya karena user dapat membaca record.
  • Dashboard KPI menghitung hanya item yang boleh diakses oleh aktor; jangan menyimpulkan permission dari angka agregat. Filter tenant wajib ikut dalam cache key ['org',organizationId,'user',userId,...].
  • Personel yang menerima email berdasarkan klasifikasi Operator/Pengawas tidak otomatis memperoleh hak mutation; read permission harus konsisten agar deep link tidak dead end. Saat perlu, buat scoped read permission dengan tujuan dan audit yang benar, bukan bypass.

7.5 Support Access action limitations

Grant memuat tenant, requester, approving admin, enumerasi resource yang disetujui, valid-from/expiry/revocation, dan READ_ONLY. Tidak boleh wildcard secara default, tidak berlaku ke tenant lain, dan tidak boleh mengedit/export luas kecuali download/preview spesifik tercakup eksplisit. Setiap operasi read menilai grant yang masih aktif pada saat request, sekalipun browser masih menyimpan halaman sebelumnya.

CHAPTER 08Desain Delegasi

State Transition Matrix & Business Invariants

40 perubahan status dan guard untuk HIRADC, Laporan Bahaya, LMS, Support Access.

8.1 Sumber kebenaran state

State disimpan di backend untuk MVP. UI membaca kode yang stabil, menerjemahkan via status registry code/label/color/description/allowedActions, dan tidak menentukan perubahan state dengan mutasi lokal. Transition = satu transaksi DB untuk record + version pointer/assignment + audit/outbox yang terkait. Mock prototype menirukan transaksi tersebut dalam state update tunggal.

8.2 State transition matrix [DESIGN]

Object Status awal Event/aksi Status hasil Precondition/guard Side effect
Hazard Report DRAFT SAVE_DRAFT DRAFT owner; partial validation Tidak buat nomor/email
Hazard Report DRAFT SUBMIT noncritical PENDING_APPROVAL submit complete, idempotent Nomor, versi efektif, audit, outbox
Hazard Report DRAFT SUBMIT critical ACCEPTED severity=CRITICAL Accepted tanpa selesai; urgent outbox
Acceptance PENDING_APPROVAL APPROVE ACCEPTED hazard.report.review Buka assignment queue
Acceptance PENDING_APPROVAL REQUEST_CORRECTION NEEDS_CORRECTION reason wajib Tetap belum accepted
Acceptance PENDING_APPROVAL REJECT REJECTED reason wajib Immutable event, stop handling
Acceptance NEEDS_CORRECTION RESUBMIT PENDING_APPROVAL complete and scoped new submission event
Handling UNASSIGNED ASSIGN_PIC ASSIGNED one active PIC; accepted assignment start + audit
Handling ASSIGNED START_WORK IN_PROGRESS current PIC/authorized timestamp
Handling IN_PROGRESS REQUEST_VERIFICATION PENDING_VERIFICATION note + evidence or exception freeze submission content
Handling PENDING_VERIFICATION VERIFY COMPLETED hazard.report.verify history + completedAt
Handling PENDING_VERIFICATION RETURN IN_PROGRESS reason wajib rework event
Handling COMPLETED REOPEN REOPENED authorized; reason wajib history persists
Handling REOPENED ASSIGN_OR_CONTINUE IN_PROGRESS PIC valid continuation event
Report Revision none CREATE_CANDIDATE DRAFT accepted report does not replace effective
Report Revision DRAFT SUBMIT PENDING_REVIEW revision reason, valid diff effective unchanged
Report Revision PENDING_REVIEW APPROVE APPROVED hazard.revision.review atomic effective pointer swap
Report Revision PENDING_REVIEW REQUEST_CORRECTION NEEDS_CORRECTION reason effective unchanged
Report Revision PENDING_REVIEW REJECT REJECTED reason effective unchanged
Risk Proposal DRAFT SUBMIT SUBMITTED core hazard details valid proposal event
Risk Proposal SUBMITTED ACCEPT ACCEPTED hiradc.proposal.review eligible formal assessment
Risk Proposal SUBMITTED REJECT REJECTED reason wajib event immutable
HIRADC Assessment DRAFT SUBMIT_REVIEW PENDING_REVIEW K/P/controls valid version snapshot frozen for review
HIRADC Assessment PENDING_REVIEW APPROVE APPROVED no self approve, permission effective pointer and audit
HIRADC Assessment PENDING_REVIEW REQUEST_REVISION NEEDS_REVISION reason wajib effective previous unchanged
HIRADC Assessment PENDING_REVIEW REJECT REJECTED reason wajib effective previous unchanged
Control Task TO_DO/ASSIGNED START IN_PROGRESS PIC/authorized task event
Control Task IN_PROGRESS REQUEST_VERIFICATION PENDING_VERIFICATION action note and policy evidence submitted action snapshot
Control Task PENDING_VERIFICATION VERIFY VERIFIED supervisor permission verification event
Control Task PENDING_VERIFICATION RETURN NEEDS_REWORK reason wajib rework event
Control Task NEEDS_REWORK RESUME IN_PROGRESS PIC/authorized new action revision
Verified Residual NOT_VERIFIED VERIFY_RESIDUAL VERIFIED ALL required controls VERIFIED distinct measured K,P and audit
LMS Attempt NONE START IN_PROGRESS prerequisites + quota quota reservation counted
LMS Attempt IN_PROGRESS SUBMIT SUBMITTED version current, answers valid atomic score/result
LMS Attempt IN_PROGRESS ABANDON ABANDONED explicit exit/expiry policy quota still counts
LMS Attempt IN_PROGRESS PUBLISH_CHANGED INTERRUPTED_BY_UPDATE assessment fingerprint changed quota refunded/excluded
Course Draft DRAFT PUBLISH PUBLISHED VERSION +1 valid lessons/assessments atomic global pointer change
Support Request REQUESTED APPROVE GRANTED tenant Org Admin reviewer read-only, scoped, expiry
Support Request REQUESTED REJECT REJECTED reason wajib no grant
Support Grant GRANTED EXPIRE/REVOKE EXPIRED/REVOKED time or authorization block further read and signed URL creation

8.3 Irregular transitions

  • HARUS TOLAK: double approval pada version yang sudah diputuskan; publish dua draft yang sama; duplikasi PIC aktif; submit attempt dua kali; self-approve HIRADC; submit atas organisasi lain; verified residual jika masih ada kontrol wajib non-VERIFIED.
  • RETRY AMAN: timeout setelah server berhasil, memakai idempotency key yang sama; API mengembalikan hasil operasi pertama atau status final saat lookup. Jangan menaikkan version atau mengirim email berulang.
  • KONFLIK: expectedLockVersion tidak cocok menghasilkan 409 VERSION_CONFLICT dengan metadata aman (currentVersion, updatedAt, retryHint); halaman harus reload/compare sebelum retry.
  • VERSI EFEKTIF: hanya versi APPROVED/ACCEPTED yang dipakai operasional. Candidate draft/pending tidak menggantikan data efektif. Historic notes/attachments pada versi lama tetap dapat dilihat sesuai izin.

8.4 Status presentation registry (contoh desain)

Domain code Label UI (Indonesia) Semantic color Catatan
DRAFT Draft Neutral Belum final
PENDING_APPROVAL / PENDING_REVIEW Menunggu Persetujuan Warning Menunggu keputusan
ACCEPTED / APPROVED Disetujui/Diterima Success Belum tentu penanganan completed
NEEDS_CORRECTION / NEEDS_REVISION Perlu Perbaikan Warning Alasan terlihat
REJECTED Ditolak Critical Record tetap histori
IN_PROGRESS Dalam Penanganan Information PIC/tindakan aktif
PENDING_VERIFICATION Menunggu Verifikasi Warning Submission menunggu review
COMPLETED / VERIFIED Selesai / Terverifikasi Success Event tersimpan
INTERRUPTED_BY_UPDATE Terhenti karena Pembaruan Neutral Attempt tidak dihitung kuota

8.5 Event audit minimum

Setiap event final mempunyai eventId, actorId, organizationId?, entityType, entityId, versionId?, action, prevState, nextState, occurredAt, requestId, reason?. Event audit append-only; catatan baru menambah baris, bukan update lama. Simpan diff field non-sensitif bila perlu tanpa menyimpan kredensial, OTP, atau raw answer key.

CHAPTER 09Normatif

API, DTO, Error Envelope & Payload Examples

Inventaris 35 endpoint representatif dan contoh payload lintas modul.

9.1 API style and routing policy

  • NestJS REST base /api/v1; browser memakai Next.js tRPC BFF sebagai pola pilihan [PROVISIONAL DESIGN]. Backend tetap memverifikasi session, X-Organization-Id yang dinormalisasi BFF, membership, permission, record ownership, RLS. Header dari client publik tidak dipercaya.
  • OpenAPI versioned artifact menjadi kontrak antarrepository; request/response dan error typed; jangan menyalin DTO manual tanpa contract test.
  • Default pagination cursor/limit untuk daftar besar; limit 1..100 [DESIGN], sort key whitelist; semua filter server-side juga scoped pada tenant.

9.2 Endpoint inventory (representatif dan normatif secara fungsi, path exact [DESIGN])

Method NestJS endpoint Input/output inti Guard
GET /api/v1/session current session Authenticated
POST /api/v1/auth/login email + password CSRF, rate-limit
POST /api/v1/auth/logout none session revoke
GET /api/v1/organizations/mine memberships No cross org data
GET /api/v1/hiradc/risks filters + page hiradc.risk.read
POST /api/v1/hiradc/proposals proposal DTO hiradc.proposal.create
POST /api/v1/hiradc/assessments assessment DTO assessment.create
POST /api/v1/hiradc/assessments/{id}/submit version + idempotency assessment.submit
POST /api/v1/hiradc/assessments/{id}/review decision/reason/version No self approval
POST /api/v1/hiradc/controls/{id}/verify decision, evidence, version Permission and status
POST /api/v1/hiradc/risks/{id}/verify-residual K,P/version All required controls verified
POST /api/v1/hiradc/exports approved version set Immutable snapshot
GET /api/v1/hazard-reports filter + page hazard.report.read
POST /api/v1/hazard-reports/drafts partial DTO createDraft
PATCH /api/v1/hazard-reports/drafts/{id} partial DTO + version saveDraft
POST /api/v1/hazard-reports/drafts/{id}/submit idempotency/version report submit
POST /api/v1/hazard-reports/{id}/review decision/reason review
POST /api/v1/hazard-reports/{id}/assignment PIC/version one active PIC
POST /api/v1/hazard-reports/{id}/actions note/evidence PIC
POST /api/v1/hazard-reports/{id}/verify decision/reason verification
POST /api/v1/hazard-reports/{id}/revisions candidate diff effective unchanged
GET /api/v1/learning/courses published only tenant learner
POST /api/v1/learning/lessons/{id}/complete fingerprint manual complete
POST /api/v1/learning/attempts version + idempotency quota locked
PATCH /api/v1/learning/attempts/{id}/answers question and answer revision owner + current version
POST /api/v1/learning/attempts/{id}/submit version/idempotency single score
GET /api/v1/learning/monitoring course and participant filters tenant scoped
POST /api/v1/content/courses/{id}/publish draft/version global Admin K3
POST /api/v1/admin/members/invite email/role/org delegation ceiling
PATCH /api/v1/admin/members/{id}/role role/version last-admin guard
POST /api/v1/support/requests purpose/scope/duration platform requester
POST /api/v1/support/requests/{id}/review decision/reason target tenant Org Admin
GET /api/v1/support/grants/{id}/resources/{resourceId} grant ID strict read only
POST /api/v1/files/uploads filename/mime/size/purpose presigned URL issuance
POST /api/v1/files/{id}/finalize file checksum + version PENDING→UPLOADED

9.3 Standard successful result envelope

{
  "data": { "id": "record-123", "status": "PENDING_REVIEW", "lockVersion": 3 },
  "meta": { "requestId": "req-abc", "serverTime": "2026-11-05T09:00:00Z" }
}

9.4 Standard domain error envelope

{
  "error": {
    "code": "VERSION_CONFLICT",
    "message": "Data telah diperbarui oleh pengguna lain.",
    "details": { "currentLockVersion": 4 },
    "requestId": "req-abc"
  }
}

Jangan masukkan stack trace, email/OTP/raw cookie, maupun existence detail untuk record tenant yang tidak berizin ke error response.

9.5 Payload Laporan Bahaya - submit

{
  "organizationId": "org-a",
  "draftId": "draft-118",
  "expectedLockVersion": 1,
  "idempotencyKey": "03d6cf5e-9d18-4a19-9ed5-fdeec3ad9d6a",
  "report": {
    "reportTypeId": "UNSAFE_CONDITION",
    "severityId": "CRITICAL",
    "areaId": "AREA_DISINFECTION",
    "specificLocation": "Ruang klorinasi",
    "occurredAt": "2026-11-05T09:00:00Z",
    "title": "Kondisi berbahaya pada sistem desinfektan",
    "description": "Deskripsi faktual hasil pengamatan petugas.",
    "immediateAction": "Area dibatasi dan pengawas dihubungi.",
    "evidenceIds": ["ev-001"],
    "extraRecipientMembershipIds": ["mem-009"]
  }
}

Expected: acceptanceStatus=ACCEPTED, handlingStatus=UNASSIGNED, generated report number, new effective revision, audit event, urgent outbox; tidak langsung COMPLETED.

9.6 Payload HIRADC - submit version

{
  "organizationId": "org-a",
  "riskId": "risk-001",
  "assessmentVersionId": "assess-003",
  "expectedLockVersion": 2,
  "idempotencyKey": "d48d7139-0eb6-402e-82db-82e9d111c040",
  "assessment": {
    "areaId": "AREA_PROCESS_CHEMICAL",
    "workActivity": "Penyiapan bahan kimia proses",
    "hazardSource": "Paparan bahan kimia dalam penyiapan",
    "riskEvent": "Paparan tidak disengaja",
    "potentialImpact": "Gangguan keselamatan operator",
    "existingControls": "Instruksi kerja dan APD sesuai prosedur",
    "initialLikelihoodK": 4,
    "initialSeverityP": 4,
    "plannedResidualK": 2,
    "plannedResidualP": 3,
    "assessmentRationale": "Berdasarkan kondisi pekerjaan dan kontrol yang direncanakan",
    "controlIds": ["control-01", "control-02"]
  }
}

Expected: skor awal 16/Very High; planned residual 6/Moderate; verified residual tetap belum ada. Assessment version menjadi pending review; keputusan harus oleh reviewer yang bukan pencipta record/versi.

9.7 Payload approval dan concurrency

{
  "organizationId": "org-a",
  "assessmentVersionId": "assess-003",
  "decision": "APPROVE",
  "reason": null,
  "expectedLockVersion": 3,
  "idempotencyKey": "f4e22221-40c8-4ad2-962d-fb67cdd937a3"
}

Guard: hiradc.assessment.review, reviewer bukan creator risiko/versi, still pending, version lock cocok; update pointer effective + audit dalam satu transaction.

9.8 Payload LMS attempt start & submit

{
  "organizationId": "org-a",
  "courseId": "course-gas-klor",
  "assessmentVersionId": "post-v2",
  "idempotencyKey": "04d6d12e-63b3-48bb-9b0a-e0cd2c4a03f0"
}
{
  "organizationId": "org-a",
  "attemptId": "attempt-003",
  "expectedLockVersion": 5,
  "idempotencyKey": "b42c7212-a183-4370-b57a-8d810b35ed49",
  "answers": [
    { "questionId": "q1", "selectedOptionId": "opt-b" },
    { "questionId": "q2", "selectedOptionId": "opt-c" }
  ]
}

Backend menghitung score dan menyimpan answer snapshot yang berkaitan dengan assessment version. Answer key tidak pernah dimasukkan ke participant-facing payload.

9.9 Upload presign response (illustrative)

{
  "data": {
    "evidenceId": "ev-001",
    "method": "PUT",
    "uploadUrl": "https://storage.example.invalid/signed/object?...",
    "requiredHeaders": { "Content-Type": "image/jpeg" },
    "expiresInSeconds": 300,
    "state": "PENDING"
  }
}

Signed URL memakai host yang sesuai dengan signature dan dilayani Nginx langsung ke Garage; query string, method dan signed headers tidak boleh dimodifikasi client/proxy. example.invalid adalah placeholder, bukan URL produksi.

9.10 BFF session mapping

Next.js membaca host-only HttpOnly session cookie, meneruskan credential ke NestJS dengan mekanisme internal aman, mengambil organizationId eksplisit dari tRPC operation, melakukan input validation, lalu NestJS menegakkan scope. BFF tidak boleh membuat header X-Organization-Id dari state sembarang tanpa validasi business session; NestJS tetap menolak header palsu. All unsafe mutations CSRF protected.

CHAPTER 10Normatif

Database Architecture, Schema & PostgreSQL RLS

Peta 39 tabel logis, composite FK, transaction isolation, migration, dan kontrol RLS.

10.1 Design principles

Relational PostgreSQL adalah single source of truth untuk sesi, organisasi, transaksi domain, LMS, outbox dan audit. pgvector tersedia tetapi fitur AI di luar MVP. Gunakan migration versioned, foreign key, NOT NULL dan CHECK/UNIQUE untuk invariants yang dapat ditegakkan DB. Public IDs sebaiknya UUID/ULID; official_no urutan bisnis yang diterbitkan di dalam transaksi dan unik per tenant.

10.2 Logical schema dan tabel utama [DESIGN]

Domain Table Kolom/indeks penting Aturan integritas
Identity users id PK, email UNIQUE CITEXT, password_hash, status, created_at Global identity, no tenant scope
Identity sessions id PK, user_id FK, token_hash UNIQUE, idle_expires_at, absolute_expires_at Opaque session token hashed at rest
Identity password_reset_otps user_id, code_hash, expires_at, used_at, attempt_count 5 min, 6 digits; one-time use
Tenant organizations id PK, slug UNIQUE, name, status, created_at Global metadata
Tenant memberships id PK, user_id, organization_id, role_id, status UNIQUE(user_id,organization_id), composite tenant FKs
RBAC permissions key PK, domain, description, delegable Global registry
RBAC role_templates id, version, category, content_hash Global, immutable template versions
RBAC organization_roles id, organization_id, name, personnel_category, ceiling Tenant role definitions
RBAC organization_role_permissions organization_id, role_id, permission_key Composite FK, unique role+permission
HIRADC risk_proposals id, organization_id, area_id, creator, status, data Owner/scope RLS
HIRADC risk_records id, organization_id, current_approved_version_id, created_by One risk per record
HIRADC assessment_versions id, organization_id, risk_id, version_no, status, score fields, lock_version UNIQUE(risk_id,version_no); approved immutable
HIRADC risk_controls id, organization_id, risk_id, stable_control_key, required Plan/control identity across versions
HIRADC assessment_version_controls organization_id, version_id, control_id, controls snapshot Version references
HIRADC control_tasks id, organization_id, control_id, pic_membership_id, status, version Execution continuity
HIRADC control_events id, organization_id, control_task_id, action, actor, payload Append-only
HIRADC risk_exports id, organization_id, manifest_json, object_id, issued_by Immutable approved snapshot
Hazard hazard_reports id, organization_id, official_no, reporter_id, acceptance, handling, effective_revision_id Unique tenant report no; lock version
Hazard hazard_revisions id, organization_id, report_id, version_no, status, data Unique report/version; immutable accepted snapshot
Hazard report_assignments id, organization_id, report_id, pic_id, started_at, ended_at Partial UNIQUE(report_id) WHERE ended_at IS NULL
Hazard report_actions id, organization_id, report_id, author, body, evidence refs Append-only
Hazard report_verifications id, organization_id, report_id, decision, note Append-only
Hazard report_notes id, organization_id, report_id, body, author Append-only even completed
LMS Global courses id PK, slug, title, current_published_version_id No tenant ownership
LMS Global course_versions id, course_id, version_no, status, config, fingerprint Immutable published
LMS Global lesson_versions id, stable_key, course_version_id, content, fingerprint Global immutable published version
LMS Global assessment_versions id, course_version_id, type, config, fingerprint No participant answer key access
LMS Global question_versions id, assessment_version_id, stem, options, correct_answer, weight Authoring security boundary
LMS Tenant course_progress id, organization_id, membership_id, course_id, current_version Tenant scope; no forced mass reset
LMS Tenant lesson_completions id, organization_id, user_id, course_id, lesson_key, fingerprint Unique completion identity by fingerprint
LMS Tenant assessment_attempts id, organization_id, user_id, assessment_version_id, status, lock_version Atomic quota reservation; version pinned
LMS Tenant attempt_answers id, organization_id, attempt_id, question_id, option_id, answer_revision Attempt owner, encrypted/privacy controls if needed
Storage file_objects id, organization_id?, purpose, object_key, mime, size, state, sha256 PENDING/UPLOADED/ATTACHED, global or tenant scoped
Storage file_attachments id, organization_id?, file_id, entity_type, entity_id, version_id File and target same scope
Audit business_audit_events id, organization_id?, entity_ref, actor, action, payload, occurred_at Append-only, least-data
Email outbox_messages id, event_id, event_type, payload, state, next_attempt_at Enqueued in business transaction
Email outbox_delivery_attempts id, outbox_id, recipient_hash, attempt, response Troubleshooting without sensitive content
Support support_requests id, organization_id, requester_id, scope, purpose, status Target tenant approves
Support support_grants id, request_id, approver_id, scopes, expires_at, revoked_at Read-only and expiring

10.3 Tenant keys and RLS

  • Pada setiap tabel tenant, gunakan organization_id NOT NULL, indeks (organization_id, status, created_at) atau indeks komposit sesuai pola query, dan composite FK pada semua relasi tenant agar join antar-tenant tidak mungkin secara struktural.
  • Application DB role bukan owner tabel dan tidak memiliki BYPASSRLS; migration menggunakan role terpisah. Terapkan ENABLE ROW LEVEL SECURITY dan FORCE ROW LEVEL SECURITY jika owner path masih mungkin, beserta explicit USING/WITH CHECK untuk SELECT/INSERT/UPDATE/DELETE yang perlu.
  • Saat request tenant: ambil DB connection dalam transaction; setelah server memvalidasi session & membership, jalankan SELECT set_config('app.organization_id', $1, true) atau SET LOCAL di transaction yang sama, serta context user/grant bila perlu. Query dan commit dijalankan dalam transaction tersebut; pool connection tidak boleh mewarisi context request sebelumnya.
  • RLS bukan satu-satunya authorization: NestJS policy memeriksa effective permission + ownership + workflow state dan support grant scopes. Super Admin tidak diberi bypass tenant RLS untuk support access. Jika support read menuntut mekanisme berbeda, rancang narrowly-scoped database function/service with audit and deny-write, lalu uji secara khusus.
  • Background worker menggunakan service account dengan kebijakan spesifik dan audit; jangan memakainya untuk melakukan operasi lintas tenant generik tanpa scoping.

10.4 Transaksi dan locking

  • submitHazardReport: validasi draft, row lock, nomor resmi unik, accepted if critical, current revision, audit, outbox satu transaksi.
  • reviewHIRADC: lock assessment version + risk pointer, enforce reviewer not creator of risk/version, conditional status update, append audit, commit.
  • reassignPIC: close existing active assignment + insert new active within transaction; partial unique index rejects races.
  • verifyResidual: evaluate all required controls in consistent transaction snapshot, lock relevant version/task, then store verified K/P and audit.
  • startAttempt: lock participant+assessment quota row or equivalent serialized key, count in-progress/submitted/abandoned, exclude interrupted-by-update, insert once by idempotency.
  • publishCourse: validate draft, lock course, snapshot lessons+assessment fingerprint, atomically switch published version pointer, queue optional event; avoid mass-update all participants synchronously.

10.5 Immutable history

Status workflow changes may update mutable head/pointer rows, but approved assessment versions, accepted report revisions, published lessons/questions, issued PDF manifests, and audit/note/event rows are immutable. Do not soft-delete or hard-delete business history through generic cleanup task. Revocation and expiry append new event or update narrow revocation status without rewriting original approval facts.

10.6 Migration safety

One-shot migration Compose job using separate privileged DB credential; take backup first for production; schema changes expand -> deploy -> contract, keep rollback window. Explicit migration lock and do not allow two concurrent migration jobs. API readiness blocks until schema compatible; never silently run destructive migration at every container startup.

CHAPTER 11Normatif

Authentication, Authorization, Security & Privacy

Session cookie, OTP, RBAC policy chain, CSRF/XSS, storage access, dan security go-live gates.

11.1 Session model [FINAL]

  • Akun invitation-only; tidak ada registrasi publik.
  • Email/password; hash password dengan Argon2id atau alternatif modern yang ditinjau [DESIGN].
  • Session opaque token dalam cookie HttpOnly, Secure pada HTTPS, SameSite yang sesuai threat model, host-only cookie (tanpa Domain untuk wildcard tenant), masa idle 60 menit dan absolute 7 hari.
  • Sesi disimpan PostgreSQL dengan hash token dan metadata security minimum; idle expiry digeser melalui aturan throttled refresh yang aman; logout/revoke mengakhiri akses di server.
  • Reset password memakai OTP 6 digit berlaku 5 menit, hash OTP, batas percobaan, single-use, anti-enumeration dan throttle permintaan. Bukan jawaban rahasia.

11.2 Authentication sequence

Login page -> tRPC BFF -> NestJS /auth/login -> PostgreSQL session
  -> response Set-Cookie host-only; BFF forwards approved cookie flags
  -> workspace resolver -> active membership/global role -> dashboard

Auth middleware menangani routing untuk UX, tetapi server policy dan PostgreSQL RLS tetap sumber enforcement. Session yang sudah kedaluwarsa harus menolak request walaupun UI masih terbuka. Cookie tidak boleh dicatat di request logs.

11.3 CSRF, XSS dan web security

Mutasi cookie-auth wajib menggunakan perlindungan CSRF (token synchronizer/double-submit dengan desain yang sesuai atau strict origin checks + defense in depth) dan validasi Origin/Host, bukan hanya SameSite. Terapkan CSP yang sesuai Next.js dan media editor, sanitasi konten rich text Tiptap, safe HTML rendering, output escaping, dan anti-clickjacking. Rate-limit login, OTP, review, file sign, attempt start, dan operasi sensitif. CORS untuk presigned Garage hanya pada origin Sikathree yang diizinkan dan required methods/headers.

11.4 Authorization model

Evaluasi session -> platform role or tenant membership -> effective permissions -> record scope/ownership -> workflow guard -> RLS. Apabila langkah mana pun gagal, fail closed. Audit setiap grant, review, role change, approval, publish, export dan support-read yang diwajibkan. Semua resource endpoints memakai opaque IDs; invalid cross tenant ID menghasilkan 404/403 yang tidak membocorkan eksistensi resource.

11.5 Security and privacy handling

  • Jangan masukkan password, OTP, session, full presigned URL, answer key, PII sensitif, atau raw rich text berbahaya pada log JSON.
  • Link evidence harus signed, short TTL, scope-aware, dan diregenerasi setelah grant/konteks berubah. Download endpoint menerapkan authorization saat menerbitkan URL; expired grant tidak boleh menerbitkan URL baru. Catat bahwa URL yang telah diterbitkan mungkin valid hingga TTL selesai; gunakan TTL pendek dan gateway controls untuk risiko revoke instan.
  • Global Admin K3 melihat content, bukan nilai peserta; Platform Super Admin melihat metadata, bukan konten tenant. Khusus support access, tenant admin menyetujui resource, waktu, dan tujuan spesifik.
  • File types diverifikasi oleh backend setelah upload; antivirus/malware scanning bila risiko dan kebijakan operasional menuntutnya [GATE evaluasi].

11.6 Security testing [GATE]

Uji IDOR lintas organisasi, role escalation, missing RLS context, SQL policy bypass via table owner, forced browsing, CSRF, XSS rich text, session fixation/revocation, invite/OTP replay, duplicate operations, signed URL scope, and support grant expiration. Tidak cukup hanya berasumsi aman karena tombol UI tersembunyi.

CHAPTER 12Normatif

File Evidence, Garage S3, Outbox & Cleanup

Presigned upload/direct gateway, email delivery semantics dan pemisahan temporary cleanup dengan histori permanen.

12.1 Garage S3 file lifecycle [FINAL]

Browser -> BFF/API: upload initialization (filename, size, MIME, purpose)
API -> DB: FileObject PENDING + scoped object key + short TTL presign
API -> Browser: signed PUT URL + required headers
Browser -> Nginx storage hostname -> Garage (no NestJS binary proxy)
Browser -> API: finalize evidence with id + integrity metadata
API -> Garage: head/check; DB FileObject UPLOADED
API domain mutation -> DB transaction: FileAttachment ATTACHED to record/version
Worker cleanup: old PENDING or UPLOADED orphan, never valid ATTACHED history

Pada awal prototype, file hanya metadata/local preview; real storage harus mengikuti presigned URL S3, DNS yang valid, CORS dan signed host preservation. storage.sikathree.web.id pernah dipakai sebagai contoh hostname; nama final perlu konfirmasi DNS/ownership [PROVISIONAL]. Nginx mesti meneruskan method, signed Host/headers dan query tanpa transformasi yang membatalkan signature.

12.2 Storage policy [DESIGN]

  • MIME allowlist awal: JPEG, PNG, WebP, PDF; format lainnya hanya setelah kebutuhan diverifikasi. Batas contoh JPEG/PNG/WebP <=10MB/file dan PDF <=20MB/file; angka dapat dikonfigurasi serta memerlukan uji provider/kapasitas.
  • Object keys opaque dan tidak memasukkan email, nama atau secret. Metadata DB menyimpan tenant/purpose/version/scope.
  • Unduh/view melalui short-lived signed GET yang hanya diberikan setelah record access check; file global authoring punya scope tersendiri.
  • Worker masuk Docker network storage karena harus dapat membersihkan object orphan; gunakan credential worker yang dibatasi untuk prefix sementara.
  • PENDING/UPLOADED/ATTACHED dibedakan jelas pada UI. Kegagalan upload/finalize/attach tidak boleh menampilkan file sebagai evidence final.

12.3 Single-node durability risk [GATE]

Garage single-node dengan replication factor 1 tidak menyediakan redundansi antar-node. Boleh untuk staging dan demo, tetapi tidak boleh dianggap cukup tahan kegagalan untuk evidence nyata tanpa strategi pemulihan dan keputusan risiko yang disahkan. Backup & Disaster Recovery detail sengaja tetap backlog sesuai diskusi, namun keberadaannya tidak menghapus status wajib sebelum go-live real data.

12.4 Transactional outbox [FINAL]

  • Setiap tindakan penting (submit laporan, laporan kritis, review/assignment/completion/reopen, dan event penting lain yang disepakati) membuat outbox record dalam transaksi DB yang sama.
  • Worker polling FOR UPDATE SKIP LOCKED, claim job terbatas, retry dengan exponential backoff + jitter, dedup event/recipient, delivery attempt logging, dead-letter/final failure handling. Delivery semantics at-least-once attempt, bukan exactly-once guarantee.
  • Penerima laporan baru: seluruh anggota aktif kategori Operator/Pengawas organisasi, pelapor, penerima tambahan yang dipilih; dedup berdasarkan identitas/email. Reviewer/admin lain mendapat email sesuai event policy, bukan broadcast semua event LMS rutin.
  • Laporan CRITICAL: ACCEPTED otomatis, priority email urgent, tidak otomatis COMPLETED. Jika email gagal, status laporan tetap valid dan worker retry; masalah email terlihat di monitoring.
  • Staging menggunakan sink email test (misalnya Mailpit), tidak mengirim email ke pengguna production.

12.5 File/audit cleanup

Cleanup registry menggunakan whitelist eksplisit dan retention TTL bernomor dari konfigurasi; hanya temporary file, expired token, expired session atau cache tepercaya yang boleh dibersihkan. Tabel business history, revisions, audit log dan attachment valid tidak boleh masuk daftar generic cleanup. Jalankan dry-run dan uji foreign key dependencies sebelum mengaktifkan scheduled job.

CHAPTER 13Normatif

Infrastructure Topology, Docker Compose & VPS Sizing

Satu VPS per environment, lima Compose project, Docker networks, secrets, sizing kandidat, dan risiko go-live.

13.1 Topology [FINAL]

Terdapat dua VPS total: 1 Production VPS dan 1 Staging VPS, bukan dua VPS per environment. Seluruh service tiap VPS berjalan lewat lima project Docker Compose terpisah dan external Docker networks internal. Tidak membutuhkan WireGuard atau inter-VPS private IP untuk komunikasi service pada satu environment.

13.2 Five Compose projects

Project Containers/jobs Networks Eksposur
sikathree-infra nginx, postgres edge, backend, storage Nginx 80/443 saja
sikathree-web Next.js edge Internal web runtime
sikathree-api NestJS API, worker, one-off migration job edge, backend, storage, outbound Worker API-independent process
sikathree-storage Garage S3 storage Single node, private S3 port
sikathree-monitoring Prometheus, Grafana, Alertmanager, Node/Postgres exporters metrics, backend limited Private management access only

13.3 Docker networks dan trust boundaries

  • sikathree_edge: reverse proxy Nginx, Next.js, NestJS API. Internal API tidak publish host port.
  • sikathree_backend: API, worker, Postgres. internal: true sesuai kemampuan Compose dan kebutuhan worker; tidak buka DB ke internet.
  • sikathree_storage: Nginx storage gateway, NestJS API, worker cleanup, Garage. Internal service port, bukan host-published.
  • sikathree_metrics: monitoring dan exporter; akses Grafana dibatasi via admin/private auth, tidak diekspos tanpa proteksi.
  • sikathree_outbound: worker membutuhkan outbound SMTP/API sesuai konfigurasi (network egress policy dan internal network split harus diuji agar DNS berfungsi). Hanya Nginx mempublikasikan host ports 80/443. Gunakan Docker name stability dan external networks untuk menghubungkan Compose projects; health checks dan startup dependency tidak diasumsikan lintas project.

13.4 Kandidat kapasitas [DESIGN, memerlukan load test]

Resource Production candidate Staging comparable test Pertimbangan
CPU 8 vCPU 8 vCPU 4 vCPU/16GB hanya bila lulus load test
RAM 32 GB 32 GB Postgres, Next, Nest, worker, Garage, monitoring berbagi host
Storage 400-500 GB NVMe 200-300 GB NVMe Evidence dan LMS media growth harus dimodelkan
Peak concurrency 120 active users 120 VUs simulated 4.000 akun × 3%, bukan 120 concurrent requests tetap

13.5 Data growth and capacity model

4.000 akun bukan ukuran disk utama; volume file berasal dari laporan, foto evidence, materi LMS, retensi, dan audit. Sebelum go-live, lakukan survei jumlah laporan/berkas, proyeksi pertumbuhan minimal 12 bulan, IOPS, throughput HTTP, kapasitas email worker, dan disk headroom. Hindari menempatkan service monitoring pada disk penuh tanpa retensi.

13.6 Environment separation

Production dan Staging memiliki environment secret, PostgreSQL, Garage, session namespace, Mailpit/test SMTP, DNS/HTTPS, metrics dan data berbeda. Tidak ada copy data production ke staging tanpa sanitasi dan approval. Persisted Docker volumes tidak dibagikan antar-environment.

13.7 Secrets and runtime config

Credential database, session, S3, SMTP dan container registry runtime disimpan di VPS masing-masing, diinjeksikan via Compose secrets atau mekanisme secret file yang aman (/run/secrets), bukan variabel NEXT_PUBLIC atau GitHub Actions secret untuk runtime app. GitHub Actions hanya memegang credential deploy yang minimal dan audit-approved. Images dipromosikan berdasarkan immutable digest, staging -> production.

13.8 Availability and disaster recovery [GATE]

Single VPS adalah single point of failure; single-node Garage tidak redundan. Pemulihan data PostgreSQL, objek Garage, config, deployment artifacts, serta tes restore belum dibahas tuntas dan tetap ditempatkan pada backlog wajib. Production real-data launch diblok sampai RPO/RTO, backup off-host/restore rehearsal, key escrow, dan ownership disepakati serta diverifikasi.

CHAPTER 14Normatif

CI/CD, Image Promotion, Migrations & Release

Dua repository, GitHub Actions/GHCR, digest promotion, approval, schema compatibility dan release gates.

14.1 Source control architecture

Dua repository produk: sikathree-web (Next.js frontend + tRPC BFF) dan sikathree-api (NestJS API/worker/migrations). Penempatan sumber konfigurasi infra, Nginx, Garage dan monitoring perlu ditetapkan sebagai ownership eksplisit; jangan diam-diam menciptakan repository ketiga jika belum disetujui.

14.2 CI pipeline setiap repo [DESIGN]

  1. Pull request: lint, typecheck, formatting, unit tests, security scanning, dependency audit, OpenAPI contract comparison, build and smoke test.
  2. Build multi-stage Docker image yang berjalan non-root, menghasilkan SBOM/attestation jika tool tersedia, tag commit SHA dan immutable digest.
  3. Push image ke GitHub Container Registry (GHCR) hanya setelah CI lulus.
  4. Deploy staging otomatis setelah syarat branch/CI yang ditetapkan; tetap dengan environment terisolasi.
  5. Jalankan one-off migration bila kompatibel, health check, E2E smoke, responsive smoke di staging.
  6. Production release hanya setelah approval/manual authorized release; promote digest yang sama dari staging, bukan rebuild source yang berbeda.
  7. Post-release health, rollback to previous digest jika schema backward-compatible; jangan rollback sembarangan setelah destructive migration.

14.3 Deployment security

GitHub workflow memakai scoped credentials dan pinned actions bila mungkin; development runtime secrets tidak masuk repository, build logs atau image layers. Audit siapa menyetujui/release. Manual workflow_dispatch saja tidak selalu sama dengan two-person approval; pilih mekanisme policy yang benar-benar ditegakkan dan sesuai GitHub plan/repo visibility.

14.4 Next.js build-time config

NEXT_PUBLIC_* dapat di-inline pada build. Gunakan konfigurasi yang tidak berubah antar-staging/production pada artifact promosi atau pola runtime config yang diuji; jangan menyematkan URL/kredensial staging ke image yang dipromosikan production.

14.5 Release readiness checklist

  • [ ] Staging build SHA/digest exact cocok dengan target production.
  • [ ] OpenAPI contract kompatibel.
  • [ ] Schema migration rehearsal dan backup valid.
  • [ ] RLS/authorization tests lulus.
  • [ ] E2E critical paths mobile & desktop lulus.
  • [ ] Alerting, metrics, logging dan external uptime aktif.
  • [ ] Secrets, DNS, TLS, Nginx CORS/signed URL diverifikasi.
  • [ ] Load testing kapasitas target terdokumentasi.
  • [ ] Backup/restore dan storage durability go-live gate terpenuhi.
  • [ ] Approval production tercatat dan incident owner siap.
CHAPTER 15Normatif

Monitoring, Logging, Alerting & Operations

Prometheus/Grafana/Alertmanager, metrics domain, privacy-safe log, external uptime dan runbook.

15.1 Practical Observability [FINAL]

Pada setiap VPS: Prometheus, Grafana, Alertmanager, Node Exporter, Postgres exporter, Garage metrics, NestJS API metrics dan worker/outbox metrics, Nginx access/error counts; external uptime check dari luar VPS. Aplikasi menulis structured JSON logs dengan Docker local logging driver + rotation. Loki dan Tempo belum termasuk MVP awal.

15.2 Golden signals [DESIGN]

Komponen Metrik wajib Indikasi masalah
Nginx RPS, 4xx/5xx, latency, upstream failure Overload / bad routing
NestJS p50/p95/p99 latency, error counts, DB pool wait, request duration Slow business endpoints
PostgreSQL CPU/mem, connections, locks, deadlocks, slow queries, disk/replication if any RLS/perf/locking issues
Garage S3 request failure/latency, disk utilization, object error Evidence operations degraded
Worker/Outbox pending, oldest age, retry count, failure, send rate Email stuck, retries
System node CPU, RAM, disk, load, IO wait All-in-one VPS saturation
User journey Hazard submit fail, assessment start/submit errors, HIRADC review 409 Critical workflow availability

15.3 Labels, logs and privacy

Gunakan label metrik rendah cardinality seperti route template/status class/operation, jangan menambahkan raw userId, reportId, email, answerId, file keys, atau signed URL ke Prometheus labels. Structured logs memakai requestId/traceId; audit bisnis berada PostgreSQL append-only terpisah dari log runtime yang dirotasi. Redact secrets dan konten pribadi dari logs.

15.4 Alert examples [DESIGN]

  • API 5xx error rate meningkat selama 5–10 menit; p95 above agreed SLO (alert thresholds perlu tuning dari load test).
  • Postgres connections at high watermark, deadlock spike, disk usage >80%, outbox oldest pending > defined operational limit.
  • Garage failed requests or object read checksum errors.
  • External uptime detects HTTPS unavailable independent of local VPS monitoring.
  • Critical alerts have owner, severity, runbook link dan non-email single point of notification risk evaluated.

15.5 Operational docs

Dokumentasikan dashboard utama, query untuk domain errors, alert severity, siapa on-call, deploy/rollback, rotate credentials dan runbook incident. Test alerts in staging before go-live. Monitoring stack sendiri perlu memory/disk budget dan protected access.

CHAPTER 16Desain Delegasi

Edge Cases, Error Handling & Acceptance Matrix

55 acceptance/negative scenarios lengkap dengan ID dan metode pengujian.

16.1 Normal / abnormal / adverse path policy

Edge case diuji pada tiga lapis: domain service (unit/integration), API/database authorization dan transaksi (integration/security), lalu UI E2E desktop/mobile. Implementasi dianggap benar hanya bila result, audit/history dan state setelah refresh konsisten; toast sukses saja tidak cukup.

16.2 Edge case & acceptance matrix [DESIGN]

Domain Skenario Expected behavior / acceptance Test ID Metode
Auth Email unknown vs wrong password Same generic error, rate limit, no enumeration AUTH-01 Unit+E2E
Auth OTP wrong/expired/reused Reject safely; attempts counted; never log OTP AUTH-02 Integration
Auth Session idle expired during form Mutation denied; no saved claim; login retry/unsaved warning AUTH-03 E2E desktop/mobile
Auth Absolute 7-day expiration Session invalid regardless of idle activity AUTH-04 Integration
Org Switch tenant with dirty form Confirmation; cancel retains context; confirm resets tenant caches ORG-01 E2E mobile
Org Membership revoked while viewing Next read/mutation denied; invalidate data ORG-02 Integration
Org Deep link record from other org Offer eligible switch after membership check; no leaked summary ORG-03 E2E
Org Cross-tenant foreign key attempted DB composite FK and RLS fail ORG-04 DB integration
Org Organization inactive Block mutation; permit read only when explicitly allowed ORG-05 Integration
RBAC Permission removed in another tab Next action fails, UI refreshes effective permissions RBAC-01 E2E
RBAC Organization Admin grants own higher rights Delegation ceiling rejects RBAC-02 Security
RBAC Last org admin disabled Reject and show explanatory error RBAC-03 Integration
RBAC Platform Admin accesses tenant without grant 403/404; no data disclosure RBAC-04 Security
RBAC Support resource not in grant Deny; audit attempt RBAC-05 Security
RBAC Support grant expires during view Block next read/download sign; warn UI RBAC-06 E2E
Hazard Incomplete draft saved Save partial but submit blocked with field errors HAZ-01 E2E mobile
Hazard Critical report submitted Auto ACCEPTED, handling unassigned, urgent outbox, not completed HAZ-02 Integration
Hazard Submit request timeout after commit Read-after-write/idempotency returns single report HAZ-03 Integration
Hazard Two supervisors assign PIC simultaneously At most 1 active PIC; 409 conflict for loser HAZ-04 Concurrency test
Hazard Completion missing evidence and exception Reject finalization HAZ-05 Integration
Hazard Notes added to completed report Allowed append-only; historic notes unchanged HAZ-06 Integration
Hazard Revision awaiting approval Operational actions use previous effective revision HAZ-07 E2E
Hazard Supervisor approves own report Allowed if permission; audit HAZ-08 Integration
Hazard Reopen without reason Reject; completed history preserved HAZ-09 Integration
HIRADC K/P values outside 1..5 Reject; server computes score HIR-01 Unit+Integration
HIRADC Creator tries to approve own record/version Reject even if review permission HIR-02 Security+E2E
HIRADC Two reviewers approve same version Single effective transaction; other 409 HIR-03 Concurrency test
HIRADC Residual actual before controls verified Reject, planned residual stays distinct HIR-04 Integration
HIRADC PIC who is supervisor verifies own control Permit under permission; audit HIR-05 Integration
HIRADC Control rejected for rework History retained; status NEEDS_REWORK HIR-06 E2E
HIRADC New assessment proposed while V2 effective V2 still governs until V3 approved HIR-07 E2E
HIRADC Official PDF snapshot after newer version Earlier issued PDF remains unchanged HIR-08 Integration
LMS Pre-Test score low Stage completes after submit; no passing requirement LMS-01 E2E
LMS Lesson opened but not clicked complete No completion persisted LMS-02 E2E
LMS Two tabs start final allowed attempt Only one counted/created under quota guard LMS-03 Concurrency test
LMS Duplicate submit attempt One immutable result; no double score LMS-04 Integration
LMS Abandoned attempt Quota counts, historical attempt preserved LMS-05 Integration
LMS Assessment changed while attempt active Interrupt old attempt; exclude quota; show version message LMS-06 E2E+Integration
LMS Lesson fingerprint unchanged on publish Retain previous completion LMS-07 Integration
LMS Lesson fingerprint changed on publish Current completion resets, history remains LMS-08 Integration
LMS Answer key exposed in participant response Fail security check; answer only server-side LMS-09 Security
LMS Production answer recovery after browser refresh Only claim persistence if recovery policy deployed; no fake autosave LMS-10 E2E/provisional
File Camera permission denied Fallback file picker FILE-01 Mobile E2E
File Upload succeeded but finalize failed Keep UPLOADED/unattached, retry finalize or cleanup FILE-02 Integration
File ATTACHED historic evidence targeted by cleanup Delete prohibited FILE-03 Integration
File Wrong signed host/header Upload fails clearly; do not show attached FILE-04 Integration
File Malicious filename/path Sanitize display; opaque object key FILE-05 Security
Email SMTP unavailable after report commit Report valid; outbox retries, monitoring alerts MAIL-01 Integration
Email Same recipient from multiple groups One deduplicated intended recipient per event MAIL-02 Unit
Deploy Staging credential points production Deployment blocked by env guard OPS-01 CI test
Deploy Migration incompatible with previous API Release blocked, no unsafe rollback OPS-02 Release rehearsal
Deploy Single VPS restart Health recovers; external uptime observes downtime OPS-03 Resilience test
Capacity 120 active users mixed workload Latency/errors meet agreed thresholds, integrity 100% PERF-01 k6
Mobile Viewport 320 and keyboard open No clipped content/action; navigation usable UX-01 Playwright/real device
Mobile Screen reader/keyboard approval dialog Focus trapped/restored; full context available UX-02 A11y

16.3 Response time dan reliability target [PROVISIONAL baseline]

  • Operasi API umum p95 <1 detik; mutasi kritis p95 <2 detik di luar upload/video transfer, pada workload staging target; threshold final ditetapkan setelah benchmark.
  • HTTP 5xx <1% pada uji peak dan 0 data integrity violations pada transaksi kritis; no extra accepted reports, duplicate attempt results, double approval, maupun cross-tenant leak.
  • Uji beban bertahap 30, 60, 120 concurrent virtual users, lalu stress 180 dan 240. Virtual users mengikuti skenario think-time dan mix aktivitas; 120 VUs bukan 120 request/detik.
  • Mobile UX target 320–430px dan tablet/desktop; WCAG 2.2 AA target audit; test on Chrome Android and Safari iOS using actual devices or representative emulation.

16.4 Definition of acceptance

Setiap use case diterima jika (1) prasyarat & izin tepat, (2) UI form/feedback benar, (3) backend mengubah state yang benar, (4) tenant row security lolos, (5) event/versi tercatat, (6) email/file side effect konsisten, (7) refresh dan navigasi mobile menampilkan hasil benar, (8) negative and concurrency case ditolak secara aman.

CHAPTER 17Normatif

Testing Strategy, E2E, Security & Capacity QA

34 test suite, 12 journeys, mobile matrices, dan k6 capacity plan.

17.1 Test pyramid

TypeScript unit tests untuk pure rules, NestJS integration tests dengan PostgreSQL RLS nyata, contract tests OpenAPI dan frontend adapters, Playwright E2E desktop/mobile, security/adversarial tests, dan k6 capacity tests. Mock prototype berguna untuk UX tetapi tidak menggantikan integration test pada backend real.

17.2 Test plan matrix

Layer Test suite Related ID Pass criteria
UNIT RiskScore: 1..25 classification HIR-01 1–4 low, 5–9 moderate, 10–14 high, 15–25 very high
UNIT Permission resolver RBAC-01/02 Denies non-delegable, no arbitrary platform role
UNIT Form conditional validation HAZ-01/05 Draft vs submit, evidence exception rules
UNIT Lesson and assessment fingerprint LMS-07/08 Deterministic meaningful content changes
UNIT Outbox recipient de-dup MAIL-02 No duplicated email recipient
INTEGRATION RLS org A vs B read/write ORG-04 Cross tenant GET/INSERT/UPDATE/delete fail
INTEGRATION RLS missing context/pool reuse ORG-04 Fail closed after transaction boundary
INTEGRATION Self-approval HIRADC HIR-02 Forbidden at service and DB scope
INTEGRATION Concurrent HIRADC review HIR-03 One approved transition only
INTEGRATION Concurrent PIC reassignment HAZ-04 Unique active PIC invariant preserved
INTEGRATION Critical hazard + outbox HAZ-02/MAIL-01 Accepted immediate, urgent outbox atomically
INTEGRATION Course publish while attempt active LMS-06 Interrupted/returned quota
INTEGRATION Attempt start quota race LMS-03 No over-allocation
INTEGRATION Idempotent submit retry HAZ-03/LMS-04 Single final state and event
INTEGRATION Evidence lifecycle FILE-02/03 PENDING->UPLOADED->ATTACHED; safe orphan cleanup
SECURITY CSRF with session cookie AUTH-03 Unsafe origins rejected
SECURITY Tenant IDOR via guessed IDs ORG-04 No data, no info leak
SECURITY RLS bypass via owner role ORG-04 App runtime cannot bypass RLS
SECURITY Support grant expired/revoked RBAC-06 No further read/sign
SECURITY Stored XSS via Tiptap and notes FILE-05 Sanitized rendering
SECURITY No answer key at participant boundary LMS-09 No correct options hidden in response
E2E Desktop Login + org switch + dashboard T-01 Correct menu, scoped data
E2E Mobile Hazard draft and camera evidence T-02 Capture/picker works with 320–430px viewport
E2E Mobile Critical hazard and reviewer workflow T-03/T-04 Automatic acceptance vs handling correct
E2E Both Effective revision preserved T-05 Case handling still uses old until review
E2E Both HIRADC assessment + control T-06/T-08 Score and verification state correct
E2E Mobile LMS Pre-Learn-Post T-09 Can fully complete on smartphone
E2E Desktop Content authoring & publication T-10 Global version released with impact preview
E2E Both Members and delegation ceiling T-11 Role changes restricted appropriately
E2E Both Support access approval and expiry T-12 Read only with expiry
LOAD 30/60/120 mixed concurrent users PERF-01 Thresholds, integrity, DB pool, CPU/RAM measured
STRESS 180/240 concurrent users PERF-01 Saturation point and safe failure measured
DEPLOY Staging promotion by digest OPS-01/02 Same artifact, approved prod release
RECOVERY Off-host backup restore drill GATE-DR Restoration documented and validated before real data

17.3 Twelve end-to-end business journeys

T-01: login/membership/org switch; T-02: hazard draft/save/submit; T-03: critical hazard auto acceptance; T-04: reviewer->PIC->action->verification; T-05: accepted report revision; T-06: HIRADC proposal; T-07: risk assessment review with no self approval; T-08: required controls->verified residual; T-09: LMS pre-test->learn->post-test; T-10: content publication/versioning; T-11: member role updates/ceiling; T-12: support grant request->tenant review->read->expiry. Jalankan happy path dan negative path untuk setiap journey.

17.4 E2E browser matrix

Viewport 320, 375, 390, 430, 768, 1024, 1280, dan 1440px; Chrome Android dan Safari iOS representatif, plus desktop Chromium/Firefox/WebKit bila tersedia. Fokus keyboard open, image picker permissions, sticky button safe-area, popup, role-switched navigation, no hover-only actions, web reader typography, and form error announcements.

17.5 Load-test k6 workload [DESIGN]

Mix simulasi awal: 65% browsing/list/detail, 20% HIRADC/Laporan mutations, 10% LMS test, 5% upload/download; proporsi ini hipotesis test, bukan data perilaku nyata. Jalankan warm-up 30 VUs, 60, peak 120, stress 180 dan 240; include think time and realistic requests. Catat 5xx, p95/p99 per route, DB pool wait, PostgreSQL locks, Garage throughput/disk IO, worker lag, CPU/mem and data consistency. Ulangi load test setelah perubahan indeks/schema/infra besar.

17.6 Test evidence

Setiap release menyertakan test report dengan commit/image digest, environment, fixtures, test ID, hasil pass/fail, screenshot responsive, traces, load result, ditemukan bug dan pemilik remediation. Tidak boleh mengklaim 'tested' jika hanya menyiapkan checklist.

CHAPTER 18Normatif

Roadmap Implementasi, Deliverable & Definition of Done

Phases prototype sampai production, dependensi, owner, dan definisi hasil akhir.

18.1 Phase-based delivery

Phase Deliverable Exit criteria
Phase 0 - Product foundation Full PRD, FIS, prototype fixtures, permission schema, API contract baseline Decision labels explicit, route/field/action mapping complete
Phase 1 - UI Foundation Design tokens, AppShell, auth simulator, role/org switch, responsive nav/dashboard Mobile viewport 320+, role simulation, 403/404 states
Phase 2 - Operational Prototype Hazard and HIRADC UI + mocked workflow services T-02..T-08 happy/negative paths
Phase 3 - LMS/Admin Prototype Course LMS, test player, member/RBAC, platform and K3 Studio T-09..T-12 with versioning and grant simulation
Phase 4 - Real Backend Foundation Postgres schema/RLS/migrations, session, RBAC, NestJS, OpenAPI, Next BFF RLS/security integration and contract tests
Phase 5 - Real Business Modules HIRADC, Hazard, LMS transactions, Garage, outbox, official PDF Domain invariants and audit pass
Phase 6 - Deployment/Hardening Compose stacks staging, CI/CD, monitoring, load and UX QA Go-live gate evidence and sign-offs
Phase 7 - Real Data Production Approved release with backup/restore and durability policy Go/no-go signed, SLO/incident owner clear

18.2 Implementation order and dependencies

  • Mulai dari global identity, membership, permission registry, RLS, auditable transaction primitives; baru domain services.
  • Mock adapter dan real adapter mematuhi interface serupa. Prototype fixtures mencakup 2 tenant, ~10 akun, ~20 risk records, ~20 hazard reports, 4 global courses, attempt variants, support grants.
  • File upload & outbox perlu service interfaces sejak awal agar domain submit tidak di-hardcode untuk memanggil SMTP langsung.
  • Status registry dan field-level Zod schemas harus berkorespondensi dengan NestJS DTO; generated OpenAPI contract mengurangi drift.
  • Mobile QA untuk Laporan Bahaya dan control task dilakukan sejak implementasi awal, bukan tahap akhir.

18.3 Ownership and governance

Product owner mengesahkan perubahan business rule, K3 reviewer mengesahkan istilah/prosedur keselamatan, Tech Lead menyetujui API/DB migration, security reviewer menilai RLS/support/signed URLs, frontend lead memvalidasi desktop/mobile. AI Coding Agent adalah pelaksana yang wajib melaporkan changed files, tests, assumption, dan unresolved risk; tidak menjadi pemegang keputusan produk.

18.4 Prototype vs MVP vs Go-live

Prototipe berhasil apabila 12 business journeys berjalan dengan fake data dan responsive UI; MVP berhasil jika backend nyata transaction+tenant isolation benar di staging; production go-live berhasil hanya setelah risk critical seperti backup/recovery, Garage storage durability, credential/monitoring, release approval, dan peak load tervalidasi. Jangan menyamakan ketiga hasil tersebut.

CHAPTER 19Normatif

AI Coding Agent Skills — Wajib Saja

14 skill wajib dari screenshot dan sumber publik, ditambah 3 custom Sikathree SKILL.md.

19.1 Prinsip pemilihan

Bagian ini sengaja memuat skill wajib saja. Tidak memasukkan Find Skills, Skill Installer, Image Gen, OpenAI Docs, Reverse Engineer Anything, accessibility additional skill, maupun GitHub Actions Efficiency sebagai skill opsional. Ketujuh skill dari screenshot yang sebelumnya dinilai wajib tetap tercakup; beberapa skill eksternal wajib melengkapi backend, database, security, Docker dan testing. Skill yang fungsinya tumpang tindih diaktifkan sesuai jenis pekerjaan, bukan semuanya setiap request.

Tingkat ketersediaan: Skill berlabel Built-in dinilai tersedia berdasarkan screenshot pengguna; path dan versi lokal belum diverifikasi melalui repository agent. Skill eksternal memiliki sumber publik untuk diverifikasi ulang sebelum instalasi. Semua skill bersifat panduan kualitas, tidak lebih tinggi dari PRD/peraturan keamanan.

19.2 Mandatory external / built-in skills registry

ID / Skill Kelompok Tugas di Sikathree Trigger Source / rujukan
frontend-design — Frontend Design Built-in (tersedia pada agent pengguna) Visual direction Modern Operational Dashboard, layout responsif, visual hierarchy, mobile UX; selaras desain Sikathree Merancang halaman atau melakukan visual refinement Sudah ada pada agent pengguna; URL tidak diverifikasi
nextjs-shadcn — Nextjs Shadcn Built-in (tersedia pada agent pengguna) Membangun aplikasi Next.js memakai komponen shadcn dan pola frontend Membangun Next.js pages, layout dan forms Sudah ada pada agent pengguna; URL tidak diverifikasi
shadcn — Shadcn Built-in/official Install, style, compose dan debug shadcn/ui components sesuai components.json Mengubah komponen shadcn atau design system https://github.com/shadcn-ui/ui/tree/main/skills/shadcn
vercel-react-best-practices — Vercel React Best Practices Built-in/official Menghindari request waterfalls, meningkatkan rendering dan bundle efficiency Membangun/review komponen Next.js dan React https://github.com/vercel-labs/agent-skills/tree/main/skills/react-best-practices
web-design-guidelines — Web Design Guidelines Built-in/official Review accessibility, form, focus, layout, mobile usability dan web interaction Audit UI/UX setelah perbedaan layout atau form https://github.com/vercel-labs/agent-skills/tree/main/skills/web-design-guidelines
review-agent — Review Agent Built-in (tersedia pada agent pengguna) Mencari bug berdampak nyata dalam perubahan kode, regresi dan konflik kontrak Setelah implementasi modul atau pull request Sudah ada pada agent pengguna; URL tidak diverifikasi
skill-creator — Skill Creator Built-in (tersedia pada agent pengguna) Membuat atau memperbarui tiga custom skill Sikathree dan memvalidasi keterbacaan SKILL.md Ketika memelihara skill internal atau onboarding agent Sudah ada pada agent pengguna; URL tidak diverifikasi
nextjs-app-architecture — Next.js App Architecture External verified App Router, Server/Client boundaries, feature folders dan Suspense Membangun arsitektur routes, data fetching, frontend server components https://github.com/aurorascharff/nextjs-app-architecture-skill
nestjs-best-practices — NestJS Best Practices External verified Modul DI, controller/service, guards, error handling, testing, clean architecture Menulis NestJS API/worker https://github.com/Kadajett/agent-nestjs-skills
postgres-best-practices — Postgres Best Practices External verified Schema, SQL, RLS, locking, indexing, connection pooling PostgreSQL Migrasi, SQL, RLS, query atau DB performance https://github.com/supabase/agent-skills/tree/main/skills/supabase-postgres-best-practices
security-best-practices — Security Best Practices External verified Secure coding review TypeScript/JavaScript, CSRF/XSS, session, authorization Security review terencana dan secure-by-default coding https://github.com/openai/skills/tree/main/skills/.curated/security-best-practices
docker-build-strategies — Docker Build Strategies External verified Multi-stage Dockerfile, non-root images, build cache, image hardening Menulis/mereview Dockerfiles https://github.com/docker/skills/tree/main/skills/docker-build-strategies
docker-compose-patterns — Docker Compose Patterns External verified Compose multi-stack, networks, volumes, healthchecks, secrets Mengubah Docker Compose config atau networking https://github.com/docker/skills/tree/main/skills/docker-compose-patterns
playwright-cli — Playwright CLI Skill External verified E2E desktop/mobile, screenshot, traces, browser workflow testing Validasi UI, simulasi role, responsive dan end-to-end https://github.com/microsoft/playwright-cli/tree/main/skills/playwright-cli

19.3 Tiga mandatory custom Sikathree skills [DESIGN]

Custom skill Trigger Jaminan utama
sikathree-business-workflows Setiap fitur HIRADC, Hazard, LMS; status, event, score, version, attempt Aturan self-approval, 5x5, PIC, critical accepted, attempt fingerprint, immutable history
sikathree-multitenancy-rbac Schema, RLS, query, guards, role editor, support grants Tenant isolation, membership, delegation ceiling, scoped support, RLS fail-closed
sikathree-api-contracts tRPC BFF ↔ NestJS DTO, OpenAPI, mutation, evidence, outbox Organization context, validation, idempotency, version conflicts, file lifecycle

Ketiga custom skill disertakan sebagai file agent-skills/custom/*/SKILL.md asli, bukan hanya referensi nama. Skill Creator dipakai ketika memperbarui skill tersebut. Skill custom wajib menyebut PRD chapter/decision source dan tidak boleh menyalin kredensial.

19.4 Mandatory agent execution rules

  1. Baca AGENTS.md, index PRD dan custom skill yang relevan sebelum menulis code domain; baca external skill yang sesuai task.
  2. Hierarki keputusan: hukum dan kebijakan keamanan > keputusan produk [FINAL] dalam PRD > [DESIGN] terdelegasi > skill guidance > kebiasaan agent. Jika konflik, laporkan, jangan mengubah silently.
  3. Untuk setiap task, catat: feature scope, route, input/output DTO, permission key, state guard, tenant scope, files changed, tests added/run, hasil/resiko.
  4. Skill Next.js dari Aurora berorientasi App Router dan dapat menyarankan Server Actions, tetapi tidak boleh menggantikan kontrak Next.js tRPC BFF -> NestJS REST tanpa approval.
  5. Skill Supabase dipakai untuk PostgreSQL umum, bukan menginstal Supabase Auth/Storage. Skill Docker hanya untuk Docker Compose 1 VPS/environment yang sudah dipilih.
  6. Jangan menjalankan command dari third-party SKILL.md tanpa meninjau script, permission, network access, filesystem writes dan version pinning. Sumber eksternal dicatat dengan commit SHA/tag setelah dipilih; jangan mengklaim pinned bila belum.
  7. Review Agent, Web Design Guidelines dan Playwright dipakai sebagai quality gates sesuai fase: code review, UI audit, actual browser tests.
  8. Skill Creator wajib untuk pemeliharaan skill internal, tidak perlu dimuat untuk semua pekerjaan coding harian.

19.5 Skill-to-workstream mapping

Workstream Skill wajib yang dipanggil
UI prototype + app shell Frontend Design, Nextjs Shadcn, Shadcn, Next.js App Architecture, Vercel React Best Practices, sikathree-multitenancy-rbac
HIRADC/Hazard/LMS domain NestJS Best Practices, sikathree-business-workflows, sikathree-api-contracts, sikathree-multitenancy-rbac
Postgres schema / RLS Postgres Best Practices, Security Best Practices, sikathree-multitenancy-rbac
Docker deployment Docker Build Strategies, Docker Compose Patterns, Security Best Practices, sikathree-api-contracts
QA / review Review Agent, Web Design Guidelines, Playwright CLI Skill, three Sikathree custom skills
Skill maintenance Skill Creator, three Sikathree custom skills

19.6 Instalasi dan verifikasi

Perintah yang telah disediakan hanya contoh, belum dijalankan. Jangan mengunduh seluruh eksternal skills otomatis pada mesin production. Gunakan lockfile/commit pin di tahap implementasi; README paket mencantumkan lokasi dan perintah. Simpan external skill sebagai dependency links, tidak mendistribusikan kembali konten pihak ketiga di ZIP.

CHAPTER 20Normatif

Open Decisions, Risk Register & Production Go-Live Gates

16 keputusan/risiko terbuka dengan owner dan go-live gate.

20.1 Decision ledger

Agar developer tidak mengarang aturan bisnis, daftar berikut harus dikonversi menjadi Architecture Decision Record saat menghasilkan keputusan baru. Open decisions tidak boleh diinterpretasikan sebagai fitur yang sudah disahkan production.

ID Area Status Default / tindakan Owner Deadline relatif
DEC-01 Public REST vs BFF-only [PROVISIONAL] Default BFF-only; final approval sebelum exposure public REST Backend/Frontend lead Sebelum API edge deploy
DEC-02 LMS answer recovery saat refresh [PROVISIONAL] Default no false autosave; pilih server-durable answer writes/recovery policy Product/Backend Sebelum LMS real launch
DEC-03 File size, MIME, malware scan [PROVISIONAL] Default 10MB image/20MB PDF, allowlist + sniff, decide scanner Security/Operations Sebelum upload production
DEC-04 Support grant duration [PROVISIONAL] Default 60 min max 120, no wildcard; owner review Product/Security Sebelum support access production
DEC-05 Attempt limit [PROVISIONAL] Default 3 per assessment version, configurable Admin K3/Product Sebelum course authoring production
DEC-06 Severity/type catalog exact [DESIGN] Catalog driven; current demo LOW/MEDIUM/HIGH/CRITICAL and common types Product/K3 Sebelum hazard API sign-off
DEC-07 HIRADC K/P descriptions [PROVISIONAL] Scores 1..5 fixed, textual criteria must be ratified K3 domain owner Sebelum formal assessment go-live
DEC-08 PDF template and library [PROVISIONAL] Immutable manifest/issued PDF, select renderer and official layout Product/K3/Tech Sebelum official PDFs issued
DEC-09 Garagе single-node durability [GATE] Replicating alternative or durable off-host protection + verified recovery Infra owner Before real data
DEC-10 Backup/DR RPO-RTO [GATE] Define retention, off-host copies, restore test, incident owner Infra owner Before real data
DEC-11 VPS sizing & 120 VUs [GATE] Validate 8vCPU/32GB candidate or measured smaller configuration Infra/QA Before real peak load
DEC-12 Production deploy approval [GATE] Enforce actual reviewer/manual approval with documented audit path Release owner Before CD prod
DEC-13 Infrastructure configuration ownership [PROVISIONAL] Decide infra manifests location and authorized change workflow Tech lead Before deployment
DEC-14 Next.js runtime config/image promotion [GATE] Ensure image digest promoted without staging values in public bundle Frontend/DevOps Before promotion
DEC-15 Email sender/provider & notification sender account [PROVISIONAL] Provider, sender, retries, test sink and quotas Operations Before transactional email
DEC-16 User account/support operational policy [PROVISIONAL] Invite expiry, password rules, inactive org read-only specifics Product/Security Before auth sign-off

20.2 Risiko utama

Risiko Severity Mitigasi wajib Evidence before go-live
Kebocoran data antarorganisasi Critical RLS + composite FK + Nest guards + negative tests RLS automated test report
Hilangnya evidence Garage single-node Critical Durable backups/redundancy strategy, restore rehearsal Signed data durability decision + restore report
Tidak tersedia backup/restore Critical Off-host backup, encrypted secrets, full restore test RPO/RTO and restoration evidence
Approval/role escalation Critical Policy engine, no self HIRADC approval, delegation ceiling, audited support grants Security test report
LMS attempt quota race High Atomic quota reservation, idempotency, fingerprint pin Concurrency test
Dua PIC aktif/report double submit High Partial unique constraints + idempotent transactions Concurrency test
Semua service satu VPS overload High Resource budgeting, 120 VUs load test, alerting, plan scale Load test & headroom measurements
Email outbox backlog Medium Retry/dedup/alert, worker resource caps Failure injection test
Mobile usability gagal saat petugas lapangan High Mobile-first tests 320px and real devices E2E screenshot/trace
PRD/skills conflict -> AI Agent drift High AGENTS precedence, change-control log, review tests Agent review report

20.3 Go-live blocker checklist

  • [ ] Tenant isolation and RLS prove fail-closed under active membership, revoked membership, and connection pooling.
  • [ ] Security audits cover session/CSRF/OTP, cross-tenant IDOR, role escalation and Support Access read-only expiry.
  • [ ] Garage durability and backup/DR policy are approved and recovery verified on test data.
  • [ ] Production secrets and TLS configured; no staging/prod cross-connect.
  • [ ] 120 concurrent mixed-load target tested on staging-comparable infra with integrity checks.
  • [ ] Authorized production release approval, digest promotion, migration rehearsal, rollback conditions and monitoring are documented.
  • [ ] Mobile E2E critical journeys and accessibility review pass.
  • [ ] Business workflows signed off by K3/product stakeholders including field catalogue K/P descriptions, hazard severity and workflow rules.
CHAPTER 21Normatif

Glossary, Traceability & Technical References

Istilah, sumber kesepakatan, referensi teknis dan prosedur revisi dokumen.

21.1 Terms and glossary

Istilah Definisi dalam Sikathree
Sikathree Sistem Informasi K3 untuk HIRADC, Laporan Bahaya, LMS
Tenant/Organization Unit data organisasi yang dipisahkan melalui membership, authorization, dan RLS
Effective Permission Izin akhir hasil role, scope, delegation policy dan guard
Assessment Version Snapshot penilaian HIRADC atau tes LMS yang terikat fingerprint/version
Risk Initial Skor K×P sebelum pengendalian
Planned Residual Skor proyeksi setelah kontrol direncanakan; belum diverifikasi
Verified Residual Skor faktual setelah semua kontrol wajib diverifikasi
Official PDF Snapshot Dokumen terbit immutable dengan manifest versi yang ditandatangani proses sistem
Critical Hazard Laporan severity CRITICAL yang otomatis ACCEPTED tetapi belum otomatis ditangani
Outbox Tabel event pengiriman asinkron yang dibuat dalam transaksi bisnis
RLS PostgreSQL Row-Level Security yang mengisolasi tenant rows
tRPC BFF Backend-for-frontend pada Next.js yang meneruskan request ke NestJS REST
Support Grant Hak baca sementara pada resource tenant yang disetujui Organization Admin

21.2 Source of decisions

Dokumen ini disusun berdasarkan kesepakatan langsung dalam diskusi proyek Sikathree sampai 5 November 2026: tiga modul, empat area K3, Dynamic RBAC, sesssion, multi-tenancy/RLS, frontend Next.js tRPC, NestJS REST+worker, PostgreSQL/pgvector, Garage, satu VPS per environment, Docker Compose modular, practical observability, UI/UX direction A dan 120 concurrent estimate. Field/action/state/edge-cases tambahan diberi label [DESIGN] dan belum diklaim sebagai hasil survei lapangan.

21.3 External technical references (informational, subject to version review)

  • Next.js App Router: https://nextjs.org/docs/app
  • NestJS: https://docs.nestjs.com/
  • PostgreSQL RLS: https://www.postgresql.org/docs/current/ddl-rowsecurity.html
  • Docker Compose networks: https://docs.docker.com/compose/how-tos/networking/
  • Garage S3: https://garagehq.deuxfleurs.fr/documentation/
  • Playwright: https://playwright.dev/
  • Grafana k6: https://grafana.com/docs/k6/latest/
  • Agent skill registry dan custom skills dijabarkan pada Bab 19 serta berkas agent-skills/ dalam ZIP.

21.4 Traceability guidance

Gunakan ID requirement sederhana REQ-{DOMAIN}-{NNN}, referensi route, permissionKey, state transition, affected tables, API operation, dan test ID pada tiket developer. Tidak ada requirement considered Done tanpa evidence implementation, test, screenshot/trace bagi mobile workflow, serta review permission dan tenant-scoping.

21.5 Document maintenance

Untuk revisi PRD, tingkatkan versi dokumen, catat perubahan keputusan [FINAL]/[DESIGN]/[PROVISIONAL], regenerasikan Markdown + PDF + HTML + prd.json dari satu source konten agar hasil saling konsisten. Jika menyetujui keputusan provisional, pindahkan ke [FINAL] via change log dan tambahkan test.

Sikathree Master PRD v1.0 · Satu sumber konten untuk Markdown, PDF, HTML dan JSON. [PROVISIONAL] belum otomatis menjadi keputusan final.
STATUS DOKUMEN
● Baseline Specification

Aturan final, rancangan yang didelegasikan, hal provisional, dan go-live gates dibedakan secara eksplisit.


AKSES CEPAT
Field-Level Specification →Permission Matrix →Acceptance Cases →Mandatory Agent Skills →
CARA MEMBACA

Gunakan pencarian, navigasi kiri, atau shortcut /. Klik ID bab untuk melihat seluruh tabel dan payload.