===== TEST SUITE (Phase 1) ===== [ok] Config: nama aplikasi dimuat [ok] Config: app.key tersedia (>=32 char) [ok] Config: security.password_min_length default 8 [ok] Validation: required ditolak [ok] Validation: email format ditolak [ok] Validation: min length ditolak [ok] Validation: confirmation same ditolak bila beda [FAIL] Validation: unique ditolak untuk email terpakai Tidak dapat terhubung ke database. [FAIL] Validation: unique mengabaikan id yang sama (update) Tidak dapat terhubung ke database. [ok] Validation: regex dengan ":" dan "," dibaca sebagai satu pattern [ok] Validation: phone format diterima/ditolak [ok] Validation: boolean passthrough [ok] CSRF: token verifikasi lulus lalu rotasi menolak token lama [ok] CSRF: token salah ditolak [FAIL] Auth: login sukses + session id Tidak dapat terhubung ke database. [FAIL] Auth: password salah ditolak Tidak dapat terhubung ke database. [FAIL] Auth: email tidak terdaftar ditolak Tidak dapat terhubung ke database. [FAIL] Authorization: super-admin bypass semua permission Tidak dapat terhubung ke database. [FAIL] Authorization: bride tidak bisa mengelola user Tidak dapat terhubung ke database. [FAIL] Authorization: guest hanya punya dashboard.view Tidak dapat terhubung ke database. [FAIL] User: create → update → password → soft-delete Tidak dapat terhubung ke database. [FAIL] User: paginated (filter active, urut) Tidak dapat terhubung ke database. [FAIL] Role: syncPermissions → permissionIds roundtrip Tidak dapat terhubung ke database. [FAIL] RateLimiter: block setelah 5 hit lalu clear Tidak dapat terhubung ke database. [ok] Helpers: format_rupiah & tanggal [ok] Helpers: str_slug [FAIL] DB: wedding_planner sehat (TABLES_COUNT) Tidak dapat terhubung ke database. [FAIL] Wedding: create → find → update → soft-delete Tidak dapat terhubung ke database. [FAIL] Wedding: uniqueSlug menangani bentrok Tidak dapat terhubung ke database. [FAIL] Wedding: uniqueSlug tetap unik terhadap soft-delete Tidak dapat terhubung ke database. [ok] Wedding: daysUntil menghitung hari [FAIL] Wedding: accessibleFor membatasi non-organizer Tidak dapat terhubung ke database. [FAIL] Wedding: requireAccess menolak non-member, mengizinkan organizer Tidak dapat terhubung ke database. [FAIL] WeddingEvent: create → update → soft-delete Tidak dapat terhubung ke database. [FAIL] WeddingMember: add (anti-duplikat), membersOf, candidates, remove Tidak dapat terhubung ke database. [FAIL] Wedding: bride hanya melihat project miliknya Tidak dapat terhubung ke database. ===== TEST SUITE (Phase 3 — Planning) ===== [FAIL] TaskCategory: create (anti-duplikat), update, hard delete Tidak dapat terhubung ke database. [FAIL] Task: create (kategori+assignee) → tasksOf → statsFor → upcoming → update → soft-delete Tidak dapat terhubung ke database. [FAIL] TimelineItem: create (join wedding) → itemsOf → update → soft-delete Tidak dapat terhubung ke database. [FAIL] RundownItem: create (auto sort) → update → itemsOfWedding join → soft-delete Tidak dapat terhubung ke database. ===== TEST SUITE (Phase 4 - Finance) ===== [FAIL] BudgetCategory: create (anti-duplikat), update, hard delete (SET NULL item) Tidak dapat terhubung ke database. [FAIL] BudgetItem: create → itemsOf → rekapByCategory (planned/actual/total) → update → soft-delete Tidak dapat terhubung ke database. [FAIL] Vendor: create → vendorsOf (payment_count, paid_total) → update → soft-delete Tidak dapat terhubung ke database. [FAIL] Payment: create → paymentsOf → upcomingFor (exclude paid) → update → soft-delete Tidak dapat terhubung ke database. [FAIL] Expense: proof_path & proof_name tersimpan + soft-delete Tidak dapat terhubung ke database. [ok] QR: fixtures versi/ukuran/mask/sha256 cocok referensi Python (8 kasus) [ok] QR: SVG valid & memuat jumlah modul gelap