Перейти до вмісту

Developer documentation

Guides for people changing the code. The deep, always-current reference is CLAUDE.md at the repository root: every route, table, setting key, admin screen and gotcha is described there. These pages are the shorter, task-shaped entry points into it.

  • One Node.js 20 process (src/server.js → src/lib/createServer.js) running an Express 5 app, server-rendered with EJS. No frontend build step, no bundler; the plain CSS and JS files in public/ are joined in memory at boot into /site.css and /site.js.
  • SQLite (better-sqlite3, synchronous) is the only store: DATA_DIR/site.db plus uploads in DATA_DIR/uploads/. Migrations are plain .sql files applied at startup.
  • src/app.js is the composition root: createApp({ content, mail, log, env, db, … }) wires routers that are all factories receiving their dependencies — which is what makes every test an in-process supertest call against an in-memory database.
  • The public site reads through one SqliteContentRepository (src/content/) and renders via res.renderPage(view, data) into src/views/layouts/base.ejs.
  • The admin panel (/admin, src/admin/) is a separate router with its own session store (SQLite), CSRF, role checks (admin / editor), audit log and error pages.
  • Uploads go through a single choke point, src/services/FileStorage.js (content sniffing, WebP re-encoding, delete guard).
  • Background work runs inside the app: the backup scheduler, the daily update check, the recycle-bin purge and the nightly upload maintenance. No cron.
  • A strict CSP (no 'unsafe-inline' anywhere) shapes the front end: no inline styles or scripts.
  • Everything a school changes lives in the database (settings, menu, pages, theme) or in .env (domain, mail, secrets). The code contains no installation-specific data (enforced by test/neutralTemplate.test.js).
  • Production is Docker Compose: the app image from GHCR, nginx with Let’s Encrypt, certbot.
Page What it covers
architecture.md Request flow, layers, where things live
data-model.md Tables, relations, soft delete, settings, files, search index
adding-a-page-type.md What to touch to add a new kind of page
writing-a-migration.md Migration rules and the traps SQLite sets
testing.md The test loop, node:test conventions, test helpers, accessibility check
release-process.md Changelog, version bump, tag, workflows, GHCR, rollback
licensing.md The chosen licence (AGPL-3.0-only), why, and dependency compatibility
publishing-checklist.md What to do before the repository goes public
public-snapshot.md How the public repository is produced from this tree, what it leaves out

See also: CONTRIBUTING.md, SECURITY.md, DEPLOYMENT.md (continuous deployment from an installation’s own repository, and how to cut a release; in Ukrainian) and the Ukrainian install guide for other schools.