No description
  • TypeScript 52.1%
  • JavaScript 41.7%
  • SCSS 3.7%
  • CSS 2.3%
  • Shell 0.1%
Find a file
Dennis fed9cc3982
Some checks are pending
Quality and release checks / deployment-contract (push) Waiting to run
Quality and release checks / check (push) Waiting to run
(f) safely reclaim unused worksheet image files
Track uploaded and existing worksheet assets, report unused files by default,
and permit explicit deletion only after a 30-day grace period and fresh
reference checks. Protect versions, publications, trash and active editor
history without exposing inaccessible records through the hold endpoint.

Fail closed on missing publication files, preserve concurrently renewed
holds, and batch large editor histories within both endpoint limits.
Document runtime modes, CLI commands, deployment, backups and retention
limits in the backend docs and environment examples.

Validation: full npm run check:release, including 546 unit tests, 130 offline
browser tests, 43 backend browser tests, backend integration (56 asset
checks), static checks and production builds. Tests use temporary backend
data; no production cleanup or backup configuration was changed.
2026-11-06 14:19:28 +00:00
.forgejo/workflows ci(release): Tag-Pipeline nutzt dieselbe Prüfung wie release:deploy 2026-10-29 20:30:12 +00:00
.github/workflows feat(deploy): gemeinsamen Rootless-Pod-Vertrag vorbereiten 2026-10-26 12:39:42 +00:00
.vscode (+) vscode settings 2026-10-19 06:49:54 +02:00
assets (f) Listings in Tabellenzellen und Listing-Titel am Seitenende 2026-11-05 08:37:50 +00:00
backend (f) safely reclaim unused worksheet image files 2026-11-06 14:19:28 +00:00
containers (f) safely reclaim unused worksheet image files 2026-11-06 14:19:28 +00:00
docs (f) safely reclaim unused worksheet image files 2026-11-06 14:19:28 +00:00
examples (d) clarify SPARK-E setup and keep screenshots replaceable 2026-11-06 13:24:07 +00:00
frontend-checks@e74a5e7684 (c) update frontend-checks submodule to latest public release 2026-10-24 20:19:23 +00:00
licenses build(deps): Bibliotheken aktualisieren und Node 26 vereinheitlichen 2026-10-26 11:52:01 +00:00
messages (c) readonly fixes 2026-11-05 13:53:38 +00:00
project.inlang (+) Initial commit 2026-06-20 15:10:13 +02:00
public feat(deploy): gemeinsamen Rootless-Pod-Vertrag vorbereiten 2026-10-26 12:39:42 +00:00
scripts (f) safely reclaim unused worksheet image files 2026-11-06 14:19:28 +00:00
services (f) support JPEG XL uploads and PDF rendering 2026-11-06 13:24:28 +00:00
src (f) safely reclaim unused worksheet image files 2026-11-06 14:19:28 +00:00
test (+) legal: add impressum and datenschutz standard, update documentation and SPDX headers 2026-10-24 20:46:05 +00:00
tests (f) safely reclaim unused worksheet image files 2026-11-06 14:19:28 +00:00
.env.development (+) add SPDX license and copyright headers (GPL-3.0-or-later) 2026-10-24 09:56:22 +00:00
.env.template (f) safely reclaim unused worksheet image files 2026-11-06 14:19:28 +00:00
.gitignore (+) legal: add impressum and datenschutz standard, update documentation and SPDX headers 2026-10-24 20:46:05 +00:00
.gitmodules (+) legal: add impressum and datenschutz standard, update documentation and SPDX headers 2026-10-24 20:46:05 +00:00
AGENTS.md build(deps): Bibliotheken aktualisieren und Node 26 vereinheitlichen 2026-10-26 11:52:01 +00:00
biome.jsonc build(deps): Bibliotheken aktualisieren und Node 26 vereinheitlichen 2026-10-26 11:52:01 +00:00
CHANGELOG.md (r) Version 1.3.3-beta.1 2026-11-06 11:45:08 +00:00
CONTRIBUTING.md build(deps): Bibliotheken aktualisieren und Node 26 vereinheitlichen 2026-10-26 11:52:01 +00:00
flake.lock (c) dev-sandbox: weitergeleitete Ports in der Gast-Firewall öffnen 2026-11-06 09:08:05 +00:00
flake.nix (c) Dev-Server nennt beim Start die Adresse vom Rechner aus 2026-11-06 09:08:06 +00:00
frontend-checks.config.mjs refactor: separate persistence and library responsibilities with strict types 2026-10-25 18:44:19 +00:00
index.html (+) add SPDX license and copyright headers (GPL-3.0-or-later) 2026-10-24 09:56:22 +00:00
LICENSE (c) updates 2026-09-13 12:37:08 +02:00
mise.toml feat(release): Version vorbereiten und Lieferung bauen trennen 2026-10-29 20:30:11 +00:00
package-lock.json (r) Version 1.3.3-beta.1 2026-11-06 11:45:08 +00:00
package.json (r) Version 1.3.3-beta.1 2026-11-06 11:45:08 +00:00
paraglide.config.js (+) add SPDX license and copyright headers (GPL-3.0-or-later) 2026-10-24 09:56:22 +00:00
playwright.config.ts build(deps): Bibliotheken aktualisieren und Node 26 vereinheitlichen 2026-10-26 11:52:01 +00:00
README.md feat(release): Version vorbereiten und Lieferung bauen trennen 2026-10-29 20:30:11 +00:00
renovate.json feat(deploy): gemeinsamen Rootless-Pod-Vertrag vorbereiten 2026-10-26 12:39:42 +00:00
SECURITY.md (c) Entwickler- und Agent-Einstieg vereinheitlichen, Review-Abschluss dokumentieren 2026-10-25 18:51:57 +00:00
THIRD_PARTY_NOTICES.md build(deps): Bibliotheken aktualisieren und Node 26 vereinheitlichen 2026-10-26 11:52:01 +00:00
tsconfig.app.json refactor: separate persistence and library responsibilities with strict types 2026-10-25 18:44:19 +00:00
tsconfig.json refactor: separate persistence and library responsibilities with strict types 2026-10-25 18:44:19 +00:00
tsconfig.node.json refactor: separate persistence and library responsibilities with strict types 2026-10-25 18:44:19 +00:00
tsconfig.types.json refactor: separate persistence and library responsibilities with strict types 2026-10-25 18:44:19 +00:00
vite.config.ts (f) support JPEG XL uploads and PDF rendering 2026-11-06 13:24:28 +00:00
vitest.config.ts build: enforce reproducible release checks and ship complete license notices 2026-10-25 18:46:55 +00:00

einfachmalab

HTML worksheet, class test, and exam editor built with SolidJS, Vite, Paraglide i18n, and XLSX export. Runs standalone in the browser via localStorage or connected to a PocketBase backend and a Playwright PDF service.

Worksheets compile to a custom-element vocabulary (<exercise-*>, <field-*>) rendered by a framework-free runtime in assets/. Exported files load the runtime from assets.dencla.de or bundle it inline for single-file offline use.

See it in action

From the worksheet library to an edited block, A4 print layout, PDF download, and an Excalidraw drawing embedded in the worksheet. This 30-second walkthrough uses the German interface and demo data on an isolated local test server.

Workflow: browse worksheets, open and edit a block, inspect the print and solution layouts, export a PDF, and create an Excalidraw drawing

Selected highlights — click a screenshot to see it at full size:

Worksheet library and sharing Edit blocks with a live preview Draw directly with Excalidraw
Shared worksheets with page previews, categories, and access levels Selected exercise block with editable text and answer-field settings Excalidraw editor with a flow diagram from graph to equation

Capture details: README media.

Quickstart

Host prerequisites: KVM access and Nix flakes.

# Host setup (once)
sudo usermod -aG kvm $USER
mkdir -p ~/.config/nix && echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
cp .env.template .env

# Start VM (forwards ports 5173, 4173, 8090, 8091, 5180; SSH on port 2200 as user dev)
nix run --impure

# Inside VM
mise run setup
mise run dev           # http://localhost:5173 (starts Vite, PocketBase, and PDF service)

Local Development (without VM)

Requires Node 26.12.1 (mise install), npm, mise and unzip. Setup installs or verifies PocketBase and Chromium:

mise run setup         # installs/verifies backend/pocketbase and Chromium too
mise run dev

Development Logins

Target Login Password
Editor (seeded user) test@einfachmalab.local testtest1234
PocketBase Admin (:5173/_/ or :8090/_/) dev@einfachmalab.local devdevdev123

Common Tasks (mise run <task>)

Task Description
setup Install dependencies, compile i18n, verify PocketBase/Chromium, create .env from template
dev Start Vite dev server (:5173), PocketBase (:8090), and PDF service (:8091)
check Sequential release gate: lint, licenses, static checks, strict types, unit, offline/backend E2E, integration and build
lint Check formatting and code style with Biome
typecheck Type-check TypeScript code with tsc -b
check:frontend Static a11y, contrast, CSS module, token, and layer checks via @dencla/frontend-checks
test:unit Run unit tests with Vitest
test Run Playwright end-to-end tests
test:backend Run integration and browser tests with temporary PocketBase data and an isolated PDF service
build Create production bundle in dist/
release:prepare <version> Set the version, update the changelog, commit, and tag v<version> (no build, no push)
release:deploy <tag> Verify and build the tagged clean checkout into deploy/ and release/einfachmalab-<tag>.tar.zst
test:containers Build and probe all roles rootless from deploy/

Repository Structure

Path Purpose
src/api/ SDK/HTTP transport, authentication and document/file persistence
src/core/ Document model, renderer, sandboxed preview overlay, importers, and exporters
src/blocks/ Worksheet building blocks (exercises, text, figures, headers)
src/fields/ Exercise answer fields (in-place, replaces, beside)
src/components/ Editor shell, library, inspector, and navigation UI
src/store/ SolidJS reactive stores, commands, shortcuts, and navigation state
src/legal/ Legal notice and privacy policy Markdown templates and local texts
src/styles/ SCSS design tokens, theme mixins, and layout rules
assets/ Standalone rendering runtime (assets/arbeitsblatt/), fonts, and vendored libraries
backend/ PocketBase schema migrations, hooks, and integration tests
services/pdf/ Playwright-based headless Chromium PDF rendering service
examples/ Sample worksheets and reference documents
tests/ Unit (tests/unit/) and E2E (tests/e2e/) test suites
docs/ Architecture, data model, and deployment specifications

Key Architecture Concepts

  • Sandboxed Double-Buffered Preview (src/core/preview/): The preview iframe is sandboxed without allow-same-origin. The editor interacts exclusively via postMessage. Structural changes render in a hidden background iframe and swap on ws:ready to preserve scroll and focus.
  • Layout Stability: Switching between task and solution modes never causes pagination reflow. In-place answers overlay allocated task space, and solution elements maintain fixed dimensions.
  • Flat Block Hierarchy: Document blocks exist in a flat array where parent-child relationships and contiguous subtree ordering are validated by invariant checks (src/core/worksheet/nesting.ts).

Betrieb

Debian 13: rootless Pod einfachmalab (UID 10011), Domain ab.dencla.de, Profil solidjs-pb. Rollen web (127.0.0.1:11180 → 8080), pb (127.0.0.1:11190 → 8090), pdf (nur im Pod: 127.0.0.1:8091). Persistente Daten: /srv/einfachmalab/pb_data; Konfiguration: /etc/apps/einfachmalab/{pb,pdf}.env, Beispiele unter containers/env/. SMTP wird in PocketBase konfiguriert (sys-einfachmalab, mail.d0b.de:465).

mise run release:deploy v<version> liefert das mit Manifest und Prüfsummen versehene Bundle für app deploy (Releases); mise run test:containers (nach Erstellen von deploy/) prüft alle Rollen rootless. Das Server-Repo d0b-infra verwaltet app, zentrale Caddy-Snippets und den Host. Entwicklung, CI und PDF nutzen Node 26; PDF verwendet Debian-Chromium. Besonderheiten: opake Vorschau, Veröffentlichungen unter /p/* mit Sandbox-CSP, Runtime-CORS und separater öffentlicher Assetspiegel. Vollständige Abläufe und Abnahme: Deployment. Die Vertragsprüfung unterscheidet gemeinsame Regeln und Profile; der Abnahmestand hält bestandene Prüfungen und offene Integrationspunkte fest.

Contributing and verification

Read CONTRIBUTING.md, AGENTS.md and the coding standards. Run npm run check:release for the complete sequential release gate, including isolated backend tests. Heavy tasks must not run concurrently on the 4 GB VM. Private vulnerability reports: SECURITY.md.

License

GPL-3.0-or-later for application code, runtime, and examples. See LICENSE. Third-party libraries, fonts, and assets retain their upstream licenses; see THIRD_PARTY_NOTICES.md. Builds, deployment bundles and offline HTML include their notices.