Commit Graph

271 Commits

Author SHA1 Message Date
a2nr 467b146988 feat: unified lesson progress — composite score & /api/lesson-progress
- composite score: exercise 70% + quiz 30%, done ≥75% (env LESSON_*)
- endpoint /api/lesson-progress menggantikan /track-progress + /quiz-attempts
- state baru 'done'/'in_progress'; deprecated per-lesson min:N% -> global threshold
- progress_status emit composite; teacher report single composite column
- frontend: submitLessonProgress/lessonProgressBeacon/fetchLessonProgress, QuizTab fix, SW url
- migration 0005; test baru: composite, lesson-progress routes, composite flow
2026-08-29 00:22:10 +07:00
a2nr 9087a77096 refactor(markdown): konsolidasi polyfill nodeCompat & hapus dependency dompurify
- CLN-01: Verifikasi dan konsolidasi polyfill worker_threads.markAsUncloneable ke helper nodeCompat.ts
- CLN-01: Dokumentasi mekanisme require-time (node-polyfill.cjs) vs import-time (nodeCompat.ts)
- CLN-02: Hapus dependency dompurify dan @types/dompurify yang tidak terpakai dari package.json
- Verifikasi seluruh test suite (13 test files, 165 tests) tetap 100% lulus
2026-08-28 11:12:39 +07:00
a2nr 2d557df061 fix(markdown): sanitasi DOMPurify, perbaikan parser flashcard & kompatibilitas SSR Node 20
- Mengganti sanitizer manual dengan isomorphic-dompurify dan hook whitelist/blocklist (BF-01 & BF-02)
- Memperbaiki parsing penjelasan flashcard non-MCQ agar mencari blockquote di seluruh body (BF-03)
- Menambahkan node-polyfill.cjs dan konfigurasi NODE_OPTIONS untuk mengatasi incompatibilitas worker_threads.markAsUncloneable pada Node 20 runtime (SSR blank screen fix)
- Menambahkan unit test keamanan embed (BF-04) dan parity tests dengan fixture backend (BF-05)
- Mendokumentasikan deduplikasi quiz tab pada detectActiveTabs (BF-06)
2026-08-28 05:24:44 +07:00
a2nr bb04245d85 feat: migrate markdown preview rendering to client-side SvelteKit 2026-08-26 19:32:28 +07:00
a2nr db4d15ba50 fix(quiz): render LaTeX/KaTeX pada opsi, pembahasan, & preview guru
- QuizTab: ganti use:renderMath (jalan sekali pas mount) dengan $effect
  yang jalan ulang autoRenderMath tiap konten kuis berubah — cover opsi
  MCQ aktif, review live, dan review hasil-load async (setelah refresh).
- QuizPreviewReadonly (content editor guru): tambah $effect autoRenderMath
  agar LaTeX di soal/opsi/penjelasan ke-render di pratinjau kunci jawaban.

autoRenderMath idempoten sehingga aman dijalankan berulang tanpa dobel render.
2026-08-23 13:15:54 +07:00
a2nr f78eaaca11 fix: regresi hapus folder tidak kosong, tambah test contentEditor
- Perbaiki pemanggilan deleteEntry di +page.svelte baris 531: argumen
  force=true tidak lagi diteruskan dengan benar setelah signature
  fungsi berubah (confirmCritical ditambah di tengah)

- Koreksi komentar dengan karakter Mandarin di content_editor.py baris 488

- Tambah test unit contentEditor.test.ts dengan 5 kasus:
  - deleteEntry force delete
  - deleteEntry confirm_critical untuk file kritis
  - deleteEntry default parameter
  - renameEntry standar
  - renameEntry confirm_critical

Fixes: hapus folder dengan isi tidak lagi gagal 409.
All tests: 119 passed.
2026-08-23 10:43:18 +07:00
a2nr 1659063784 fix(playground): view tab Arduino/Flowchart/Circuit mengikuti ruang kosong & tambah link Playground di menu burger
- playground +page: jadikan main.container flex-column + .playground-page flex:1
  agar memenuhi ruang sisa setelah navbar (sebelumnya height:100% resolve ke
  tinggi intrinsik karena parent display:block)
- pg-content: tambah flex-direction:column supaya flex:1 grow tinggi bukan lebar
- override :global .flowchart-container & .circuit-wrapper jadi height:100%;flex:1;
  min-height:0 (hilangkan min-height:400px / height:550px fix) agar melar
- Navbar: tambah link Playground di dropdown burger tepat di bawah Tema Gelap
- terverifikasi Playwright desktop(1280x800) & mobile(390x780): semua tab 98-100%
2026-08-23 09:27:11 +07:00
anggoro ffceb519be feat(content-editor): konfirmasi ganda file navigasi kritis & hapus narrow sidebar
- Tambah PROTECTED_BASENAMES (home.md, sub-home.md) dengan konfirmasi
  kedua saat rename/delete agar tidak merusak navigasi siswa (tidak
  bisa di-undo). Diteruskan ke renameEntry/deleteEntry di contentEditor.ts.
- Hapus fitur featureSidebarNarrow + CSS terkait (tidak dipakai).
- Footer & backend: penyesuaian rute/test content editor.
2026-08-23 08:18:02 +07:00
anggoro a1ccef2d71 feat(content-editor): tambah template Exp Wiring & buat iframe Velxio mengisi area
- Tambah FEATURE_TEMPLATES 'expected-wiring' (grup Penilaian) untuk
  menyisipkan blok ---EXPECTED_WIRING--- yang dipakai velxio-evaluator
  grading wiring (sudah diekstrak backend lesson_service.py).
- Perbaiki iframe Velxio tab Arduino tidak dinamis: tambah height:100%
  pada .velxio-tab-content agar mengisi tinggi area kosong di desktop & mobile.
2026-08-23 08:17:42 +07:00
a2nr c90a8787f7 feat(teacher-nav): tambah Edit Content & Progress di navbar, pindah route /progress -> /teacher/progress, perbaiki toolbar editor
- Navbar: item 'Edit Content' (/teacher/content) & 'Progress' (/teacher/progress)
  muncul hanya saat akun guru login, ditaruh di atas divider login/logout
- Pindahkan route /progress -> /teacher/progress (git mv) agar konsisten dg /teacher/content
- Hapus link Progress di Footer (sudah ada di navbar)
- Editor content: tombol Fitur (toggle sidebar) dipindah ke header samping Simpan/Publish,
  Simpan/Publish diubah jadi icon, hapus tombol panah floating di tepi & di header sidebar,
  tombol dock/undock & minimize dipindah ke pojok kanan (mode desktop)
- Bump APP_VERSION 28 -> 29
2026-08-22 21:30:06 +07:00
a2nr f7fa1c70c2 fix(content-editor): bersihkan tab saat pindah asset & perbaiki upload gagal 500
- Reset previewActiveTabs/previewSlides saat pindah ke asset & saat hapus
  file aktif, agar tab dinamis (C/Python/Circuit/Arduino/Flowchart) tidak
  menetap setelah berpindah konteks.
- Ganti Pillow Image.verify() dengan Image.load() di validasi upload asset.
  verify() false-positive CRC pada chunk IDAT PNG valid -> backend 500.
  load() cukup membuktikan file adalah gambar yang bisa di-decode.
2026-08-22 09:39:46 +07:00
a2nr daa813f511 feat(content-editor): remove Preview tab, load Circuit/Velxio/Flowchart components
- Remove Preview tab (preview already shown in left content panel)
- Circuit tab loads actual CircuitEditor component with extracted initial_circuit
- Velxio tab loads velxio iframe with embed mode
- Flowchart tab loads flowchart iframe
- C/Python tabs remain as read-only CodeEditor with extracted code
2026-08-21 23:46:15 +07:00
a2nr fbc8a3fb03 feat(content-editor): dynamic tabs for C/Python/circuit preview
Add dynamic chrome tabs based on previewActiveTabs from markdown parsing.
When teacher writes ---INITIAL_CODE--- or ---INITIAL_PYTHON--- blocks,
the corresponding C/Python tab appears with read-only code preview.

- Widen activeTab type to string for dynamic tab IDs
- Extract code blocks client-side from raw markdown body
- Render chrome tabs dynamically from allTabs derived state
- Auto-switch away from invalid tabs when preview updates
2026-08-21 23:27:37 +07:00
a2nr 0d299055b0 fix(content-editor): reuse WorkspaceHeader icons & CSS, make editor fill parent
- Replace inline SVGs with Unicode icons from WorkspaceHeader (⊞ ▽ △ ◀)
- Use shared .panel-btn / .panel-actions / .btn-float-toggle CSS classes
- Match .resize-handle and .panel-header styling from lesson page
- Make CodeEditor dynamically fill workspace at any height (flex + height:100%)
- Override .cm-editor max-height in content-editor to remove fixed 60vh cap
2026-08-21 22:26:36 +07:00
a2nr b75eb06346 feat(content-editor): dockable/floating workspace, mobile view modes, asset preview
- Floating/dockable editor panel with drag & resize handles
- Mobile view modes: hidden → 50% → 100% toggle cycle
- Mobile tree-first: show file tree when no file selected, back button to return
- Asset file preview with image display and copy-path button
- Touch support for drag and resize on mobile
- Fix missing closing div in asset preview section
2026-08-21 19:03:53 +07:00
a2nr 084eb71a71 feat(content-editor): tambah editor konten guru dengan draft & publish
Backend:
- Model ContentDraft + migration 0004_content_drafts
- CRUD draft: save, reload, preview, publish, discard
- Tree ops: create file/folder, rename, delete dengan draft cleanup
- Refactor _render_markdown_string() agar bisa render dari buffer
- Refactor teacher_auth ke modul shared (teacher_auth.py)
- Blueprint routes/content_editor.py (17 endpoint)
- Permission error handling di semua write operations
- Tambah Pillow ke requirements.txt
- Mount content/ & assets/ dari :ro ke :rw

Frontend:
- Page /teacher/content dengan panel tree + editor + preview
- ContentFileTree, LessonContentView, QuizPreviewReadonly components
- contentEditor.ts service layer & contentEditor.svelte.ts state manager
- CodeEditor support @codemirror/lang-markdown + sync code prop
- Tambah @codemirror/lang-markdown dependency
2026-08-21 15:55:21 +07:00
a2nr ac10692b61 feat(prereq): dukung ambang minimum (min: N%) pada prasyarat materi
Tambahkan logika ambang minimum skor (opsional) di daftar prasyarat.
Tanpa ambang, status scored berapa pun (termasuk 0/x) memenuhi syarat
(backward compatible). Dengan ambang `min: N%`, earned/total harus
melebihi ambang untuk membuka kunci materi berikutnya.

Perubahan:
- Parser bullet prasyarat mendukung suffix `min: N%` (contoh: min: 75%)
- is_prerequisite_met: completed → selalu terpenuhi; scored → terpenuhi
  kecuali di bawah ambang; not_started → belum terpenuhi
- routes/lessons.py: 3 titik kunci sekarang pakai get_missing_prerequisites
- latex_test.md: tambahkan prereq quiz_test min: 75% (demo nyata)
- examples/content disinkronkan dengan content
- Tambah test_prerequisite_logic.py (28 unit test) + 3 integration test
2026-08-17 21:57:10 +07:00
a2nr 16031fa728 fix(docs/api): hilangkan sync berulang di api_reference + UI API Reference di /docs
- routes/docs.py: pakai current_app, bukan create_app() per request — tidak
  lagi memicu DB sync ulang di setiap hit /docs/api-reference (dead code
  route_modules/rule_map dihapus)
- frontend: entry statis API Reference di sidebar /docs, fetch lazy
  /api/docs/api-reference, render method badge + auth + docstring
- test: 4 test yatim di test_teacher_bootstrap diberi marker unit;
  Makefile test-stats kini menampilkan count per marker + orphan (harus 0)
- docs_service: hapus dead code _read_md_cached, sederhanakan cache-check
  _parse_frontmatter (satu getmtime, kondisi jelas)
- lesson_service: gabung pemanggilan bleach.clean dobel jadi satu dengan
  css_sanitizer opsional — hilangkan NoCssSanitizerWarning (7x)
- conftest: fixture autouse _isolate_database lewati isolasi untuk test unit
  supaya make test-unit tetap jalan tanpa DB walau DATABASE_URL diset

Verifikasi: unit 114 passed, full suite 239 passed (0 warnings) dengan
Postgres test, svelte-check 0 error, vitest 114 passed, docs-validate ok.
2026-08-17 16:37:30 +07:00
a2nr 429b23e9b8 fix(docs): frontend load must fetch /api/docs (not /docs) for SSR proxy
- hooks.server.ts only proxies /api/* to Flask (strips /api prefix)
- load() fetching /docs (no /api) caused SSR recursion/500
- Revert to /api/docs so proxy reaches Flask /docs route correctly
- selectDoc client fetch already uses /api/docs (correct)
2026-08-17 13:05:59 +07:00
a2nr d243df898a fix(docs): correct API route prefix — strip /api to match Flask proxy convention
- Flask docs routes changed from /api/docs to /docs (no /api prefix)
  because hooks.server.ts proxies /api/* by stripping /api, so /api/docs
  reached Flask as /docs (404). Other routes (lessons, help) also lack /api.
- Frontend load functions now fetch /docs and /docs/<slug> (not /api/docs)
- Fixes 500 on /docs SSR (proxy ECONNREFUSED / 404 from stripped route)
2026-08-17 12:40:48 +07:00
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 a5aedf66d4 refactor(test): unified test runner, markers, elemes.sh cleanup
- Add pytest.ini with unit/integration/e2e markers + --strict-markers
- Add Makefile as centralized test runner entrypoint
- Add @pytest.mark.integration to 7 DB-dependent test files
- Add @pytest.mark.unit to 6 pure-logic test files
- Refactor elemes.sh: test-* commands delegate to 'python -m pytest -m <marker>'
- Move test_elemes_sh.sh -> scripts/ (path-adjusted), add test-shell Makefile target
- Add test-worker target for compiler_worker/tests (separate PYTHONPATH)
- Update runclearbuild smoke gate to use -m unit + sub-home subset
- Add .github/workflows/ci.yml: test-unit + test-integration on PR to dev
- 239 tests collected (110 unit, 125 integration) — no count reduction
2026-08-17 11:29:29 +07:00
a2nr 25269fca08 fix(quiz/progress): perbaiki temuan audit — btn:disabled, css mati, indentasi 2026-08-17 09:23:05 +07:00
a2nr 9aef612f01 feat(quiz/progress): pindah navigator ke quiz view, tampilkan guru di /progress, tambah 1 siswa, fix breakdown eval/diag
- Task 1: pindahkan .quiz-navigator & .quiz-controls dari QuizTab ke
  QuizQuestionView; refactor props jadi mgr: LessonManager; CSS ke lesson.css.
  Navigator+kontrol kuis selalu terlihat di mobile walau workspace hidden.
- Task 2: get_all_students_progress tidak filter role guru; field role per row;
  badge 'Guru', bulk-action & empty-state & ringkasan hanya hitung siswa.
- Task 3: endpoint POST /students/add (reuse StudentRoundTripRow +
  find_student_import_conflicts + run_student_import); validate_single_student_input;
  AddStudentDialog + addStudent(); import/export/bulk-delete CSV lama tetap ada.
- Fix (Opsi A): breakdown eval/diag hanya hitung MCQ (flashcard netral) —
  selaraskan dengan skor resmi FE; perbaiki tampilan eval:4/6 yg membingungkan.
  Tambah field type ke QuizAnswerPayload.

Test: backend 239 passed (termasuk test baru teacher-in-report, add-student,
breakdown-excludes-flashcards); svelte-check 0 error; build sukses.
version.ts 27->28.
2026-08-17 08:32:42 +07:00
a2nr 2d5f100808 feat(quiz): perbaikan refresh quiz + enhancement UI kuis
- QUIZ-01: beforeunload hanya kirim beacon (tanpa finalisasi state) sehingga
  Cancel dialog membatalkan reload dan quiz lanjut; beforeNavigate tidak lagi
  memfinalisasi untuk tipe 'leave' (full-page unload/reload); review
  disembunyikan untuk page_unload (display policy anti-eksploitasi)
- QUIZ-02: opsi MCQ tampil 2-kolom grid (single-col untuk <=2 pilihan,
  fallback 1 kolom di mobile sempit)
- QUIZ-03: hapus info "soal X dari Y / X dijawab" + progress bar dari
  workspace dan question view
- QUIZ-04: opsi tinggi workspace mobile hide/30%/50%/70%/full dengan
  stepUp/stepDown untuk swipe & tombol resize
- QUIZ-05: workspace flashcard hanya 2 tombol "Sudah Mengerti"/"Tidak
  Mengerti" (tracking understood), indikator di summary review

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
2026-08-16 19:17:42 +07:00
a2nr 58cb35a01a feat(quiz): tag kategori diagnostik + breakdown evaluasi/diagnostik di kuis & report guru
- Backend parser (_parse_flashcards): deteksi marker ::diagnostic di baris sendiri -> category='diagnostik' (default evaluasi), strip dari tampilan.
- Persistensi: kolom answers_json (migration 0003) simpan ringkasan per-soal {question_id, selected_option_id, is_correct, category}.
- quiz_attempts: validasi/serialize answers_json + endpoint GET /quiz-attempts/<lesson> untuk review-after-refresh.
- quiz-session: hitung evalCorrect/evalTotal/diagCorrect/diagTotal/diagUnmastered; skor resmi = evaluasi saja.
- Frontend: QuizTab badge per-soal + breakdown 'Belum dikuasai'; progress guru tampil badge Eval/Diag per lesson.
- Content: pindahkan ::diagnostic ke baris sendiri (fix kerusakan fenced code/blockquote dari edit sebelumnya).
- Tests: unit parser kategori + payload answers.
2026-08-15 09:33:23 +07:00
a2nr 79edcd1596 fix: sync lesson registry termasuk sub-bab (sub-home.md) agar kolom materi muncul di CSV guru
lesson_specs() hanya memindai home.md root sehingga lesson di
bab/<folder>/sub-home.md tidak pernah masuk tabel lessons. Akibatnya kolom
materi sub-bab hilang saat guru import/export siswa CSV.

- services/lesson_service.py: tambah find_all_sub_home_folders() (enumerate
  level-1 folder di CONTENT_DIR berisi sub-home.md)
- services/lesson_registry.py: lesson_specs() gabungkan union root + sub-bab,
  dedupe slug (root priority) — satu lesson entitas
- services/tests/test_lesson_registry.py: test unit + DB integration

Verifikasi: 3 passed, 2 skipped (unit); test_sync_includes_sub_bab_lessons
passed (DB); 58 passed total termasuk test_repositories + student_management
tanpa regresi.
2026-08-14 07:07:25 +07:00
a2nr 432a8c2eca fix: show lesson progress on sub-home /bab pages
The /bab/<folder> endpoint returned raw get_sub_home_data() output, so
lessons had no completed/locked fields and green checkmarks never
appeared. api_bab now reads the student token, injects progress via
get_ordered_lessons_with_learning_objectives (scoped to the folder's
sub-home.md), and computes lock status from prerequisites — matching
/lessons. The bab page load also forwards the student token, and tests
cover progress injection and prerequisite locking.
2026-08-14 05:23:50 +07:00
a2nr 67ed58a327 feat: scope sub-home lesson lists & make sub-home cache mtime-aware
Lengkapi rencana sub-home (fitur bab sudah ada sejak 2f689af) dengan
perilaku sidebar/navigasi yang akurat per sub-folder:

- get_lessons()/get_ordered_lessons_with_learning_objectives() menerima
  source_path opsional sehingga daftar materi dapat diambil dari
  sub-home.md alih-alih home.md root
- api_lesson: ordered_lessons + prev/next di-scope ke sub-home.md bila
  folder memilikinya, fallback ke daftar global home.md
- get_sub_home_data kini mtime-cached (bukan lru_cache) sehingga edit
  sub-home.md langsung terlihat tanpa restart; edit juga meng-invalidate
  find_lesson_file agar materi baru terdeteksi

Testing & docs:
- test_sub_home.py (unit): _read_md_cached mtime, find_sub_home_for_lesson,
  get_sub_home_data refresh, ordered_lessons via source_path
- test_sub_home_api.py (integration): GET /bab/<folder> + scoped
  ordered_lessons di /lesson/<slug>.json
- docs/13-content-sub-home.md (baru), README + docs/02-backend-flask.md
  diperbarui dengan catatan fallback
- elemes.sh: perintah `test` + verifikasi tes sub-home di runclearbuild
2026-08-13 20:08:50 +07:00
a2nr 7e17da46c2 fix(frontend): hide CircuitJS toolbar & menu bar in lesson embeds
Append &hideMenu=true to the circuitjs.html iframe src used by
renderCircuitEmbeds so lesson content embeds render clean without
the toolbar and menu bar. The embed path in CircuitEditor.svelte
is untouched, so the editor keeps its full toolbar.

Verified:
- Bundle contains embed URL (with hideMenu=true) and editor URL
  (without) as separate variants
- svelte-check: 0 errors
- /lesson/rangkaian_dasar returns 200 on the running stack
2026-08-12 07:49:34 +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 a14a212cc6 test(elemes): lock all three exportall build tags; note runbuild for unbundled services 2026-08-10 12:03:53 +07:00
a2nr c83a47b357 fix(elemes): align exportall/importall image tags with podman-compose (lms-*, not lms-c-*) 2026-08-10 12:03:10 +07:00
a2nr 5508c2dc7a docs: replace hard-coded container names with service-based podman-compose/label resolution 2026-08-10 11:34:54 +07:00
a2nr c453ddde2d test(elemes): per-command log assertions + cover dbupgrade/dbstatus/dbrestore 2026-08-10 11:29:09 +07:00
a2nr 394eb11082 refactor(elemes): delegate run_compose to run_compose_out; fail dbbackup on pg_dump error 2026-08-10 11:29:09 +07:00
a2nr 3935b7e01e test(elemes): add regression test for dynamic PROJECT_NAME resolution 2026-08-10 11:25:44 +07:00
a2nr 6ba508c7bc fix(verify): skip stale check when image tag unknown (avoid bogus podman images call) 2026-08-10 11:25:44 +07:00
a2nr 0b513b3900 docs(exportall): update image name hints to match compose (lms-backend, lms-frontend, lms-velxio) 2026-08-10 11:23:20 +07:00
a2nr 34ab1cde73 fix(verify): dynamic label-based verification for any PROJECT_NAME 2026-08-10 11:23:13 +07:00
a2nr 8976acd154 fix(dbbackup,dbrestore): use compose_exec for postgres service 2026-08-10 11:22:59 +07:00
a2nr 34dc9c9b90 fix(teacher,dbupgrade,dbstatus): use compose_exec for elemes service 2026-08-10 11:22:50 +07:00
a2nr a0c69ece8e fix(db_init): use compose_exec/compose_restart instead of hard-coded container names 2026-08-10 11:22:41 +07:00
a2nr 4f73bd725e feat(elemes): add compose_exec/compose_restart helpers for service-targeted ops 2026-08-10 11:22:28 +07:00
a2nr c356e234fa fix(frontend): resolve 26 svelte-check type errors
- add @types/node for hooks.server process/env types
- fix katex auto-render import path (contrib/auto-render)
- declare global Web Bluetooth API types in ble-deployer
- guard simApi null in CircuitEditor autosave interval
- default-type imports for CodeEditor/CircuitEditor
- make lesson slug getter non-nullable
- add expected_flowchart to LessonContent type
- key lesson workspace by slug; drop phantom onReset prop
- guard CodeTab render when lesson data is null
2026-08-09 12:28:17 +07:00
a2nr 9ee92cfaaf feat(teacher): manajemen akun guru canonical + first-run otomatis; cabut backend CSV (PG only)
- feat: ./elemes.sh teacher — upsert satu akun guru canonical (prompt nama default TEACHER_NAME, token tersembunyi via stdin, rotasi token saat guru sudah ada, idempotent); TEACHER_NAME/TEACHER_TOKEN di .env
- feat: first-run otomatis — db_init jalankan alembic upgrade head + bootstrap guru bila TEACHER_TOKEN terisi (run/runbuild/runclearbuild)
- refactor: backend CSV dicabut penuh — hapus mount tokens_siswa.csv, TOKENS_FILE, STORAGE_BACKEND=csv, csv_backend.py, csv_importer.py, generate_tokens.py, script migrate/verify/export CSV, command generatetoken/dbimport/dbverify/dbexport/synclessons; storage fail-loud postgresql-only
- fix: dbrestore gagal diam-diam saat restore ke DB berisi data (dump tanpa --clean) — dbbackup kini --clean --if-exists + dbrestore reset schema public; roundtrip terverifikasi
- test: suite kontrak PG-native + route auth/progress integrasi PG; 183 passed container, 96 passed host, frontend 91 passed
- docs: README, documentation.md, docs/01/02/11, load-test/README disinkronkan ke realita PostgreSQL-only; proposal.md dipertahankan (historis)
- chore: load-test token sintetis di-seed ke PG (content_parser), config.py bersih TOKENS_FILE, .dockerignore/.gitignore dibersihkan
2026-08-09 11:21:08 +07:00
a2nr d602b0f642 feat(student-management): kelola siswa round-trip CSV + bulk delete (PG)
- Export siswa terpilih/seluruh + progress ke CSV round-trip (token tidak
  pernah diekspor; teacher tidak ikut; urutan deterministik)
- Import preview all-or-nothing: siswa existing di-restore (nama+progress,
  token lama dipertahankan), siswa baru dibuat dari student_id kosong +
  token; conflict tidak menyebut raw token/digest
- Bulk delete multi-seleksi dengan validasi ketat (teacher terlindungi,
  zero-delete bila ada ID bermasalah)
- fix(import): deteksi delimiter berbasis schema — menerima titik koma
  (;) maupun koma (,), ekspor tetap ';' + BOM; header tab/campuran ditolak
  dengan pesan jelas (regresi: file Excel/Sheets kini bisa diimpor)
- refactor: progress_status.py — kontrak status legacy tunggal dipakai
  storage PG, export, dan import; report siswa hanya role student
- UI /progress: dialog import/export + bulk delete, selection store,
  respon import tanpa raw token; APP_VERSION 22 -> 26
- ops: ORIGIN env var di podman-compose.yml
- docs: README section 9 (workflow round-trip + delimiter) dan
  docs/11-database-migration (kelola siswa via round-trip CSV)
- test: parser round-trip (45), repositories, route management (24,
  PostgreSQL), frontend 91, fixtures CSV valid/invalid
2026-08-09 07:29:19 +07:00
a2nr ac37db5c91 feat(storage): migrasi penyimpanan CSV ke PostgreSQL (SQLAlchemy + Alembic)
- facade storage: csv_backend + postgres_backend, dipilih via STORAGE_BACKEND
- token disimpan sebagai HMAC-SHA256 digest (TOKEN_PEPPER), tanpa plaintext
- schema alembic 0001: users, access_tokens, lessons, student_progress
- importer CSV idempotent + dry-run + sparse model (not_started tanpa row)
- lesson registry: sync dari home.md (lesson hilang di-deactivate, bukan dihapus)
- routes progress/auth: report & reset via DB, validasi via token hash
- elemes.sh: dbupgrade/dbstatus/dbimport/synclessons/dbverify/dbbackup/dbrestore/dbexport
- podman-compose: service postgres (PG18), tokens_siswa.csv mount :ro
- frontend: api client + progress page; tests kontrak dual-backend + isolasi DB
- load-test: skenario database (locustfile_db.py)
- docs: 01-11 termasuk 11-database-migration.md (arsitektur & operasional)
2026-08-08 04:57:08 +00:00
a2nr 575787af59 test(load-test): task sesi interaktif + parser konten rekursif + e2e smoke check
- content_parser.py: scan rekursif subfolder (dasar/arduino/circuit) + inject 50 token
- locustfile.py: task interactive_session_python (create→poll→input→verify→delete)
- e2e_session_check.py: smoke-test 13 skenario via proxy Flask
- README: skenario load test 50 pengguna 2 device
chore(elemes): update velxio submodule ke elemes-v3.2 (2b17470)
2026-08-02 14:14:59 +00:00
a2nr ec66d794a8 feat(playground): alur interaktif Run→prompt→jawab + file tree collapsible & dukungan .h
- store: normalisasi lifecycle sesi (runStatus/runSessionId/outputCursor/runError,
  stdinQueue tetap untuk kompatibilitas)
- +page.svelte: session controller — start, polling recursive setTimeout non-overlap,
  delta output via cursor, stop + cleanup unmount/generation counter
- ConsolePanel.svelte: input interaktif (onSendInput/onStop async, mode antrean vs kirim)
- FileTree.svelte: validasi rename (foo.h diterima di C), tombol + langsung mode rename,
  collapsible shell dengan handle persisten
- playground-files.ts: validasi nama file (basename, traversal, duplikat case-insensitive)
- api.ts/compiler.ts: client sesi interaktif
- tests: playground.test.ts + playground-files.test.ts
2026-08-02 14:14:53 +00:00