diff --git a/documentation.md b/documentation.md new file mode 100644 index 0000000..067ed97 --- /dev/null +++ b/documentation.md @@ -0,0 +1,507 @@ +# Proposal Refactoring: LMS Belajar Pemrograman C + +**Tanggal:** 24 Maret 2026 +**Project:** LMS-C (Learning Management System untuk Pemrograman C) +**Workspace:** `elemes/` + +--- + +## 1. Ringkasan Eksekutif + +Proposal ini mengusulkan refactoring LMS-C dari arsitektur **Flask monolith + Jinja2 templates** menjadi arsitektur **Flask API + SvelteKit PWA**. Tujuannya adalah memberikan pengalaman belajar yang optimal di **desktop dan mobile** dengan code editor yang proper, performa cepat, dan kemampuan instalasi sebagai aplikasi (PWA). + +--- + +## 2. Kondisi Saat Ini + +### Arsitektur +- **Backend:** Flask monolith (`app.py`, 982 baris) — semua logic dalam satu file +- **Frontend:** Jinja2 templates + vanilla JavaScript + Bootstrap 5 +- **Code Editor:** Plain textarea dengan line numbers manual (bukan code editor sesungguhnya) +- **Compiler:** Factory pattern — CCompiler (gcc) dan PythonCompiler +- **Auth:** Token-based via CSV file (`tokens_siswa.csv`) +- **Deploy:** Podman container + Tailscale sidecar untuk HTTPS +- **Flutter app:** 0% — hanya folder kosong, tidak ada kode sama sekali + +### Masalah Utama +1. **Monolith 982 baris** — sulit di-maintain dan di-test +2. **Bukan code editor** — textarea biasa, tidak ada syntax highlighting saat mengetik, bracket matching, atau auto-indent +3. **Tidak mobile-friendly** — code editor tidak bisa dipakai di mobile +4. **Tidak bisa offline** — tidak ada caching mekanisme +5. **Vanilla JS** — duplikasi kode di setiap template (login logic di-copy paste) +6. **Tidak installable** — harus buka browser setiap kali + +--- + +## 3. Evaluasi Framework + +### 3.1 Flutter Web + Mobile + +| Aspek | Evaluasi | +|-------|----------| +| **Rendering** | CanvasKit — render ke HTML canvas, BUKAN native DOM | +| **Code Editor** | Tidak ada widget setara CodeMirror/Monaco. `code_text_field` sangat terbatas | +| **Bundle Size** | 2-4 MB initial download (CanvasKit engine) | +| **Mobile** | Excellent untuk native app, tapi web version bermasalah | +| **Accessibility** | Buruk — canvas rendering, tidak bisa "Find in Page", screen reader tidak jalan | +| **SEO** | Tidak ada — semua di-render di canvas | +| **Markdown** | Ecosystem terbatas untuk rendering markdown | + +**Verdict:** ❌ Tidak cocok untuk LMS yang content-heavy dengan code editor sebagai fitur utama. + +**Alasan utama penolakan:** Flutter Web me-render SELURUH UI ke HTML ``. Ini berarti: +- Siswa tidak bisa copy-paste text dari lesson content secara natural +- Browser "Find in Page" (Ctrl+F) tidak berfungsi +- Code editor di Flutter tidak bisa match fitur CodeMirror 6 (syntax highlighting, bracket matching, multiple cursors, mobile keyboard support) +- Bundle 2-4 MB sangat berat untuk siswa dengan koneksi mobile + +### 3.2 Next.js (React) PWA + +| Aspek | Evaluasi | +|-------|----------| +| **Rendering** | Native DOM + SSR/SSG | +| **Code Editor** | Monaco Editor (VS Code engine) — sangat powerful tapi 5MB+ | +| **Bundle Size** | 200-400 KB base, 5MB+ dengan Monaco | +| **Mobile** | Baik, tapi Monaco Editor tidak optimal di mobile | +| **Ecosystem** | Sangat besar, banyak library | +| **Complexity** | Lebih kompleks dari Svelte (virtual DOM, hooks, etc.) | + +**Verdict:** ⚠️ Bisa dipakai, tapi overkill dan Monaco terlalu berat. + +### 3.3 SvelteKit PWA (REKOMENDASI) + +| Aspek | Evaluasi | +|-------|----------| +| **Rendering** | Native DOM + SSR, compile-time (no virtual DOM) | +| **Code Editor** | CodeMirror 6 — production-grade, mobile-friendly, 150KB | +| **Bundle Size** | 50-100 KB base + 150KB CodeMirror = ~250KB total | +| **Mobile** | Excellent — native HTML/CSS responsive, CodeMirror 6 support touch | +| **PWA** | Built-in via `@vite-pwa/sveltekit` | +| **SSR** | Built-in — fast first paint untuk konten markdown | +| **Learning Curve** | Minimal — Svelte lebih sederhana dari React | +| **TypeScript** | Native support | + +**Verdict:** ✅ Pilihan terbaik untuk project ini. + +### 3.4 Flask + HTMX/Alpine.js + +| Aspek | Evaluasi | +|-------|----------| +| **Perubahan** | Minimal dari arsitektur sekarang | +| **Code Editor** | Bisa pakai CodeMirror, tapi integrasi manual | +| **Mobile** | Terbatas — tetap server-rendered, tidak ada PWA | +| **Offline** | Tidak ada | + +**Verdict:** ⚠️ Perbaikan inkremental, bukan refactor sebenarnya. + +### Tabel Perbandingan + +| Kriteria | Flutter Web | Next.js | **SvelteKit** | Flask+HTMX | +|----------|:-----------:|:-------:|:-------------:|:----------:| +| Code editor quality | 2/10 | 9/10 | **9/10** | 5/10 | +| Bundle size | 2/10 | 5/10 | **9/10** | 10/10 | +| Mobile experience | 4/10 | 7/10 | **9/10** | 4/10 | +| PWA support | 3/10 | 7/10 | **9/10** | 2/10 | +| SSR / first paint | 2/10 | 9/10 | **9/10** | 8/10 | +| Complexity | 6/10 | 5/10 | **8/10** | 9/10 | +| Markdown rendering | 4/10 | 8/10 | **9/10** | 8/10 | +| **Total** | **23/70** | **50/70** | **62/70** | **46/70** | + +--- + +## 4. Arsitektur yang Diusulkan + +### 4.1 Overview + +``` + ┌─────────────────────────────┐ + │ Internet (HTTPS) │ + └──────────────┬──────────────┘ + │ + ┌──────────────▼──────────────┐ + │ Tailscale Funnel (:443) │ + │ (elemes-ts container) │ + └──────────────┬──────────────┘ + │ + ┌──────────────▼──────────────┐ + │ SvelteKit Frontend (:3000) │ + │ - SSR pages │ + │ - CodeMirror 6 editor │ + │ - PWA + Service Worker │ + │ - Responsive UI │ + └──────────────┬──────────────┘ + │ /api/* + ┌──────────────▼──────────────┐ + │ Flask API Backend (:5000) │ + │ - Code compilation (gcc) │ + │ - Token authentication │ + │ - Progress tracking (CSV) │ + │ - Lesson content parsing │ + └─────────────────────────────┘ +``` + +### 4.2 Tiga Container + +| Container | Base Image | Port | Fungsi | +|-----------|-----------|------|--------| +| `elemes-frontend` | Node 20 slim | 3000 | SvelteKit SSR, static assets, PWA | +| `elemes-api` | Python 3.11 slim + gcc | 5000 | Flask JSON API, compilation, auth | +| `elemes-ts` | Tailscale | 443 | HTTPS termination, Funnel | + +### 4.3 Alur Data + +``` +Siswa buka browser + → GET /lesson/hello_world + → SvelteKit SSR: fetch /api/lesson/hello_world dari Flask + → Flask: parse markdown, return JSON {lesson_html, initial_code, ...} + → SvelteKit: render HTML + hydrate CodeMirror editor + → Siswa tulis kode C di CodeMirror + → Klik "Run" + → POST /api/compile {code: "..."} + → Flask: write temp file → gcc compile → run → return output + → SvelteKit: tampilkan output di OutputPanel + → Jika benar → POST /api/track-progress + → Flask: update CSV file +``` + +--- + +## 5. Struktur Direktori + +``` +lms-c/ # Root — konten saja +├── content/ # 25 lesson markdown +│ ├── home.md +│ ├── hello_world.md +│ ├── variables.md +│ └── ... (25 file) +├── assets/ # Gambar untuk lesson +├── tokens_siswa.csv # Data siswa & progress +├── config/ +│ └── sinau-c-tail.json # Tailscale config +├── state/ # Runtime state (certs, logs) +└── .env # Environment variables + +elemes/ # Semua kode aplikasi +├── documentation.md # Dokumen ini +│ +├── api/ # ── Flask API Backend ── +│ ├── app.py # create_app() factory +│ ├── config.py # Environment config +│ ├── requirements.txt # Python dependencies +│ ├── Dockerfile +│ ├── gunicorn.conf.py +│ ├── compiler/ # Compiler module (tidak berubah) +│ │ ├── __init__.py # CompilerFactory +│ │ ├── base_compiler.py # Abstract base +│ │ ├── c_compiler.py # gcc wrapper +│ │ └── python_compiler.py # python wrapper +│ ├── routes/ # Flask Blueprints (JSON only) +│ │ ├── auth.py # /api/login, logout, validate-token +│ │ ├── compile.py # /api/compile +│ │ ├── lessons.py # /api/lessons, /api/lesson/ +│ │ └── progress.py # /api/track-progress, progress-report +│ ├── services/ # Business logic +│ │ ├── token_service.py # CSV token operations +│ │ └── lesson_service.py # Markdown parsing +│ └── tests/ # pytest +│ ├── test_auth.py +│ ├── test_compile.py +│ ├── test_lessons.py +│ └── test_progress.py +│ +├── frontend/ # ── SvelteKit PWA Frontend ── +│ ├── package.json +│ ├── svelte.config.js # adapter-node +│ ├── vite.config.ts # PWA plugin + API proxy +│ ├── Dockerfile +│ └── src/ +│ ├── app.html # Root HTML shell +│ ├── app.css # Global styles +│ ├── lib/ +│ │ ├── components/ +│ │ │ ├── CodeEditor.svelte # CodeMirror 6 (KRITIS) +│ │ │ ├── Navbar.svelte # Navigation + auth +│ │ │ ├── LessonCard.svelte # Card lesson +│ │ │ ├── OutputPanel.svelte # Output kompilasi +│ │ │ ├── ProgressBadge.svelte # Badge status +│ │ │ └── Footer.svelte +│ │ ├── stores/ +│ │ │ ├── auth.ts # Token state +│ │ │ └── theme.ts # Dark/light +│ │ ├── services/ +│ │ │ └── api.ts # Flask API client +│ │ └── types/ +│ │ ├── lesson.ts +│ │ ├── auth.ts +│ │ └── compiler.ts +│ ├── routes/ +│ │ ├── +layout.svelte # Navbar + Footer +│ │ ├── +page.svelte # Home (lesson grid) +│ │ ├── lesson/[slug]/ +│ │ │ └── +page.svelte # Lesson viewer +│ │ └── progress/ +│ │ └── +page.svelte # Teacher dashboard +│ └── static/ +│ ├── manifest.json # PWA manifest +│ └── icons/ # App icons +│ +└── podman-compose.yml # 3 services +``` + +--- + +## 6. Komponen Kritis: Code Editor + +CodeMirror 6 adalah code editor web paling mature yang support mobile. Berikut fitur yang akan diimplementasi: + +### Fitur Editor +- **Syntax highlighting** — C language mode (`@codemirror/lang-cpp`) +- **Line numbers** — gutter di sisi kiri +- **Bracket matching** — highlight bracket pasangan +- **Auto-close brackets** — otomatis tutup `{`, `(`, `[` +- **Dark/Light theme** — toggle dengan `@codemirror/theme-one-dark` +- **Undo/Redo** — Ctrl+Z / Ctrl+Shift+Z +- **Tab handling** — insert 4 spasi (bukan tab karakter) +- **Ctrl+Enter** — shortcut untuk Run +- **Copy-paste prevention** — bisa diaktifkan per-lesson (configurable) +- **Mobile keyboard support** — CodeMirror 6 handle virtual keyboard natively + +### Perbandingan dengan Editor Saat Ini + +| Fitur | Saat Ini (textarea) | SvelteKit (CodeMirror 6) | +|-------|:-------------------:|:------------------------:| +| Syntax highlighting saat mengetik | ❌ | ✅ | +| Auto-indent | ❌ | ✅ | +| Bracket matching | ❌ | ✅ | +| Auto-close brackets | ❌ | ✅ | +| Undo/Redo | Basic browser | ✅ Full history | +| Mobile keyboard | Problematic | ✅ Native support | +| Dark/Light theme | Partial | ✅ Full themes | +| Find & Replace | ❌ | ✅ Ctrl+F | +| Multiple cursors | ❌ | ✅ | + +--- + +## 7. Mobile Strategy: PWA + +### Apa itu PWA? +Progressive Web App memungkinkan web app di-install seperti native app di mobile dan desktop, tanpa harus publish ke App Store / Play Store. + +### Fitur PWA yang diimplementasi +1. **Add to Home Screen** — siswa bisa install dari browser +2. **Standalone mode** — berjalan tanpa browser chrome (address bar hilang) +3. **Splash screen** — branding saat app loading +4. **Offline reading** — lesson content di-cache oleh service worker +5. **Auto-update** — service worker update otomatis saat ada versi baru + +### Responsive Design + +| Viewport | Layout | +|----------|--------| +| Desktop (>1024px) | 2 kolom: lesson content (8/12) + sidebar (4/12) | +| Tablet (768-1023px) | 2 kolom: lesson content (7/12) + sidebar (5/12) | +| Mobile (<768px) | 1 kolom, sidebar jadi accordion expandable | + +### Code Editor di Mobile +- Default height 200px dengan tombol expand +- CodeMirror 6 handle virtual keyboard secara native +- Touch-friendly buttons (target area lebih besar) +- Auto-scroll ke cursor saat virtual keyboard muncul + +--- + +## 8. Tailscale Integration + +### Arsitektur Deployment +``` + Tailscale Network + │ + ┌────────────────▼────────────────┐ + │ elemes-ts (Tailscale container) │ + │ hostname: sinau-c-dev │ + │ HTTPS :443 (Funnel) │ + │ │ │ + │ ▼ proxy │ + │ elemes-frontend :3000 │ + │ (SvelteKit) │ + │ │ │ + │ ▼ /api/* │ + │ elemes-api :5000 │ + │ (Flask + gcc) │ + └─────────────────────────────────┘ +``` + +### Akses Development +- **Internal:** `http://localhost:3000` (langsung ke SvelteKit) +- **External via Tailscale:** `https://sinau-c-dev..ts.net` +- **Funnel (public):** Bisa diaktifkan untuk akses tanpa Tailscale client + +### Perubahan dari Setup Saat Ini +- Tailscale proxy target berubah dari Flask (:5000) ke SvelteKit (:3000) +- SvelteKit yang meng-handle semua request client, lalu proxy `/api/*` ke Flask internal + +--- + +## 9. Fase Implementasi + +### Phase 0: Backend Decomposition +**Tujuan:** Pecah Flask monolith menjadi modular API + +- Buat struktur `elemes/api/` +- Extract services: `lesson_service.py`, `token_service.py` +- Extract routes ke Blueprints: `auth.py`, `compile.py`, `lessons.py`, `progress.py` +- Rewrite `app.py` sebagai factory function +- Tambah `flask-cors` +- Write unit tests + +**Output:** Flask API yang return JSON, siap dikonsumsi frontend + +### Phase 1: SvelteKit Scaffolding +**Tujuan:** Setup project SvelteKit dengan dependencies + +- Initialize project dengan TypeScript +- Install CodeMirror 6, PWA plugin, marked +- Configure adapter-node dan API proxy + +### Phase 2: Core Components +**Tujuan:** Build komponen reusable + +- Auth store + API service +- CodeEditor (CodeMirror 6) +- Navbar, Footer, LessonCard, OutputPanel + +### Phase 3: Pages +**Tujuan:** Build semua halaman + +- Home page (lesson grid + SSR) +- Lesson page (content + editor + output) +- Progress report (teacher dashboard) + +### Phase 4: Mobile + PWA +**Tujuan:** Optimasi mobile dan installability + +- Responsive CSS +- PWA manifest + service worker +- Offline lesson caching +- Mobile-optimized editor + +### Phase 5: Containerization + Tailscale +**Tujuan:** Deploy ke containers + +- Frontend Dockerfile (Node 20) +- API Dockerfile (Python 3.11 + gcc) +- Update podman-compose.yml (3 services) +- Update Tailscale config + +### Phase 6: Cleanup +**Tujuan:** Hapus kode lama + +- Remove Jinja2 templates +- Remove vanilla JS +- Remove flutter_app/ placeholder +- Remove flask-talisman (CSP di SvelteKit) + +--- + +## 10. Stack Teknologi + +### Backend (Flask API) +| Teknologi | Versi | Fungsi | +|-----------|-------|--------| +| Python | 3.11 | Runtime | +| Flask | 2.3+ | Web framework (API only) | +| Flask-CORS | latest | Cross-origin untuk SvelteKit | +| Gunicorn | 21.2 | Production WSGI server | +| gcc | system | C compiler | +| python-markdown | 3.5 | Markdown → HTML | + +### Frontend (SvelteKit) +| Teknologi | Versi | Fungsi | +|-----------|-------|--------| +| Node.js | 20 LTS | Runtime | +| SvelteKit | 2.x | Full-stack framework | +| Svelte | 5.x | UI framework | +| TypeScript | 5.x | Type safety | +| CodeMirror 6 | 6.x | Code editor | +| @vite-pwa/sveltekit | latest | PWA support | +| marked | latest | Client-side markdown (jika perlu) | +| highlight.js | 11.x | Syntax highlighting di konten | + +### Infrastructure +| Teknologi | Fungsi | +|-----------|--------| +| Podman | Container runtime | +| Podman Compose | Container orchestration | +| Tailscale | VPN + HTTPS (Funnel) | + +--- + +## 11. API Endpoints + +Semua endpoint Flask akan di-prefix dengan `/api/`: + +### Authentication +| Method | Endpoint | Request | Response | +|--------|----------|---------|----------| +| POST | `/api/login` | `{token}` | `{success, student_name}` | +| POST | `/api/logout` | — | `{success}` | +| POST | `/api/validate-token` | `{token}` | `{success, student_name}` | + +### Lessons +| Method | Endpoint | Response | +|--------|----------|----------| +| GET | `/api/lessons` | `[{title, filename, description, completed}]` | +| GET | `/api/lesson/` | `{lesson_html, exercise_html, initial_code, solution_code, expected_output, key_text, title, prev, next}` | +| GET | `/api/key-text/` | `{key_text}` | + +### Compilation +| Method | Endpoint | Request | Response | +|--------|----------|---------|----------| +| POST | `/api/compile` | `{code, language?}` | `{success, output, error}` | + +### Progress +| Method | Endpoint | Request/Params | Response | +|--------|----------|----------------|----------| +| POST | `/api/track-progress` | `{token, lesson_name}` | `{success}` | +| GET | `/api/progress-report` | `?token=xxx` | `{students: [{name, progress: {}}]}` | +| GET | `/api/export-csv` | `?token=xxx` | CSV file download | + +--- + +## 12. Verifikasi + +### Testing Strategy +1. **Backend:** pytest di dalam container (`podman exec elemes-api pytest -v`) +2. **Frontend unit:** Vitest (`npm run test`) +3. **Frontend E2E:** Playwright (`npm run test:e2e`) +4. **Manual:** Cek di desktop dan mobile viewport + +### Checklist Verifikasi +- [ ] Home page menampilkan 25 lesson cards +- [ ] Login dengan token berhasil +- [ ] Lesson page menampilkan konten markdown +- [ ] Code editor berfungsi (syntax highlighting, line numbers) +- [ ] Run code → output ditampilkan +- [ ] Kode benar → progress ter-track +- [ ] Progress report menampilkan data siswa +- [ ] Export CSV berfungsi +- [ ] Responsive di mobile (375x667) +- [ ] PWA installable +- [ ] Tailscale Funnel accessible + +--- + +## 13. Risiko dan Mitigasi + +| Risiko | Dampak | Mitigasi | +|--------|--------|----------| +| CodeMirror 6 bundle size di mobile | Slow initial load | Lazy-load CodeMirror hanya di lesson page | +| Flask API downtime saat refactor | Siswa tidak bisa belajar | Parallel running: old templates tetap jalan | +| Markdown parsing perbedaan Python vs JS | Rendering berbeda | Flask tetap parse markdown (single source of truth) | +| Tailscale config berubah | Akses terputus | Backup config lama, rollback plan ready | + +--- + +*Dokumen ini adalah proposal. Implementasi dimulai setelah disetujui.*