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
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:
@@ -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 */ }
|
||||
|
||||
@@ -151,9 +151,11 @@ model TenantMembership {
|
||||
model Project {
|
||||
id String @id @default(uuid())
|
||||
einsatzNr String?
|
||||
// "EINSATZ" = echter Einsatz (mit Journal), "UEBUNG" = Übung (Auswertung statt Journal).
|
||||
// "EINSATZ" = echter Einsatz (mit Journal), "UEBUNG" = Übung (Cockpit statt Journal).
|
||||
// Als String (nicht Enum) gehalten, damit die idempotente Raw-SQL-Migration einfach bleibt.
|
||||
mode String @default("EINSATZ")
|
||||
// Nur für Übungen: Gesamt-Auswertung / Lessons Learned (Freitext).
|
||||
exerciseEvaluation String?
|
||||
title String
|
||||
location String?
|
||||
description String?
|
||||
@@ -183,11 +185,31 @@ model Project {
|
||||
journalEntries JournalEntry[]
|
||||
journalCheckItems JournalCheckItem[]
|
||||
journalPendenzen JournalPendenz[]
|
||||
exerciseGoals ExerciseGoal[]
|
||||
rapports Rapport[]
|
||||
|
||||
@@map("projects")
|
||||
}
|
||||
|
||||
// ─── Übungs-Cockpit: Übungsziele mit Zielerreichung ──────────
|
||||
|
||||
model ExerciseGoal {
|
||||
id String @id @default(uuid())
|
||||
text String
|
||||
// Zielerreichung: OPEN | REACHED | PARTIAL | MISSED
|
||||
status String @default("OPEN")
|
||||
note String?
|
||||
sortOrder Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
projectId String
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([projectId])
|
||||
@@map("exercise_goals")
|
||||
}
|
||||
|
||||
model Feature {
|
||||
id String @id @default(uuid())
|
||||
type String
|
||||
|
||||
Reference in New Issue
Block a user