add : docomentation
This commit is contained in:
parent
7384b6e585
commit
9e5617274e
|
|
@ -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.
|
||||
|
|
@ -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/<slug>.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/<slug>`)
|
||||
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`).
|
||||
|
|
@ -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.
|
||||
|
|
@ -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<string, number>, expectedNodes: Record<string, NodeResult>): 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.
|
||||
Loading…
Reference in New Issue