feat(exercise): Übungsmodus mit Übungs-Cockpit + direkte Einstiegs-Buttons
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 40m38s

- Topbar: direkte Buttons "Neuer Einsatz" (rot) und "Neue Übung" (blau)
  statt versteckt im Menü; öffnen den Dialog direkt im richtigen Modus
- Übungs-Cockpit ersetzt bei Übungen das Journal: Übungsziele mit
  Zielerreichung (Offen/Erreicht/Teilweise/Nicht erreicht) + Auswertung
- Neues Model ExerciseGoal + Project.exerciseEvaluation (Auto-Migration)
- API-Routen /projects/[id]/exercise-goals (Liste/Erstellen/Update/Löschen)
- Deutliches "ÜBUNG"-Banner gegen Verwechslung mit echtem Einsatz
- Sidebar-Tab heisst bei Übung "Auswertung"
- Version 1.4.4

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pepe Ziberi
2026-07-18 21:16:32 +02:00
parent 1641101b73
commit 1c8f619252
13 changed files with 560 additions and 34 deletions

View File

@@ -71,6 +71,7 @@ async function migrate() {
`ALTER TABLE projects ADD COLUMN IF NOT EXISTS "einsatzleiter" TEXT`,
`ALTER TABLE projects ADD COLUMN IF NOT EXISTS "journalfuehrer" TEXT`,
`ALTER TABLE projects ADD COLUMN IF NOT EXISTS "mode" TEXT NOT NULL DEFAULT 'EINSATZ'`,
`ALTER TABLE projects ADD COLUMN IF NOT EXISTS "exerciseEvaluation" TEXT`,
`ALTER TABLE projects ADD COLUMN IF NOT EXISTS "editingById" TEXT`,
`ALTER TABLE projects ADD COLUMN IF NOT EXISTS "editingUserName" TEXT`,
`ALTER TABLE projects ADD COLUMN IF NOT EXISTS "editingSessionId" TEXT`,
@@ -117,6 +118,17 @@ async function migrate() {
"createdById" TEXT REFERENCES users(id) ON DELETE SET NULL,
UNIQUE("tenantId", "reportNumber")
)`,
// Exercise goals (Übungs-Cockpit)
`CREATE TABLE IF NOT EXISTS exercise_goals (
id TEXT PRIMARY KEY DEFAULT gen_random_uuid(),
text TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'OPEN',
note TEXT,
"sortOrder" INTEGER NOT NULL DEFAULT 0,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"projectId" TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE
)`,
]
for (const sql of tableMigrations) {
try { await prisma.$executeRawUnsafe(sql) } catch (e) { /* table might already exist */ }