CG-Feedback-Monitor/server/db/queries/checklists.ts
Lars 234f87d408 V2-Dev-Stand: Skala 1-10, Benefits/Concerns, DEV-Isolation und Gitea-Doku.
Bündelt die Neuentwicklung in AssigmentMonitorV2 (eigene Ports/DB), die Umstellung auf numerische Bewertungen, Meeting-Checklisten, KI-Tagging und die geplante Feedback-Kaskade — als Basis für Versionsverwaltung in Gitea.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-08 17:35:05 +02:00

64 lines
3.3 KiB
TypeScript

import {
getAllRows, getRowsWhereEquals, getRowsWhereIn, insertRow, updateRow, deleteRowById, deleteRowsWhereEquals,
} from '../crud'
import type { ChecklistItemDef, ChecklistResponse } from '../../../src/db/types'
export const listChecklistItemDefsForPhaseTemplate = (phaseTemplateId: number): ChecklistItemDef[] => {
const rows = getRowsWhereEquals<ChecklistItemDef>('checklistItemDefs', 'phaseTemplateId', phaseTemplateId)
return rows.sort((a, b) => a.order - b.order)
}
/** Bulk-Variante für Berichte über mehrere Phasentypen hinweg (Assignment-Report-PDF, Gesamtprotokoll). */
export const listChecklistItemDefsForPhaseTemplates = (phaseTemplateIds: number[]): ChecklistItemDef[] =>
getRowsWhereIn<ChecklistItemDef>('checklistItemDefs', 'phaseTemplateId', phaseTemplateIds).sort((a, b) => a.order - b.order)
export const addChecklistItemDef = (def: Omit<ChecklistItemDef, 'id'>): number => insertRow('checklistItemDefs', def)
export const updateChecklistItemDef = (id: number, patch: Partial<ChecklistItemDef>): number =>
updateRow('checklistItemDefs', id, patch)
/** Räumt zugehörige `checklistResponses` mit auf — gleiches Verteidigungs-Prinzip wie `deleteFeedbackCriterionItem`. */
export function deleteChecklistItemDef(id: number): void {
deleteRowsWhereEquals('checklistResponses', 'checklistItemId', id)
deleteRowById('checklistItemDefs', id)
}
/** Cascade-Baustein für `deletePhaseTemplate`/`deleteAssignmentType` — löscht alle Checklisten-Punkte samt Antworten einer Phase. */
export function deleteChecklistItemDefsForPhaseTemplate(phaseTemplateId: number): void {
for (const def of listChecklistItemDefsForPhaseTemplate(phaseTemplateId)) {
deleteChecklistItemDef(def.id!)
}
}
export const listChecklistResponsesForMeeting = (meetingInstanceId: number): ChecklistResponse[] =>
getRowsWhereEquals<ChecklistResponse>('checklistResponses', 'meetingInstanceId', meetingInstanceId)
/** Bulk-Variante für Berichte über mehrere Meetings hinweg (Assignment-Report-PDF, Gesamtprotokoll). */
export const listChecklistResponsesForMeetings = (meetingInstanceIds: number[]): ChecklistResponse[] =>
getRowsWhereIn<ChecklistResponse>('checklistResponses', 'meetingInstanceId', meetingInstanceIds)
/**
* Upsert per Komposit-Schlüssel (meetingInstanceId, checklistItemId, instituteeId ?? null), gleiches
* Find-or-Insert-Muster wie `setAssessmentScore`/`saveAssessmentNote` in MeetingView.tsx. `criterionItemId`
* überschreibt pro Antwort individuell die Konfigurations-Vorgabe (`ChecklistItemDef.linkedCriterionItemId`)
* — siehe CLAUDE.md „Individuelle Kriterium-Zuordnung pro Checklisten-Antwort".
*/
export function upsertChecklistResponse(input: {
meetingInstanceId: number
instituteeId?: number
checklistItemId: number
rating: ChecklistResponse['rating']
note: string
criterionItemId?: number
}): number {
const existing = getAllRows<ChecklistResponse>('checklistResponses').find(r =>
r.meetingInstanceId === input.meetingInstanceId &&
r.checklistItemId === input.checklistItemId &&
(r.instituteeId ?? null) === (input.instituteeId ?? null),
)
if (existing?.id) {
updateRow('checklistResponses', existing.id, { rating: input.rating, note: input.note, criterionItemId: input.criterionItemId })
return existing.id
}
return insertRow('checklistResponses', input)
}