Skip to content

Architecture decisions

Generated from docs/decisions/*.md

Project-wide decisions for ulams, in MADR format. Decisions that only concern one application live next to it (api/docs/adr, admin/docs/adr, front/docs/adr; those are retroactive records mined from the pre-monorepo history).

Workflow (see CLAUDE.md): the agent proposes an ADR with status Proposed; the product owner approves it, which changes the status to Accepted. Superseded records stay and link to their replacement.

The index below is generated from each record’s title and Status: line: run node scripts/adr-index.mjs (or yarn adr:index) after adding or changing a record, never edit the rows by hand. CI fails when it is stale.

This list is built from the files in docs/decisions on every build, so a new ADR appears here with its status as soon as it is merged. How to write one: Decisions and documentation.

# Decision Status Date
0001 Monorepo with vendored packages Accepted (2026-10-08) 2026-10-08
0002 Rename EscolaLMS / Wellms to ulams Accepted (2026-10-08) 2026-10-08
0003 H5P as an isolated GPL service (Lumi) Accepted (2026-10-08) 2026-10-08
0004 Theming with CSS custom properties, no styled-components Accepted (2026-10-08) 2026-10-08
0005 Turborepo and Yarn workspaces Accepted (2026-10-08) 2026-10-08
0006 Remove the recommender package Accepted (2026-10-08) 2026-10-08
0007 Tenancy: database per tenant, provisioned by the tenancy package Accepted (2026-10-08) 2026-10-08
0008 Reference frontend: Astro SSR, framework-free SDK, schema-described UI catalogue Accepted (2026-10-09) 2026-10-08
0009 LLM layer: an ai package on the official Anthropic SDK Accepted (2026-10-09) 2026-10-08
0010 Course Builder: a versioned Course Blueprint applied through domain services Accepted (2026-10-09) 2026-10-08
0011 Builder streaming: AG-UI events over SSE from Laravel, carrying A2UI surfaces Accepted (2026-10-09) 2026-10-08
0012 LTI 1.3: one lti package, first-party platform side, packbackbooks tool side Accepted (2026-10-09) 2026-10-09
0013 Adapt Path B: JSON sources in the API, builds in an isolated GPL-3.0 worker Accepted (2026-10-09) 2026-10-09
0014 Third-party packages run on a per-tenant content origin, files served through the API Accepted (2026-10-09) 2026-10-09
0015 H5P service per tenant: derived internal token, platform-only libraries, least-privilege mounts Accepted (2026-10-09) 2026-10-09
0016 LiaScript: versioned Markdown documents played without a SCORM package Accepted (2026-10-09) 2026-10-09
0017 One upload guard and safe extractor for every upload path Accepted (2026-10-09) 2026-10-09
0018 External content completes topics; completion events fire after progress is saved Accepted (2026-10-09) 2026-10-09
0019 Conformance against real LMSs and builders in an opt-in nightly workflow Accepted (2026-10-09) 2026-10-09
0020 Public comparison with other learning platforms: sourced data, neutral values Accepted (2026-10-09) 2026-10-09
0021 High-availability reference architecture Accepted (2026-10-09) 2026-10-09
0022 Course Builder studio in the reference web app, with its own author session Accepted (2026-10-09) 2026-10-09
0023 A2UI surfaces travel as AG-UI activity snapshots (a2ui-surface) Accepted (2026-10-09) 2026-10-09
0024 Fake LLM driver: normalised cassettes and synthetic answers Accepted (2026-10-09) 2026-10-09
0025 How a Course Blueprint maps to LMS entities Accepted (2026-10-09) 2026-10-09
0026 A first-party DOCX converter instead of PhpWord Accepted (2026-10-09) 2026-10-09
0027 Course Builder access: one permission, author acts, admins look Accepted (2026-10-09) 2026-10-09
0028 Generation stages, grounding check and quiz support check Accepted (2026-10-09) 2026-10-09
0029 The SSE endpoint wakes on a cache key, not Valkey pub/sub Accepted (2026-10-09) 2026-10-09
0030 Living Course: source revisions and update proposals on top of the Course Blueprint Accepted (2026-10-09) 2026-10-09
0031 Fragment-level change detection is deterministic Accepted (2026-10-09) 2026-10-09
0032 Source connectors as plugins; Git through host APIs; one SSRF-safe HTTP client Accepted (2026-10-09) 2026-10-09
0033 Progress preservation rules for content updates Accepted (2026-10-09) 2026-10-09
0034 A tamper-evident audit trail for Living Course Accepted (2026-10-09) 2026-10-09
0038 Brand identity: Orbital Folio Proposed (2026-10-09) 2026-10-09
0039 Author preview of draft courses runs on its own routes with the author’s token Proposed 2026-10-09
0040 PostgreSQL 17 with a tested dump-and-restore upgrade Proposed 2026-10-09
0041 SeaweedFS replaces MinIO; per-tenant S3 identities; server-side reads use the internal endpoint Proposed 2026-10-09
0042 No WebSocket server: Soketi and Pusher removed, Reverb only when a feature needs push Proposed 2026-10-09
0043 An enforced morph map with stable aliases for polymorphic types Proposed 2026-10-09
0044 Content Security Policy: report collector, enforcement, tool origins from the API Proposed 2026-10-09
0045 H5P learner state through the BFF; no API token in the browser Proposed 2026-10-09
0046 cmi5 on the content origin with a one-time launch token and an LRS-only session token Proposed 2026-10-09
0047 OpenAPI as PHP attributes; doctrine/annotations removed; spec snapshot test Proposed 2026-10-09
0048 Course sites: publish into the current site by default; new sites through provisioning and session transfer Proposed 2026-10-09
0049 A CommerceProvider interface before Sylius, with a Wellms cart adapter Proposed 2026-10-09
0050 Lesson content-type registry: deterministic LiaScript rendering and allow-listed H5P libraries Proposed 2026-10-09
0051 Critic loop with a retry budget and an isolated Playwright solvability runner Proposed 2026-10-09
0052 Learner layouts as a Layout topic type rendered from the catalogue Proposed 2026-10-09
0053 Simulations: single-file HTML on the content origin, sandboxed, typed postMessage, off by default Proposed 2026-10-09
0054 Component playground in the docs site instead of Storybook Proposed 2026-10-09
0055 Course experiments with delayed retention, surveys and a tenant-level consent model Proposed 2026-10-09
0056 Admin and legacy front served by nginx-unprivileged with runtime JSON config Accepted 2026-10-09
0057 learner-insights package: an append-only signal stream keyed by blueprint element IDs Proposed 2026-10-09
0058 Rule-based risk scoring with reasons behind a RiskScorer interface Proposed 2026-10-09
0059 Personal remediations: learner-scoped, grounded, cached per struggle pattern Proposed 2026-10-09
0060 AI tutor: course-scoped full-text retrieval, citations and an attempt guard Proposed 2026-10-09
0061 Personalisation privacy: off by default, opt-out or consent, minimal data, explainable, erasable Proposed 2026-10-09
0062 Adaptive interface as a presentation profile over catalogue components Proposed 2026-10-09
0063 Tenants inherit the platform AI settings, with per-tenant overrides Proposed 2026-10-09
0064 The studio reports “applied” only from authoritative state Proposed 2026-10-09
0065 Demo login supports the tutor role Proposed 2026-10-09
0066 init.sh never regenerates an existing APP_KEY Proposed 2026-10-09
0067 The quiz time limit default is read from ulams_gift_quiz.max_quiz_time Proposed 2026-10-09
0068 The scheduler loop claims each minute with a shared cache lock Proposed 2026-10-09
0069 CI typechecks, lints and tests the web app, ui and sdk Proposed 2026-10-09
0070 The admin runs umi/max on Node 24 through a small shim Proposed 2026-10-09
0071 API security hardening: auth on admin routes, allow-listed payment input, bounded group walks Proposed 2026-10-09
0072 The agent-first ulams CLI: one command registry generates the parser, help, describe, MCP tools and docs Proposed 2026-10-09
0073 CLI machine contract: JSON envelope, NDJSON, exit codes and error codes Proposed 2026-10-09
0074 Scoped personal access tokens with an agent audit log and Idempotency-Key Proposed 2026-10-09
0075 Device login with our own RFC 8628 flow approved in the web app; Passport’s device grant stays off Proposed 2026-10-09
0076 ulams mcp: a local MCP server (spec 2026-07-28, SDK v2) generated from the CLI registry Proposed 2026-10-09
0077 CLI distribution: npm, bun-compiled binaries and a Docker image; no telemetry Proposed 2026-10-09
0078 A platform-only HTTP API for tenant management Proposed 2026-10-09
0079 Course-as-code: Markdown with directives + YAML, Blueprint v2 and a committed sync base Proposed 2026-10-09
0080 Interactive preview in the studio: learner pages from the blueprint, in a frame Proposed 2026-10-09
0081 ulams:upgrade: an idempotent per-tenant upgrade command with a step registry Proposed 2026-10-09
0082 Quiz attempt deadline holds on every queue driver Proposed 2026-10-09
0083 Course Builder: a stage change is one transaction under the run lock Proposed 2026-10-09
0084 CLI and MCP commands for the course builder and Living Course Proposed 2026-10-09
0085 The platform tenant API: operations, permission and what stays off Proposed 2026-10-09
0086 Interactive topic type: author-uploaded JavaScript packages in an opaque sandbox on the content origin Proposed 2026-10-09
0087 The ulams-ix bridge protocol and the @ulams/interactive-bridge library (MIT) Proposed 2026-10-09
0088 Content packages under demo-content/, played only as sandboxed content Proposed (amended 2026-10-09) 2026-10-09
0089 Six demo academies: three free interactive courses, one theme preset each, sourced content, EN/PL as two courses Proposed 2026-10-09
0090 Living Course: choices made during implementation Proposed 2026-10-09
0091 Shared hosting: cron-driven workers and an operator-created tenant database Proposed 2026-10-09
0092 Production reference: one VPS behind Cloudflare, flat tenant hosts, a tunnel and R2 Proposed 2026-10-09
0093 A public showcase endpoint and hero interactives on the demo landings Proposed 2026-10-09
0094 Interactive demo courses are written as Markdown module files and seeded through the domain services Proposed 2026-10-10
0095 The Ulam course: every statement traced to a fact sheet, sources numbered, four licensed photographs Proposed 2026-10-10
0096 The product landing in Polish and Simplified Chinese: Astro i18n routing, one document per language Proposed 2026-10-10

Retroactive records mined from the history of each application before the monorepo: