03 — Audit konsistensi UX dan interaction contract¶
Status, baseline, dan batas audit¶
Dokumen ini adalah audit statis dan proposal kontrak, bukan bukti bahwa seluruh layar sudah lolos inspeksi visual atau UAT. Audit dilakukan dalam server-development mode dari workspace /home/scola/odoo, pada frontend develop@68b77d88f78b3d32f0ede3a54b665e067b014062 dan backend main@2ff6ac7cb41810bbc3b66821cdad004b52d1658a (snapshot 2026-08-08). Baseline produk yang diaudit tetap bersifat kandidat sampai 01-product-contract.md disetujui. Delta backend e749832/2ff6ac7 tidak mengubah component atau interaction paths yang diaudit dan belum diuji runtime; karena itu tidak menutup finding UX.
Pedoman aktif yang dibaca sebelum audit: AGENTS.md, docs/ai-guidelines/AI_AGENT_MASTER_GUIDE.md, docs/ai-guidelines/development-guide.md, docs/ai-guidelines/workspace-governance.md, docs/ai-guidelines/architecture-api.md, docs/ai-guidelines/ui-design-pattern.md, docs/ai-guidelines/menu-architecture.md, docs/ai-guidelines/datetime-timezone.md, docs/ai-guidelines/rbac-user-management.md, docs/ai-guidelines/DOCUMENTATION_GOVERNANCE.md, dan docs/qa/testing-guidelines.md. Seluruh docs/recon/ serta docs/documentation-planning/ juga digunakan sebagai evidence set.
Klasifikasi yang dipakai persis sebagai berikut:
- Release blocker — dapat membuat workflow supported salah hari, salah state, tidak aman, tidak dapat diselesaikan oleh actor resmi, atau menampilkan aksi yang bertentangan dengan otoritas backend.
- Major consistency issue — kontrak lintas halaman berbeda dan menimbulkan kegagalan, salah tafsir, aksesibilitas buruk, atau support burden nyata, tetapi belum terbukti sebagai release-stopping data/security defect sendiri.
- Minor polish — variasi visual/copy yang tidak mengubah task outcome atau authority.
- Intentional domain-specific difference — variasi yang dibenarkan oleh bentuk tugas/data; harus tetap memenuhi kontrak aksesibilitas, state, dan feedback minimum.
Semua temuan bertanda Static adalah kesimpulan dari source pada baseline tersebut. Temuan bertanda Runtime gate belum boleh dinyatakan selesai tanpa browser/API test pada Golden Tenant dan viewport yang ditentukan. Audit ini tidak mengklaim inventaris pixel-level yang exhaustif.
Ringkasan risiko¶
| Klasifikasi | ID | Ringkasan |
|---|---|---|
| Release blocker | UX-001–UX-005 | Hari sekolah attendance dapat bergeser; CTA dan authority berbeda; save/completion/correction ambigu; state Sakit tidak round-trip; bukti attendance tidak memiliki kontrol file/privacy memadai. |
| Major consistency issue | UX-006–UX-010, UX-012–UX-018 | Feedback, modal, primitive, sort/pagination, mobile shell, filter/tab, form validation, state/error, destructive action, terminology, dan responsive table belum memakai satu kontrak. |
| Minor polish | UX-011 | Hierarki header dan spacing halaman supported masih bervariasi. |
| Intentional domain-specific difference | UX-019–UX-020 | Card vs table dan loading scoped vs page-level boleh berbeda bila contract minimum tetap lulus. |
Tidak ada temuan di tabel ini yang boleh dinormalisasi menjadi perilaku produk. Release blocker UX juga dipetakan ke 08-stabilization-backlog.md.
Register temuan¶
| ID | Area / halaman terdampak | Klasifikasi | Temuan dan dampak | Evidence | Confidence / verification gate |
|---|---|---|---|---|---|
| UX-001 | Date/time; W05 create/pending attendance, weekly/daily report | Release blocker | Default tanggal mutasi menggunakan new Date().toISOString().slice(0, 10), yaitu tanggal UTC, bukan hari sekolah. Di sekolah non-UTC, create/pending dapat diarahkan ke hari sebelumnya/berikutnya di sekitar batas UTC. Portal siswa sudah memakai facade timezone, sehingga perilaku antar-role berbeda. |
src/views/AttendanceManagement/Admin/AttendanceSheetNew.vue:196,405; src/views/AttendanceManagement/Admin/AttendanceSheetList.vue:184; src/views/FacultyViews/WeeklyStudentReport.vue:590,628; src/views/FacultyViews/ClassDailyReport.vue:313; pembanding src/views/AttendanceManagement/Student/Attendance.vue:27; SSOT docs/ai-guidelines/datetime-timezone.md:3-16,55-58. |
Static: Confirmed from code. Runtime gate: uji timezone sekolah barat/timur UTC pada 23:30/00:30 lokal dan pastikan request memakai tanggal lokal sekolah. |
| UX-002 | W05 monitor/create untuk principal dan vice-principal | Release blocker | Shared list menampilkan Create/Pending berdasarkan capability FE, tetapi controller mutation mengecualikan principal/VP. Aksi terlihat dapat berakhir 403 dan membuat correction ownership tampak lebih luas daripada authority sebenarnya. | src/views/AttendanceManagement/Admin/AttendanceSheetList.vue:9-20,192; src/router/principalRoutes.js:196-218; src/router/vicePrincipalRoutes.js:214-231; ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:146-199,3335-3337; docs/documentation-planning/documentation-blockers.md:391-403 (BLK-B04). |
Static: Confirmed from code. Runtime gate: principal/VP dapat read, tidak melihat mutation CTA, dan mutation langsung tetap 403. Product decision PO-01 tetap diperlukan bila policy hendak diubah. |
| UX-003 | W05 save, completion, edit/correction | Release blocker | Tombol Save langsung menghasilkan sheet done; sheet completed dapat diedit dan dikirim ke endpoint sama tanpa reason, cutoff, approval, atau audit contract. Label save tidak menjelaskan apakah ini draft, finalisasi, atau koreksi. |
src/views/AttendanceManagement/Faculty/AttendanceSheet.vue:667-671,733-772; ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:3398-3422,4307-4334; docs/documentation-planning/documentation-blockers.md:325-338 (BLK-A21). |
Static: Confirmed from code; desired transition Requires product decision. Runtime gate mengikuti state table yang disetujui PO-01/AM-02/SG-01. |
| UX-004 | W05 status, legend, summary, parent/student view | Release blocker | FE menjadikan Sakit subtype/remark dari Izin, sedangkan canonicalizer backend mengembalikan Izin sebelum mempertimbangkan remark. Istilah dan aggregation tidak round-trip; UI lain masih menampilkan Sakit sebagai summary/status tersendiri. |
src/i18n/attendanceStatus.js:33-54; src/views/AttendanceManagement/Admin/AttendanceSheetNew.vue:217-223; ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:63-73,2855-2875,4313-4324; docs/documentation-planning/documentation-blockers.md:340-352 (BLK-A22). |
Static: Confirmed from code; glossary Requires product decision SG-02. Runtime gate: create → read → aggregate → parent/student round-trip untuk setiap approved state/subtype. |
| UX-005 | W05 proof attachment dan error validation | Release blocker | Browser accept hanya hint; file dikirim sebagai raw Data URL dan backend menyimpan tanpa allowlist ukuran/jenis/content yang terbukti. Raw proof masuk serializer yang dipakai portal. UI belum dapat memberi validation error server yang aman untuk kontrak file yang belum ada. |
src/views/AttendanceManagement/Faculty/AttendanceSheet.vue:315-319,592-603,749-750; ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:2795-2796,2816-2833,4323-4324; docs/documentation-planning/documentation-blockers.md:354-368 (BLK-A23). |
Static: Confirmed from code. Runtime/security gate: MIME/extension/signature/size negative tests, parent-child authorization, payload minimization, retention, dan DPO approval. |
| UX-006 | Notifications/toasts lintas AppLayout dan mutation pages | Major consistency issue | Ada beberapa taxonomy/rendering feedback. useAlerts.showError menghasilkan type error, tetapi AlertStack hanya memetakan danger, sehingga error jatuh ke visual info. AlertStack hanya dipasang pada desktop branch; mutation page yang tidak memasang stack lokal kehilangan feedback pada mobile, sedangkan page yang memasang stack lokal dapat menggandakan alert pada desktop. Toaster memakai taxonomy error berbeda dan close copy berbahasa Inggris. |
src/composables/useAlerts.js:47-52; src/components/AlertStack.vue:30-59,66-87; src/layouts/AppLayout.vue:18-29,37-75; src/views/AdminViews/AcademicConfig/AcademicYear/AcademicYearList.vue:243,278-288; src/views/AdminViews/AcademicConfig/StudyGroup/StudyGroupList.vue:501,508; src/components/Toaster.vue:52,60. |
Static: Confirmed from code. Runtime gate: success/warning/error persistent behavior pada mobile dan desktop; tepat satu renderer; error memakai semantics/warna/ARIA yang benar. |
| UX-007 | Forms, save/cancel, dialogs | Major consistency issue | AppModal memakai default visible copy Cancel/Save; backdrop dan Escape tetap memancarkan close walaupun mutation loading, dan tidak ada dirty-form contract. AppConfirmDialog juga memiliki default copy Inggris. Pengguna dapat kehilangan input atau menutup UI saat outcome request belum diketahui. |
src/components/ui/AppModal.vue:6-12,51-68,144-175; src/components/ui/AppConfirmDialog.vue:61-91; UI language SSOT docs/ai-guidelines/AI_AGENT_MASTER_GUIDE.md:103-105,267. |
Static: Confirmed from code. Runtime gate: double-submit, Escape/backdrop saat loading, dirty cancel, request timeout, dan localized copy. |
| UX-008 | Buttons, tables, tabs, title/content primitives | Major consistency issue | Root-level dan components/ui/ menyediakan primitive bernama sama dengan prop/behavior berbeda. Page yang masih memakai root primitive tidak otomatis memperoleh loading, pagination, accessibility, atau visual contract versi UI. |
src/components/AppButton.vue:1-40; src/components/ui/AppButton.vue:1-16,72-111; src/components/AppTable.vue:1-28; src/components/ui/AppTable.vue:1-34,247-305; src/components/AppTabs.vue:1-26; src/components/ui/AppTabs.vue:1-25,76-139; contoh residual src/views/AdminViews/Infrastructure/Maintenance.vue:28-30. |
Static: Confirmed from code. Runtime gate: inventory imports pada supported surface bernilai nol untuk primitive deprecated, kecuali allowlist bertanggal dan ber-owner. |
| UX-009 | Tables, pagination, sorting; student and academic masters | Major consistency issue | Saat totalItems disediakan untuk server pagination, AppTable tidak memotong data tetapi tetap melakukan sort lokal pada props.data. Header sortable secara default; hasil tampak seperti sort seluruh dataset padahal hanya current page. Student, academic year, study group, dan session memakai pola server total tersebut. |
src/components/ui/AppTable.vue:61-103,294,423-471; src/views/AdminViews/StudentDatabase/StudentList.vue:115-118; src/views/AdminViews/AcademicConfig/AcademicYear/AcademicYearList.vue:61-62; src/views/AdminViews/AcademicConfig/StudyGroup/StudyGroupList.vue:122-125; src/views/AdminViews/AcademicConfig/Session/SessionList.vue:108-109. |
Static: Confirmed from code. Runtime gate: sort kolom pada data >1 page harus server-global atau non-sortable; page traversal tidak mengubah ordering contract. |
| UX-010 | Responsive shell dan mobile topbar | Major consistency issue | Mobile AppLayout hanya merender slot topbar; beberapa page supported tidak menyediakan slot itu, sementara attendance portal menyediakannya. Akibatnya title/back/navigation bergantung pada page, bertentangan dengan mobile-shell SSOT. |
src/layouts/AppLayout.vue:18-29; src/views/AdminViews/AcademicConfig/AcademicYear/AcademicYearList.vue:2-9; src/views/AdminViews/AcademicConfig/GradeLevel/GradeLevelList.vue:2-9; src/views/AdminViews/AcademicConfig/Session/SessionList.vue:2-6; src/views/AdminViews/AcademicConfig/StudyGroup/StudyGroupList.vue:2-8; pembanding src/views/AttendanceManagement/Student/Attendance.vue:204-207; SSOT docs/ai-guidelines/ui-design-pattern.md:31-33. |
Static: Confirmed from code. Runtime gate: setiap canonical route pada 360/390 px memiliki title, back/menu affordance, focus order, dan tidak tertutup bottom navigation. |
| UX-011 | Page headers, breadcrumbs, spacing | Minor polish | Supported candidates memakai raw h1, AppTitle, atau page-specific header; spacing juga masih p-4 md:p-6, bukan satu standard container. Ini melemahkan hierarchy dan predictability, tetapi belum sendiri mengubah business outcome. |
src/views/AdminViews/AcademicConfig/AcademicYear/AcademicYearList.vue:4-9; src/views/AdminViews/AcademicConfig/GradeLevel/GradeLevelList.vue:4-9; src/views/AttendanceManagement/Admin/AttendanceSheetNew.vue:3-5; standard docs/ai-guidelines/ui-design-pattern.md:31-33. |
Static: Confirmed from code. Visual gate: canonical title, subtitle, breadcrumb/back action, CTA zone, dan spacing pada desktop/mobile snapshots. |
| UX-012 | Tabs, filters, search, reset behavior | Major consistency issue | Fungsi setara memakai AppTabs, native select, custom autocomplete, dan button-row; semantics keyboard/ARIA, debounce, reset-to-page-1, dan persisted query state tidak konsisten. Study group memiliki tiga native filter dan beberapa custom search dropdown; Session memakai custom inputs; Student memakai AppTabs + native select + AppTable search. |
src/views/AdminViews/StudentDatabase/StudentList.vue:63-118,441,534; src/views/AdminViews/AcademicConfig/StudyGroup/StudyGroupList.vue:96-125,248-314,362-418,1672-1678; src/views/AdminViews/AcademicConfig/Session/SessionList.vue:35-53,297-455,598; src/components/ui/AppTabs.vue:1-25,76-139. |
Static: Confirmed from code. Runtime gate: keyboard navigation, label association, reset, browser back/forward, debounce cancellation, page reset, and empty search vs empty dataset. |
| UX-013 | Forms, labels, required indication, validation | Major consistency issue | Canonical AppInput memiliki required marker dan inline error, tetapi mutation pages masih memakai raw labels/controls tanpa marker/error contract seragam. Attendance operator baru memvalidasi register/session/date melalui toast; roster line completeness tetap tidak dijamin. Field-level error, summary error, dan focus-to-first-error belum satu pola. |
src/components/ui/AppInput.vue:5-10,57,81-94,165-179; src/views/AttendanceManagement/Admin/AttendanceSheetNew.vue:33-58,371-379; roster evidence ../custom_addons_scola/gcgscola/scola_attendance/controllers/attendance_api_mixin.py:3335,3398-3422,4238-4275,4307-4334. |
Static: Confirmed from code. Runtime gate: required marker matches backend requiredness; invalid field is announced and focused; no partial mutation; server error mapped without exposing internals. |
| UX-014 | Loading, empty states, and error recovery | Major consistency issue | State handling bervariasi antara CSS spinner, table skeleton, plain empty text, dan error card tanpa retry. SSOT meminta Loader2, descriptive empty state, dan actionable retry bila mungkin. Portal attendance menampilkan error tetapi tidak selalu menawarkan retry pada blok yang sama. | src/components/ui/AppTable.vue:118-180; src/views/AttendanceManagement/Student/Attendance.vue:283-300,363-366; src/views/AttendanceManagement/Parent/Attendance.vue:344-366,419-427; SSOT docs/ai-guidelines/ui-design-pattern.md:60-96. |
Static: Confirmed from code. Runtime gate: initial load, empty-success, 403, 404, 422, 500, timeout/offline, retry, dan stale-content behavior per canonical page. |
| UX-015 | Confirmation and destructive/state-changing actions | Major consistency issue | Sebagian page memakai browser-native confirm, sementara tersedia AppConfirmDialog. Native confirm tidak memiliki standard impact summary, loading lock, localized button label, atau structured recovery copy. Risiko paling tinggi pada delete, submit, approve, post, close, dan reconciliation. |
Core example src/views/AdminViews/AcademicConfig/AcademicCalendar/AcademicCalendarList.vue:802; optional examples src/views/AdminViews/Budget/BudgetPlanningPage.vue:284-324; src/views/AccountingManagement/Journal/JournalEntryList.vue:810-843; canonical component src/components/ui/AppConfirmDialog.vue:4,34-36,61-91. |
Static: Confirmed from code. Runtime gate: irreversible/high-impact action names object, state/downstream effect, actor, and recovery; loading prevents duplicate/close; Escape/cancel creates no mutation. |
| UX-016 | Status labels and terminology | Major consistency issue | Navigation/copy memakai Kehadiran, Absensi, Presensi, Attendance Sheet, dan Register untuk surfaces yang beririsan. Domain-specific distinction per-session vs daily belum dipresentasikan sebagai glossary yang konsisten. Ini menambah risiko memilih workflow yang salah dan memperbesar support burden. |
src/i18n/locales/id.json:644,819,842,1079,1165,1199-1202,1516-1579,1881-1985; src/config/apps/appFragments/counselorApp.js:101; src/config/apps/appFragments/parentPortalApp.js:139; state source src/i18n/attendanceStatus.js:33-54. |
Static: Confirmed from code; preferred terminology Requires product decision SG-01/SG-02. Runtime gate: same page ID has one label per locale, aliases searchable but not simultaneously exposed. |
| UX-017 | Responsive tables and tab accessibility; student vs parent summaries | Major consistency issue | Student AttendanceList memakai raw tabs/tables tanpa tab roles dan tanpa horizontal overflow wrapper; parent counterpart sudah menambah tablist/tab/tabpanel serta overflow-x-auto. Data sejenis memberi keyboard/mobile behavior berbeda berdasarkan role. |
src/views/AttendanceManagement/Student/AttendanceList.vue:1-31,54-88; src/views/AttendanceManagement/Parent/AttendanceList.vue:1-41,64-75,104. |
Static: Confirmed from code. Runtime gate: 320/360/768 px, keyboard arrows/tab/focus, screen-reader names, no clipped actions/columns, and equivalent data semantics. |
| UX-018 | Error handling and HTTP semantics | Major consistency issue | Banyak page menampilkan error.message langsung melalui toast/card. Tanpa normalized error taxonomy, 403, validation, conflict, timeout, dan internal error dapat tampak sama atau membocorkan backend wording. Pola retry/idempotency juga tidak terikat pada mutation state. |
W05 examples src/views/AttendanceManagement/Admin/AttendanceSheetNew.vue:285-287,323-326,408-410; portal examples src/views/AttendanceManagement/Parent/Attendance.vue:177-181,210-212,293-296; API architecture requires explicit domain API docs/ai-guidelines/architecture-api.md:33-38. |
Static: Confirmed from code for direct message use; actual leak Requires runtime verification. Runtime gate: mapped 401/403/404/409/422/429/5xx/offline; correlation ID safe; retry only for classified idempotent operations. |
| UX-019 | Portal cards versus operator tables | Intentional domain-specific difference | Siswa/orang tua dapat memakai cards/calendar untuk satu subjek/anak, sedangkan operator memakai table untuk banyak record. Penyamaan layout tidak diperlukan selama state labels, dates, privacy projection, and related-page links konsisten. | Portal shape src/views/AttendanceManagement/Student/Attendance.vue:204-300; operator table src/views/AttendanceManagement/Admin/AttendanceSheetList.vue:1-68. |
Static: acceptable proposal, not product approval. Runtime gate: task completion, equivalent state meaning, responsive/accessibility, and privacy tests. |
| UX-020 | Button/section loading versus full-page loading | Intentional domain-specific difference | Loading boleh dibatasi ke tombol untuk mutation atau section untuk independent panels; full-page spinner hanya untuk data yang memblokir seluruh task. Perbedaan ini disengaja jika semua affected controls locked dan stale state diberi label. | Button loading contract src/components/ui/AppButton.vue:3-16,103-111; table scoped loading src/components/ui/AppTable.vue:118-139; SSOT spinner docs/ai-guidelines/ui-design-pattern.md:60-67. |
Static: proposed exception. Runtime gate: concurrency, stale data, cancellation, focus, and retry behavior. |
Coverage terhadap area yang diminta¶
| Audit area | Finding/contract utama | Status audit |
|---|---|---|
| Page headers, breadcrumbs | UX-010, UX-011; IC-01 | Static sample + route-wide runtime/visual gate required |
| Tabs | UX-012, UX-017; IC-02 | Static confirmed on representative core pages |
| Filters and search | UX-012; IC-03 | Static confirmed; query persistence runtime gate |
| Forms, field labels, required indication | UX-007, UX-013; IC-04 | Static confirmed; backend-required parity gate |
| Date/time format and defaults | UX-001; IC-05 | Static release blocker; timezone boundary runtime gate |
| Empty/loading states | UX-014, UX-020; IC-06 | Static pattern audit; full route traversal pending |
| Validation | UX-005, UX-013, UX-018; IC-04/IC-13 | Static; negative API/browser tests required |
| Save/cancel behavior | UX-003, UX-007; IC-07 | Static; state/dirty/idempotency runtime tests required |
| Confirmation/destructive actions | UX-015; IC-08 | Static source inventory; product state decisions pending |
| Notifications/toasts | UX-006; IC-09 | Static confirmed; mobile/desktop rendering runtime gate |
| Pagination/tables | UX-009, UX-017, UX-019; IC-10 | Static confirmed; multi-page dataset gate |
| Status labels/terminology | UX-004, UX-016; IC-11 | Static; glossary decision pending |
| Responsive behavior | UX-010, UX-017, UX-019; IC-12 | Static inference only; viewport test mandatory |
| Error handling | UX-014, UX-018; IC-13 | Static; response-class matrix runtime gate |
Proposed Scola interaction contract¶
Kontrak berikut adalah proposal baseline, bukan existing behavior. Setiap butir menjadi measurable acceptance gate pada supported surface.
| Contract ID | Aturan baseline | Ukuran kelulusan |
|---|---|---|
| IC-01 Shell, header, breadcrumb | Setiap canonical route authenticated memakai AppLayout; mobile menyediakan #topbar; satu page title, optional subtitle, breadcrumb/back target canonical, dan primary CTA pada zone yang konsisten. |
100% route supported lulus static mount inventory; 320/360/390/768/1280 px tidak kehilangan title/navigation; breadcrumb tidak menuju alias/forbidden route. |
| IC-02 Tabs | Gunakan satu canonical tabs primitive dengan tablist/tab/tabpanel, keyboard arrows, visible focus, stable key, dan deep-link bila tab adalah meaningful task state. Button-row hanya untuk command, bukan tab. |
Axe/manual keyboard test lulus; browser back/forward memulihkan tab yang deep-linkable; tidak ada raw tab implementation pada supported surface kecuali allowlist. |
| IC-03 Filter/search | Filter memiliki label, reset yang jelas, debounce/cancellation untuk remote search, selalu kembali ke page 1, dan membedakan “tidak ada data” dari “tidak ada hasil”. Query penting disimpan di URL, bukan state tersembunyi. | Contract tests untuk reset/debounce/page; reload/back-forward deterministik; stale response tidak mengganti query terbaru. |
| IC-04 Form/validation | Label, helper, unit/format, required marker, disabled/read-only reason, inline error, summary error, dan focus-to-first-error konsisten. Required frontend harus sama atau lebih ketat dari backend tetapi tidak boleh menjanjikan rule yang backend tidak enforce. | Field schema/contract test; missing/invalid/cross-scope payload rejected atomically; browser announces error; no partial write. |
| IC-05 Date/time | Semua school-day default/range/display memakai src/utils/timezone.js; date-only tetap YYYY-MM-DD; user-facing display menggunakan locale approved; request tidak memakai raw toISOString() untuk memilih hari sekolah. |
check:datetime-timezone lulus; test offset negatif/positif, DST bila relevan, and UTC boundary; FE request and BE persisted day identical. |
| IC-06 Loading/empty/error | Initial loading, scoped loading, empty-success, empty-filter, access denied, offline/timeout, and server error adalah state berbeda. Empty state menjelaskan prerequisite/next safe action; retry hanya bila aman. | Story/component state matrix + E2E forced responses; tidak ada blank screen, infinite spinner, atau retry mutation non-idempotent tanpa token. |
| IC-07 Save/cancel | Primary save menyebut outcome (Simpan draf, Selesaikan, Kirim untuk persetujuan). Submit dikunci saat request berlangsung; dirty cancel meminta confirmation; outcome unknown tidak dilabeli gagal sebelum reconciliation. |
Double-click/concurrent/interrupted tests menghasilkan satu effect; Escape/backdrop tidak menutup loading mutation; refresh/retry resolves deterministic state. |
| IC-08 High-impact confirmation | Delete/post/approve/close/cancel/reconcile menampilkan object, target state, downstream effect, reversibility, dan recovery owner. Browser-native confirm tidak dipakai pada supported surface. |
Static scan nol window.confirm/global confirm pada supported routes; state and audit tests; cancel makes zero API mutation. |
| IC-09 Notifications | Satu provider + satu renderer per shell. Taxonomy canonical info/success/warning/error; copy Bahasa Indonesia; error uses alert semantics, success status semantics; persistent notification dipakai bila recovery butuh waktu. |
Exactly one rendered notification per event on mobile/desktop; type-to-style/ARIA component tests; no unlocalized default close labels. |
| IC-10 Table/pagination/sort | Server-pagination selalu server-sort/filter atau kolom ditandai non-sortable. Sort indicator menyatakan scope; totals, page reset, selection, and bulk actions remain coherent. Mobile uses responsive table/card contract without hiding critical actions. | Dataset >2 pages verifies global ordering; mutation refresh keeps/clears selection intentionally; no clipped column/action at supported viewport. |
| IC-11 Status/terminology | UI menampilkan approved domain glossary; raw backend states dipetakan; action label menyatakan transition; aliases tidak tampil sebagai competing terms. | Snapshot of label registry + round-trip transition tests; one canonical term per concept/locale; glossary decision IDs linked. |
| IC-12 Responsive/accessibility | Semua supported task dapat selesai pada declared viewports; controls memiliki accessible name, focus order, 44px target where mobile, keyboard path, contrast, and reduced-motion behavior. | Automated accessibility scan plus keyboard/manual viewport matrix; no horizontal page overflow; table overflow/card alternative tested. |
| IC-13 Error contract | FE memetakan 401, 403, 404, 409, 422, 429, 5xx, timeout/offline ke safe localized messages dan supported recovery. Backend internals tidak dirender mentah. | Mocked response contract tests; 403 tidak menjadi “data kosong”; 409 offers refresh/reconcile; correlation reference safe and support-usable. |
| IC-14 Attachment/privacy | File control menyebut accepted type/size/purpose; server validates signature/type/size; progress/cancel; field projection dan download authority sesuai role/scope; retention visible only after DPO approval. | Negative upload/security tests, malware scan integration where required, parent-child/company isolation, payload size/projection assertions, deletion/retention audit. |
Remediation order dan runtime acceptance gates¶
- Sebelum core workflow testing: tutup UX-001–UX-005 bersama AUTH findings dan attendance business decisions. Jangan membuat workaround copy untuk defect tersebut.
- Sebelum navigation/UI freeze: tetapkan canonical primitive, shell, feedback, tab/filter, and error contracts; migrasikan hanya supported surface terlebih dahulu (UX-006–UX-018).
- Per tranche workflow: jalankan component/contract tests, lalu E2E positive/negative, then responsive/accessibility inspection pada Golden Tenant. Pedoman test mensyaratkan inspect actual route/DOM dan validasi environment sebelum menulis/menjalankan E2E (
docs/qa/testing-guidelines.md:1-79). - Sebelum baseline GREEN: route crawl harus menunjukkan tidak ada blank/placeholder, missing topbar, unhandled 403/422/500, local-only server sort, duplicated toast, raw confirm, atau unapproved terminology pada supported surface.
Evidence minimum per hasil test: build hashes FE/BE/database/module set, tenant/account/active role, route, viewport/timezone, API request/response class, state before/after, screenshot/trace only as QA artifact (bukan committed ad-hoc artifact), and linked defect ID.
Definition of UX-ready¶
UX supported surface dapat dibekukan untuk Scola V1 hanya bila:
- UX-001–UX-005 closed dengan code, negative tests, business/security approval yang relevan, dan runtime evidence;
- tidak ada Major consistency issue tanpa remediation atau explicit Accepted Limitation yang tidak menyangkut security/data integrity/core task completion;
- IC-01–IC-14 memiliki automated evidence bila dapat diotomasi dan named manual owner untuk sisanya;
- setiap Intentional domain-specific difference memiliki alasan task/data, bukan sekadar warisan component;
- terminology/state glossary, supported viewport, and error/recovery behavior telah disetujui;
- hasil audit ulang terhadap served bundle, bukan hanya source, dicatat pada exact release build.