From 9e5617274e53db77a9a68762391fefbfa3124978 Mon Sep 17 00:00:00 2001 From: a2nr Date: Thu, 14 May 2026 16:33:45 +0700 Subject: [PATCH] add : docomentation --- docs/01-architecture-setup.md | 121 ++++++++++++++++++++++++++++++++++ docs/02-backend-flask.md | 72 ++++++++++++++++++++ docs/03-frontend-sveltekit.md | 39 +++++++++++ docs/04-lesson-evaluation.md | 43 ++++++++++++ 4 files changed, 275 insertions(+) create mode 100644 docs/01-architecture-setup.md create mode 100644 docs/02-backend-flask.md create mode 100644 docs/03-frontend-sveltekit.md create mode 100644 docs/04-lesson-evaluation.md diff --git a/docs/01-architecture-setup.md b/docs/01-architecture-setup.md new file mode 100644 index 0000000..084aa11 --- /dev/null +++ b/docs/01-architecture-setup.md @@ -0,0 +1,121 @@ +# 01. Architecture & Setup + +## High-Level System Architecture + +The Elemes LMS-C project uses a multi-container architecture orchestrated via Podman, with a Tailscale Funnel acting as the public ingress point. + +``` +Internet (HTTPS :443) + │ + ▼ +Tailscale Funnel (elemes-ts) + │ + ├── / → SvelteKit Frontend (elemes-frontend :3000) + ├── /assets/ → Flask Backend (elemes :5000) + ├── /velxio/api/compile → Flask Backend (Rate-limited Proxy :5000) + ├── /velxio/ → Velxio Arduino Simulator (velxio :80) + │ + ▼ +SvelteKit Frontend (elemes-frontend :3000) + ├── SSR pages (lesson content embedded in HTML) + ├── CodeMirror 6 editor (lazy-loaded) + ├── CircuitJS simulator (iframe, GWT-compiled) — mode "circuit" + ├── Velxio Arduino simulator (iframe, React) — mode "velxio" + ├── API proxy: /api/* → Flask + └── PWA manifest + │ + ▼ /api/* +Flask API Backend (elemes :5000) + ├── Code compilation (Proxied to Compiler Worker) + ├── Arduino Proxy (/velxio-compile → Velxio :80) + ├── Token authentication (CSV) + ├── Progress tracking + └── Lesson content parsing (markdown) + │ + ▼ HTTP +Compiler Worker (compiler-worker :8080) + ├── gVisor Sandbox (runsc runtime) + ├── Gunicorn (4 workers) + └── Isolation: gcc / python3 execution + │ +Velxio Arduino Simulator (velxio :80) + ├── React + Vite frontend (editor + simulator canvas) + ├── FastAPI backend (arduino-cli compile) + ├── AVR8 / RP2040 CPU emulation (browser) + └── PostMessage bridge ↔ Elemes (EmbedBridge.ts) +``` + +## Container Setup + +| Container | Image | Port | Fungsi | +|-----------|-------|------|--------| +| `elemes` | Python 3.11 | 5000 | Flask API (auth, lessons, progress, compile-proxy) | +| `compiler-worker` | Python 3.11 + gcc | 8080 | **Sandboxed** execution engine (gVisor) | +| `elemes-frontend` | Node 20 | 3000 | SvelteKit SSR | +| `velxio` | Node + Python + arduino-cli | 80 | Simulator Arduino (React + FastAPI) | +| `elemes-ts` | Tailscale | 443 | HTTPS Funnel + reverse proxy | + +## Directory Structure + +``` +project/ +├── .env # Konfigurasi environment +├── content/ # Folder materi pelajaran (file .md) +│ ├── home.md # Halaman utama & daftar pelajaran +│ ├── hello_world.md # Contoh materi +│ └── ... +├── assets/ # Gambar untuk materi (opsional) +│ └── gambar.png +├── tokens_siswa.csv # Data token siswa (auto-generated) +├── state/ # State Tailscale (auto-generated) +└── elemes/ # Folder engine LMS (JANGAN DIUBAH) + ├── elemes.sh # Script untuk menjalankan LMS + └── ... +``` + +## Setup and Execution + +The primary entry point for managing the system is the `elemes.sh` script located in the `elemes` folder. + +1. **Initialization:** + ```bash + cd elemes + ./elemes.sh init + ``` + Generates `.env`, `content/`, and `tokens_siswa.csv` from examples. Safe to run multiple times. + +2. **Configuration:** + Edit `../.env` to set branding and Tailscale configuration: + ```env + APP_BAR_TITLE=Pemrograman C - SMK Nusantara + COPYRIGHT_TEXT=SMK Nusantara @ 2025 + PAGE_TITLE_SUFFIX=SMK Nusantara + CONTENT_DIR=content + TOKENS_FILE=tokens.csv + ELEMES_HOST=lms-smk-nusantara + TS_AUTHKEY=tskey-auth-xxxx + ``` + +3. **Running the Application:** + ```bash + ./elemes.sh runbuild # Build images and start containers + ./elemes.sh run # Start containers without rebuilding + ./elemes.sh stop # Stop all containers + ``` + +4. **Managing Users (Tokens):** + To update columns in the CSV based on available lessons: + ```bash + ./elemes.sh generatetoken + ``` + Then manually edit `tokens_siswa.csv` (using semicolon `;` delimiter) to add student rows. The first data row is always the teacher token. + +## Security Overview + +The system incorporates several security layers to ensure stability and safety: +1. **Isolated Execution:** User-submitted C and Python code runs inside a `compiler-worker` container protected by a **gVisor (`runsc`) sandbox**, preventing RCE attacks from reaching the host kernel. +2. **Rate Limiting & Tarpitting:** + - Anonymous users: Limited to **1 compile per 2 minutes** per IP, with a global queue of 20 slots. + - Login endpoints: Max **50 requests per minute per IP**. + - Failed logins: Suffer a **1.5-second tarpit delay** to neutralize brute-force attacks. +3. **Cookie Security:** The `student_token` session cookie uses `httponly: true`, `samesite: 'Lax'`, and dynamically sets `secure: true` based on the `COOKIE_SECURE` environment variable. diff --git a/docs/02-backend-flask.md b/docs/02-backend-flask.md new file mode 100644 index 0000000..8c98597 --- /dev/null +++ b/docs/02-backend-flask.md @@ -0,0 +1,72 @@ +# 02. Backend (Flask API) + +The backend is built with Flask, providing API endpoints for the SvelteKit frontend to fetch lessons, track progress, manage authentication, and proxy compilation requests. + +## Application Factory (`elemes/app.py`) + +- `def create_app():` + Initializes the Flask application, loads configuration from `elemes/config.py` (which reads from `.env`), and registers the following blueprints: + - `auth_bp` (`routes/auth.py`) + - `lessons_bp` (`routes/lessons.py`) + - `compile_bp` (`routes/compile.py`) + - `progress_bp` (`routes/progress.py`) + +## Core API Routes + +### Authentication (`routes/auth.py`) +- `def login():` (POST `/login`) + Receives `token` in JSON payload. Validates via `token_service.validate_token()`. On success, sets the `student_token` cookie. Rate-limited and includes a 1.5s tarpit for failures. +- `def logout():` (POST `/logout`) + Clears the `student_token` cookie. +- `def validate_token_route():` (POST `/validate-token`) + Checks if the current `student_token` cookie is valid. + +### Lessons (`routes/lessons.py`) +- `def api_lessons():` (GET `/lessons`) + Returns a list of all lessons and the rendered `home.md` content via `lesson_service.get_ordered_lessons_with_learning_objectives()`. +- `def api_lesson(filename):` (GET `/lesson/.json`) + Returns the fully parsed lesson data (content, initial code, circuits, key texts, active tabs) via `lesson_service.render_markdown_content(filepath)`. +- `def get_key_text(filename):` (GET `/get-key-text/`) + Returns only the required keywords for a specific lesson without exposing the full content logic. + +### Compilation (`routes/compile.py`) +- `def compile_code():` (POST `/compile`) + Accepts `code` and `language`. Routes execution to the sandboxed worker using the `CompilerFactory`. Incorporates rate-limiting for anonymous users. +- `def velxio_compile():` (POST `/velxio-compile` mapped from `/velxio/api/compile`) + A proxy endpoint that forwards Arduino compilation requests to the Velxio container, enforcing rate limits for anonymous users. + +### Progress Tracking (`routes/progress.py`) +- `def track_progress():` (POST `/track-progress`) + Accepts `lesson_name` and `status`. Updates the CSV file via `token_service.update_student_progress()`. +- `def api_progress_report():` (GET `/progress-report.json`) + Returns a matrix of all student progress. Requires a teacher token. +- `def export_progress_csv():` (GET `/progress-report/export-csv`) + Exports progress data as a CSV download. Requires a teacher token. + +## Services + +### Token Service (`services/token_service.py`) +Manages reads and writes to the `tokens_siswa.csv` file. +- `def _load_tokens_safely() -> Tuple[Dict[str, dict], List[str]]:` Reads CSV data safely. +- `def validate_token(token):` Returns `True` if the token exists. +- `def is_teacher_token(token):` Returns `True` if the token belongs to the first row (the teacher). +- `def get_student_progress(token):` Returns a dictionary of lesson progress for a specific token. +- `def update_student_progress(token, lesson_name, status="completed"):` Writes progress back to the CSV. + +### Lesson Service (`services/lesson_service.py`) +Parses Markdown files to extract content and configuration. +- `def get_ordered_lessons_with_learning_objectives(progress=None):` Returns lessons ordered as they appear in `home.md`, optionally injected with user progress status. +- `def render_markdown_content(file_path):` The core parsing function. Uses regex to extract markers like `---INITIAL_CODE---`, `---VELXIO_CIRCUIT---`, etc. It identifies the `active_tabs` needed for the frontend. +- `def _parse_flashcards(text):` Specifically parses `---QUIZ_FLASHCARD---` blocks into a structured JSON array for the frontend MCQ/Flashcard component. + +## Compiler Framework (`compiler/`) + +The compilation logic is abstracted via a factory pattern. + +- `class CompilerFactory:` (`compiler/__init__.py`) + - `def get_compiler(self, language):` Returns the appropriate `BaseCompiler` instance (e.g., `CCompiler` or `PythonCompiler`). +- `class BaseCompiler(ABC):` (`compiler/base_compiler.py`) + - `def compile(self, code, timeout=10):` Abstract method. + - `def run(self, file_path, timeout=5):` Abstract method. +- `class CCompiler(BaseCompiler):` and `class PythonCompiler(BaseCompiler):` + Implementation wrappers that construct payloads and send HTTP requests to the `compiler-worker` container (`http://compiler-worker:8080/execute`). diff --git a/docs/03-frontend-sveltekit.md b/docs/03-frontend-sveltekit.md new file mode 100644 index 0000000..0ee3870 --- /dev/null +++ b/docs/03-frontend-sveltekit.md @@ -0,0 +1,39 @@ +# 03. Frontend (SvelteKit) + +The frontend is built using SvelteKit and Vite. It utilizes Svelte 5 for its reactivity model. + +## Framework & State Management + +The frontend uses two main state management patterns: +1. **Svelte 5 Runes (`$state`, `$derived`, `$effect`)**: Used extensively in `.svelte` and `.svelte.ts` files. For instance, the lesson view uses `lessonState.svelte.ts` to manage all reactive data (active tabs, compilation status) outside of the UI components, moving away from a "God Component" architecture. +2. **Writable Stores**: Used in standard `.ts` files (e.g., `lib/stores/auth.ts`, `lib/stores/theme.ts`) where Runes are not processed by the Svelte compiler. + +## API Services (`lib/services/api.ts`) + +This module provides wrappers for all backend calls. In production, SvelteKit uses `hooks.server.ts` to proxy requests starting with `/api/` to the Flask backend. + +- `export function login(token: string, customFetch = fetch)` +- `export function logout(customFetch = fetch)` +- `export function validateToken(token: string, customFetch = fetch)` +- `export function getLessons(customFetch = fetch)` +- `export function getLesson(slug: string, customFetch = fetch, token = '')` +- `export function getKeyText(filename: string, customFetch = fetch)` +- `export function compileCode(req: CompileRequest, customFetch = fetch)` +- `export function trackProgress(lessonName: string, status: string = 'completed', customFetch = fetch)` +- `export function resetProgress(lessonName: string, customFetch = fetch)` + +## Key Components + +- **`LessonWorkspace.svelte`**: The main presentational component for the interactive lesson area. It wraps the editor, output panels, and tab switchers. +- **`CodeEditor.svelte`**: Wraps CodeMirror 6. It is lazy-loaded to reduce the initial bundle size and provides syntax highlighting for C and Python. It also implements strict anti-paste measures. +- **`VelxioIframe.svelte`**: Isolates the initialization of the `VelxioBridge`, the `postMessage` logic, and auto-save capabilities specific to the Arduino simulator. +- **`CircuitEditor.svelte`**: Wraps the Falstad CircuitJS simulator (a GWT-compiled app) inside an iframe. It mounts a transparent `CrosshairOverlay.svelte` on touch devices to enable precise interactions by translating touch events to synthetic mouse events. + +## Security & Anti Copy-Paste + +To prevent students from copying lesson text or pasting external code: +1. **`lib/actions/noSelect.ts`**: A Svelte action that applies CSS (`user-select: none`) and attaches DOM event listeners (`onselectstart`, `oncopy`, `oncontextmenu` calling `preventDefault()`) to the lesson content. +2. **Code Editor Defenses**: `CodeEditor.svelte` implements multiple layers: + - DOM handlers for `paste`, `drop`, and `beforeinput`. + - CodeMirror transaction filters to block `input.paste` and heuristics (e.g., blocking inserts > 20 characters or > 2 lines). + - Clipboard API overriding when available. diff --git a/docs/04-lesson-evaluation.md b/docs/04-lesson-evaluation.md new file mode 100644 index 0000000..3a4186a --- /dev/null +++ b/docs/04-lesson-evaluation.md @@ -0,0 +1,43 @@ +# 04. Lesson Evaluation + +The LMS determines the type of lesson and how to evaluate it based on specific markers found in the Markdown content. + +## Markdown Markers + +| Mode | Marker | Evaluation Logic | +|------|--------|------------------| +| **C / Python** | `---INITIAL_CODE---` / `---INITIAL_PYTHON---` | Standard stdout matching against `---EXPECTED_OUTPUT---` and presence of `---KEY_TEXT---`. | +| **Circuit** | `---INITIAL_CIRCUIT---` | Node voltage matching against `---EXPECTED_CIRCUIT_OUTPUT---` and `---KEY_TEXT_CIRCUIT---`. | +| **Arduino (Velxio)** | `---INITIAL_CODE_ARDUINO---` | Serial output sequence matching, lenient graph wiring comparison, and `---KEY_TEXT---`. | +| **Quiz** | `---QUIZ_FLASHCARD---` | State completion tracking (all questions answered correctly). | + +## Evaluators (`lib/services/`) + +The evaluation logic is isolated into specific service files: + +### General & C/Python (`evaluators.ts`, `exercise.ts`) +- `export function checkKeyText(code: string, keyText: string): boolean` + Checks if all lines in the `keyText` are present in the provided `code`. +- `export function processLanguageEvaluation(...)` + Coordinates the compilation request and output verification for C and Python. + +### Circuit Evaluation (`evaluators.ts`, `exercise.ts`) +- `export function evaluateCircuitSubmission(...)` + Handles the flow of extracting the circuit state. +- `export function validateNodes(actualVoltages: Record, expectedNodes: Record): boolean` + Validates if the actual node voltages match the expected voltages within a specified tolerance. + +### Arduino/Velxio Evaluation (`velxio-evaluator.ts`, `velxio-bridge.ts`) +- `class VelxioBridge` (`velxio-bridge.ts`) + Manages the `window.postMessage` protocol between the LMS and the Velxio iframe. + - Commands: `elemes:load_code`, `elemes:load_circuit`, `elemes:get_source_code`, `elemes:get_serial_log`, `elemes:get_wires`. + - Events: `velxio:ready`, `velxio:compile_result`. +- `export function evaluateVelxioSubmission(...)` + Orchestrates the 3-part Arduino evaluation: + 1. **Key Text**: Checks the retrieved source code. + 2. **Serial Output**: Uses `matchSerialSubsequence(actual, expected)` to ensure expected log lines appear in the correct order. + 3. **Wiring**: Performs a lenient graph comparison (expected edges must exist; extra edges are allowed; ground pins are normalized). + +### Flowchart Evaluation (`flowchart-evaluator.ts`) +- `export function evaluateFlowchartSubmission(...)` + Parses flowchart JSON data and verifies structural correctness against the expected model.