Files
Adminator 1e51ef7def Nachtrag: alle bisher untracked Ordner + hängende Änderungen mit-committen
- Konzept/, didaktik_geografie/, didaktik_simulation/, v2-modules/, v2-platform/
- 12 code-workspace-Files
- STATUS-*.md
- viele M/D/R-Änderungen an bereits getrackten Files
- .gitignore verstärkt: **/.humaninput/, **/secret_keys.txt

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-08 02:27:02 +02:00

369 lines
16 KiB
SQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- ============================================================
-- GeoGraSim V2 — additive Schema-Erweiterungen
-- Idempotent: kann mehrfach laufen, kein DROP, kein RENAME.
-- V1-Tabellen (students, classes, teachers, licenses) bleiben unangetastet.
-- ============================================================
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS=0;
-- ------------------------------------------------------------
-- Locales (Sprache + Land + Variante)
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS locales_v2 (
code VARCHAR(32) PRIMARY KEY,
language CHAR(2) NOT NULL,
country CHAR(2) NOT NULL,
variant VARCHAR(16) NOT NULL,
display_name VARCHAR(100) NOT NULL,
is_easy BOOLEAN NOT NULL DEFAULT FALSE,
is_active BOOLEAN NOT NULL DEFAULT TRUE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT IGNORE INTO locales_v2 (code, language, country, variant, display_name, is_easy) VALUES
('de-AT-standard', 'de', 'AT', 'standard', 'Deutsch (Österreich)', FALSE),
('de-AT-easy', 'de', 'AT', 'easy', 'Deutsch (Österreich) — Leichte Sprache', TRUE);
-- ------------------------------------------------------------
-- Lehrplan-Anker-Pool (Land-präfixiert)
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS lehrplan_anchors_v2 (
code VARCHAR(64) PRIMARY KEY,
country CHAR(2) NOT NULL,
scheme VARCHAR(32) NOT NULL,
level VARCHAR(100) NOT NULL,
topic VARCHAR(255) NOT NULL,
competence TEXT NOT NULL,
display_order INT DEFAULT 0,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
KEY idx_country_scheme (country, scheme)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ------------------------------------------------------------
-- Modul-Registrierung (von Atlas beim Integrieren befüllt)
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS module_info_v2 (
slug VARCHAR(64) PRIMARY KEY,
display_name VARCHAR(255) NOT NULL,
display_name_easy VARCHAR(255) NOT NULL,
version VARCHAR(20) NOT NULL,
spec_version VARCHAR(20) NOT NULL,
icon VARCHAR(20) DEFAULT '',
short_description TEXT NOT NULL,
short_description_easy TEXT NOT NULL,
long_description TEXT NOT NULL,
long_description_easy TEXT NOT NULL,
estimated_duration_min INT NOT NULL DEFAULT 25,
card_image_url VARCHAR(500) DEFAULT NULL,
entry_url VARCHAR(500) NOT NULL,
maintainer_instance VARCHAR(64) NOT NULL,
status ENUM('draft', 'beta', 'stable', 'archived') NOT NULL DEFAULT 'draft',
installed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
KEY idx_status (status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Modul ↔ Lehrplan-Anker (Many-to-Many)
CREATE TABLE IF NOT EXISTS module_lehrplan_v2 (
module_slug VARCHAR(64) NOT NULL,
anker_code VARCHAR(64) NOT NULL,
PRIMARY KEY (module_slug, anker_code),
KEY idx_anker (anker_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Modul ↔ Glossar-Schwerpunkte (Many-to-Many)
CREATE TABLE IF NOT EXISTS module_glossar_v2 (
module_slug VARCHAR(64) NOT NULL,
glossar_slug VARCHAR(64) NOT NULL,
PRIMARY KEY (module_slug, glossar_slug),
KEY idx_glossar (glossar_slug)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Modul-Difficulty-Levels
CREATE TABLE IF NOT EXISTS module_levels_v2 (
module_slug VARCHAR(64) NOT NULL,
level_id VARCHAR(20) NOT NULL,
label VARCHAR(100) NOT NULL,
label_easy VARCHAR(100) NOT NULL,
display_order INT DEFAULT 0,
PRIMARY KEY (module_slug, level_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Modul-Telemetry-Milestones (vorab deklariert)
CREATE TABLE IF NOT EXISTS module_milestones_v2 (
module_slug VARCHAR(64) NOT NULL,
milestone_id VARCHAR(64) NOT NULL,
label VARCHAR(255) NOT NULL,
display_order INT DEFAULT 0,
PRIMARY KEY (module_slug, milestone_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ------------------------------------------------------------
-- Resume-State pro Schüler*in × Modul (opake JSON-Blob)
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS module_state_v2 (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
student_id INT NOT NULL,
module_slug VARCHAR(64) NOT NULL,
state_json LONGTEXT NOT NULL,
summary VARCHAR(500) DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
created_by_version ENUM('v1','v2') DEFAULT 'v2',
UNIQUE KEY uniq_student_module (student_id, module_slug),
KEY idx_updated (updated_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ------------------------------------------------------------
-- Endergebnisse (POST /api/result)
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS assessments_v2 (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
student_id INT NOT NULL,
class_id INT NOT NULL,
module_slug VARCHAR(64) NOT NULL,
module_version VARCHAR(20) NOT NULL,
spec_version VARCHAR(20) NOT NULL,
completed BOOLEAN NOT NULL,
abandoned BOOLEAN NOT NULL DEFAULT FALSE,
score INT NOT NULL,
score_max INT NOT NULL,
duration_s INT NOT NULL,
difficulty VARCHAR(20) NOT NULL,
mode ENUM('free','teacher_started','assessment','demo') NOT NULL,
module_specific_data LONGTEXT DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by_version ENUM('v1','v2') DEFAULT 'v2',
KEY idx_student (student_id),
KEY idx_class_module (class_id, module_slug),
KEY idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Milestones erreicht pro Assessment
CREATE TABLE IF NOT EXISTS assessment_milestones_v2 (
assessment_id BIGINT NOT NULL,
milestone_id VARCHAR(64) NOT NULL,
PRIMARY KEY (assessment_id, milestone_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Lehrplan-Coverage pro Assessment
CREATE TABLE IF NOT EXISTS assessment_lehrplan_v2 (
assessment_id BIGINT NOT NULL,
anker_code VARCHAR(64) NOT NULL,
coverage ENUM('full','partial','none') NOT NULL,
PRIMARY KEY (assessment_id, anker_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Freitext-Antworten pro Assessment
CREATE TABLE IF NOT EXISTS assessment_freetext_v2 (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
assessment_id BIGINT NOT NULL,
prompt_id VARCHAR(64) NOT NULL,
prompt_text TEXT NOT NULL,
answer_text TEXT NOT NULL,
KEY idx_assessment (assessment_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ------------------------------------------------------------
-- Telemetry-Events (Heartbeat / Milestone / Stuck / a11y-Blocker)
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS telemetry_events_v2 (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
student_id INT NOT NULL,
class_id INT NOT NULL,
module_slug VARCHAR(64) NOT NULL,
module_version VARCHAR(20) NOT NULL,
event_type ENUM('heartbeat','milestone','stuck','accessibility-blocker') NOT NULL,
phase VARCHAR(64) DEFAULT NULL,
phase_label VARCHAR(255) DEFAULT NULL,
step VARCHAR(20) DEFAULT NULL,
current_score INT DEFAULT NULL,
score_max INT DEFAULT NULL,
time_in_phase_s INT DEFAULT NULL,
total_time_s INT DEFAULT NULL,
milestone_id VARCHAR(64) DEFAULT NULL,
milestone_label VARCHAR(255) DEFAULT NULL,
score_delta INT DEFAULT NULL,
idle_s INT DEFAULT NULL,
last_action_label VARCHAR(255) DEFAULT NULL,
hint VARCHAR(500) DEFAULT NULL,
blocker_type VARCHAR(64) DEFAULT NULL,
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
KEY idx_student_ts (student_id, ts),
KEY idx_class_ts (class_id, ts),
KEY idx_module_ts (module_slug, ts),
KEY idx_type (event_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ------------------------------------------------------------
-- Schüler-Modul-Fortschritt (für Lerngeschichte)
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS student_progress_v2 (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
student_id INT NOT NULL,
module_slug VARCHAR(64) NOT NULL,
total_attempts INT DEFAULT 0,
best_score INT DEFAULT 0,
best_score_max INT DEFAULT 0,
last_completed_at TIMESTAMP NULL DEFAULT NULL,
total_duration_s BIGINT DEFAULT 0,
UNIQUE KEY uniq_student_module (student_id, module_slug),
KEY idx_student (student_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Schüler-Lehrplan-Coverage (welche Anker hat Schüler*in abgedeckt)
CREATE TABLE IF NOT EXISTS lehrplan_progress_v2 (
student_id INT NOT NULL,
anker_code VARCHAR(64) NOT NULL,
best_coverage ENUM('full','partial','none') NOT NULL,
reached_via_module VARCHAR(64) NOT NULL,
reached_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (student_id, anker_code),
KEY idx_student (student_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ------------------------------------------------------------
-- Hochgeladene Artefakte (Bilder, Karten, Audio aus Modulen)
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS artifacts_v2 (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
student_id INT NOT NULL,
module_slug VARCHAR(64) NOT NULL,
mime_type VARCHAR(100) NOT NULL,
url VARCHAR(500) NOT NULL,
thumbnail_url VARCHAR(500) DEFAULT NULL,
label VARCHAR(255) DEFAULT NULL,
bytes BIGINT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
KEY idx_student (student_id),
KEY idx_module (module_slug)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Verknüpfung Artefakt ↔ Assessment
CREATE TABLE IF NOT EXISTS assessment_artifacts_v2 (
assessment_id BIGINT NOT NULL,
artifact_id BIGINT NOT NULL,
PRIMARY KEY (assessment_id, artifact_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ------------------------------------------------------------
-- A11y-Profil-Erweiterung (additiv zu V1-students)
-- Neue Spalten in der bestehenden students-Tabelle, additiv mit DEFAULTs.
-- ------------------------------------------------------------
ALTER TABLE students
ADD COLUMN IF NOT EXISTS easy_language BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN IF NOT EXISTS high_contrast BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN IF NOT EXISTS reduced_motion BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN IF NOT EXISTS screen_reader BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN IF NOT EXISTS text_scale ENUM('normal','large','xlarge') NOT NULL DEFAULT 'normal',
ADD COLUMN IF NOT EXISTS locale_pref VARCHAR(32) DEFAULT NULL,
ADD COLUMN IF NOT EXISTS country_pref CHAR(2) DEFAULT 'AT',
ADD COLUMN IF NOT EXISTS nachteilsausgleich BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN IF NOT EXISTS avatar_slug VARCHAR(64) DEFAULT 'fuchs-explorer';
-- Lehrperson-Erweiterung: is_admin-Flag für V2-Plattform-Config
ALTER TABLE teachers
ADD COLUMN IF NOT EXISTS is_admin BOOLEAN NOT NULL DEFAULT FALSE;
-- ------------------------------------------------------------
-- Plattform-Config (Heartbeat-Intervall, Token-TTL, Rate-Limits)
-- Lehrperson mit Admin-Rolle kann das im Admin-Board justieren.
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS platform_config_v2 (
config_key VARCHAR(64) PRIMARY KEY,
config_value VARCHAR(255) NOT NULL,
value_type ENUM('int', 'float', 'string', 'bool', 'json') NOT NULL DEFAULT 'string',
min_value VARCHAR(255) DEFAULT NULL,
max_value VARCHAR(255) DEFAULT NULL,
label VARCHAR(255) NOT NULL,
label_easy VARCHAR(255) DEFAULT NULL,
help_text TEXT DEFAULT NULL,
group_name VARCHAR(64) NOT NULL DEFAULT 'general',
display_order INT DEFAULT 0,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
updated_by INT DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT IGNORE INTO platform_config_v2
(config_key, config_value, value_type, min_value, max_value, label, help_text, group_name, display_order) VALUES
('heartbeat_interval_min_s', '10', 'int', '5', '60', 'Heartbeat — Min-Intervall (Sek.)', 'Untergrenze für Modul-Telemetrie. Schnellere Module dürfen nicht öfter pingen.', 'telemetry', 10),
('heartbeat_interval_max_s', '30', 'int', '15', '120', 'Heartbeat — Max-Intervall (Sek.)', 'Obergrenze. Ruhige Module dürfen seltener pingen.', 'telemetry', 20),
('stuck_threshold_s', '90', 'int', '30', '300', 'Stuck-Schwellwert (Sek.)', 'Nach wieviel Sek. Inaktivität wird ein Stuck-Event gefeuert.', 'telemetry', 30),
('telemetry_rate_limit_per_s','1','int', '1', '10', 'Telemetry Rate-Limit (Events/Sek.)','Max. Events pro Sekunde pro Schüler*in.', 'telemetry', 40),
('telemetry_event_cap_per_session','2000','int','100','10000','Telemetry Event-Cap pro Sitzung','Nach dieser Anzahl werden Heartbeats verworfen (Milestones bleiben).', 'telemetry', 50),
('token_ttl_s', '3600', 'int', '300', '28800','Token-Lebensdauer (Sek.)', 'Wie lange ein Login-Token gültig ist. Default 1h.', 'auth', 10),
('token_refresh_window_s', '300', 'int', '60', '1800', 'Token-Refresh-Fenster (Sek.)', 'Wieviele Sek. vor Ablauf ein Token erneuert wird.', 'auth', 20),
('telemetry_retention_days', '30', 'int', '7', '365', 'Telemetry-Aufbewahrung (Tage)', 'Wie lange Telemetry-Events in der DB bleiben, bevor sie gelöscht werden.', 'telemetry', 60);
-- ------------------------------------------------------------
-- Health-Metriken (pro API-Endpoint, für Auto-Tuning Phase 2)
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS health_metrics_v2 (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
endpoint VARCHAR(128) NOT NULL,
method VARCHAR(10) NOT NULL,
duration_ms INT NOT NULL,
status_code INT NOT NULL,
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
KEY idx_endpoint_ts (endpoint, ts),
KEY idx_ts (ts)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ------------------------------------------------------------
-- Klassen-Aufträge (V2-Variante, additiv zu V1-class_assignments)
-- Lehrperson vergibt ein Modul mit Schwierigkeit (+ Settings) an die Klasse.
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS class_assignments_v2 (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
class_id INT NOT NULL,
teacher_id INT NOT NULL,
module_slug VARCHAR(64) NOT NULL,
difficulty VARCHAR(20) NOT NULL,
custom_params JSON DEFAULT NULL, -- V3: Lehrperson-eigene Parameter-Overrides
starts_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
ends_at TIMESTAMP NULL DEFAULT NULL,
active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by_version ENUM('v1','v2') DEFAULT 'v2',
KEY idx_class_active (class_id, active),
KEY idx_module (module_slug)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ------------------------------------------------------------
-- Schüler-Level-Unlocks pro Modul
-- Im freien Modus: Schüler*in sieht nur Stufen, die freigeschaltet sind.
-- Im Auftragsmodus: Pflicht-Stufe vorgegeben (außer Nachteilsausgleich).
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS student_level_unlock_v2 (
student_id INT NOT NULL,
module_slug VARCHAR(64) NOT NULL,
highest_unlocked_level VARCHAR(20) NOT NULL DEFAULT 'L1',
highest_completed_level VARCHAR(20) DEFAULT NULL,
best_score_per_level JSON DEFAULT NULL, -- {"L1": {"score": 95, "max": 100}, "L2": {...}}
attempts_per_level JSON DEFAULT NULL, -- {"L1": 3, "L2": 1}
last_played_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (student_id, module_slug),
KEY idx_student (student_id),
KEY idx_module (module_slug)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ------------------------------------------------------------
-- Sentry für Spec-Version-Tracking
-- ------------------------------------------------------------
CREATE TABLE IF NOT EXISTS spec_history_v2 (
id INT AUTO_INCREMENT PRIMARY KEY,
spec_version VARCHAR(20) NOT NULL,
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
notes TEXT DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO spec_history_v2 (spec_version, notes) VALUES
('1.0-draft', 'Initial V2 schema, Atlas Nachtschicht 2026-05-16');
SET FOREIGN_KEY_CHECKS=1;
-- ============================================================
-- Ende init.sql
-- ============================================================