Add comprehensive proposal for refactoring LMS-C architecture to Flask API and SvelteKit PWA

master
a2nr 2026-03-24 19:47:22 +07:00
parent d59eae3bd0
commit aeef8fc99d
1 changed files with 507 additions and 0 deletions

507
documentation.md Normal file
View File

@ -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 `<canvas>`. 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/<slug>
│ │ └── 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.<tailnet>.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/<slug>` | `{lesson_html, exercise_html, initial_code, solution_code, expected_output, key_text, title, prev, next}` |
| GET | `/api/key-text/<slug>` | `{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.*