Add comprehensive proposal for refactoring LMS-C architecture to Flask API and SvelteKit PWA
parent
d59eae3bd0
commit
aeef8fc99d
|
|
@ -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.*
|
||||
Loading…
Reference in New Issue