6.0 KiB
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)
├── /playground → Interactive Playground (SvelteKit)
│
▼
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"
├── Interactive Playground (route /playground) — PTY sessions, FileTree, stdinQueue
├── Embed pipeline (```embed fence → bleach sanitize → iframe render)
├── 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 (PostgreSQL)
├── 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
├── backups/ # PostgreSQL dumps (./elemes.sh dbbackup)
├── state/ # State Tailscale (auto-generated)
└── elemes/ # Folder engine LMS (JANGAN DIUBAH)
├── elemes.sh # Script untuk menjalankan LMS
└── ...
Akun siswa & guru tersimpan di PostgreSQL (container
postgres) — tidak ada file CSV token. Akun guru dikelola via./elemes.sh teacher.
Setup and Execution
The primary entry point for managing the system is the elemes.sh script located in the elemes folder.
-
Initialization:
cd elemes ./elemes.sh initGenerates
.env,content/,assets/, andstate/from examples (no token files — accounts live in PostgreSQL). Safe to run multiple times. -
Configuration: Edit
../.envto set branding and Tailscale configuration:APP_BAR_TITLE=Pemrograman C - SMK Nusantara COPYRIGHT_TEXT=SMK Nusantara @ 2025 PAGE_TITLE_SUFFIX=SMK Nusantara CONTENT_DIR=content TEACHER_NAME=Guru LMS # default teacher display name TEACHER_TOKEN= # teacher token for non-interactive first-run bootstrap # (leave empty to create the account later via ./elemes.sh teacher) ELEMES_HOST=lms-smk-nusantara TS_AUTHKEY=tskey-auth-xxxx -
Running the Application:
./elemes.sh runbuild # Build images and start containers ./elemes.sh run # Start containers without rebuilding ./elemes.sh stop # Stop all containers -
Managing Users: The system keeps a single canonical teacher account (used to access the
/progressdashboard). Create or update it with:./elemes.sh teacherIt prompts for a display name (Enter =
TEACHER_NAMEfrom.env, default "Guru LMS") and a hidden token via stdin. It upserts the account: creates it when none exists, updates the name and rotates the token when the account exists, and only updates the name when the token is unchanged (idempotent).Student accounts are managed from the
/progresspage via round-trip CSV (export → edit → import).Automatic first-run:
runbuild/run/runclearbuildautomatically run schema migrations (alembic upgrade head) on startup, and bootstrap the teacher account whenTEACHER_TOKENis set in.env. IfTEACHER_TOKENis empty, the app starts without a teacher account — the operator just runs./elemes.sh teacher.
Security Overview
The system incorporates several security layers to ensure stability and safety:
- Isolated Execution: User-submitted C and Python code runs inside a
compiler-workercontainer protected by a gVisor (runsc) sandbox, preventing RCE attacks from reaching the host kernel. - 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.
- Cookie Security: The
student_tokensession cookie useshttponly: true,samesite: 'Lax', and dynamically setssecure: truebased on theCOOKIE_SECUREenvironment variable.