121 KiB
BUILD PROMPT: "CompetenceTrack" — A Free, Open-Source School Competency & Grading Platform (Digidoo Clone)
0. Context & Mission
You are building a full-stack web application called CompetenceTrack (working name — feel free to suggest alternatives). It is a free, open-source, donation-funded school project, inspired by the commercial product Digidoo (digidoo.com). The goal is to give teachers a digital tool to:
- Track student competencies ("Kompetenzraster" / competency grids) instead of paper checklists.
- Link individual assessments/performance checks to specific competencies.
- Visualize each student's progress with a radar/flower chart ("Competence Flower").
- Auto-generate report cards / progress reports with one click.
- Optionally calculate grades from weighted competencies and assessments.
This project is not for profit — it will be given away for free to schools, and any support the project receives will go toward the school. Because of this:
- No paid tiers, no license checks, no telemetry/tracking, no vendor lock-in.
- Prioritize simplicity, low hosting cost, and easy self-hosting (a school or a single teacher should be able to run this on a small VPS or even a Raspberry Pi).
- Database must be SQLite (see §4) — no external DB server required.
- Code must be clean, well-documented, and easy for future student/volunteer contributors to maintain.
1. Reference Product Analysis (what we are learning from, NOT copying verbatim)
Digidoo (https://www.digidoo.com/de/) is a German/Austrian EdTech SaaS. Do not copy their branding, illustrations, exact wording, logo, or any copyrighted text/images — this must be an original UI/UX and original copywriting, only inspired by the feature set and workflow concept. Core concepts observed on their site that we want to reproduce functionally:
- Competency grids ("Kompetenzraster"): Pre-built and customizable sets of subject/grade-level competencies (e.g., per state curriculum, per subject, per grade level) that teachers can use as templates or fully customize.
- Learning progress entries: Teachers log individual observations/entries per student, linking them to one or more competencies, over time (a running log, not a single snapshot).
- Performance assessments ("Leistungsfeststellung"): Structured tests/assignments/checks that are linked to competencies, feeding into the same student timeline.
- Competence Flower ("Kompetenzblume"): A radar/spider chart per student showing strength per competency category — "the bigger the petal, the stronger the performance" — used for parent-teacher conferences and progress meetings.
- One-click reports: Automatically generated, competency-based report text (not generic phrases) and full report-card documents (PDF) — no copy-pasting or manual formatting.
- Grade management ("Notenverwaltung"): Configurable weighting between learning-progress entries and formal assessments to compute a transparent final grade — the teacher decides the weighting formula, not a black box.
- Role/permission system: Teachers, school administrators, groups/classes, subject hand-offs when a student changes teacher or school.
- Multi-school-type support: Elementary school, middle school (Sekundarstufe I), high school/Gymnasium (Sekundarstufe II) — different competency catalogs and grading rules per school type/grade band.
- Data portability: Users can export all their data (competencies, entries, reports) at any time in common formats (CSV/JSON/PDF).
- Free tier that "just works": A permanently free "Basis" plan with core functionality — since our whole project is free, we implement this as simply "the whole app, free, no tiers."
We are explicitly excluding from scope (not needed since this is free/single-org, not a multi-tenant SaaS business):
- Billing/subscriptions/Stripe integration.
- Marketing site, SEO landing pages, blog/CMS ("Wissenswertes" articles), press page.
- SSO/enterprise integrations (WebUntis, etc.) — keep as a "future idea," not MVP.
2. High-Level Goals & Non-Goals
Goals
- A teacher can register/log in, create classes, add students, and assign a competency grid (template or custom) to a class/subject.
- A teacher can log learning-progress entries and assessments per student, linked to competencies.
- The system auto-calculates a competency mastery level per student per competency (based on the entries logged, using a configurable scale).
- The system shows a radar chart ("Competence Flower") per student.
- The system can compute a weighted grade per subject per student, based on teacher-defined weighting rules.
- The system can generate a PDF report per student (competency summary + optional grade) with one click.
- Data model supports elementary and secondary school competency structures (configurable grade bands, subjects, and competency hierarchies).
- Everything runs self-hosted with SQLite — zero external DB dependency.
- Fully responsive UI, usable on tablets (teachers observed using tablets in classrooms).
- GDPR-friendly by design (data minimization, full export, full delete) even though this isn't a commercial SaaS — schools still handle student data and should be able to trust the tool.
Non-Goals (v1)
- No payments, no multi-tenant SaaS billing.
- No native mobile apps (a responsive PWA is enough).
- No real-time collaborative editing.
- No AI-generated report text in v1 (flag as a "Phase 2 / stretch goal" — see §11).
3. Tech Stack (proposed — adjust if you have a strong reason, but justify the change)
- Frontend: React (or Next.js in a single full-stack app) + TypeScript. UI library: Tailwind CSS + shadcn/ui for accessible, clean components. Charting: Recharts or Chart.js (radar chart for the "Competence Flower").
- Backend: Node.js (within Next.js API routes / App Router server actions) or a separate lightweight Express/Fastify API — pick ONE cohesive full-stack framework to keep this simple for a small volunteer team. Next.js (App Router) is recommended so frontend + backend live in one deployable app.
- Database: SQLite, accessed through Prisma ORM (or Drizzle ORM as an alternative — pick one and justify). Reasoning: SQLite keeps hosting trivial (single file, easy backups, works great for a single school's scale of data — thousands of students, not millions), and Prisma/Drizzle gives us migrations, type safety, and an easy upgrade path to Postgres later if a school ever outgrows SQLite (design the schema to be Postgres-compatible too, avoiding SQLite-only quirks).
- Auth: Self-hosted email/password auth with hashed passwords (bcrypt/argon2) + session cookies (or a lightweight library like Lucia Auth / Auth.js with a credentials provider). No third-party paid auth services. Support optional TOTP-based 2FA (stretch goal, since Digidoo offers 2FA).
- PDF generation: A server-side PDF library (e.g.,
@react-pdf/rendereror Puppeteer-based HTML-to-PDF) for report cards. - File storage: Local filesystem storage for generated PDFs/exports (school-hosted, no S3 dependency required, but abstract storage behind an interface so S3-compatible storage can be swapped in later).
- Hosting target: Single Docker container (or docker-compose with a volume for the SQLite file + generated files), deployable on a small VPS. Include a
docker-compose.yml. - i18n: German and English UI strings from day one (the reference product targets DACH schools), using a simple i18n library (e.g.,
next-intl). Structure all UI text through translation keys — do not hardcode strings. - Testing: Vitest/Jest for unit tests, Playwright for a handful of critical E2E flows (login, create competency grid, log an entry, generate report).
Deliver a docs/ARCHITECTURE.md explaining the chosen stack and why, plus a docs/SELF_HOSTING.md explaining how a non-technical school IT admin can deploy this with Docker.
4. Database Design (SQLite via Prisma/Drizzle)
Design a normalized relational schema. Suggested entities (adjust field names to your ORM conventions; this is the conceptual model, not literal DDL):
Core organizational entities
- School — id, name, schoolType (enum: elementary, middle, gymnasium, other), country, timezone, createdAt.
- User — id, schoolId (nullable for solo teachers not tied to a school), email, passwordHash, firstName, lastName, role (enum: TEACHER, SCHOOL_ADMIN, SUPER_ADMIN), locale, twoFactorSecret (nullable), createdAt, deletedAt (soft delete).
- SchoolYear — id, schoolId, label (e.g. "2026/2027"), startDate, endDate.
- ClassGroup ("Klasse/Gruppe") — id, schoolId, schoolYearId, name, gradeLevel (int), schoolType.
- ClassGroupTeacher (many-to-many) — classGroupId, userId, role (e.g., HOMEROOM_TEACHER, SUBJECT_TEACHER).
- Student — id, schoolId, firstName, lastName, dateOfBirth (nullable, minimize data collected), externalId (nullable, for import matching), createdAt, deletedAt.
- Enrollment — id, studentId, classGroupId, schoolYearId, startDate, endDate (nullable = still enrolled). This models students moving between classes/schools over time.
Subject & competency structure
- Subject — id, schoolId (nullable = global/template), name, gradeLevelMin, gradeLevelMax.
- CompetencyTemplate — id, name, description, subjectId (nullable if cross-subject), schoolType, gradeLevelMin, gradeLevelMax, isGlobalTemplate (bool), createdByUserId (nullable for system-provided templates), version.
- CompetencyCategory — id, competencyTemplateId, name, order (for grouping competencies into "petals" of the flower — e.g., "Reading," "Writing," "Listening" within Language Arts).
- Competency — id, categoryId, code (short reference like "D.3.LES.01"), title, description, order, masteryLevels (JSON or related table — see below).
- MasteryLevelDefinition — id, competencyId (or categoryId, if scale is shared), levelValue (e.g., 1–4), label (e.g., "not yet demonstrated," "developing," "proficient," "advanced"), description.
- ClassCompetencyAssignment — links a ClassGroup + Subject to a chosen CompetencyTemplate for a given SchoolYear, plus any per-school customizations (could be a cloned/forked copy of the template rather than a live reference, so a school's edits don't affect the global template — design a "clone on customize" strategy).
Progress tracking & assessment
- LearningProgressEntry — id, studentId, competencyId, teacherId, classGroupId, date, masteryLevelValue, note (free text, optional), createdAt. This is the append-only observation log.
- Assessment ("Leistungsfeststellung") — id, classGroupId, subjectId, teacherId, title, date, type (enum: TEST, ORAL, PROJECT, HOMEWORK, OTHER), maxScore (nullable), weight (default weight for grading).
- AssessmentCompetencyLink (many-to-many) — assessmentId, competencyId, weight (how much this assessment contributes to that competency's mastery).
- AssessmentResult — id, assessmentId, studentId, score (nullable), masteryLevelValue (nullable), note.
Grading
- GradingScheme — id, classGroupId or subjectId, name, type (enum: NUMERIC_GRADE, VERBAL_FEEDBACK, COMBINED), scaleDefinition (JSON — e.g., grade 1–6, or 1–15 points, configurable per country/state).
- GradingWeightRule — id, gradingSchemeId, sourceType (enum: LEARNING_PROGRESS, ASSESSMENT), targetRef (competencyId or assessmentId or categoryId), weightPercent. Defines "how much of the final grade comes from what."
- ComputedGrade — id, studentId, subjectId, classGroupId, schoolYearId, period (e.g., "Semester 1"), computedValue, computedAt, isFinalized (bool), overriddenValue (nullable, teacher can manually override with a reason), overrideReason.
Reporting
- Report — id, studentId, classGroupId, schoolYearId, period, generatedByUserId, generatedAt, status (enum: DRAFT, FINAL), pdfFilePath, includesGrades (bool).
- ReportSection — id, reportId, competencyCategoryId (nullable), generatedText, order — stores the generated narrative per section so reports remain auditable/editable before finalizing.
Auditing & compliance
- AuditLog — id, userId, action, entityType, entityId, timestamp, metadata (JSON) — for accountability (who edited a grade, who exported data).
- DataExportRequest — id, requestedByUserId, scope (student/class/school), status, filePath, requestedAt, completedAt — supports the "you can always export your data" principle.
Design requirements:
- Use UUIDs (or ULIDs) as primary keys for portability, not SQLite autoincrement-only ints, to make future multi-instance sync/export easier.
- All timestamps in UTC.
- Soft deletes on Student/User (never hard-delete a student's historical record silently — provide an explicit "permanently erase" GDPR-style flow instead that cascades properly and logs an AuditLog entry).
- Write Prisma/Drizzle schema files, plus at least one seed script (
prisma/seed.ts) that creates: a demo school, a demo teacher login, 2 demo classes, ~15 demo students, a sample competency template (Math + German, elementary level, 2 categories, ~6 competencies each with a 4-point mastery scale), a handful of learning-progress entries and one assessment, so the app is explorable immediately afterdocker-compose up. - Provide migration scripts and document the "SQLite → Postgres" upgrade path in
docs/ARCHITECTURE.md(which ORM features to avoid to keep this portable — e.g., avoid raw SQLite-only pragmas in app logic, avoid case-sensitive collation assumptions, use ORM-level constraints not SQLite triggers). - Enable SQLite WAL mode and document backup strategy (just copy the
.sqlitefile + files directory; note SQLite's concurrent-write limitations and why that's fine at single-school scale, with guidance on when a school should be advised to migrate to Postgres).
5. Core User Roles & Permissions
- Teacher: Manage their own classes, students in their classes, log entries/assessments, view competence flowers, generate reports, customize competency grids for their classes.
- School Admin: Everything a teacher can do, plus manage the school's user list, manage school-wide competency templates, manage school years/classes, view audit logs, run data exports/erasure.
- Super Admin (project maintainer / self-hoster's own account): Manage global competency template library (the "starter" templates shipped with the app, akin to Digidoo's pre-built state curricula), manage schools if the instance hosts more than one school, system settings.
Implement middleware-level authorization checks (not just UI hiding) on every API route — a Teacher must never be able to query another school's data even by guessing IDs. Write tests specifically for this (IDOR-style access control tests).
6. Key Feature Specs (User Stories + Acceptance Criteria)
6.1 Onboarding & Auth
- As a new user, I can register with email/password, verify my email (or skip verification in self-hosted mode via config flag), and log in.
- As a user, I can reset my password via email link.
- As a user, I can optionally enable TOTP 2FA.
- Acceptance: passwords hashed with argon2id, rate-limited login attempts, session expiry configurable, CSRF protection on all mutating routes.
6.2 School / Class / Student setup
- As a teacher, I can create a class group, set its grade level and school type, and add students (manually one-by-one, or via CSV import with column mapping).
- As a teacher, I can assign one or more subjects to a class.
- Acceptance: CSV import validates rows, shows a preview + error list before committing, supports re-running with corrections.
6.3 Competency grid management
- As a teacher/admin, I can browse a library of starter competency templates (seeded ones + any the school has created), filtered by school type, grade level, and subject.
- As a teacher, I can assign a template to a class+subject for the school year, which creates an editable school-owned copy (so edits don't mutate the shared template).
- As a teacher/admin, I can edit competency categories/items/mastery-level definitions on my school's copy, or build a fully custom grid from scratch.
- Acceptance: template cloning is atomic (categories + competencies + mastery levels all copied together); editing a school copy never changes the original global template.
6.4 Logging learning progress
- As a teacher, from a class roster view, I can quickly log an entry for a student: pick competency (or multiple), pick mastery level, add optional note, save — optimized for fast repeated entry during/after class (keyboard-friendly, minimal clicks, works well on tablet).
- As a teacher, I can see a student's full timeline of entries.
- Acceptance: entry creation is <3 interactions from the roster view for the common case; entries are immutable-by-default but editable by the original author within a configurable time window, with all edits captured in AuditLog.
6.5 Assessments
- As a teacher, I can create an assessment (test/oral/project/etc.), link it to one or more competencies with weights, and record per-student results (score and/or mastery level).
- Acceptance: bulk entry UI (spreadsheet-like grid: students × one assessment) for fast grading of a whole class at once.
6.6 Competence Flower (radar chart)
- As a teacher/parent-in-meeting, I can view a per-student radar chart where each axis is a competency category and the value is the computed current mastery level (most recent entries weighted, or average — make the aggregation method configurable per template: "latest value," "average of last N," "weighted by recency").
- Acceptance: chart updates live as new entries are logged; hovering/tapping a petal shows the underlying entries; exportable as an image (PNG/SVG) for use in printed materials or slides.
6.7 Grade computation
- As a teacher, I can define a grading scheme per subject/class (numeric grade scale, or verbal feedback, or combined) and a weighting rule set (e.g., "60% assessments, 40% learning-progress mastery average").
- As a teacher, I can view the computed grade per student with a transparent breakdown ("this grade = X% from Assessment A, Y% from competency category B, ...").
- As a teacher, I can manually override a computed grade with a required justification note (stored in AuditLog + ComputedGrade.overrideReason).
- Acceptance: computation logic is a pure, well-tested function (given inputs, deterministic output) — cover with unit tests including edge cases (missing data points, all-verbal no numeric grade, partial-year enrollment).
6.8 Reports
- As a teacher, I can generate a report for a student (or a whole class in bulk) for a given period, combining: a competency summary (with the flower chart embedded), narrative text generated from templated phrases per mastery level per competency (NOT AI-generated in v1 — use a configurable phrase-template system: e.g., "shows [level.label] performance in [competency.title]"), and optionally the computed grade.
- As a teacher, I can review/edit the generated draft text before finalizing (report status DRAFT → FINAL; FINAL reports are locked and versioned).
- As a teacher, I can export a report as PDF and download it, or bulk-export a whole class as a ZIP of PDFs.
- Acceptance: PDF is well-formatted (printable A4, school-branding-agnostic — configurable logo/header per school), generation completes in a reasonable time even for a class of 30, and the phrase-template system is data-driven (stored in DB / config, not hardcoded strings) so schools can localize/adjust wording.
6.9 Data portability & privacy
- As a school admin, I can export all of a class's or school's data as structured JSON/CSV at any time.
- As a school admin, I can permanently erase a student's data (with confirmation + audit trail) when required (e.g., student leaves the school and retention period expires).
- Acceptance: exports include everything needed to reconstruct history in another system; erasure cascades correctly across all tables including generated PDFs on disk.
6.10 Dashboard
- As a teacher, my home dashboard shows: my classes, recent activity (entries logged this week), students who haven't had an entry logged in X days (flag for follow-up), upcoming report deadlines (configurable per school year).
7. UI/UX Requirements
- Original visual design — do not reuse Digidoo's illustrations, exact color palette, or copy. Build a clean, warm, education-appropriate design system (define a small design token set: colors, spacing, typography) — consider Tailwind + shadcn/ui defaults customized with an accent color distinct from Digidoo's.
- Mobile/tablet-first for the "log an entry" flow specifically (teachers use this standing in a classroom); desktop-first is fine for admin/setup screens and reports.
- Full keyboard navigation and screen-reader labels (WCAG 2.1 AA target) — schools may have accessibility obligations.
- Support German and English from day one via the i18n system (§3); default to German since the target audience is DACH schools, but make English complete too since this is described as an open-source/free project others may adopt.
- Empty states and onboarding checklists for a brand-new school ("1. Create your first class → 2. Assign a competency grid → 3. Add students → 4. Log your first entry").
8. Non-Functional Requirements
- Self-hostability: one
docker-compose.yml, one.env.example, aREADME.mdwith copy-pasteable setup instructions targeting a non-expert school IT person. Target: fromgit cloneto running app in under 10 commands. - Performance: fast on modest hardware — SQLite + server-rendered pages where sensible (Next.js SSR/RSC) to keep client bundle small; paginate long lists (student rosters, entry timelines).
- Backups: document and script a simple daily backup (cron job copying the SQLite file + generated files directory to a backup location); consider using
litestreamor SQLite's.backupcommand and mention it as a recommended addition. - Security: input validation on every API boundary (e.g., Zod schemas), parameterized queries only (ORM prevents SQL injection by default — don't bypass with raw string interpolation), secure cookie flags, rate limiting on auth endpoints, dependency vulnerability scanning in CI.
- Licensing: since this is a free/donation project, ship it under an OSI-approved open-source license (recommend MIT or AGPLv3 — explain the trade-off: AGPL prevents someone from taking this code and reselling it as a closed SaaS without contributing back, which may suit a "for the school, not for profit" mission better than MIT; let the team choose).
- CI/CD: GitHub Actions workflow running lint, typecheck, unit tests, and E2E smoke tests on every PR.
9. Project Structure (suggested)
/app # Next.js App Router pages (or /src/app)
/(auth)
/(dashboard)
/api
/components
/lib
/db # Prisma/Drizzle client, schema
/grading # pure grading calculation functions + tests
/reports # report generation + PDF rendering
/permissions # authorization helpers
/prisma (or /drizzle)
schema.prisma
seed.ts
migrations/
/docs
ARCHITECTURE.md
SELF_HOSTING.md
DATA_MODEL.md # ER diagram + entity descriptions
CONTRIBUTING.md
/tests
unit/
e2e/
docker-compose.yml
.env.example
README.md
LICENSE
10. Deliverables & Definition of Done for v1 (MVP)
- Auth (register/login/reset, optional 2FA) working end-to-end.
- School → SchoolYear → ClassGroup → Student → Enrollment CRUD, with CSV import for students.
- At least 2 seeded starter competency templates (e.g., "Elementary Math – Grade 3" and "Elementary German – Grade 3") with categories, competencies, and a 4-level mastery scale.
- Teachers can assign/clone a template to a class+subject, edit their school's copy.
- Fast entry-logging UI from a class roster.
- Assessments with bulk grid entry.
- Competence Flower radar chart per student, computed from real entry data, with a configurable aggregation method.
- Grading scheme + weight rules + computed grade with breakdown + manual override.
- Report generation (draft → final → PDF) with templated narrative text, single and bulk (class) export.
- Data export (JSON/CSV) and erasure flow, with audit logging.
- i18n scaffolding with DE + EN complete for all implemented screens.
- Dockerized self-hosting setup + docs, seed script for demo data.
- Test suite: unit tests for grading logic and permissions (target meaningful coverage on these two modules specifically, not just an overall % target), Playwright E2E covering: register → create class → assign template → add students → log entries → generate report.
README.mdexplaining the project's mission (free tool built for/with a school, donation-supported) and how to contribute.
11. Phase 2 / Stretch Goals (explicitly out of scope for v1, but document as future ideas in docs/ROADMAP.md)
- AI-assisted (optional, user-triggered) drafting of report narrative text, clearly marked as a draft for teacher review — never auto-finalized.
- SSO (OIDC) support for schools with existing identity providers.
- Parent portal (read-only view of their child's competence flower and finalized reports).
- Kita/early-childhood observation module (as Digidoo has hinted at on their roadmap).
- Optional Postgres deployment mode for larger multi-school instances.
- Native offline-first PWA mode for spotty classroom Wi-Fi.
12. Instructions for the AI Coding Agent
When you start implementing:
- First produce
docs/ARCHITECTURE.mdand the full Prisma/Drizzle schema (§4) and get my confirmation before writing app code. - Then scaffold the Next.js project, auth, and the seed script — get the demo environment runnable first.
- Build features in this order: School/Class/Student setup → Competency templates → Entry logging → Assessments → Competence Flower → Grading → Reports → Data export/erasure.
- After each feature, write its unit/E2E tests before moving to the next.
- Keep commits small and descriptive; write a CHANGELOG.
- Flag any point where you are uncertain about a competency/grading policy that varies by German state (Bundesland) — expose it as a configuration option rather than hardcoding one state's rules, and note the assumption in
docs/DATA_MODEL.md. - Remember throughout: this is a free, non-commercial, donation-supported school project. Prefer boring, dependency-light, self-hostable solutions over anything that introduces a paid third-party service or vendor lock-in.
PRD v2 — "SchoolOS" (formerly "CompetenceTrack")
A Free, Self-Hosted, All-in-One School Platform (Digidoo-inspired competency core + full school operations)
0. Mission & Non-Negotiable Principles
This is a free, donation-supported school project, not a commercial SaaS. It is being built for a real school; any support it receives goes back to the school. These principles override every design decision below:
- DB: SQLite. Single-file, self-hostable, cheap to run and back up. (One exception, scoped narrowly: an embedded vector store for AI search — see §9.6 — which can also run fully local/in-process.)
- No hardcoding, anywhere. Every list, label, rule, threshold, escalation window, warning count, template, and permission must come from the database or an admin-editable config table — never a constant baked into code. If a value could plausibly differ between two schools or change next semester, it is a DB row, not a literal.
- No mock data, ever — not in dev, not in demo, not in tests-as-shipped-UI. Seed scripts may create realistic sample rows for local development (clearly documented as seed data, easily wiped), but the shipped application must never silently render placeholder/fake data as if real.
- No duplicate functionality across pages. Every capability lives in exactly one canonical place. Example: anything date/deadline/appointment-related belongs only on the Calendar page — not also embedded as a mini-widget with its own logic elsewhere unless it's a true read-only summary widget pulling from the same single source (see §8, Dashboard Widgets — a widget is a view, never a second implementation). Before adding any feature, check whether an existing page/module already owns that responsibility; if so, extend it there or surface it as a widget, don't rebuild it.
- Tablet-first, touch-first, with full parity and a well-adapted layout for desktop/PC. This is the primary device class for teachers and students in-classroom.
- Everything is dynamic and role/permission-aware, driven by real DB relationships (school → year → class → subject → student → user), never assumed.
- Open-source license recommended: AGPLv3 (prevents a third party from taking this free/community project and reselling it closed-source without contributing back) — team to confirm.
1. Module Map
The platform is organized into cohesive modules, each owning its data and UI completely (principle #4 above). This PRD defines each module's scope precisely so responsibilities never blur.
| # | Module | Owns |
|---|---|---|
| A | Academics Core | Competency grids, learning-progress entries, assessments, competence flower, grading, report cards (carried over from PRD v1 — see §2, condensed) |
| B | Signage | TV/billboard displays: announcement slides, sponsor slides, emergency/fire/counseling alerts |
| C | Communication | Direct messaging, escalation rules, class/grade social rooms, class-hours messaging locks |
| D | Learning Hub | Videos, interactive exercises, worksheets, vocab trainer, learning game, AI-assisted content authoring |
| E | AI Tutor | In-context homework help, hint-only policy, full lockout during tests, content translation for foreign students |
| F | Exam Mode | Kiosk/lockdown test-taking, teacher live controls, student warning system, incident log |
| G | Digital Notebook | Typed + stylus/pen notebook per student per subject, teacher pen annotation on tests/homework |
| H | Notifications | All push/in-app notifications, the only place alerts render outside their originating context banner |
| I | Calendar | All dates/deadlines/appointments/exam schedules/report deadlines — the only source of truth for "when" |
| J | Dashboard & Widgets | Per-user customizable home screen assembled from read-only widgets pulling from A–I |
| K | Identity & Admin | Users, roles, schools, classes, disciplinary records, audit log, permission/rule configuration |
Every module below lists: purpose, roles involved, key entities, core flows, and explicit rules given by the school.
2. Module A — Academics Core (condensed; full detail in PRD v1)
Unchanged from the original spec: CompetencyTemplate → CompetencyCategory → Competency → MasteryLevelDefinition, LearningProgressEntry, Assessment/AssessmentResult, GradingScheme/GradingWeightRule/ComputedGrade, Report/ReportSection. See PRD v1 §4 and §6.1–6.7 for the full entity list and user stories — carry those forward unchanged. New in v2:
- Assessment results integrate with Exam Mode (Module F): an Assessment can be flagged
deliveryMode = DIGITAL_LOCKED, which triggers the kiosk/lockdown flow when a student starts it. - Reports can optionally embed the student's Digital Notebook entries for the period as an appendix (teacher-selectable, off by default for privacy/size).
3. Module B — Digital Signage (TV / Billboards)
Purpose: Replace physical bulletin boards with school-controlled TV displays for announcements, class/period info, sponsor content, and — critically — emergency alerts.
Roles: School Admin/Management authors & publishes; Sponsor content is admin-approved only (no self-serve); Teachers can request a slide be added (goes to an admin approval queue, not published directly) unless the school configures otherwise (config-driven per §0.2).
Entities:
SignageDisplay— id, schoolId, location/name (e.g., "Main Hall Screen 1"), resolution profile, isActive.SignageSlide— id, schoolId, type (enum: ANNOUNCEMENT, SPONSOR, INFO, SCHEDULE), title, body/media, priority, startAt, endAt, createdByUserId, approvalStatus.SignagePlaylist— id, displayId (or "all displays"), ordered list of slides, rotation duration per slide.EmergencyAlert— id, schoolId, type (enum: FIRE, LOCKDOWN, MEDICAL, GENERAL_EMERGENCY, COUNSELING_NOTICE), message, triggeredByUserId, triggeredAt, resolvedAt, affectedScope (whole school / specific building / specific class).
Core flows:
- Normal rotation: displays cycle through active, date-windowed slides per their playlist, weighted by priority.
- Emergency override (highest priority, non-negotiable): any
EmergencyAlertcreated by an authorized user (Admin, or any Teacher for fire/medical — configurable per school policy) immediately interrupts every display's rotation, shows a full-screen alert with type-specific styling (e.g., red/fire iconography for FIRE), and simultaneously fires a push notification (Module H) to all staff devices, and, for FIRE/LOCKDOWN, to all logged-in student/parent devices per school policy. Alert clears only when explicitly resolved by an authorized user, logged in AuditLog. - Counseling notice: a lower-urgency variant — visible only on staff-facing displays/dashboards, not broadcast school-wide, used e.g. to flag "counselor needed in room X" without alarming the whole building.
- Sponsor slides: admin uploads, sets a date window and rotation weight; never auto-published from a teacher request.
Rule from the school: any teacher-submitted slide must pass admin approval before appearing — build this as a queue with approve/reject + optional edit, not a silent auto-publish, unless the admin later flips a config flag to allow trusted teachers to self-publish INFO-type slides for their own class.
4. Module C — Communication (Messaging & Escalation)
This is the most rule-heavy module. Implement the escalation logic as data-driven policy rows, not hardcoded if/else chains, so admin can adjust thresholds without a code change.
Entities:
MessageThread— id, schoolId, type (enum: DIRECT, CLASS_ANNOUNCEMENT, SOCIAL_ROOM), participantsOrScope.Message— id, threadId, senderId, body, sentAt, readReceipts.EscalationPolicy— id, schoolId, fromRole, toRole, requiredPriorContactRole, waitingPeriodBusinessDays (default 3), isActive, overriddenByUserId (nullable, for admin-configured exceptions). All numbers here (the "3 business days") are read from this table, never hardcoded.EscalationRequest— id, studentId or parentId (requester), subject, firstContactThreadId, firstContactAt, eligibleToEscalateAt (computed = firstContactAt + policy.waitingPeriodBusinessDays business days, using the school calendar to skip holidays), status (enum: WAITING, ELIGIBLE, ESCALATED, RESOLVED).SocialRoom— id, schoolId, scope (enum: CLASS, GRADE_LEVEL/"Stufe", CUSTOM_GROUP), name, moderatorUserIds, isActive.ClassMessagingLock— id, classGroupId, lockedByUserId (the teacher), lockedFrom, lockedUntil (nullable = "until class ends," or explicit time) — while active, students in that class cannot send/receive in student-facing threads (staff-to-student announcements still deliver).DisciplinaryRecord— id, userId (student or, separately, staff-disciplinary variant), type, description, issuedByUserId, linkedIncident (nullable FK to an ExamWarning or a reported message), visibleToParent (bool), createdAt.
Core rules (exactly as specified by the school, encoded as the default EscalationPolicy rows — admin can edit or disable):
- Parent → Admin: allowed only for genuinely necessary matters, and only after the parent has messaged the student's homeroom teacher about that subject at least once. If no reply within 3 business days, the parent gains the right to message Admin about that specific thread (system auto-creates/unlocks the Admin channel on that
EscalationRequest, referencing the original thread for context). - Student → Admin/Counseling: same pattern — student must first message the homeroom teacher; after 3 business days without reply, gains the right to escalate to the counseling unit ("Rehberlik" — modeled as a
Counselorrole/department) and/or Admin. - Teacher → Admin: direct, no escalation gate required.
- Admin/Management override: Admin can loosen, tighten, or remove any
EscalationPolicyrow per school, per role pair, or per individual case (overriddenByUserId+ reason, logged). Admin can also issue aDisciplinaryRecordagainst a teacher or student directly from a messaging or exam-incident context. - Social rooms: class-scoped or grade/"Stufe"-scoped group discussion spaces ("mini Facebook"), moderated by assigned staff; posts/threads, not just DMs. Config per school: which scopes are enabled, whether posts need moderation approval before visible.
- Class-hours lock: a teacher can toggle
ClassMessagingLockfor their class; while active, students in that class are blocked from sending in student↔student and student↔staff threads (but can still receive urgent Signage/Notification-level alerts) until the teacher lifts it or class period ends (integrate with Module I's period/timetable data to auto-lift at period end if the teacher doesn't manually lift it — config toggle for auto vs. manual).
Business-day computation must read the school's holiday/weekend calendar from Module I (Calendar), not assume a fixed Mon–Fri with no holidays.
5. Module D — Learning Hub (Student Self-Study Resources)
Purpose: A curriculum-aligned self-study resource center (functionally inspired by tools like Sofatutor — do not copy their branding, exact video content, or exact wording; build original or licensed/open content, organized the same way: by subject and grade level).
Entities:
LearningResource— id, schoolId (nullable = shared/global library), subjectId, gradeLevel, type (enum: VIDEO, INTERACTIVE_EXERCISE, WORKSHEET, VOCAB_SET, GAME_MODULE), title, description, contentRef (file path or embed URL), competencyLinks (many-to-many toCompetency, so resources surface contextually — e.g., from a student's weak competency-flower petal, "here's a resource to help"), createdByUserId (teacher/admin/AI-assisted), reviewStatus (enum: DRAFT, PENDING_REVIEW, PUBLISHED), aiGenerated (bool).WorksheetSolution— attached to a WORKSHEET resource, hidden by default, revealable by student after attempt or by teacher setting.VocabSet/VocabItem— user-entered or teacher-provided vocab lists feeding the vocab trainer's spaced-repetition practice loop.GameProgress— per-student progress/score state for the learning game module, scoped by subject.
Core flows:
- Teachers/Admin can create, edit, or request AI-assisted drafting of a resource (AI drafts → always lands in
PENDING_REVIEW, never auto-published — a human must approve, consistent with §0.2's "no silent hardcoded/auto content" spirit and basic content-quality control). - Resources are discoverable by subject/grade browse, search, and contextually — surfaced automatically next to a student's weak competency in Module A's Competence Flower and in AI Tutor suggestions (Module E).
- Printable worksheets export as PDF with an optional teacher toggle to include/exclude the solutions page.
6. Module E — AI Tutor & AI Content Assistance
Purpose & hard policy (as specified by the school — implement as enforced server-side logic, not just prompt instructions, since this is a safety/integrity requirement, not a suggestion):
- The AI tutor may: explain a concept, walk through a similar worked example, give a hint on where a student is stuck, define a term, and — for a specific single question a student is stuck on — nudge them toward the next step.
- The AI tutor must never: produce a direct final answer to an assigned homework/assessment question, complete an assignment on the student's behalf, or operate at all while any
AssessmentwithdeliveryMode = DIGITAL_LOCKEDis active for that student (hard gate — see Module F; the AI chat endpoint checks "is this student currently inside an active exam session?" and refuses if so, independent of any client-side UI state). - Every AI Tutor interaction is logged (
AiTutorInteraction: id, studentId, subjectId/competencyId if applicable, promptSummary, responseSummary, timestamp, flaggedAsHomeworkAttempt bool) so teachers/admin can audit for misuse patterns, without necessarily storing full raw chat transcripts if the school prefers privacy-minimized logging (config toggle: summary-only vs full-transcript retention, with a retention period). - Translation: AI-powered on-demand translation of learning content and (optionally) UI copy for foreign-language students, requested per-resource or per-message, with the translated text clearly labeled "AI-translated" and a way to flag a bad translation for staff review.
Content-authoring assist (Module D bridge): the same AI capability can be invoked by teachers/admin to draft Learning Hub resources or Signage announcement copy — always landing in a review/draft state, never publishing directly.
7. Module F — Exam Mode (Digital Lockdown & Proctoring)
Purpose: A secure, kiosk-style test-taking mode for digitally delivered assessments, plus the in-test behavior/warning system the school specified.
Entities:
ExamSession— id, assessmentId, studentId, deviceId, startedAt, status (enum: ACTIVE, PAUSED, RESUMED, ENDED, CANCELLED), pausedByUserId (nullable), pauseReason (enum: BATHROOM_REQUEST, TEACHER_INITIATED, STUDENT_DISTRESS, THIRD_WARNING, OTHER).ExamWarning— id, examSessionId, issuedByUserId (teacher), reason (free text or preset e.g. "talking," "looking at other screen"), sequenceNumber (1st/2nd/3rd), issuedAt.ExamIncidentEvent— id, examSessionId, type (enum: LOCK_BREACH_ATTEMPT, BATHROOM_REQUESTED, BATHROOM_GRANTED, DISTRESS_SIGNAL, PAUSED, RESUMED, CANCELLED), metadata, timestamp.
Core flow (exactly as specified):
- When a student opens a
DIGITAL_LOCKEDassessment, the client enters kiosk/fullscreen lockdown: the device locks to the exam UI only — no other tabs/apps, no AI Tutor access (hard-gated per Module E), timer visible per assessment config. - Bathroom request: student taps a "request break" control → teacher gets a real-time alert (Module H) → if the teacher approves, that student's individual
ExamSessionpauses (other students' sessions are unaffected) → resumes when the teacher (or the student, per config) marks return. - Distress signal: student can send an "I feel unwell / need help" signal at any time → immediate high-priority alert to the teacher (distinct styling/sound from a routine bathroom request) → teacher attends; if unresolved, teacher can pause or fully cancel that student's exam (cancellation reason required, logged, visible to parent/admin).
- Behavior warnings: teacher can issue an
ExamWarningto a specific student mid-test (e.g., for talking or looking at another student's screen). 1st and 2nd warnings are logged and shown to the student as an alert; the 2nd is explicitly flagged as "final warning." On the 3rd, the system auto-pauses that student's exam; the teacher then decides to resume or end it. Every warning and the resulting record is stored on the student's disciplinary/record trail, visible to parents and admin (reusesDisciplinaryRecordfrom Module C, linked vialinkedIncident). - Teacher has a live class exam-monitor view: every student's session status (active/paused/warned) at a glance, one-tap pause/resume/cancel/warn per student.
- All lockdown enforcement must be defense-in-depth: client-side kiosk/fullscreen API + Workbox-based service worker to intercept navigation attempts, and a server-side session flag that independently blocks other API calls (AI Tutor, Learning Hub, Messaging) for the duration — never trust the client alone for an integrity feature.
8. Module G — Digital Notebook
Purpose: Digital replacement for the paper exercise notebook — environmental motivation stated explicitly — while supporting Germany's range of school notebook/exercise-book conventions.
Entities:
NotebookTemplate— id, schoolId (nullable = global), name, ruling type (e.g., lined, squared/Kariert, blank), gradeLevel/subject applicability — mirrors the real German notebook types (Lineatur) so pages "feel" like the paper equivalent students already know.NotebookPage— id, studentId, subjectId, classGroupId, templateId, createdAt, content (structured: typed text blocks + vector "ink" strokes for stylus input, stored e.g. as SVG/stroke-JSON, not baked raster images, so it stays editable/searchable/annotatable).NotebookAnnotation— id, pageId (or linked to an Assessment submission), authorUserId (teacher), strokeData/comment, createdAt — used for teacher correction marks/pen feedback directly on a test or notebook page.
Core flows:
- Students write via keyboard and/or stylus (pen) — both can coexist on the same page (e.g., typed answer + hand-drawn diagram).
- Teachers annotate directly on a digital test submission or notebook page with pen input — highlighting, circling, margin comments — captured as its own
NotebookAnnotationlayer so the original student work is never overwritten (non-destructive review, mirroring how a teacher marks a real paper test in red pen). - Notebook pages are organized per subject per student per school year, browsable like a real notebook (page-by-page / date-by-date), exportable as PDF.
9. Cross-Cutting Modules
9.1 Module H — Notifications (single source of alerts)
All push/in-app alerts — messaging, exam warnings/bathroom requests, signage emergencies, escalation-eligibility notices, learning-hub review-queue items — route through one Notification entity and one delivery pipeline (browser push via the Web Push API, service-worker-delivered per Workbox, plus an in-app notification center). No module renders its own separate "toast/badge" system outside this pipeline — per the no-duplication rule (§0.4), every other module emits into Module H rather than building its own alert UI.
Notification — id, recipientUserId, type, priority (enum: NORMAL, URGENT, EMERGENCY), title, body, deepLinkRef (points back to the owning module/entity), createdAt, readAt, deliveredChannels (JSON: push/in-app/etc).
9.2 Module I — Calendar (single source of "when")
All dates live here: class timetable/periods, exam schedules, report-card deadlines, school holiday calendar (feeds Module C's business-day math), signage slide date windows (referenced, not duplicated — Calendar shows a read-only reflection sourced from SignageSlide.startAt/endAt, it doesn't own a second date field). Same non-duplication logic applies to every other module with a date.
9.3 Module J — Dashboard & Widgets
Every user role gets a customizable home dashboard: add/remove/reorder widgets from an approved catalog (each widget is a thin, read-only view into one owning module — e.g., "Today's Notifications," "My Classes' Exam Sessions Live," "Upcoming Calendar Items," "Class Competence Flower Summary," "Learning Hub: resources pending review"). Widget layout persists per user (UserDashboardLayout — userId, widgetInstances JSON: widgetType, position, size, config). Widgets never contain their own business logic beyond fetching/rendering — this enforces §0.4 structurally, not just by convention.
9.4 Module K — Identity, Roles & Admin
Extends PRD v1's role model (Teacher / School Admin / Super Admin) with:
- Counselor ("Rehberlik") role — receives escalated student/parent threads per Module C.
- Parent role — read-only into their child's reports/grades/competence flower (from Module A), messaging per Module C's rules, visibility into
DisciplinaryRecordentries flaggedvisibleToParent. - Student role — Learning Hub, AI Tutor (gated), Exam Mode, Digital Notebook, Communication (gated by escalation rules and class locks).
- Sponsor is not a login role — sponsor content is admin-managed only (per Module B).
- All escalation thresholds, warning limits, kiosk enforcement toggles, and messaging rules are exposed in a single Admin Policy Console so a non-technical admin can tune the whole rules engine without touching code — this is the concrete implementation of "admin can loosen/tighten/remove these rules."
9.5 Touch/Tablet UI-UX Overhaul
- Minimum touch target 44×44pt (WCAG/Apple HIG baseline), larger on primary actions (exam controls, entry-logging buttons).
- Enlarged cards/list rows in tablet breakpoint, denser layout on desktop breakpoint — one responsive design system, not two separate codebases.
- Kiosk/fullscreen mode: implement via the Fullscreen API + a Workbox-powered service worker (offline shell caching, reliable "install as app" PWA behavior, and push notification delivery even when the browser tab isn't focused).
- Free browser push notifications: Web Push API, no paid push-notification vendor required.
9.6 AI/Search Infrastructure Note (re: suggested repos)
- Workbox (GoogleChrome/workbox): use for the PWA service worker — offline shell caching, kiosk-mode reliability, and Web Push delivery (Module H, §9.5). This is the clearest direct fit.
- Comlink (GoogleChromeLabs/comlink): use to offload heavy client-side work (e.g., stylus stroke rendering/processing in the Digital Notebook, or client-side AI-translation pre/post-processing) to a Web Worker via a simple RPC-style API, keeping the main thread responsive for touch input — directly supports the "touch performance" requirement.
- Chroma (chroma-core/chroma): an embeddable vector database, usable to power semantic search over Learning Hub resources and as retrieval-augmented context for the AI Tutor (so it answers "using this school's actual curriculum materials" rather than generic knowledge). Can run embedded/local — keep it as an optional, swappable component behind an interface, not a hard dependency, so a school without AI features enabled never needs to run it. Primary relational data stays in SQLite regardless (§0.1) — Chroma, if used, only stores content embeddings for search/retrieval, not core school records.
10. Updated Non-Functional Requirements
- Reconfirm §0's five principles apply to every module above, not just Module A.
- Security posture from PRD v1 (§8) still applies, plus: Exam Mode integrity must be defense-in-depth (§7.6); Emergency Alerts (§3) must have the lowest possible latency path — treat as a "fire drill"-grade reliability requirement, test failure/retry behavior explicitly.
- Data minimization: AI Tutor logging defaults to summary-only (§6); Digital Notebook stroke data belongs to the student and must be exportable/erasable like any other student record (PRD v1 §6.9).
- Accessibility (WCAG 2.1 AA) applies across all new modules, including Signage (captioned/legible from a distance) and Exam Mode (must remain usable with assistive tech even inside lockdown).
11. Revised MVP Phasing
Given the expanded scope, ship in stages rather than one giant release — each stage fully functional and demo-able:
Stage 1 — Foundation (carries PRD v1 MVP): Identity/roles/schools/classes/students, Module A (Academics Core) end-to-end, Calendar (Module I) as the shared date backbone, Notifications (Module H) skeleton, Dashboard/Widgets (Module J) with 2–3 widgets.
Stage 2 — Communication & Signage: Module C in full (messaging, escalation policy engine, social rooms, class lock), Module B (signage, including Emergency Alert override), wired into Module H/I.
Stage 3 — Learning & AI: Module D (Learning Hub, manual authoring first, AI-assist as a fast-follow), Module E (AI Tutor with hard test-time gating from day one — never ship AI Tutor before Exam Mode's gate exists, to avoid ever shipping a homework-solving loophole).
Stage 4 — Exam Mode & Digital Notebook: Module F (kiosk lockdown, warnings, monitor view) and Module G (typed + stylus notebook, teacher annotation) — these are the highest-integrity/most device-sensitive modules, saved for last so the touch/kiosk foundation (§9.5) is mature first.
Each stage gets its own seed data, its own test suite additions, and its own entry in docs/ROADMAP.md.
12. Instructions for the AI Coding Agent (updated)
- Re-confirm the full schema (PRD v1 §4 + all new entities in §2–9 above) and get sign-off before writing feature code — the schema is now large enough that a wrong early decision is expensive.
- Build a single shared Policy/Config layer (backing Module K's Admin Policy Console) before implementing Module C's escalation logic or Module F's warning thresholds — both must read from it, proving the "no hardcoding" rule structurally rather than by discipline alone.
- Build Module H (Notifications) and Module I (Calendar) early, in Stage 1, precisely because every later module depends on them — this prevents each subsequent module from inventing its own notification/date logic (the exact duplication the school explicitly forbade).
- When implementing Module F (Exam Mode), write the server-side session-gating check (§7.6) before the pretty kiosk UI — the security property must not depend on the UI shipping correctly.
- Flag explicitly, in
docs/DATA_MODEL.md, every place a rule/threshold is read from a policy table (so a future audit can confirm zero hardcoded business rules). - Follow PRD v1 §12's remaining process guidance (small commits, tests per feature, changelog, boring/dependency-light choices) unchanged.
PRD v3 — Addendum: Module L — Legal, Data Protection & Rights Compliance (EU/DE)
This is an addendum to PRD v1 (Academics Core) and PRD v2 (full module map A–K). It adds Module L, which every other module must satisfy, and updates several existing entities to be compliant with EU GDPR (DSGVO), the German Federal Data Protection Act (BDSG), and — critically, because schools are public bodies — the state-level School Acts (Landesschulgesetze) and School Data Protection Ordinances (Schul-Datenschutzverordnungen), which vary across all 16 German Bundesländer and often override or supplement the GDPR baseline for public schools.
Hard disclaimer to carry into the product and into
docs/: This PRD gives the engineering requirements needed to make compliance possible. It is not legal advice, and this document (nor any AI tool) can make the final legal determination for a specific school. Every school deploying this platform must involve its own Datenschutzbeauftragter (DPO), its Schulträger (school authority), and — for co-determination matters — its Personalrat/Lehrerrat before go-live. Encode this as a literal onboarding gate in the product (§L.9).
L.1 Governing Framework (what applies, and why it's layered)
- GDPR (DSGVO) — the EU-wide baseline: lawful basis (Art. 6), special category data (Art. 9), children's data (Art. 8), data protection by design/default (Art. 25), records of processing (Art. 30), DPIA (Art. 35), data subject rights (Art. 12–22), processor agreements (Art. 28).
- BDSG — German federal implementing law, adds specifics (e.g., § 26 BDSG on employee data processing — relevant to teacher accounts, audit logs, and any monitoring capability).
- Landesschulgesetz (state School Act) of the school's Bundesland — this is usually the actual legal basis for processing student data in a public school (Art. 6(1)(c)/(e) GDPR: legal obligation / public task), not consent — consent is often the wrong legal basis for a school-student relationship because of the power imbalance, except for genuinely optional features (e.g., opting into the Learning Hub's game leaderboard, or the newsletter-style features).
- Schul-Datenschutzverordnung / VO-DV I / equivalent per state — the operative rules on retention periods, which data categories a school may collect, video/photo rules, cloud-hosting rules, and pupil-file (Schülerakte) handling. These differ by state and must not be hardcoded (§L.6).
- Landespersonalvertretungsgesetz (LPVG) / BPersVG — governs co-determination rights of the staff council (Personalrat) for public-sector employees (teachers are usually civil servants/public employees) — this is the legal hook for teacher rights around any system that can monitor behavior or performance (§L.4).
- KJSG / Kinderrechte / UN-Kinderrechtskonvention — general child-rights framework informing "best interests of the child" design choices (age-appropriate UI, no dark patterns, no manipulative engagement mechanics in the Learning Hub's game module).
L.2 Data Protection by Design & by Default (Art. 25) — mapped to existing modules
Apply these to every module from PRD v2, not just new ones:
- Data minimization at the schema level: re-audit every entity in Modules A–K; any optional field must default to not collected. Example already flagged in PRD v1 §4:
Student.dateOfBirthis nullable — keep it that way, and only populate it if the school's state rules actually require it for the pupil file. - Purpose limitation: each table/module must document, in
docs/DATA_MODEL.md, the specific legal basis and purpose for that data (e.g.,ExamWarning→ purpose: exam integrity & pedagogical record; legal basis: Schulgesetz duty to ensure fair assessment conditions). - Pseudonymization where feasible: e.g.,
AiTutorInteraction(Module E) should store a pseudonymous student reference plus subject/competency context by default, resolvable to the real student only through an access-controlled join, not stored redundantly in logs/exports. - Storage limitation: every entity with personal data needs a
retentionPolicyRefpointing to Module L's retention config (§L.6), and a scheduled job that flags/executes deletion once the retention period lapses — not a manual "someone remembers to clean this up" process. - Access control by default = deny: reaffirm PRD v1 §5's authorization-by-role, extended: a Teacher's default access to a student is scoped to classes they currently teach that student in — losing that assignment (end of enrollment/school year) must automatically narrow their access, not require a manual revoke.
L.3 Special-Category & Sensitive Data (Art. 9 GDPR) — flag every touchpoint
Several features from PRD v2 can touch special category data (health, and potentially religion/ethnicity if ever captured, though this platform should never collect race/ethnicity/religion/sexual orientation/union membership/political opinion — explicitly out of scope, no field for it anywhere in the schema):
- Exam "distress signal" (Module F, §7): a student signaling they feel unwell during a test is health-adjacent data. Requirements:
- Store only a minimal event flag (
ExamIncidentEvent.type = DISTRESS_SIGNAL) plus optional free text the student/teacher chooses to add — never a structured "symptom" or diagnosis field. - Restrict visibility to the involved teacher + admin/counseling on a need-to-know basis; do not surface it on general dashboards or to other teachers by default.
- Short default retention unless the incident escalates into a formal record (e.g., leads to an actual accommodation or medical event requiring documentation) — configurable per school policy (§L.6), but default to the shortest period that satisfies the school's duty of care.
- Store only a minimal event flag (
- Disciplinary records (
DisciplinaryRecord, Module C/F) are not Art. 9 special-category data per se, but are highly sensitive personal data about a minor — apply the same need-to-know visibility model, and makevisibleToParenta real, enforced access-control flag, not just a UI toggle. - Counseling notices (Module B, §3) must never broadcast identifying detail on general-audience displays — the whole point of the "counseling notice ≠ emergency alert" distinction in PRD v2 is to avoid exposing a student's need for support to the wider school.
- Foreign-student translation (Module E): a student's home language, inferred from translation requests, is not classic special-category data, but is a data point that can reveal national origin — treat with the same minimization discipline (don't build a persistent "ethnic/linguistic profile," just serve the translation request and discard the routing metadata beyond what's needed for the UI session).
L.4 Teacher Rights & Staff Co-Determination (Personalrat / Unions)
This is a distinct legal track from student data protection — it protects teachers, and it is a hard gate, not a nice-to-have:
- Any feature capable of monitoring staff behavior or performance — this plausibly includes:
AuditLogentries on teacher actions, message-read receipts, exam-monitor dashboards showing how promptly a teacher responds to a bathroom/distress request, Learning Hub content-authoring approval/rejection rates, or any future "teacher activity" analytics widget — triggers co-determination rights of the Personalrat (staff council) under the relevant state's LPVG (or, for federal matters, BPersVG). In the private-sector analogy this is the same principle as § 87(1) No. 6 BetrVG. - Product requirement: before any such feature ships to a real school, it must be documented in a Dienstvereinbarung-ready spec sheet: what is logged, who can see it, how long it's kept, and what it will/won't be used for (explicitly: not for unilateral performance evaluation without the Personalrat's agreement). Ship this spec sheet as a generated doc per module (
docs/personalrat/<module>.md), not just prose buried in this PRD. - Union involvement: recommend the school proactively loop in its GEW (Gewerkschaft Erziehung und Wissenschaft) or VBE representative and its Personalrat during rollout — not a product feature per se, but the onboarding flow (§L.9) should surface this as a required checklist item before enabling any monitoring-capable module.
- Teacher data subject rights: teachers have the same GDPR rights as anyone (access, rectification, erasure where applicable, objection) over their own account data, message logs, and audit trail — build a self-service "my data" export for staff accounts, same mechanism as the student-facing one (PRD v1 §6.9), reused rather than duplicated (per the no-duplication rule).
- Working-time/communication boundary: the class-hours messaging lock (Module C) and any after-hours notification behavior should be configurable so the platform doesn't itself become a vector for pressuring teachers to be reachable outside contracted hours — expose a per-teacher "quiet hours" setting for non-urgent notifications (urgent/emergency alerts from Module B always bypass this, by design).
L.5 Student Rights
- Right of access (Art. 15): a student (or, for younger students, their parent/guardian on their behalf per §L.7) can request and receive a full export of their data — competency entries, grades, notebook pages, messages, disciplinary records, AI Tutor interaction summaries — reusing the Module K data-export pipeline (PRD v1 §6.9), not a bespoke second exporter.
- Right to rectification (Art. 16): factual errors (wrong competency entry, mis-recorded assessment score) must be correctable via the existing edit/audit-logged flows already specified in Module A — no new mechanism needed, just confirm the audit trail satisfies "who changed what, when, why."
- Right to erasure (Art. 17), bounded by retention duties: a student's account and actively used data can be erased on request or on leaving the school, except for records the school is legally obligated to retain (e.g., final grades/report cards for the statutory retention period — varies by state, see §L.6). Implement as: erasure request → system erases everything not covered by an active retention policy, and clearly reports back what was retained and why (transparency even in partial erasure).
- No solely-automated decisions with legal/significant effect (Art. 22):
ComputedGrade(Module A) must always have a human teacher confirm/finalize it before it becomes an official grade — this is already implied by PRD v1's "teacher can override" design; make it a hard requirement, not optional: aComputedGradecannot reachisFinalized = truewithout afinalizedByUserId(a human). Same principle forExamWarning's third-strike auto-pause (Module F): the pause can be automatic (it's a safety/integrity mechanism, not a "decision about the student" in the Art. 22 sense), but any resulting disciplinary consequence requires a human (teacher/admin) to actually create theDisciplinaryRecord— the system must never auto-generate a disciplinary entry without a human actor attached. - Protection from profiling beyond pedagogical purpose: competency/AI-tutor data must not be repurposed into any kind of broader "student risk score" or similar without an entirely separate legal basis and DPIA — explicitly out of scope; flag this as a forbidden feature, not just an unbuilt one, in
docs/ROADMAP.md's "will not build" section.
L.6 Retention Periods — config-driven, not hardcoded (extends §0.2/§0.3 from PRD v2)
German statutory retention periods for pupil records (Zeugnisse, Schülerakten, Prüfungsunterlagen, etc.) vary by Bundesland and sometimes by record type (e.g., final Abitur-related records often must be kept far longer than routine coursework). Do not hardcode a single number anywhere.
- New entity:
DataRetentionPolicy— id, schoolId, dataCategory (enum mapping to the entities above: LEARNING_PROGRESS, ASSESSMENT_RESULT, FINAL_REPORT, DISCIPLINARY_RECORD, EXAM_INCIDENT, MESSAGE, AI_TUTOR_LOG, NOTEBOOK_PAGE, SIGNAGE_LOG), retentionPeriodMonths, legalBasisNote (free text — admin/DPO fills in the state-specific rule they're relying on), reviewedByUserId, reviewedAt. - Every module that writes personal data must resolve its retention period from this table at write time or via a scheduled sweep — never assume a number in application code.
- Ship the table empty of defaults for legally-mandated categories (force the school's DPO to actually fill in their state's correct numbers rather than shipping a guessed default that could be wrong) — but ship sensible short defaults for non-mandated, product-only categories (e.g.,
AI_TUTOR_LOGsummary retention defaulting to something modest like 12 months, editable).
L.7 Parent Rights
- Information duty (Art. 13/14): on account creation, parents/guardians receive a plain-language privacy notice (not just a legal-boilerplate one) covering what's collected, why, for how long, and who can see it — generated from the same
DataRetentionPolicy/module documentation so it can never drift out of sync with what the system actually does. - Consultation/approval before rollout: most German state School Acts require the Schulkonferenz and/or Elternbeirat to be consulted (and often to formally approve) before a school introduces new pupil-data-processing software. Build this as a literal onboarding checklist step (§L.9) — the product should not let an admin silently "switch on" a new high-impact module (Signage emergency broadcast to parents, Exam Mode, AI Tutor) without acknowledging this step happened.
- Access to their child's records: parents get read access to grades, reports, competence flower, and any
DisciplinaryRecordflaggedvisibleToParent— already specified in Module A/C/F; this section just anchors it as a legal right, not a product nicety, so it's never gated behind a paywall or admin discretion in a way that would violate that right. - Messaging rights per Module C: the parent escalation rule (parent → homeroom teacher first, 3 business days, then Admin) is a product/pedagogical workflow rule, not a restriction on the parent's underlying legal right to contact the school about their child — make sure the UI frames it as "here's the fastest effective path" and always leaves a true emergency/safety path available that bypasses the queue (tie into Module B's emergency alert / a dedicated "urgent safety concern" contact route that skips the escalation gate entirely).
L.8 School's Rights & Obligations (Controller Responsibilities)
- Controller vs. processor: the school (via its Schulträger) is normally the data controller; if a self-hosted instance is operated by the school itself, the school is both controller and, practically, its own processor/operator (simplifies Art. 28 needs). If a third party (e.g., the agency building this, or a hosting provider) operates the instance for the school, an Art. 28 Auftragsverarbeitungsvertrag (AVV) is required — ship a template AVV in
docs/legal/avv-template.md, clearly marked as a starting draft for the school's DPO/lawyer to finalize, not a ready-to-sign legal document. - Records of Processing Activities (Art. 30): generate a
docs/legal/verzeichnis-verarbeitungstaetigkeiten.md(RoPA) directly from the module/entity documentation — every module in PRD v2 already needs a purpose+legal-basis note (§L.2); assembling those into the formal Art. 30 register should be close to mechanical, not a separate research project. - DPIA trigger (Art. 35): this platform, taken as a whole, plausibly meets the criteria for a mandatory Datenschutz-Folgenabschätzung — large-scale processing of children's data, systematic monitoring (Exam Mode's behavior warnings, Signage's emergency systems), and special-category-adjacent data (health signals). Do not let a school go live with Modules F (Exam Mode) or E (AI Tutor) without a completed DPIA on file — build this as an actual admin-facing gate: those modules stay disabled in the Admin Policy Console until a
DpiaRecord(id, schoolId, moduleScope, completedAt, approvedByUserId, documentRef) exists for them. - Datenschutzbeauftragter (DPO) role: add
DPOas a permission profile in Module K — not a full admin, but someone with read access to the compliance surfaces (RoPA, retention policy table, DPIA records, audit logs across the school) and the specific power to gate-approve high-risk modules before they activate.
L.9 Product-Level Compliance Onboarding Gate
Concretely implement the above as a required onboarding flow for every new school instance, before the platform is usable for real student data:
- Enter Schulträger/DPO contact details.
- Fill in the state (Bundesland) → auto-loads that state's known retention-period prompts (labels only — the school must still confirm actual numbers; never silently assume) into
DataRetentionPolicy. - Acknowledge Elternbeirat/Schulkonferenz consultation status per module before that module can be turned on for real use (a simple checklist, logged with who/when).
- Acknowledge Personalrat consultation status for any monitoring-capable module (§L.4), same mechanism.
- Complete/upload the DPIA before Modules E and F unlock (§L.8).
- Only after these steps does the Admin Policy Console (PRD v2 §9.4) allow those modules to leave "disabled" state.
This turns "must comply with EU/German data protection law" from a documentation aspiration into an actual enforced product flow — consistent with PRD v2 §0's "no hardcoding / everything DB-driven / dynamic" principle: compliance status itself is DB-driven state that gates feature availability, not a one-time audit that's forgotten after launch.
L.10 On the Klotzkette/claude-fuer-deutsches-recht reference repository
This is a large, community-maintained collection of Claude Code skills/prompts for German legal practice (labor law, corporate law, insolvency law, data protection law, procedural law, and — relevantly — clusters touching Schulrecht/Hochschulrecht, school and higher-education law). It is explicitly published as an experimental aid for legal drafting workflows, not a certified compliance product, and its own README repeatedly disclaims that it gives no assurance of correctness or professional-rules compliance.
Recommended, bounded use for this project:
- Use its
datenschutzrecht(data protection law) skill as a drafting assistant when preparing the AVV template (§L.8), the RoPA structure (§L.8), and the parent-facing privacy notice (§L.7) — i.e., as a way to get a solid first draft faster, in the correct German legal style/structure. - Do not treat any output from it (or from this PRD, or from Claude generally) as a substitute for sign-off by the school's actual Datenschutzbeauftragter or legal counsel — encode that caveat directly into any generated legal-adjacent document (
docs/legal/*.mdfiles should carry a header disclaimer). - It is a prompt/skill library, not a code dependency — it has no runtime role in the application itself; keep it entirely out of the app's dependency tree and treat it purely as a tool the development team (or the school's admin/DPO) can consult while authoring the compliance documents in
docs/legal/.
L.11 Updated Definition of Done (compliance-specific additions)
On top of PRD v1 §10 and PRD v2 §11, a school instance is not considered production-ready until:
docs/DATA_MODEL.mdhas a purpose + legal-basis note for every entity holding personal data.DataRetentionPolicyrows exist (school-confirmed, not defaulted) for every legally-mandated category.docs/legal/verzeichnis-verarbeitungstaetigkeiten.md(RoPA) is generated and reviewed.- AVV signed (if a third party operates the instance) or explicitly marked not-applicable (self-hosted-by-school).
- DPIA completed and on file before Modules E (AI Tutor) or F (Exam Mode) are enabled.
- Elternbeirat/Schulkonferenz consultation logged per module.
- Personalrat consultation logged for every monitoring-capable module.
- Student/parent/teacher self-service data-export flows tested end-to-end.
- Privacy notice generator produces an accurate, plain-language notice reflecting actual configured retention periods (no drift between docs and DB config).
PRD (Consolidated) — "SchoolOS" — A Free, Self-Hosted, All-in-One School Platform
(Digidoo-inspired competency core, expanded into a full school operations platform, fully EU/German data-protection compliant. This document merges and supersedes the three prior drafts — Digidoo-clone build prompt, School Platform PRD v2, and Legal Compliance addendum v3 — into a single reference PRD.)
0. Mission & Non-Negotiable Principles
This is a free, donation-supported school project, not a commercial SaaS. It is being built for a real school; any support it receives goes back to the school. These principles override every design decision in this document:
- DB: SQLite. Single-file, self-hostable, cheap to run and back up. (One narrow exception: an optional embedded vector store for AI search — §9 — which can also run fully local/in-process.)
- No hardcoding, anywhere. Every list, label, rule, threshold, escalation window, warning count, template, retention period, and permission must come from the database or an admin-editable config table — never a constant baked into code. If a value could plausibly differ between two schools, two German states, or change next semester, it is a DB row, not a literal.
- No mock data, ever — not in dev, not in demo, not in shipped UI. Seed scripts may create realistic sample rows for local development (clearly documented as seed data, easily wiped), but the shipped application must never silently render placeholder/fake data as if real.
- No duplicate functionality across pages. Every capability lives in exactly one canonical place (e.g., all dates live only in the Calendar module; all alerts render only through the Notifications module). Before adding any feature, check whether an existing module already owns that responsibility; extend it there or surface it as a read-only widget — never rebuild it.
- Tablet-first, touch-first, with full parity and a well-adapted layout for desktop/PC. This is the primary device class for teachers and students in-classroom.
- Everything is dynamic and role/permission-aware, driven by real DB relationships (school → year → class → subject → student → user), never assumed.
- Fully compliant with EU and German data protection law (GDPR/DSGVO, BDSG, and the relevant state's Schulgesetz/Schul-Datenschutzverordnung), with explicit, engineered protections for student rights, teacher rights and staff co-determination (Personalrat/unions), parent rights, and the school's own controller obligations — detailed fully in Module L (§11). This is not a documentation afterthought: compliance status is itself DB-driven state that gates feature availability (§11.9).
- Recommended open-source license: AGPLv3 (prevents a third party from taking this free/community project and reselling it closed-source without contributing back) — team to confirm.
Hard disclaimer to carry into the product and into
docs/: This PRD gives the engineering requirements needed to make legal compliance possible. It is not legal advice. Every school deploying this platform must involve its own Datenschutzbeauftragter (DPO), its Schulträger, and — for co-determination matters — its Personalrat/Lehrerrat before go-live (see §11.9).
1. Reference Product Analysis (functional inspiration only, not a visual/brand copy)
Digidoo (digidoo.com) is a German/Austrian EdTech SaaS. Do not copy their branding, illustrations, exact wording, logo, or any copyrighted text/images — build an original UI/UX and original copywriting, only inspired by the feature set and workflow concept. Core concepts we reproduce functionally in Module A (§4):
- Competency grids ("Kompetenzraster"): pre-built and customizable sets of subject/grade-level competencies teachers can use as templates or fully customize.
- Learning progress entries: teachers log individual observations per student, linked to one or more competencies, over time (a running log, not a snapshot).
- Performance assessments ("Leistungsfeststellung"): structured tests/assignments/checks linked to competencies, feeding the same student timeline.
- Competence Flower ("Kompetenzblume"): a radar/spider chart per student showing strength per competency category.
- One-click reports: automatically generated, competency-based report text and full report-card documents (PDF).
- Grade management ("Notenverwaltung"): configurable weighting between learning-progress entries and formal assessments to compute a transparent final grade.
- Free tier that "just works": since this whole project is free, the entire app is simply free — no tiers.
We explicitly exclude anything tied to Digidoo's commercial SaaS business (billing/subscriptions, marketing site, SSO/enterprise integrations like WebUntis) as out of MVP scope.
2. Module Map
The platform is organized into cohesive modules, each owning its data and UI completely (principle #4 above).
| # | Module | Owns |
|---|---|---|
| A | Academics Core | Competency grids, learning-progress entries, assessments, competence flower, grading, report cards |
| B | Signage | TV/billboard displays: announcement slides, sponsor slides, emergency/fire/counseling alerts |
| C | Communication | Direct messaging, escalation rules, class/grade social rooms, class-hours messaging locks |
| D | Learning Hub | Videos, interactive exercises, worksheets, vocab trainer, learning game, AI-assisted content authoring |
| E | AI Tutor | In-context homework help, hint-only policy, full lockout during tests, content translation for foreign students |
| F | Exam Mode | Kiosk/lockdown test-taking, teacher live controls, student warning system, incident log |
| G | Digital Notebook | Typed + stylus/pen notebook per student per subject, teacher pen annotation on tests/homework |
| H | Notifications | All push/in-app notifications — the only place alerts render outside their originating context banner |
| I | Calendar | All dates/deadlines/appointments/exam schedules/report deadlines — the only source of truth for "when" |
| J | Dashboard & Widgets | Per-user customizable home screen assembled from read-only widgets pulling from A–I |
| K | Identity & Admin | Users, roles, schools, classes, disciplinary records, audit log, permission/rule configuration |
| L | Legal & Data Protection | GDPR/DSGVO compliance engine, retention policy, DPIA gating, RoPA, rights fulfillment for all parties |
3. Tech Stack
- Frontend: React (or Next.js in a single full-stack app) + TypeScript. UI: Tailwind CSS + shadcn/ui. Charting: Recharts or Chart.js (radar chart for the Competence Flower).
- Backend: Next.js (App Router) full-stack, keeping frontend + backend in one deployable app — simplest for a small volunteer team.
- Database: SQLite via Prisma ORM (or Drizzle — pick one, justify). Reasoning: trivial hosting (single file, easy backups, ample for a single school's scale), migrations + type safety, and a documented upgrade path to Postgres if a school ever outgrows SQLite (avoid SQLite-only quirks in app logic to keep this portable).
- Auth: Self-hosted email/password (argon2id hashing) + session cookies (Lucia Auth / Auth.js credentials provider). No third-party paid auth. Optional TOTP 2FA.
- PDF generation:
@react-pdf/rendereror Puppeteer-based HTML-to-PDF for report cards. - File storage: Local filesystem (school-hosted), abstracted behind a storage interface so S3-compatible storage can be swapped in later.
- Hosting target: Single Docker container / docker-compose with a volume for the SQLite file + generated files, deployable on a small VPS.
- i18n: German and English UI strings from day one (
next-intlor equivalent) — all UI text through translation keys, never hardcoded. - PWA/Kiosk infrastructure: Workbox for the service worker — offline shell caching, reliable kiosk/fullscreen "install as app" behavior, and Web Push delivery (Modules F, H, §9).
- Worker offloading: Comlink to offload heavy client-side work (stylus stroke processing in the Digital Notebook, client-side AI-translation pre/post-processing) to a Web Worker via simple RPC, keeping the main thread responsive for touch input (§9).
- AI/semantic search (optional): Chroma, an embeddable vector database, for semantic search over Learning Hub resources and retrieval-augmented context for the AI Tutor. Keep it behind an interface, not a hard dependency — a school without AI features never needs to run it. Core relational data always stays in SQLite (§0.1); Chroma, if used, stores only content embeddings for retrieval, never core school records (§9).
- Testing: Vitest/Jest (unit), Playwright (E2E for critical flows: login, create competency grid, log an entry, generate report, run an exam session).
Deliver docs/ARCHITECTURE.md (stack rationale + self-hosting path) and docs/SELF_HOSTING.md (Docker deployment for a non-technical school IT admin).
4. Module A — Academics Core
4.1 Entities
Organizational:
- School — id, name, schoolType (elementary/middle/gymnasium/other), country, timezone, createdAt.
- User — id, schoolId (nullable), email, passwordHash, firstName, lastName, role, locale, twoFactorSecret (nullable), createdAt, deletedAt (soft delete).
- SchoolYear — id, schoolId, label, startDate, endDate.
- ClassGroup — id, schoolId, schoolYearId, name, gradeLevel, schoolType.
- ClassGroupTeacher (M:N) — classGroupId, userId, role (HOMEROOM_TEACHER, SUBJECT_TEACHER).
- Student — id, schoolId, firstName, lastName, dateOfBirth (nullable, minimize what's collected), externalId (nullable, import matching), createdAt, deletedAt.
- Enrollment — id, studentId, classGroupId, schoolYearId, startDate, endDate (nullable = still enrolled) — models students moving between classes/schools over time.
Subject & competency structure:
- Subject — id, schoolId (nullable = global template), name, gradeLevelMin/Max.
- CompetencyTemplate — id, name, description, subjectId (nullable), schoolType, gradeLevelMin/Max, isGlobalTemplate, createdByUserId (nullable for system templates), version.
- CompetencyCategory — id, competencyTemplateId, name, order (groups competencies into "petals" of the flower — e.g. Reading/Writing/Listening within Language Arts).
- Competency — id, categoryId, code, title, description, order, masteryLevels (related table).
- MasteryLevelDefinition — id, competencyId (or categoryId if shared), levelValue, label, description.
- ClassCompetencyAssignment — links a ClassGroup+Subject to a chosen CompetencyTemplate for a SchoolYear, plus per-school customizations. Clone-on-customize: assigning a template creates an editable school-owned copy so edits never mutate the global template.
Progress & assessment:
- LearningProgressEntry — id, studentId, competencyId, teacherId, classGroupId, date, masteryLevelValue, note (optional), createdAt — append-only observation log.
- Assessment ("Leistungsfeststellung") — id, classGroupId, subjectId, teacherId, title, date, type (TEST/ORAL/PROJECT/HOMEWORK/OTHER), maxScore (nullable), weight, deliveryMode (enum incl.
DIGITAL_LOCKED, which triggers Module F's kiosk flow). - AssessmentCompetencyLink (M:N) — assessmentId, competencyId, weight.
- AssessmentResult — id, assessmentId, studentId, score (nullable), masteryLevelValue (nullable), note.
Grading:
- GradingScheme — id, classGroupId or subjectId, name, type (NUMERIC_GRADE/VERBAL_FEEDBACK/COMBINED), scaleDefinition (JSON, configurable per country/state).
- GradingWeightRule — id, gradingSchemeId, sourceType (LEARNING_PROGRESS/ASSESSMENT), targetRef, weightPercent.
- ComputedGrade — id, studentId, subjectId, classGroupId, schoolYearId, period, computedValue, computedAt, isFinalized, finalizedByUserId (required, human — see §11.5), overriddenValue (nullable), overrideReason.
Reporting:
- Report — id, studentId, classGroupId, schoolYearId, period, generatedByUserId, generatedAt, status (DRAFT/FINAL), pdfFilePath, includesGrades, optional appendix of Digital Notebook entries for the period (teacher-selectable, off by default).
- ReportSection — id, reportId, competencyCategoryId (nullable), generatedText, order.
Auditing:
- AuditLog — id, userId, action, entityType, entityId, timestamp, metadata (JSON).
- DataExportRequest — id, requestedByUserId, scope, status, filePath, requestedAt, completedAt.
Design requirements: UUID/ULID primary keys (not SQLite-only autoincrement, for portability). All timestamps UTC. Soft deletes on Student/User with an explicit, audit-logged "permanently erase" flow, never a silent hard delete. SQLite WAL mode enabled; document backup strategy (copy the .sqlite file + files directory; consider litestream). Seed script (prisma/seed.ts) creates a demo school, teacher login, 2 classes, ~15 students, one sample competency template (Math + German, elementary, 2 categories, ~6 competencies each, 4-point scale), sample entries and one assessment — app explorable immediately after docker-compose up.
4.2 Roles for this module
Teacher, School Admin, Super Admin — see full role model in §10 (Module K), which extends this with Counselor, Parent, Student, and DPO.
4.3 Core user stories
- Onboarding & auth: register/login/reset with argon2id-hashed passwords, optional TOTP 2FA, rate-limited login, CSRF protection on mutating routes.
- School/class/student setup: create classes, set grade level/school type, add students (manual or CSV import with preview + error list + re-run).
- Competency grid management: browse starter templates filtered by school type/grade/subject; assign (clone) to a class+subject; edit the school's copy or build custom.
- Logging learning progress: fast entry from a class roster (<3 interactions), full student timeline, entries editable by the original author within a configurable window, all edits audit-logged.
- Assessments: create, link to competencies with weights, bulk spreadsheet-like results entry for a whole class.
- Competence Flower: per-student radar chart, aggregation method configurable per template (latest value / average of last N / weighted by recency), hover/tap shows underlying entries, exportable as PNG/SVG.
- Grade computation: transparent weighted breakdown, manual override with required justification (audit-logged), computation is a pure deterministic function with unit tests covering edge cases (missing data, all-verbal, partial-year enrollment).
- Reports: draft → review/edit → finalize (locked + versioned) → PDF, single or bulk-class export, phrase-template system (data-driven, not hardcoded) for narrative text per mastery level.
- Data portability & privacy: export all class/school data as JSON/CSV; permanent erasure with confirmation + audit trail, cascading correctly including generated PDFs on disk (this flow is unified with Module L's rights fulfillment, §11.5).
- Dashboard: classes, recent activity, students without a recent entry (follow-up flag), upcoming report deadlines — surfaced as widgets in Module J, not a separate dashboard implementation.
5. Module B — Signage (TV / Billboards)
Replaces physical bulletin boards with school-controlled TV displays for announcements, class/period info, sponsor content, and emergency alerts.
Roles: Admin/Management authors & publishes; sponsor content is admin-approved only (no self-serve); teachers can request a slide (goes to an approval queue by default, config-togglable to trusted self-publish for INFO-type slides).
Entities:
- SignageDisplay — id, schoolId, location/name, resolution profile, isActive.
- SignageSlide — id, schoolId, type (ANNOUNCEMENT/SPONSOR/INFO/SCHEDULE), title, body/media, priority, startAt, endAt, createdByUserId, approvalStatus.
- SignagePlaylist — id, displayId (or all displays), ordered slide list, rotation duration per slide.
- EmergencyAlert — id, schoolId, type (FIRE/LOCKDOWN/MEDICAL/GENERAL_EMERGENCY/COUNSELING_NOTICE), message, triggeredByUserId, triggeredAt, resolvedAt, affectedScope.
Core flows:
- Normal rotation cycles active, date-windowed slides weighted by priority.
- Emergency override (highest priority, non-negotiable): any
EmergencyAlertimmediately interrupts every display's rotation with a full-screen, type-styled alert, and simultaneously fires a push notification (Module H) to staff, and for FIRE/LOCKDOWN to logged-in students/parents per school policy. Clears only on explicit resolution by an authorized user, logged in AuditLog. - Counseling notice: lower-urgency, staff-facing only variant — not broadcast school-wide, avoids exposing a student's need for support (also see §11.3).
- Sponsor slides: admin-uploaded, date-windowed, weighted rotation, never auto-published from a teacher request.
6. Module C — Communication (Messaging & Escalation)
The escalation logic is implemented as data-driven policy rows, never hardcoded if/else chains.
Entities:
- MessageThread — id, schoolId, type (DIRECT/CLASS_ANNOUNCEMENT/SOCIAL_ROOM), participantsOrScope.
- Message — id, threadId, senderId, body, sentAt, readReceipts.
- EscalationPolicy — id, schoolId, fromRole, toRole, requiredPriorContactRole, waitingPeriodBusinessDays (default 3), isActive, overriddenByUserId (nullable). All numbers here are read from this table, never hardcoded.
- EscalationRequest — id, requesterId, subject, firstContactThreadId, firstContactAt, eligibleToEscalateAt (computed using the school calendar to skip holidays — Module I), status (WAITING/ELIGIBLE/ESCALATED/RESOLVED).
- SocialRoom — id, schoolId, scope (CLASS/GRADE_LEVEL/CUSTOM_GROUP), name, moderatorUserIds, isActive.
- ClassMessagingLock — id, classGroupId, lockedByUserId, lockedFrom, lockedUntil (nullable = "until class ends," period-aware via Module I).
- DisciplinaryRecord — id, userId, type, description, issuedByUserId, linkedIncident (nullable FK to an ExamWarning or reported message), visibleToParent (bool, enforced access control, not just UI — §11.5), createdAt.
Core rules (default EscalationPolicy rows, admin-editable):
- Parent → Admin: only for genuinely necessary matters, and only after messaging the student's homeroom teacher first. If no reply within 3 business days, the parent gains the right to escalate to Admin on that thread.
- Student → Admin/Counseling: same pattern — homeroom teacher first, then counseling/admin after 3 business days without reply.
- Teacher → Admin: direct, no escalation gate.
- Admin override: can loosen, tighten, or remove any
EscalationPolicyrow, or grant a case-by-case exception (logged with reason). Can issue aDisciplinaryRecordagainst a teacher or student from a messaging or exam-incident context. - Social rooms: class- or grade/"Stufe"-scoped group discussion spaces, moderated, config-controlled per school (which scopes enabled, moderation-before-visible or not).
- Class-hours lock: teacher toggles
ClassMessagingLockfor their class; students blocked from student↔student and student↔staff messaging until lifted (auto-lift at period end via Module I, or manual — config toggle) — students still receive urgent Signage/Notification-level alerts. - True-emergency bypass: the escalation queue always has a parallel "urgent safety concern" path that skips the 3-business-day gate entirely (§11.7) — the escalation rule is a workflow-efficiency rule, never a barrier to reporting a genuine safety issue.
Business-day computation reads the school's holiday/weekend calendar from Module I, never assumes fixed Mon–Fri.
7. Module D — Learning Hub
A curriculum-aligned self-study resource center, functionally inspired by tools like Sofatutor — original or licensed/open content only, organized the same way (by subject/grade), never copying branding, exact video content, or exact wording.
Entities:
- LearningResource — id, schoolId (nullable = shared library), subjectId, gradeLevel, type (VIDEO/INTERACTIVE_EXERCISE/WORKSHEET/VOCAB_SET/GAME_MODULE), title, description, contentRef, competencyLinks (M:N to
Competency, so resources surface contextually — e.g. from a weak competency-flower petal), createdByUserId, reviewStatus (DRAFT/PENDING_REVIEW/PUBLISHED), aiGenerated (bool). - WorksheetSolution — attached to a WORKSHEET resource, hidden by default, revealable by student after attempt or by teacher setting.
- VocabSet / VocabItem — vocab lists feeding a spaced-repetition vocab trainer.
- GameProgress — per-student progress/score for the learning game, scoped by subject.
Core flows: teachers/admin create/edit or request AI-assisted drafting (always lands PENDING_REVIEW, never auto-published — human review required). Resources are discoverable by subject/grade browse, search, and contextually (surfaced next to a weak Competence Flower petal and in AI Tutor suggestions). Printable worksheets export as PDF with a teacher toggle to include/exclude the solutions page.
8. Module E — AI Tutor & AI Content Assistance
Hard policy — enforced server-side, not just prompt instructions:
- May: explain a concept, walk through a similar worked example, give a hint, define a term, nudge toward the next step on a specific question.
- Must never: produce a direct final answer to an assigned homework/assessment question, complete an assignment for the student, or operate at all while any
AssessmentwithdeliveryMode = DIGITAL_LOCKEDis active for that student — the AI chat endpoint independently checks "is this student currently inside an active exam session?" server-side and refuses if so, regardless of client-side UI state (ties into Module F's defense-in-depth, §8). - Every interaction is logged (
AiTutorInteraction: id, studentId, subjectId/competencyId, promptSummary, responseSummary, timestamp, flaggedAsHomeworkAttempt) for teacher/admin audit — defaulting to summary-only, pseudonymized retention per §11.2/§11.3, with a school-configurable toggle for full-transcript retention and an explicit retention period from Module L. - Translation: on-demand AI translation of learning content (and optionally UI copy) for foreign-language students, labeled "AI-translated," with a flag-for-review path for bad translations. Home-language inference from translation requests is treated with the same minimization discipline as any other data point (§11.3) — no persistent linguistic/ethnic profile is built.
- Content-authoring assist (bridges Module D): the same AI capability drafts Learning Hub resources or Signage copy, always landing in a review/draft state.
Module E must never ship ahead of Module F's server-side test-time gate (§13, phasing).
9. Module F — Exam Mode (Digital Lockdown & Proctoring)
Entities:
- ExamSession — id, assessmentId, studentId, deviceId, startedAt, status (ACTIVE/PAUSED/RESUMED/ENDED/CANCELLED), pausedByUserId (nullable), pauseReason (BATHROOM_REQUEST/TEACHER_INITIATED/STUDENT_DISTRESS/THIRD_WARNING/OTHER).
- ExamWarning — id, examSessionId, issuedByUserId, reason, sequenceNumber, issuedAt.
- ExamIncidentEvent — id, examSessionId, type (LOCK_BREACH_ATTEMPT/BATHROOM_REQUESTED/BATHROOM_GRANTED/DISTRESS_SIGNAL/PAUSED/RESUMED/CANCELLED), metadata, timestamp.
Core flow:
- Opening a
DIGITAL_LOCKEDassessment enters kiosk/fullscreen lockdown — device locks to the exam UI only, no other tabs/apps, no AI Tutor access (hard-gated), timer visible per config. - Bathroom request: student taps "request break" → real-time alert to teacher (Module H) → teacher approval pauses that individual
ExamSessiononly → resumes on return. - Distress signal: student sends "I feel unwell / need help" at any time → immediate high-priority alert, distinct styling/sound from a routine request → teacher attends; unresolved → teacher pauses or cancels that student's exam (reason required, logged, visible to parent/admin). This is health-adjacent data — store only a minimal event flag plus optional free text, never a structured symptom/diagnosis field, restricted to need-to-know visibility (§11.3).
- Behavior warnings: teacher issues an
ExamWarningfor talking/looking around, etc. 1st and 2nd logged and shown to the student (2nd explicitly "final warning"); 3rd auto-pauses that student's exam — but the pause itself is a safety/integrity mechanism, not an Art. 22 "decision" about the student; any resulting disciplinary consequence requires a human to actually create the linkedDisciplinaryRecord— the system never auto-generates one (§11.5). - Teacher gets a live class exam-monitor view: every student's session status at a glance, one-tap pause/resume/cancel/warn.
- Lockdown enforcement is defense-in-depth: client-side kiosk/fullscreen API + Workbox service worker to intercept navigation attempts, and an independent server-side session flag blocking AI Tutor/Learning Hub/Messaging calls for the duration — never trust the client alone for an integrity feature.
Module F is the highest integrity/device-sensitivity module — see phasing (§13): built last, after the touch/kiosk foundation (§9 tech stack) is mature.
10. Module G — Digital Notebook
Digital replacement for the paper exercise notebook (explicit environmental motivation), supporting Germany's range of notebook/exercise-book conventions.
Entities:
- NotebookTemplate — id, schoolId (nullable = global), name, ruling type (lined/squared-Kariert/blank), gradeLevel/subject applicability.
- NotebookPage — id, studentId, subjectId, classGroupId, templateId, createdAt, content (typed text blocks + vector "ink" strokes stored as SVG/stroke-JSON, not raster, so it stays editable/searchable/annotatable).
- NotebookAnnotation — id, pageId (or linked Assessment submission), authorUserId, strokeData/comment, createdAt — non-destructive teacher correction marks, captured as its own layer so original student work is never overwritten.
Core flows: students write via keyboard and/or stylus, both coexisting on a page. Teachers annotate directly on a digital test/notebook page with pen input (highlighting, circling, margin comments), mirroring paper red-pen correction. Pages organized per subject per student per school year, browsable page-by-page/date-by-date, exportable as PDF.
11. Cross-Cutting Modules H–K, and Module L (Legal & Data Protection)
11.1 Module H — Notifications (single source of alerts)
Every push/in-app alert — messaging, exam warnings/bathroom requests, signage emergencies, escalation-eligibility notices, learning-hub review-queue items — routes through one Notification entity and one delivery pipeline (Web Push API via Workbox service worker + an in-app notification center). No module renders its own separate toast/badge system; every other module emits into Module H (per §0.4).
Notification — id, recipientUserId, type, priority (NORMAL/URGENT/EMERGENCY), title, body, deepLinkRef, createdAt, readAt, deliveredChannels (JSON).
11.2 Module I — Calendar (single source of "when")
All dates live here: class timetable/periods, exam schedules, report-card deadlines, school holiday calendar (feeds Module C's business-day math), signage slide date windows (read-only reflection of SignageSlide.startAt/endAt, not a duplicate field). Same non-duplication logic applies to every other module with a date.
11.3 Module J — Dashboard & Widgets
Every role gets a customizable home dashboard: add/remove/reorder widgets from an approved catalog, each a thin read-only view into one owning module. Layout persists per user (UserDashboardLayout — userId, widgetInstances JSON: widgetType, position, size, config). Widgets never contain business logic beyond fetch/render — structurally enforcing §0.4.
11.4 Module K — Identity, Roles & Admin
Roles: Teacher, School Admin, Super Admin (project/instance maintainer), Counselor ("Rehberlik" — receives escalated threads per Module C), Parent (read-only into their child's reports/grades/flower/visible disciplinary records, messaging per Module C), Student (Learning Hub, gated AI Tutor, Exam Mode, Digital Notebook, gated Communication), and DPO (Module L, §11.8 — compliance-surface read access + gate-approval power over high-risk modules). Sponsor is not a login role — sponsor content is admin-managed only. All escalation thresholds, warning limits, kiosk toggles, and messaging rules are exposed in a single Admin Policy Console so a non-technical admin can tune the entire rules engine without a code change.
11.5 Module L — Legal, Data Protection & Rights Compliance (EU/DE)
This module governs every other module. It layers EU GDPR (DSGVO), the German Federal Data Protection Act (BDSG), and the state-level School Acts (Landesschulgesetze) and School Data Protection Ordinances, which vary across all 16 Bundesländer and often override/supplement the GDPR baseline for public schools — plus Landespersonalvertretungsgesetz (LPVG)/BPersVG for staff co-determination, and general child-rights principles (KJSG/UN-CRC).
Data protection by design & default (Art. 25), applied to every module:
- Data minimization at schema level — every optional field defaults to not collected (e.g.,
Student.dateOfBirthstays nullable, populated only if state rules actually require it). - Purpose limitation — each table documents its legal basis/purpose in
docs/DATA_MODEL.md(e.g.,ExamWarning→ exam integrity & pedagogical record; legal basis: Schulgesetz duty of fair assessment). - Pseudonymization where feasible (e.g.,
AiTutorInteractionstores a pseudonymous reference by default). - Storage limitation — every personal-data entity has a
retentionPolicyRefintoDataRetentionPolicy(below), swept by a scheduled job, never a manual "someone remembers" process. - Access control defaults to deny — a Teacher's access to a student is scoped to classes currently taught; losing that assignment auto-narrows access.
Special-category / sensitive data (Art. 9) — explicit flags at every touchpoint:
- The Exam Mode distress signal (§8) is health-adjacent: minimal event flag only, restricted visibility, short default retention unless it escalates into a formal record.
DisciplinaryRecord— highly sensitive minor data even if not technically Art. 9; same need-to-know visibility model;visibleToParentis a real enforced access-control flag, never just a UI toggle.- Signage counseling notices (§5) never broadcast identifying detail school-wide.
- No field anywhere in the schema for race/ethnicity/religion/sexual orientation/union membership/political opinion — explicitly out of scope, permanently.
Teacher rights & staff co-determination (Personalrat/unions):
- Any feature capable of monitoring staff behavior or performance (
AuditLogon teacher actions, message read-receipts, exam-monitor response-time visibility, content-approval analytics, etc.) triggers Personalrat co-determination rights under the relevant state LPVG (or BPersVG) — analogous to § 87(1) No. 6 BetrVG in the private sector. - Before shipping to a real school, each such feature needs a Dienstvereinbarung-ready spec sheet (
docs/personalrat/<module>.md): what's logged, who sees it, retention, and an explicit statement it won't be used for unilateral performance evaluation without Personalrat agreement. - Recommend looping in GEW/VBE and the Personalrat during rollout — surfaced as a required onboarding checklist item (§11.9) before enabling any monitoring-capable module.
- Teachers get the same self-service data-export as students (reusing the one pipeline, §0.4), and a per-teacher "quiet hours" setting for non-urgent notifications (urgent/emergency alerts always bypass this by design).
Student rights:
- Access (Art. 15): full export via the one Module K export pipeline — competency entries, grades, notebook pages, messages, disciplinary records, AI Tutor interaction summaries.
- Rectification (Art. 16): via existing audit-logged edit flows in Module A.
- Erasure (Art. 17), bounded by retention duties: account/active data erasable on request or on leaving school, except records under an active
DataRetentionPolicy; erasure response reports what was retained and why. - No solely-automated decisions with legal/significant effect (Art. 22):
ComputedGrade.isFinalizedcannot becometruewithout afinalizedByUserId(a human). Exam Mode's third-strike pause may be automatic (safety mechanism), but any resultingDisciplinaryRecordrequires a human actor — never auto-generated. - No repurposing into a broader "risk score" or similar — explicitly a forbidden feature (not just unbuilt), documented in
docs/ROADMAP.md's "will not build" section.
Retention periods — config-driven (extends §0.2):
- New entity DataRetentionPolicy — id, schoolId, dataCategory (LEARNING_PROGRESS/ASSESSMENT_RESULT/FINAL_REPORT/DISCIPLINARY_RECORD/EXAM_INCIDENT/MESSAGE/AI_TUTOR_LOG/NOTEBOOK_PAGE/SIGNAGE_LOG), retentionPeriodMonths, legalBasisNote (free text, filled by the school's DPO), reviewedByUserId, reviewedAt.
- Ship empty of defaults for legally-mandated categories (forces the DPO to enter their state's actual correct numbers, never a guessed default); ship modest editable defaults for non-mandated, product-only categories (e.g., AI Tutor log summaries ~12 months).
Parent rights:
- Information duty (Art. 13/14): plain-language privacy notice generated from the same module documentation/retention config, so it can never drift from what the system actually does.
- Consultation/approval before rollout: most state School Acts require Schulkonferenz/Elternbeirat consultation before new pupil-data software goes live — a literal onboarding checklist step (§11.9); no silent activation of high-impact modules (Signage emergency broadcast, Exam Mode, AI Tutor) without acknowledging this happened.
- Access to their child's records: grades, reports, competence flower,
visibleToParent-flagged disciplinary entries — never paywalled or admin-discretionary in a way that would violate this right. - Messaging rights: the escalation rule (§6) is a workflow-efficiency rule, never a barrier to a genuine safety concern — a parallel urgent path always bypasses the gate.
School's rights & obligations (controller responsibilities):
- Controller vs. processor: the school (via its Schulträger) is normally the data controller; a self-hosted instance run by the school itself simplifies Art. 28 needs, while a third-party-operated instance requires a signed Art. 28 AVV — ship a starting-draft template in
docs/legal/avv-template.md, explicitly marked for the DPO/lawyer to finalize. - Records of Processing Activities (Art. 30):
docs/legal/verzeichnis-verarbeitungstaetigkeiten.md, generated mechanically from each module's purpose+legal-basis notes. - DPIA (Art. 35): the platform plausibly meets mandatory-DPIA criteria (large-scale children's-data processing, systematic monitoring via Exam Mode, health-adjacent signals). Modules E (AI Tutor) and F (Exam Mode) stay disabled in the Admin Policy Console until a
DpiaRecord(id, schoolId, moduleScope, completedAt, approvedByUserId, documentRef) exists. - DPO role (Module K extension): read access to RoPA, retention policy table, DPIA records, and school-wide audit logs, plus gate-approval power over high-risk modules.
Product-level compliance onboarding gate — implemented as a required flow for every new school instance before real student data is usable:
- Enter Schulträger/DPO contact details.
- Select the Bundesland → auto-loads that state's known retention-period prompts (labels only, never assumed numbers) into
DataRetentionPolicyfor confirmation. - Log Elternbeirat/Schulkonferenz consultation status per module before it can go live for real use.
- Log Personalrat consultation status for every monitoring-capable module.
- Complete/upload the DPIA before Modules E and F unlock.
- Only then does the Admin Policy Console allow those modules to leave "disabled" state.
This makes compliance a DB-driven, enforced product flow, consistent with §0.2/§0.6 — never a one-time audit forgotten after launch.
On the Klotzkette/claude-fuer-deutsches-recht reference repository: a large, community-maintained collection of Claude Code skills/prompts for German legal practice (labor, corporate, insolvency, data-protection, procedural law, plus Schulrecht/Hochschulrecht clusters), explicitly published as an experimental legal-drafting aid, not a certified compliance product. Bounded recommended use: consult its datenschutzrecht skill as a drafting assistant when preparing the AVV template, the RoPA structure, and the parent-facing privacy notice — a faster, correctly-structured first draft. Never treat its output (or this PRD's, or any AI's) as a substitute for sign-off by the school's actual DPO or legal counsel — every generated docs/legal/*.md file should carry that disclaimer as a literal header. It is a prompt/skill library, not a runtime dependency — keep it entirely out of the app's dependency tree.
12. Touch/Tablet UI-UX & AI Infrastructure Notes
- Minimum touch target 44×44pt, larger on primary actions (exam controls, entry-logging buttons).
- Enlarged cards/list rows at tablet breakpoint, denser layout at desktop breakpoint — one responsive design system, not two codebases.
- Kiosk/fullscreen mode: Fullscreen API + Workbox service worker (offline shell caching, reliable PWA install, push delivery even when the tab isn't focused).
- Free browser push notifications via the Web Push API — no paid vendor required.
- Full keyboard navigation and screen-reader labels (WCAG 2.1 AA target), extended to Signage (legible from a distance) and Exam Mode (usable with assistive tech even inside lockdown).
- Original visual design — no reuse of Digidoo's illustrations, palette, or copy; a small design-token set (colors, spacing, typography), warm and education-appropriate, distinct accent color.
- Mobile/tablet-first specifically for the entry-logging flow; desktop-first is fine for admin/setup and reports.
- German and English complete from day one; default German (DACH audience), English complete since this is an open project others may adopt.
- Empty states and an onboarding checklist for a brand-new school ("1. Create your first class → 2. Assign a competency grid → 3. Add students → 4. Log your first entry").
13. Non-Functional Requirements
- Self-hostability: one
docker-compose.yml, one.env.example, aREADME.mda non-expert school IT person can follow — target under 10 commands fromgit cloneto a running app. - Performance: SQLite + server-rendered pages where sensible; paginate long lists (rosters, entry timelines).
- Backups: documented, scripted daily backup (cron copying the SQLite file + files directory); consider
litestream; document SQLite's concurrent-write limits and when a school should be advised to migrate to Postgres. - Security: Zod (or equivalent) input validation at every API boundary, parameterized queries only, secure cookie flags, rate limiting on auth endpoints, dependency vulnerability scanning in CI. Exam Mode integrity is defense-in-depth (§9.6). Emergency Alerts (§5) need the lowest possible latency path, treated as fire-drill-grade reliability, with explicit failure/retry testing.
- Data minimization: AI Tutor logging defaults to summary-only (§8); Digital Notebook stroke data is exportable/erasable like any other student record (§11.5).
- Accessibility: WCAG 2.1 AA across all modules.
- CI/CD: GitHub Actions running lint, typecheck, unit tests, E2E smoke tests on every PR.
14. Project Structure (suggested)
/app # Next.js App Router pages
/(auth)
/(dashboard)
/api
/components
/lib
/db # Prisma/Drizzle client, schema
/grading # pure grading calculation functions + tests
/reports # report generation + PDF rendering
/permissions # authorization helpers
/compliance # retention sweeps, DPIA gate checks, RoPA generation
/prisma (or /drizzle)
schema.prisma
seed.ts
migrations/
/docs
ARCHITECTURE.md
SELF_HOSTING.md
DATA_MODEL.md # ER diagram + entity descriptions + purpose/legal-basis notes
CONTRIBUTING.md
ROADMAP.md # incl. explicit "will not build" section
/legal
avv-template.md
verzeichnis-verarbeitungstaetigkeiten.md
/personalrat
<module>.md # co-determination spec sheets per monitoring-capable module
/tests
unit/
e2e/
docker-compose.yml
.env.example
README.md
LICENSE
15. Revised MVP Phasing
Given the scope, ship in stages, each fully functional and demo-able:
Stage 1 — Foundation: Identity/roles/schools/classes/students, Module A (Academics Core) end-to-end, Calendar (Module I) as the shared date backbone, Notifications (Module H) skeleton, Dashboard/Widgets (Module J, 2–3 widgets), and the compliance foundation: DataRetentionPolicy table, docs/DATA_MODEL.md purpose/legal-basis notes, and the onboarding gate skeleton (§11.9 steps 1–2).
Stage 2 — Communication & Signage: Module C in full (messaging, escalation policy engine, social rooms, class lock, the urgent-safety bypass path), Module B (signage, including Emergency Alert override), wired into Module H/I. Add onboarding gate steps 3–4 (Elternbeirat/Schulkonferenz and Personalrat consultation logging) since Module C introduces monitoring-adjacent surfaces (read receipts, audit trail).
Stage 3 — Learning & AI: Module D (Learning Hub, manual authoring first, AI-assist fast-follow), Module E (AI Tutor with hard test-time gating from day one — never ship before Module F's gate exists). DPIA gate (§11.9 step 5) must be functional before Module E can be enabled for real use.
Stage 4 — Exam Mode & Digital Notebook: Module F (kiosk lockdown, warnings, monitor view) and Module G (typed + stylus notebook, teacher annotation) — highest-integrity/most device-sensitive modules, saved for last so the touch/kiosk foundation is mature first, and gated behind the completed DPIA per §11.9.
Each stage gets its own seed data, test-suite additions, and docs/ROADMAP.md entry.
16. Definition of Done (MVP + full platform)
Core functionality (per module, §4–10):
- Auth (register/login/reset, optional 2FA) end-to-end.
- School → SchoolYear → ClassGroup → Student → Enrollment CRUD with CSV import.
- At least 2 seeded starter competency templates with categories, competencies, and a mastery scale.
- Template assign/clone + school-copy editing.
- Fast entry-logging UI from a class roster.
- Assessments with bulk grid entry.
- Competence Flower radar chart, computed from real data, configurable aggregation.
- Grading scheme + weight rules + computed grade with breakdown + manual override (human-finalized only, §11.5).
- Report generation (draft → final → PDF), single and bulk export.
- Data export (JSON/CSV) and erasure flow, audit-logged, unified across student/teacher/parent (§11.5).
- i18n scaffolding, DE + EN complete for implemented screens.
- Dockerized self-hosting + docs, seed script for demo data.
- Signage with working Emergency Alert override.
- Communication with the full escalation-policy engine and urgent-safety bypass.
- Learning Hub with at least manual (non-AI) content authoring functional.
- AI Tutor shipped only after Exam Mode's server-side gate exists and is tested.
- Exam Mode with the full bathroom/distress/warning flow and defense-in-depth enforcement.
- Digital Notebook with typed + stylus input and non-destructive teacher annotation.
- Test suite: unit tests for grading logic, permissions, and the escalation-policy business-day calculator specifically (not just an overall coverage %); Playwright E2E covering register → create class → assign template → add students → log entries → generate report, plus a signage-emergency-override smoke test and an exam-session lifecycle smoke test.
Compliance (Module L, §11.5) — a school instance is not production-ready until:
docs/DATA_MODEL.mdhas a purpose + legal-basis note for every personal-data entity.DataRetentionPolicyrows exist (school-confirmed, not defaulted) for every legally-mandated category.docs/legal/verzeichnis-verarbeitungstaetigkeiten.md(RoPA) generated and reviewed.- AVV signed (third-party-operated instance) or explicitly marked not-applicable (self-hosted-by-school).
- DPIA completed and on file before Modules E or F are enabled.
- Elternbeirat/Schulkonferenz consultation logged per module.
- Personalrat consultation logged for every monitoring-capable module.
- Student/parent/teacher self-service data-export flows tested end-to-end.
- Privacy notice generator produces an accurate, plain-language notice matching actual configured retention periods (no drift between docs and DB config).
README.md should state the project's mission plainly: a free tool built for/with a school, donation-supported, and explain how to contribute.
17. Phase 2 / Stretch Goals (out of scope for v1 — document in docs/ROADMAP.md)
- SSO (OIDC) support for schools with existing identity providers.
- Optional Postgres deployment mode for larger multi-school instances.
- Native offline-first PWA mode for spotty classroom Wi-Fi.
- Explicitly forbidden, not just deferred (§11.5): any feature that repurposes competency/AI-Tutor/behavioral data into a cross-context "student risk score" or similar profiling construct without a wholly separate legal basis and DPIA.
18. Instructions for the AI Coding Agent
- Produce
docs/ARCHITECTURE.mdand the full Prisma/Drizzle schema (all entities across §4–11) and get sign-off before writing app code — this schema is large enough that an early wrong decision is expensive. - Build the shared Policy/Config layer (backing the Admin Policy Console, §11.4, and
DataRetentionPolicy, §11.5) before implementing Module C's escalation logic or Module F's warning thresholds — both must read from it, proving "no hardcoding" structurally, not just by discipline. - Build Module H (Notifications) and Module I (Calendar) early, in Stage 1, precisely because every later module depends on them — prevents each module from inventing its own notification/date logic.
- When implementing Module F, write the server-side session-gating check before the kiosk UI — the security/integrity property must not depend on the UI shipping correctly.
- Flag explicitly, in
docs/DATA_MODEL.md, every place a rule/threshold/retention-period is read from a policy table, and every entity's purpose + legal basis (so a future compliance audit can confirm zero hardcoded business rules and a complete RoPA). - Never enable Module E or F for a school instance until the corresponding onboarding-gate step (§11.9) is satisfied — build this as an actual code-level check, not a documented process someone might skip.
- Keep commits small and descriptive; maintain a CHANGELOG. After each feature, write its unit/E2E tests before moving to the next.
- Flag any point where a competency/grading/retention policy varies by German Bundesland — expose it as configuration, never hardcode one state's rules, and note the assumption in
docs/DATA_MODEL.md. - Remember throughout: this is a free, non-commercial, donation-supported school project. Prefer boring, dependency-light, self-hostable solutions over anything introducing a paid third-party service or vendor lock-in — and treat every compliance requirement in §11 as a hard constraint, not a stretch goal.