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