Commit Graph

3 Commits

Author SHA1 Message Date
a2nr 9c2563a2bf feat(docs): docs viewer, API reference generator, markdown rendering
- Add YAML frontmatter (title/order/category) to 13 docs/*.md files
- Add services/docs_service.py: mtime-cache, frontmatter parsing w/ fallback,
  bleach sanitize, path traversal protection
- Add routes/docs.py: GET /api/docs, GET /api/docs/<slug>, GET /api/docs/api-reference
- Register docs_bp in app.py
- Add frontend /docs + /docs/[slug] routes (sidebar nav + markdown render)
- Add frontend/src/types/docs.ts interfaces
- Add link from /help page to /docs viewer
- Add scripts/validate_docs.py: frontmatter + broken link validation
- Add elemes.sh docs-validate command

Endpoints documented in API reference: /quiz-attempts/<lesson>,
/sessions, /bab/<folder>, /compile/sessions, /lesson/<slug>.json + all 30 routes
2026-08-17 11:45:05 +07:00
a2nr 24502380aa feat(quiz): strict focus-loss anti-cheat + audit attempt
Kebijakan strict: kehilangan fokus saat kuis aktif langsung mengakhiri kuis
dengan penalti, satu attempt per kuis tercatat audit, pembahasan disembunyikan
saat focus_lost, badge pelanggaran muncul di laporan guru.

Backend:
- tabel quiz_attempts (migration 0002) + endpoint POST /quiz-attempts/submit
  idempotent dengan unique constraint (satu attempt per token+lesson, 409
  untuk duplikat), bounded termination_reason
- models/repositories/storage: QuizAttempt + record/query pelanggaran untuk
  laporan guru (progress)

Frontend:
- quiz-integrity.ts: policy hub (isFocusLossEvent, terminateQuiz,
  shouldShowQuizReview) + attempt_id via crypto.randomUUID()
- lesson.svelte.ts: finalisasi idempotent; sendBeacon untuk exit path yang
  bisa suspend (focus_lost/page_unload), fetch keepalive untuk reason lain
- QuizTab.svelte: summary menyembunyikan pembahasan saat focus_lost
- progress/+page.svelte: badge pelanggaran focus_lost di laporan guru
- APP_VERSION 26 -> 27

Tests & docs:
- 204 backend test pass (unit host + integrasi container, DB elemes_test)
- 107 frontend test pass, svelte-check 0 error
- docs/12-quiz-integrity.md (baru), docs/07-quiz-authoring.md + README FAQ
  anti-cheat diperbarui
2026-08-11 20:55:39 +07:00
a2nr 02d5969619 refactor(quiz): restructure quiz session, question view, and tab safety
Restructure quiz flow into QuizSession primitive + atomic quiz state in
LessonManager, and extract QuizQuestionView for split-view display.

Tab-safety fix: add lesson-tabs.ts with pickDefaultTab(), getAvailableTabs()
mirroring the exact {#if} conditions in +page.svelte, and ensureActiveTab()
safety-net that falls back to pickDefaultTab() when the desired tab is not
rendered. A reactive $effect in lesson/[slug]/+page.svelte validates
activeTab against lesson data on every change, preventing the "tab quiz
kosong" (empty workspace) regression for quiz-only lessons and phantom-tab
state after data changes.

Files:
- lib/services/lesson-tabs.ts (+test): pure helpers, 18 tests pass
- lesson/[slug]/+page.svelte: ensureActiveTab reactive guard + QuizQuestionView
- lesson/[slug]/lesson.svelte.ts: atomic startQuiz, getExitStatus, idempotent
  submit on navigate/exit
- lib/services/quiz-session.ts (+test), lib/types/quiz.ts, QuizTab.svelte
  (mgr-driven), QuizQuestionView.svelte, lesson.css
- services/lesson_service.py, services/tests/test_lesson_service_quiz.py
  (test_lesson_service_quiz.py), requirements.txt (+pytest)
- docs/07-quiz-authoring.md
- version.ts APP_VERSION 21 -> 22 (forces SW update for the fix)
- examples/content/dasar/quiz_test.md synced to live content root
2026-08-01 00:14:29 +07:00