Lewati ke isi

CBT Best-Practice Gap Analysis & Implementation Plan - 2026-05-27

Dokumen ini membandingkan implementasi CBT Scola di frontend dan backend dengan referensi best practice resmi untuk pembuatan soal, ujian, bank soal, runner ujian, integrity/proctoring, accessibility, upload media, analytics, dan interoperability.

0. Recon Context

Item Nilai
Mode Default, local repo recon, docs-only
Frontend root /Users/salfath/scola-fe-v2
Backend root /Users/salfath/scola-odoo-module
Scope FE src/views/ExamManagement, src/views/AdminViews/CBT, src/views/StudentViews/CBT, src/services/cbt, src/router, docs/domains/cbt
Scope BE scola_cbt dan bridge admission terkait CBT
Dokumen governance dibaca docs/ai-guidelines/development-guide.md, docs/ai-guidelines/workspace-governance.md, docs/ai-guidelines/architecture-api.md, docs/qa/testing-guidelines.md
Recon pendamping docs/domains/cbt/fe-be-question-exam-sync-recon-2026-05-27.md

0.1 Implementation Status

Update 2026-05-27:

  • P0/P1 policy runtime sebagian sudah diimplementasikan:
  • grace_period_minutes ikut menghitung attempt deadline.
  • auto_submit_on_timeout=false mencegah auto-submit otomatis saat save/sync/submit mencapai timeout.
  • allow_negative_marking dan negative_mark_percentage dipakai saat auto-score objective answers.
  • show_score_immediately dipakai sebagai policy gate untuk payload hasil setelah submit.
  • max_attempts pada runner start membaca effective policy payload.
  • P1 import fidelity sudah diimplementasikan untuk CSV mcq_multi: correct_answer menerima beberapa jawaban seperti A,C atau A|C.
  • P1 route gating sudah diimplementasikan:
  • public CBT routes diberi featureFlag: "scola_cbt";
  • router guard mengecek feature flag untuk public routes;
  • parent route /spmb/admission/:id tidak lagi tergantung scola_cbt, sementara route SPMB CBT tetap gated.

P1 lanjutan sudah diimplementasikan:

  • Secure upload hardening untuk asset soal:
  • backend memvalidasi allowlist ekstensi dan MIME per tipe media, base64 validity, ukuran file maksimum, signature dasar untuk PDF/PNG/JPEG, dan skema URL http/https;
  • frontend memperketat accept list upload, validasi URL, dan metadata asset.
  • Accessibility/accommodation runtime:
  • asset soal memiliki alt_text, caption, transcript, language, dan flag decorative;
  • image asset wajib punya alt text kecuali ditandai dekoratif;
  • participant memiliki extra_time_minutes, screen_reader_mode, reduced_motion, dan accommodation_notes;
  • attempt deadline menambahkan extra time participant dan policy payload mengirim accommodation ke runner.
  • Session lock/multi-login hardening:
  • runner FE mengirim client_session_id stabil per tab/session;
  • backend attempt menyimpan active session, user agent, IP, heartbeat;
  • saat policy block_multi_login aktif, session berbeda diblokir selama heartbeat belum stale.
  • Optional Safe Exam Browser integration:
  • exam memiliki field cbt_seb_required, cbt_seb_config_key_hash, dan cbt_seb_browser_exam_key;
  • runner start menolak akses jika SEB required dan header key yang dikonfigurasi tidak cocok.

0.2 Audit Matrix - Status Implementasi Aktual

Audit ulang 2026-05-27 terhadap codebase FE /Users/salfath/scola-fe-v2 dan BE /Users/salfath/scola-odoo-module.

Legend:

  • done: implementasi dan evidence code sudah ada, dengan QC teknis yang relevan.
  • partial: implementasi utama sudah ada, tetapi acceptance plan belum tertutup penuh.
  • not done: requirement plan belum terlihat di codebase aktif.
  • not verified: requirement mungkin sebagian ada, tetapi acceptance plan belum diverifikasi sesuai gate yang diminta.
Phase / Area Status Ringkasan audit Evidence / catatan
Phase 0 - regression harness dasar partial Baseline unit/contract tests untuk policy, import, scoring, runner sudah ada dan lulus. Namun acceptance Phase 0 juga menuntut regression harness lebih luas sebagai backlog permanen, dan itu belum sepenuhnya terdokumentasi sebagai matrix otomatis. Test file aktif di scola_cbt/tests dan tests/unit/services; belum ada audit matrix status otomatis lintas FE-BE.
Phase 1 - policy runtime enforcement done Runtime policy utama sudah dipakai di backend: grace_period_minutes, auto_submit_on_timeout, negative marking, show_score_immediately, max_attempts, block_multi_login. Lihat runner_attempt_api.py, runner_start_api.py, attempt.py.
Phase 2 - secure question media upload done Hardening upload server-side dan metadata accessibility minimum sudah ada. Allowlist ekstensi/MIME, size, signature, dan URL validation di question.py; FE authoring/import asset metadata di CBTQuestionForm.vue dan CBTQuestionSetDetail.vue.
Phase 3 - import fidelity + QTI subset done mcq_multi import, warning vs error, export/import QTI subset, dan FE export/import flow sudah ada. question_api.py, question_set_api.py, qti_subset.py.
Phase 4 - curriculum metadata + blueprint done Metadata kurikulum inti sekarang sudah ada di question bank (course/chapter, learning_objective_code, learning_outcome_code, cognitive_level, grade_phase_code) dan exam CBT sudah punya blueprint coverage validator ringan dengan warning saat publish. Metadata question ada di question.py dan question_api.py; FE authoring/import ada di CBTQuestionForm.vue dan CBTQuestionSetDetail.vue; blueprint exam ada di exam.py, exam_read_api.py, exam_lifecycle_api.py, dan CBTExamDetail.vue.
Phase 5 - accessibility + accommodation runtime done Accommodation payload participant sudah dipakai runner, surface FE untuk extra_time_minutes / screen_reader_mode / reduced_motion sudah ada, choice input tetap keyboard-focusable dengan focus-visible/ARIA, asset preview memakai alt/caption/transcript, dan warning waktu tidak lagi bergantung pada warna saja. Accommodation model di participant.py; runner FE memakai policy.accommodations, aria-live, role=\"radiogroup\", input sr-only, dan reduced-motion class di CBTRunner.vue; asset preview ada di QuestionAssetsPreview.vue.
Phase 6 - session lock + optional SEB done Session lock backend, client_session_id, stale timeout, route heartbeat eksplisit, FE heartbeat flow, launch instruction SEB pada runner/public/admission start, serta indicator session conflict yang eksplisit di runner dan proctor dashboard sudah ada. Session validation di runner_controller.py; heartbeat route ada di runner_attempt_api.py dan FE runner memakainya via cbtRunnerService.js + useExamState.js; overlay SEB dan multi-login ada di CBTRunner.vue; proctor surface ada di ProctorDashboard.vue.
Phase 7 - analytics maturity done Minimum sample threshold, distractor analysis per choice, version-aware metadata, dan lifecycle item approved/needs_revision/retired sudah ada. Backend analytics mengekspor review_status, version, root_question_id, dan version_count di exam.py; FE menampilkan status/version dan action review di CBTItemAnalysis.vue.
Phase 8 - event schema, privacy, retention done CBT_EVENT_SCHEMA_V1, schema_version, canonical FE runner event names, audit filtering minimum by event_code/actor/exam/attempt, retention matrix administratif, sanitasi metadata audit sensitif, policy retention per tenant, cron cleanup tenant-aware, minimisasi identifier pada analytics/integrity/proctor read payload untuk role monitor, dan hardening export operasional utama sudah ada. Helper schema ada di event_schema.py; policy retention tenant dan cleanup job ada di policy.py dan cbt_data.xml; FE settings memakai retention fields editabel di CBTSettings.vue.
Short answer auto-grading done Auto-grade deterministic/similarity untuk short_answer sudah aktif di authoring, import, scoring, dan QTI subset. attempt.py, CBTQuestionForm.vue.
Essay auto-grading heuristic done Auto-grade essay berbasis rubric threshold sekarang sudah punya lifecycle authoring yang lebih lengkap: rubric template reusable, version history template, snapshot rubric pada soal/jawaban, breakdown per criterion, dan audit override manual yang konsisten. question.py, question_api.py, attempt.py, grading_read_api.py, grading_write_api.py, RubricBuilderModal.vue, CBTQuestionForm.vue, GradingWorkspace.vue.
QC acceptance plan partial Automated server QC sudah dijalankan: backend full CBT unit discover, targeted frontend CBT/menu Vitest, diff hygiene, module upgrade dev DB, dan health check Odoo dev. Manual smoke end-to-end lintas peran masih membutuhkan eksekusi browser operasional dengan data seeded/nyata. Backend 128 tests OK; frontend targeted 72 tests OK; module upgrade scola_cbt pada scoladev exit 0; health check 127.0.0.1:8074/web/health pass.

Kesimpulan audit:

  • Status implementasi kode Phase 1-8 sudah tertutup di codebase aktif server /home/scola/odoo.
  • Area yang sudah cukup solid untuk dinyatakan selesai: Phase 1, 2, 3, 4, 5, 6, 7, 8, plus short answer auto-grading dan essay rubric auto-grading heuristic.
  • Area yang masih perlu sign-off operasional sebelum klaim produksi penuh: manual smoke end-to-end berbasis skenario browser/operasional. QC server automated dan module upgrade dev sudah diverifikasi pada 2026-05-28.

0.3 Closure Checklist - Backlog Penutupan

Checklist ini menurunkan hasil audit menjadi pekerjaan penutupan yang konkret. Tujuannya bukan menambah scope baru, tetapi menutup item partial dan not done sampai status implementasi bisa dinyatakan benar-benar lengkap.

Prioritas A - Tutup gap implementasi aktif

Item Status audit Scope kerja minimum Acceptance minimum
Phase 4A - metadata curriculum inti done Field learning_objective_code, learning_outcome_code, cognitive_level, dan grade_phase_code sekarang ada di question bank; FE authoring dan import contract sudah tersambung Question create/update/import sekarang membaca metadata ini; existing question tanpa metadata tetap valid
Phase 4B - blueprint coverage validator done Blueprint coverage validator ringan sekarang ada di exam CBT, lengkap dengan warning payload saat publish dan surface FE untuk konfigurasi + tampilan coverage Publish exam dengan blueprint kurang coverage mengembalikan warning payload yang ditampilkan FE; exam tanpa blueprint tetap berjalan
Phase 5A - runner accessibility audit done Runner sekarang memakai input pilihan yang tetap keyboard-focusable, focus-visible treatment, aria-live untuk timer, role=\"radiogroup\", dan warning waktu non-color Contract FE runner mengunci keyboard-only path dan status waktu dapat dipahami tanpa hanya mengandalkan warna
Phase 5B - accommodation FE surface done Runner sekarang menampilkan surface aktif untuk screen_reader_mode, reduced_motion, dan extra_time_minutes, serta mengurangi animasi saat reduced motion aktif Runner menghormati reduced-motion/readability toggle dan menampilkan effective remaining time yang konsisten
Phase 6A - runner heartbeat done Route heartbeat eksplisit /runner/heartbeat dan FE heartbeat loop sudah ditambahkan; periodic full state reconciliation tetap dipertahankan sebagai jalur terpisah Session stale/recovery sekarang punya jalur heartbeat yang eksplisit dan teruji secara struktur
Phase 6B - FE SEB UX done Runner dan halaman start publik/admission menampilkan instruksi saat seb_required=true; indicator conflict session sekarang eksplisit di overlay multi-login runner dan badge proctor dashboard User tidak lagi hanya menerima error backend mentah saat SEB wajib, dan pengawas bisa melihat conflict session tanpa membaca log mentah
Phase 7A - minimum sample threshold done Threshold sample pada analytics backend dan FE label insufficient data sudah ada Sample kecil tidak lagi menghasilkan kualitas/rekomendasi final
Phase 7B - distractor analysis done Statistik pilihan per opsi untuk upper/lower group sudah ditambahkan FE item analysis menampilkan opsi pengecoh yang efektif/tidak efektif
Phase 7C - version-aware analytics + item lifecycle done Analytics dan list question sekarang membawa metadata version-aware; question model punya status approved / needs_revision / retired Workflow review bank soal bisa memisahkan item aktif vs item revisi/retired dan analytics dapat memberi konteks versi
Phase 8A - canonical event schema done CBT_EVENT_SCHEMA_V1, schema_version, event code, dan canonical FE runner event names sudah dipasang pada jalur integrity + audit event utama Event runner integrity dan audit event penting memakai shape metadata yang sama
Phase 8B - privacy & retention done Retention matrix administratif, privacy notice, gating exposure cbt_token, dan sanitasi metadata audit sensitif sudah ditambahkan Policy/settings admin dan payload audit tidak lagi mengandalkan metadata mentah untuk field sensitif
Phase 8C - audit filtering/export hardening done Filter audit by event_code, actor, exam, dan attempt sudah ada; hardening exposure secret pada read API sudah ditambahkan; export XLSX sudah disanitasi dari spreadsheet formula injection dan filename abuse; bulk export sekarang punya gate akses terpisah dari read analytics; payload analytics/integrity/proctor meminimalkan identifier untuk role monitor read-only; detail flag proctor juga menyanitasi metadata sensitif. Audit log CBT bisa difilter lebih presisi tanpa membaca metadata mentah, payload read operasional utama tidak lagi mengirim identifier penuh ke seluruh role monitor, detail integrity flag tidak lagi memaparkan token/session metadata sensitif, dan export operasional utama sudah hardened.

Prioritas B - Tutup gap verifikasi

Item Status audit Scope kerja minimum Acceptance minimum
QC1 - module upgrade test dev DB done Upgrade module scola_cbt dijalankan pada database dev scoladev di server /home/scola/odoo Upgrade command exit 0 pada 2026-05-28 dan health check Odoo dev pass.
QC2 - manual smoke end-to-end partial Ulangi flow create question set → import → create exam → start runner → autosave → submit → grade → analytics/report Semua langkah tercatat dengan hasil pass/fail yang eksplisit
QC3 - runner E2E smoke done Eksekusi Playwright smoke yang relevan untuk flow runner/session dan kontrak schedule CBT yang hardened Auth setup Playwright hijau; targeted tests/e2e/smoke/cbt_smoke.spec.ts dan tests/e2e/smoke/exam_roles_smoke.spec.ts hijau/skip terhadap https://be-dev.gcgscola.id dengan E2E_REUSE_EXISTING_SERVER=true

Urutan kerja penutupan yang disarankan

  1. Akhiri dengan QC1/QC2/QC3 supaya status final bisa dinyatakan verified, bukan hanya implemented.

Definisi selesai untuk klaim "100% terimplementasi"

Dokumen ini baru bisa dinyatakan 100% terimplementasi jika seluruh kondisi berikut terpenuhi:

  • tidak ada lagi item partial atau not done di audit matrix;
  • QC acceptance pada ## 7. QC Gates sudah benar-benar dijalankan, bukan diasumsikan;
  • keputusan runtime di ## 8. Product Decisions Closed sudah tercermin di implementasi aktif;
  • backlog penutupan di bagian ini sudah kosong atau seluruhnya dipindahkan ke roadmap yang memang dinyatakan out-of-scope.

1. Referensi Best Practice

Referensi dipilih dari sumber primer atau dokumen resmi, bukan blog/vendor sekunder.

Referensi Area yang dipakai untuk pembanding URL
1EdTech Question and Test Interoperability (QTI) Interoperability item/test, portable item bank, response processing, assessment package exchange https://www.1edtech.org/standards/qti/index
1EdTech Caliper Analytics Event model untuk aktivitas belajar/assessment dan telemetry lintas sistem https://www.1edtech.org/standards/caliper
W3C WCAG 2.2 Accessibility UI/content, keyboard access, non-text content, timing, input assistance https://www.w3.org/TR/WCAG22/
OWASP File Upload Cheat Sheet File type allowlist, content validation, storage, size limit, malware risk control https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html
OWASP Logging Cheat Sheet Security event logging, auditability, log content hygiene, monitoring https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html
OWASP Session Management Cheat Sheet Session lifecycle, secure session IDs/cookies, server-side controls https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html
NIST SP 800-63B / 800-63B-4 Digital identity, authentication/session assurance, reauthentication guidance https://pages.nist.gov/800-63-4/sp800-63b.html
Safe Exam Browser Lockdown browser untuk high-stakes exam, browser/runtime restriction beyond JS fullscreen https://safeexambrowser.org/about_overview_en.html

2. Baseline Implementasi Saat Ini

2.1 Area yang sudah kuat

Area Bukti implementasi Catatan
Same-origin CBT API FE memakai namespace /api/scola_cbt/...; README domain sudah menandai namespace canonical Selaras dengan architecture-api.md; tidak perlu VITE_API_URL production
Question bank core BE scola.cbt.question.item punya tipe soal mcq, mcq_multi, true_false, short_answer, essay, rich HTML sanitized, choices, asset relation, difficulty, points, tags, versioning Core authoring sudah cukup untuk operasional sekolah
Authoring FE CBTQuestionForm.vue mengirim type, content, explanation, difficulty, points, tags, assets, choices FE support jawaban multi benar via choices is_correct
CSV import CBTQuestionSetDetail.vue menyediakan import wizard; BE question_api.py punya endpoint import Praktis, tetapi belum QTI dan ada gap multi-correct
Runner server-authoritative BE runner memeriksa attempt ownership/token, state, remaining time, auto-submit saat timeout, bulk sync Basis integrity runner sudah benar: backend bukan sekadar menerima state FE
Attempts limit runner_start_api.py mengecek exam.max_attempts sebelum membuat attempt baru Policy ini sudah runtime-enforced
Objective grading attempt.py melakukan auto-score objective; mcq_multi memiliki partial credit Sudah lebih baik dari sekadar exact match untuk multi-select
Manual grading/rubric hook BE menyimpan rubric_data; FE grading workspace membaca rubric data Hook ada, tetapi belum rubric management lengkap
Analytics dasar BE menghitung difficulty index dan discrimination index; FE menampilkan item analysis Useful untuk review kualitas soal
Integrity event logging FE runner dan BE runner_integrity_api.py mencatat tab/window/fullscreen/copy/paste/multi_login sebagai event Saat ini sifatnya logging/flagging, belum blocking penuh
Admission context SPMB CBT route dan bridge admission sudah tersedia Sinkronisasi FE-BE admission sudah direkon di dokumen pendamping

2.2 Bukti file utama

Area File
FE settings policy src/views/AdminViews/CBT/CBTSettings.vue
FE question authoring src/views/ExamManagement/Faculty/QuestionBank/CBTQuestionForm.vue
FE import wizard src/views/ExamManagement/Faculty/QuestionBank/CBTQuestionSetDetail.vue
FE public CBT routes src/router/sharedExperienceRoutes.js
FE SPMB routes src/router/spmbRoutes.js
BE question model /Users/salfath/scola-odoo-module/scola_cbt/models/question.py
BE import API /Users/salfath/scola-odoo-module/scola_cbt/controllers/question_api.py
BE policy model /Users/salfath/scola-odoo-module/scola_cbt/models/policy.py
BE runner start /Users/salfath/scola-odoo-module/scola_cbt/controllers/runner_start_api.py
BE runner state/answer/sync/submit /Users/salfath/scola-odoo-module/scola_cbt/controllers/runner_attempt_api.py
BE integrity API /Users/salfath/scola-odoo-module/scola_cbt/controllers/runner_integrity_api.py
BE scoring /Users/salfath/scola-odoo-module/scola_cbt/models/attempt.py
BE item analysis /Users/salfath/scola-odoo-module/scola_cbt/models/exam.py

3. Gap Analysis

Severity:

  • P0: harus dibenahi sebelum high-stakes exam.
  • P1: penting untuk menjaga trust, fairness, atau security.
  • P2: meningkatkan kualitas assessment dan interoperability.
  • P3: improvement strategis/lanjutan.

3.1 Runtime policy tidak sepenuhnya enforce di backend

Dimensi Best practice Implementasi sekarang Severity Gap
Policy enforcement Policy yang ditampilkan admin harus menjadi kontrol runtime server-side FE settings menampilkan grace_period_minutes, block_multi_login, show_score_immediately, allow_negative_marking, negative_mark_percentage, fullscreen_required; BE policy menyimpan dan serialize field-field itu P0/P1 Sebagian policy belum terlihat dipakai sebagai keputusan runtime. max_attempts dan timeout sudah enforced, tetapi negative marking, grace period, block multi-login, dan show score masih perlu ditautkan ke scoring/runner/result

Detail:

  • CBTSettings.vue menyimpan field policy lengkap.
  • policy.py menyimpan field policy dan override exam.
  • runner_attempt_api.py memakai timeout check, tetapi belum terlihat penggunaan grace_period_minutes atau auto_submit_on_timeout sebagai toggle.
  • attempt.py scoring tidak membaca allow_negative_marking atau negative_mark_percentage.
  • runner_integrity_api.py menerima event multi_login, tetapi hanya membuat flag.
  • runner_attempt_api.py mengembalikan hasil berdasarkan attempt.exam_id.cbt_show_result, bukan payload policy show_score_immediately.

Rekomendasi:

  • Jadikan policy payload sebagai source of truth runtime, bukan hanya UI/admin metadata.
  • Buat helper backend seperti exam.get_effective_cbt_policy() atau gunakan scola.cbt.policy.build_policy_payload(policy, exam) secara konsisten di runner/scoring/result.
  • Tambahkan tests untuk setiap field policy yang punya efek user-facing.

3.2 Interoperability belum QTI, masih CSV lokal

Dimensi Best practice Implementasi sekarang Severity Gap
Item/test portability QTI dipakai untuk pertukaran soal, assessment test, choices, response processing, dan metadata antar LMS/assessment platform BE import hanya CSV; FE import wizard menyebut kolom lokal P2 Belum ada import/export QTI. Migrasi bank soal antar sistem akan manual dan rawan kehilangan metadata

Detail:

  • question_api.py import route mendecode base64 CSV UTF-8 dan membaca csv.DictReader.
  • Tidak ditemukan implementasi aktif QTI di src atau scola_cbt.
  • README domain lama menyebut QTI sebagai kondisi ideal, tetapi status aktif belum ada.

Rekomendasi:

  • Mulai dari QTI subset realistis: mcq, mcq_multi, true_false, short_answer, essay, choices, points, feedback/explanation.
  • Buat adapter internal: QuestionItem <-> AssessmentItem.
  • Tambahkan export QTI dulu sebelum import penuh agar format internal tervalidasi.

3.3 CSV import mcq_multi tidak mendukung multi correct answer

Dimensi Best practice Implementasi sekarang Severity Gap
Multi-select fidelity Format import harus mewakili kemampuan authoring dan scoring FE form mendukung banyak choice benar; BE import validasi correct_answer hanya satu dari A-E untuk mcq_multi P1 Soal multi-select yang dibuat via import berubah menjadi single-correct secara praktis

Detail:

  • question_api.py menerima mcq_multi, tetapi correct_answer divalidasi satu huruf A-E.
  • Saat membuat choice, is_correct diisi letter == correct, sehingga hanya satu jawaban benar.
  • attempt.py sudah bisa scoring multi-select partial credit, jadi gap ada di import contract, bukan scoring core.

Rekomendasi:

  • Dukung format correct_answer berisi A,C,D atau A|C|D untuk mcq_multi.
  • Validasi duplikasi, unknown choice, dan empty choice.
  • FE template import harus membedakan mcq single answer dan mcq_multi multi answer.

3.4 Blueprint assessment dan curriculum metadata belum aktif

Dimensi Best practice Implementasi sekarang Severity Gap
Assessment design quality Bank soal idealnya punya objective/competency/topic/grade/cognitive level dan blueprint coverage agar ujian balanced BE question item hanya punya subject inherited, tags, difficulty; FE type lama punya blueprintId, tetapi active flow tidak memakai blueprint P2 Ujian belum bisa divalidasi terhadap kompetensi, CP/TP, level kognitif, atau target coverage

Detail:

  • question.py tidak punya field aktif untuk learning objective, competency, grade/phase, cognitive level, atau blueprint.
  • docs backend menyatakan blueprint pernah diganti/tidak dipakai.
  • Scola punya domain learning outcomes/report-card, tetapi CBT question bank belum terhubung ke metadata itu.

Rekomendasi:

  • Tambahkan metadata minimal: learning_objective_id, learning_outcome_id atau mapping CP/TP, cognitive_level, grade_level, topic.
  • Buat optional exam blueprint: target jumlah/points per difficulty, topic, objective, question type.
  • Saat publish exam, validasi coverage dan tampilkan warning, bukan hard block pada fase awal.

3.5 Accessibility dan accommodation belum menjadi model runtime

Dimensi Best practice Implementasi sekarang Severity Gap
Accessibility UI dan konten assessment harus memenuhi WCAG: keyboard, focus, contrast, non-text alternatives, timing controls, input assistance Runner punya UI dasar, timer, media preview, dan HTML content; belum terlihat metadata alt/caption/transcript atau audit WCAG khusus runner P1 Risiko peserta berkebutuhan akses khusus tidak mendapat pengalaman setara
Accommodation Time extension/accommodation harus dapat ditetapkan per peserta/attempt dan tercatat Proctor bisa extend time, tetapi belum ada model accommodation preconfigured per peserta P1 Extra time bersifat operasional saat ujian, belum policy formal

Detail:

  • question.asset menyimpan name, asset_type, binary/url, tetapi tidak ada alt text, caption, transcript, language, atau accessibility note.
  • Runner menyembunyikan input native (class="hidden") pada radio/checkbox dan memakai label visual; perlu audit keyboard/focus/screen-reader secara khusus.
  • Timing hanya berbasis remaining seconds; belum ada per-user accommodation duration di start attempt.

Rekomendasi:

  • Tambahkan metadata asset: alt_text, caption, transcript, language, decorative.
  • Tambahkan scola.cbt.participant.accommodation atau field pada participant: extra_time_minutes, requires_screen_reader_mode, needs_manual_proctor_note.
  • Runner harus punya smoke/a11y checks untuk keyboard-only answer, focus-visible, aria labels, dan time warning.

3.6 Upload media soal belum mengikuti hardening OWASP

Dimensi Best practice Implementasi sekarang Severity Gap
File upload security Server harus enforce allowlist extension/MIME, signature validation, size limit, safe filename, storage control, malware risk handling FE hanya validasi name/source; BE asset model hanya memastikan ada file atau URL P1 Attachment soal menjadi attack surface jika file arbitrary/base64 diterima tanpa validasi server-side

Detail:

  • CBTQuestionForm.vue mengirim file_content, file_name, atau URL.
  • question.asset hanya punya binary attachment, filename, URL, dan constraint "file or URL required".
  • Tidak terlihat allowlist per asset_type, max size, MIME sniffing, file signature check, remote URL policy, atau AV/CDR hook di CBT asset model/controller.

Rekomendasi:

  • Tambahkan allowlist per tipe: image/audio/video/document dengan extension dan MIME resmi.
  • Validasi magic number/signature untuk file umum.
  • Terapkan size limit server-side.
  • Normalisasi filename dan blokir path traversal/control chars.
  • Untuk URL, allow http/https, optional domain allowlist, dan jangan auto-fetch tanpa SSRF guard.

3.7 Proctoring masih best-effort browser JS, belum high-stakes lockdown

Dimensi Best practice Implementasi sekarang Severity Gap
Lockdown exam Untuk high-stakes exam, JS fullscreen/tab detection hanya sinyal, bukan lockdown; SEB atau mekanisme secure browser diperlukan README domain menandai SEB sebagai gap; runner punya fullscreen/tab/window/copy/paste event logging P1/P2 Integrity cukup untuk school-level monitoring, tetapi belum cukup untuk exam high-stakes tanpa proctoring tambahan
Multi-login Session conflict harus diblokir server-side jika policy aktif multi_login adalah event type di integrity API P1 Event bisa dicatat, tetapi belum ada session lock yang mencegah pengerjaan paralel

Rekomendasi:

  • Tambahkan server-side attempt session lock: active_session_id, last_heartbeat_at, device_hash, ip, user_agent.
  • Terapkan block_multi_login: sesi baru menolak atau mengakhiri sesi lama sesuai policy.
  • Buat SEB integration optional: config key, permitted URL, launch link, SEB user-agent/config key verification.
  • Tetap pertahankan JS flags sebagai telemetry, bukan sebagai satu-satunya enforcement.

3.8 Event/audit schema belum distandardisasi untuk analytics lintas sistem

Dimensi Best practice Implementasi sekarang Severity Gap
Event analytics Assessment telemetry sebaiknya konsisten, structured, queryable, dan bisa diekspor/interoperable BE audit log dan integrity flags sudah ada; Caliper belum dipakai P2 Event names dan payload belum menjadi canonical event schema lintas FE-BE/reporting

Detail:

  • runner_attempt_api.py sudah membuat audit event untuk timeout autosubmit.
  • runner_integrity_api.py menyimpan event_type, timestamp, dan JSON data.
  • Belum ada schema version, actor/session metadata standar, retention policy, atau export mapping.

Rekomendasi:

  • Definisikan CBT_EVENT_SCHEMA_V1 untuk runner, proctor, grading, publish, policy changes.
  • Setiap event wajib punya event_code, actor_type, actor_id, exam_id, attempt_id, participant_id, timestamp UTC, source, payload schema.
  • Jika interoperability analytics dibutuhkan, buat mapper ke Caliper sebagai fase lanjutan.

3.9 Item analytics belum matang untuk decision-grade psychometrics

Dimensi Best practice Implementasi sekarang Severity Gap
Psychometric review Item analysis perlu minimum sample, distractor analysis, version-aware trend, reliability, dan workflow revise/retain/retire BE menghitung difficulty/discrimination; FE memberi label dan rekomendasi P2 Berguna sebagai insight awal, tetapi belum cukup untuk keputusan bank soal jangka panjang

Detail:

  • exam.py menggunakan upper/lower 27 percent dan difficulty index.
  • Tidak terlihat minimum sample threshold sebelum menilai kualitas soal.
  • Tidak ada distractor analysis per opsi.
  • Tidak ada item lifecycle status seperti approved, needs_revision, retired.

Rekomendasi:

  • Tambahkan threshold: contoh "insufficient data" jika attempts < N.
  • Tambahkan distractor analysis: pilihan mana yang dipilih oleh upper/lower group.
  • Simpan stats per question version, bukan hanya current item.
  • Tambahkan workflow review bank soal setelah exam.

3.10 Rubric masih data hook, belum rubric authoring lifecycle

Dimensi Best practice Implementasi sekarang Severity Gap
Essay/rubric grading Rubric harus bisa dibuat, versioned, dipakai lintas soal, dan menghasilkan audit grading yang konsisten CBT sekarang punya rubric builder, rubric template reusable dengan version history, snapshot rubric pada question/answer, breakdown auto-grade per criterion, dan audit override manual yang konsisten P2 Gap implementasi utama sudah tertutup; yang tersisa tinggal verifikasi operasional/QC lintas flow

Rekomendasi:

  • Pertahankan template rubric sebagai reusable source of truth dan gunakan snapshot pada question/attempt untuk menjaga auditability.
  • Verifikasi end-to-end bahwa publish → attempt → grading tetap konsisten saat template rubric berubah versinya setelah soal dipakai.

3.11 Route gating FE masih punya inkonsistensi

Dimensi Best practice Implementasi sekarang Severity Gap
Feature flag consistency Semua entry point modul CBT harus gated dengan feature flag yang tepat; non-CBT SPMB tidak boleh tergantung CBT Public CBT routes /cbt/public dan /cbt/public/runner/:exam_id tidak punya featureFlag; route detail SPMB parent punya featureFlag: "scola_cbt" P1 Tenant tanpa CBT bisa melihat public CBT entry; sebaliknya pendaftar SPMB bisa terganggu akses detail admission non-CBT jika CBT off

Rekomendasi:

  • Tambahkan featureFlag: "scola_cbt" ke public CBT routes atau enforce di component route guard setara.
  • Pindahkan featureFlag: "scola_cbt" dari parent /spmb/admission/:id ke child/CTA CBT saja.
  • Tambahkan route metadata tests untuk public CBT dan SPMB admission.

3.12 Privacy dan retention belum eksplisit di domain CBT

Dimensi Best practice Implementasi sekarang Severity Gap
Privacy/security logging Log harus cukup untuk audit, tetapi tidak menyimpan rahasia/PII berlebih; retention harus jelas Audit/integrity log ada; kebijakan retention/privacy belum tertulis di domain CBT P2 Data CBT berisi jawaban, nilai, event integrity, dan calon siswa; perlu aturan akses/retensi

Rekomendasi:

  • Dokumentasikan retention untuk attempts, answers, proctor logs, exports.
  • Audit export hasil dan akses report.
  • Masking/minimization untuk payload event integrity.
  • Tambahkan admin-only controls untuk export/delete sesuai kebijakan sekolah/tenant.

4. Prioritas Gap

Prioritas Gap Alasan
P0/P1 Runtime policy enforcement UI admin memberi ekspektasi kebijakan, jadi backend harus benar-benar menjalankan kebijakan itu
P1 Upload media hardening Attachment soal adalah permukaan risiko langsung
P1 Route gating CBT/SPMB Dampak akses fitur per tenant dan pengalaman pendaftar
P1 Accessibility/accommodation dasar Berdampak fairness dan kesiapan ujian untuk peserta berkebutuhan akses
P1/P2 Proctoring/session lock Penting untuk high-stakes dan multi-login
P2 mcq_multi import Data correctness bank soal
P2 Blueprint/curriculum metadata Kualitas desain assessment dan coverage
P2 Event schema + analytics maturity Kualitas audit/reporting jangka panjang
P2 Rubric lifecycle Kualitas grading essay
P3 QTI/Caliper full interoperability Strategis, tetapi bisa bertahap setelah core runtime kuat

5. Implementation Plan

Phase 0 - Lock acceptance criteria dan regression harness

Tujuan:

  • Menjaga perubahan berikutnya tidak memecah kontrak FE-BE CBT.
  • Menjadikan gap sebagai backlog yang testable.

FE:

  • Tambahkan/rapikan route metadata tests untuk:
  • public CBT routes punya gating CBT,
  • SPMB admission parent tidak over-gated oleh CBT,
  • CBT child route tetap gated.
  • Tambahkan contract fixture untuk policy payload FE.

BE:

  • Tambahkan unit tests baseline untuk:
  • effective policy payload,
  • runner timeout existing behavior,
  • scoring existing behavior,
  • import CSV existing behavior.

Acceptance:

  • Test baseline lulus sebelum perubahan behavior.
  • Dokumen ini dan recon FE-BE tetap menjadi SSOT backlog.

Phase 1 - Enforce CBT policy runtime

Tujuan:

  • Semua setting admin yang user-facing memiliki efek runtime atau disembunyikan sampai implementasi siap.

BE:

  • Buat helper get_effective_policy(exam) di model/policy service.
  • Runner:
  • grace_period_minutes ikut menghitung deadline server-side.
  • auto_submit_on_timeout=false tidak langsung auto-submit, tetapi memblokir save/submit sesuai keputusan product.
  • fullscreen_required masuk response policy dan integrity threshold.
  • Scoring:
  • allow_negative_marking dan negative_mark_percentage diterapkan pada objective wrong answers sesuai policy.
  • Result:
  • show_score_immediately diselaraskan dengan cbt_show_result atau ditetapkan precedence-nya.
  • Session:
  • block_multi_login mulai dari deny second active session.

FE:

  • Settings UI menampilkan helper text "runtime enforced" hanya setelah backend support.
  • Runner menampilkan policy effective dari backend, bukan asumsi lokal.

Tests:

  • BE unit tests untuk negative marking, grace period, show score, multi-login.
  • FE contract tests untuk policy mapping.

Phase 2 - Secure question media upload

Tujuan:

  • Attachment soal aman secara server-side dan punya metadata accessibility minimum.

BE:

  • Validasi upload di controller/model:
  • extension allowlist,
  • MIME allowlist,
  • file signature untuk format umum,
  • max size per asset type,
  • normalized filename.
  • URL asset:
  • validate scheme,
  • optional domain allowlist,
  • no server-side fetch tanpa SSRF guard.
  • Tambahkan fields:
  • alt_text,
  • caption,
  • transcript,
  • language,
  • decorative.

FE:

  • Question authoring form meminta alt text untuk image non-decorative.
  • Audio/video/document punya caption/transcript hint.
  • Import/export asset metadata tidak memecah existing question payload.

Tests:

  • BE reject executable disguised upload.
  • BE reject oversize.
  • FE validation tidak menjadi satu-satunya enforcement.

Phase 3 - Fix import fidelity dan siapkan QTI subset

Tujuan:

  • Import lokal tidak merusak semantics soal.
  • Interoperability mulai masuk tanpa mengubah core authoring.

BE:

  • CSV mcq_multi mendukung A,C atau A|C.
  • Tambahkan import report yang membedakan warning vs error.
  • Buat serializer internal untuk question item.
  • Implement export QTI subset untuk objective/essay basic.
  • Import QTI subset setelah export stabil.

FE:

  • Update template import dengan contoh mcq_multi.
  • Tambahkan opsi export QTI di question set detail jika backend siap.

Tests:

  • Multi-correct import menghasilkan beberapa is_correct=True.
  • Export lalu import QTI mempertahankan type, choices, points, explanation.

Phase 4 - Curriculum metadata dan blueprint

Tujuan:

  • Bank soal bisa dipakai untuk ujian yang coverage-nya terukur.

BE:

  • Tambahkan metadata question:
  • learning objective / CP-TP relation,
  • cognitive level,
  • grade/phase,
  • topic.
  • Tambahkan optional blueprint model:
  • target per objective,
  • target per difficulty,
  • target per type,
  • total points/questions.
  • Exam publish warning jika coverage tidak memenuhi blueprint.

FE:

  • Authoring form metadata dibuat progressive disclosure.
  • Exam creation menampilkan coverage matrix dan warning.

Tests:

  • Publish exam with insufficient coverage returns warning payload.
  • Existing exam tanpa blueprint tetap berjalan.

Phase 5 - Accessibility dan accommodation runtime

Tujuan:

  • Runner dan content soal siap untuk peserta dengan kebutuhan akses.

BE:

  • Tambahkan accommodation per participant/attempt:
  • extra time,
  • reduced motion/readability flags,
  • manual proctor note.
  • Deadline attempt menghitung accommodation + grace period.
  • Audit setiap accommodation yang dipakai.

FE:

  • Runner keyboard-only path diuji.
  • Focus visible dan ARIA label pada question navigator/options.
  • Media preview memakai alt/caption/transcript.
  • Time warning tidak hanya bergantung pada warna.

Tests:

  • A11y smoke untuk runner.
  • Accommodation extra time ter-reflect di remaining_seconds.

Phase 6 - Proctoring hardening dan optional SEB

Tujuan:

  • School-level proctoring tetap ringan, high-stakes exam punya opsi lockdown lebih kuat.

BE:

  • Attempt session lock:
  • session id,
  • device hash,
  • IP/user-agent,
  • heartbeat,
  • stale timeout.
  • Enforce block_multi_login.
  • SEB optional fields:
  • seb_required,
  • seb_config_key,
  • seb_allowed_browser_exam_key.

FE:

  • Runner mengirim heartbeat.
  • Jika SEB required, tampilkan launch instruction/link sebelum start.
  • Proctor dashboard menampilkan session conflict.

Tests:

  • Second active session ditolak saat block_multi_login=true.
  • Stale session bisa direcover sesuai policy.

Phase 7 - Analytics maturity

Tujuan:

  • Item analysis menjadi alat review bank soal, bukan hanya dashboard pasca ujian.

BE:

  • Minimum sample threshold.
  • Distractor analysis per choice.
  • Version-aware stats.
  • Item lifecycle: approved, needs_revision, retired.

FE:

  • Item analysis menampilkan "insufficient data" jika sample kecil.
  • Tambahkan action "mark for revision" ke bank soal.

Tests:

  • Small sample tidak menghasilkan rekomendasi final.
  • Stats terpisah per version.

Phase 8 - Event schema, privacy, retention

Tujuan:

  • Audit CBT konsisten, aman, dan siap diekspor.

BE:

  • Definisikan CBT_EVENT_SCHEMA_V1.
  • Terapkan event_code dan schema version di runner/proctor/grading/policy/report export.
  • Enforce retention per tenant via policy aktif + cleanup job terjadwal.

FE:

  • Event client memakai canonical event names.
  • Admin audit log bisa filter event code, actor, exam, attempt.

Tests:

  • Event schema contract tests.
  • Audit export tidak membocorkan token/public secret.

6. Suggested Work Order

Urutan praktis:

  1. Fix route gating dan mcq_multi import karena scope kecil dan risikonya jelas.
  2. Enforce policy runtime karena menyentuh trust admin dan peserta.
  3. Harden upload media sebelum memperluas asset/QTI.
  4. Tambahkan accommodation/accessibility metadata dasar.
  5. Bangun session lock dan optional SEB untuk high-stakes.
  6. Baru lanjut QTI/Caliper/blueprint penuh.

7. QC Gates

Frontend:

  • npm run lint
  • npm run type-check
  • Targeted Vitest untuk route/menu/contract CBT.
  • E2E smoke runner jika route auth, runner flow, atau session behavior berubah.

Backend:

  • Unit tests scola_cbt/tests untuk policy, import, scoring, runner.
  • Module upgrade test di database dev.
  • Manual smoke:
  • create question set,
  • import CSV,
  • create exam,
  • start runner,
  • autosave,
  • submit,
  • grade,
  • analytics/report.

Docs-only verification untuk dokumen ini:

  • git diff --check
  • scan trailing whitespace pada docs/domains/cbt/*.md

Verification 2026-05-28 di server /home/scola/odoo:

  • Backend full CBT unit discover: python3 -m unittest discover /home/scola/odoo/custom_addons_scola/gcgscola/scola_cbt/tests -> 128 tests OK.
  • Frontend targeted CBT/menu Vitest: npx vitest run tests/menu/routerFeatureFlagGuard.spec.js tests/menu/spmbRoutesContract.spec.js tests/unit/services/cbtRunnerService.spec.js tests/unit/cbtRunnerAccessibilityContract.spec.js tests/unit/services/questionService.spec.js tests/unit/services/cbtExam.service.spec.js --reporter=verbose -> 72 tests OK.
  • Module upgrade dev: /home/scola/odoo/odoo17-venv/bin/python3 /home/scola/odoo/odoo-bin -c /home/scola/odoo/odoo-devscola.conf -d scoladev -u scola_cbt --stop-after-init --without-demo=all -> exit 0.
  • Health check dev endpoints observed passing on active Odoo ports including 127.0.0.1:8074/web/health.
  • Manual QA/sign-off procedure: cbt-qa-runbook-2026-05-28.md.

8. Product Decisions Closed

Keputusan runtime yang sudah dipakai implementasi aktif:

  • show_score_immediately pada effective policy menjadi gate payload hasil setelah submit; jika policy tidak menyediakan nilai, fallback tetap exam.cbt_show_result.
  • Jika auto_submit_on_timeout=false, backend menolak save/sync/submit saat timeout tanpa auto-submit; runner FE menampilkan status timeout dan meminta tindak lanjut pengawas.
  • Negative marking untuk mcq_multi memakai persentase policy yang sama, diterapkan per wrong selected option setelah partial credit correct selections.
  • SEB adalah toggle per exam melalui cbt_seb_required dan header key optional (cbt_seb_config_key_hash / cbt_seb_browser_exam_key).
  • Curriculum metadata CBT memakai model ringan domain CBT (chapter, objective/outcome code, cognitive level, phase code) agar tidak mengunci dependency ke model CP/TP report-card.
  • Retention default tenant: attempts 365 hari, answers 365 hari, integrity flags 180 hari, audit logs 365 hari, export 30 hari.

9. Kesimpulan

Implementasi CBT Scola sudah kuat untuk operasional ujian online sekolah: authoring soal, question set, exam, runner, autosave, scoring, grading, proctor dashboard, integrity logs, analytics, export, dan admission context sudah ada serta cukup sinkron antara FE dan BE.

Gap implementasi kode Phase 1-8 sudah ditutup pada baseline server ini. Sisa pekerjaan sebelum klaim produksi penuh adalah smoke operasional end-to-end dengan data sekolah nyata/seeded dan sign-off alur browser oleh role terkait.