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_minutesikut menghitung attempt deadline.auto_submit_on_timeout=falsemencegah auto-submit otomatis saat save/sync/submit mencapai timeout.allow_negative_markingdannegative_mark_percentagedipakai saat auto-score objective answers.show_score_immediatelydipakai sebagai policy gate untuk payload hasil setelah submit.max_attemptspada runner start membaca effective policy payload.- P1 import fidelity sudah diimplementasikan untuk CSV
mcq_multi:correct_answermenerima beberapa jawaban sepertiA,CatauA|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/:idtidak lagi tergantungscola_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 flagdecorative; - image asset wajib punya alt text kecuali ditandai dekoratif;
- participant memiliki
extra_time_minutes,screen_reader_mode,reduced_motion, danaccommodation_notes; - attempt deadline menambahkan extra time participant dan policy payload mengirim accommodation ke runner.
- Session lock/multi-login hardening:
- runner FE mengirim
client_session_idstabil per tab/session; - backend attempt menyimpan active session, user agent, IP, heartbeat;
- saat policy
block_multi_loginaktif, session berbeda diblokir selama heartbeat belum stale. - Optional Safe Exam Browser integration:
- exam memiliki field
cbt_seb_required,cbt_seb_config_key_hash, dancbt_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¶
- Akhiri dengan QC1/QC2/QC3 supaya status final bisa dinyatakan
verified, bukan hanyaimplemented.
Definisi selesai untuk klaim "100% terimplementasi"¶
Dokumen ini baru bisa dinyatakan 100% terimplementasi jika seluruh kondisi berikut terpenuhi:
- tidak ada lagi item
partialataunot donedi audit matrix; - QC acceptance pada
## 7. QC Gatessudah benar-benar dijalankan, bukan diasumsikan; - keputusan runtime di
## 8. Product Decisions Closedsudah 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.vuemenyimpan field policy lengkap.policy.pymenyimpan field policy dan override exam.runner_attempt_api.pymemakai timeout check, tetapi belum terlihat penggunaangrace_period_minutesatauauto_submit_on_timeoutsebagai toggle.attempt.pyscoring tidak membacaallow_negative_markingataunegative_mark_percentage.runner_integrity_api.pymenerima eventmulti_login, tetapi hanya membuat flag.runner_attempt_api.pymengembalikan hasil berdasarkanattempt.exam_id.cbt_show_result, bukan payload policyshow_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 gunakanscola.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.pyimport route mendecode base64 CSV UTF-8 dan membacacsv.DictReader.- Tidak ditemukan implementasi aktif QTI di
srcatauscola_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.pymenerimamcq_multi, tetapicorrect_answerdivalidasi satu huruf A-E.- Saat membuat choice,
is_correctdiisiletter == correct, sehingga hanya satu jawaban benar. attempt.pysudah bisa scoring multi-select partial credit, jadi gap ada di import contract, bukan scoring core.
Rekomendasi:
- Dukung format
correct_answerberisiA,C,DatauA|C|Duntukmcq_multi. - Validasi duplikasi, unknown choice, dan empty choice.
- FE template import harus membedakan
mcqsingle answer danmcq_multimulti 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.pytidak punya field aktif untuk learning objective, competency, grade/phase, cognitive level, atau blueprint.docsbackend 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_idatau 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.assetmenyimpan 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.accommodationatau 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.vuemengirimfile_content,file_name, atau URL.question.assethanya 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.pysudah membuat audit event untuk timeout autosubmit.runner_integrity_api.pymenyimpanevent_type, timestamp, dan JSON data.- Belum ada schema version, actor/session metadata standar, retention policy, atau export mapping.
Rekomendasi:
- Definisikan
CBT_EVENT_SCHEMA_V1untuk 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.pymenggunakan 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/:idke 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_minutesikut menghitung deadline server-side.auto_submit_on_timeout=falsetidak langsung auto-submit, tetapi memblokir save/submit sesuai keputusan product.fullscreen_requiredmasuk response policy dan integrity threshold.- Scoring:
allow_negative_markingdannegative_mark_percentagediterapkan pada objective wrong answers sesuai policy.- Result:
show_score_immediatelydiselaraskan dengancbt_show_resultatau ditetapkan precedence-nya.- Session:
block_multi_loginmulai 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_multimendukungA,CatauA|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:
- Fix route gating dan
mcq_multiimport karena scope kecil dan risikonya jelas. - Enforce policy runtime karena menyentuh trust admin dan peserta.
- Harden upload media sebelum memperluas asset/QTI.
- Tambahkan accommodation/accessibility metadata dasar.
- Bangun session lock dan optional SEB untuk high-stakes.
- Baru lanjut QTI/Caliper/blueprint penuh.
7. QC Gates¶
Frontend:
npm run lintnpm 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/testsuntuk 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_immediatelypada effective policy menjadi gate payload hasil setelah submit; jika policy tidak menyediakan nilai, fallback tetapexam.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_multimemakai persentase policy yang sama, diterapkan per wrong selected option setelah partial credit correct selections. - SEB adalah toggle per exam melalui
cbt_seb_requireddan 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.