# Enterprise Notification & Task Management System ## Anforderungsanalyse ### Was wird gebaut? Ein mehrstufiges Notification- und Task-Management-System, das die bestehende Notification-Infrastruktur (Prisma-Model, Bell-Icon, SSE, SMTP) zu einem vollwertigen Enterprise-System ausbaut. Vier Kernfähigkeiten: 1. **Personal Reminders** — User legen eigene Erinnerungen an (Datum/Zeit, optionale Wiederholung, verknüpft mit Entity) 2. **Targeted Notifications** — Admins/Manager senden Notifications an User, Rollen, Projektbeteiligte, OrgUnits 3. **Task Management** — Actionable Tasks mit Status-Tracking, Dashboard-Widget, Entity-Verknüpfung 4. **AI Assistant Integration** — Assistent liest offene Tasks, führt sie aus (Urlaub genehmigen, Allokation erstellen, etc.) ### Bestehende Infrastruktur (wiederverwendbar) | Komponente | Status | Datei | |------------|--------|-------| | `Notification` Prisma-Model | Vorhanden (einfach) | `packages/db/prisma/schema.prisma:1291` | | Notification tRPC-Router | list, unreadCount, markRead, create | `packages/api/src/router/notification.ts` | | NotificationBell + Drawer | Bell-Icon mit Badge, Dropdown-Panel | `apps/web/src/components/notifications/NotificationBell.tsx` | | SSE EventBus (Redis Pub/Sub) | `NOTIFICATION_CREATED` Event | `packages/api/src/sse/event-bus.ts` | | SMTP Email | `sendEmail()` + SystemSettings | `packages/api/src/lib/email.ts` | | AI Assistant Tools | `list_notifications`, `mark_notification_read` | `packages/api/src/router/assistant-tools.ts` | | Dashboard Widget-Registry | 8 Widgets, Pattern etabliert | `apps/web/src/components/dashboard/widgets/` | ### Betroffene Pakete - **packages/db** — Schema-Erweiterung (Notification -> Task-Felder, neues Broadcast-Model) - **packages/shared** — Enums, Typen, Zod-Schemas - **packages/api** — Router-Erweiterung (notification.ts, assistant-tools.ts), Targeting-Logik, Scheduler - **apps/web** — UI (Task-Widget, Reminder-UI, Notification-Center, Admin-Panel) --- ## Datenmodell-Design ### Erweiterung des bestehenden `Notification`-Models Das bestehende Model wird um Task-/Reminder-/Targeting-Felder erweitert. Kein neues Model nötig — ein einheitliches System für Notifications + Tasks + Reminders. ```prisma model Notification { id String @id @default(cuid()) userId String // -- Typ & Kategorie -- category NotificationCategory @default(NOTIFICATION) // NEU type String // z.B. "VACATION_REQUESTED", "TASK_ASSIGNED", "REMINDER" priority NotificationPriority @default(NORMAL) // NEU // -- Inhalt -- title String body String? entityId String? entityType String? link String? // NEU: Deep-Link zur relevanten Seite // -- Task-Felder (nur fuer category TASK / APPROVAL) -- taskStatus TaskStatus? // NEU: OPEN / IN_PROGRESS / DONE / DISMISSED taskAction String? // NEU: maschinenlesbare Aktion z.B. "approve_vacation:clxyz123" assigneeId String? // NEU: wem der Task zugewiesen ist dueDate DateTime? // NEU: Faelligkeitsdatum completedAt DateTime? // NEU: Zeitpunkt der Erledigung completedBy String? // NEU: wer hat erledigt (User-ID, oder "ai-assistant") // -- Reminder-Felder -- remindAt DateTime? // NEU: wann soll erinnert werden recurrence String? // NEU: "daily" | "weekly" | "monthly" | null nextRemindAt DateTime? // NEU: naechster Erinnerungszeitpunkt (berechnet) // -- Targeting-Metadaten (fuer Bulk-Sends) -- sourceId String? // NEU: Referenz auf die urspruengliche Broadcast-Nachricht senderId String? // NEU: wer hat die Notification erstellt (User-ID) channel String @default("in_app") // NEU: "in_app" | "email" | "both" // -- Timestamps -- readAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // NEU user User @relation(fields: [userId], references: [id], onDelete: Cascade) assignee User? @relation("taskAssignee", fields: [assigneeId], references: [id]) sender User? @relation("notificationSender", fields: [senderId], references: [id]) @@index([userId, readAt]) @@index([userId, category, taskStatus]) // NEU: Task-Queries @@index([nextRemindAt]) // NEU: Reminder-Scheduler @@index([assigneeId, taskStatus]) // NEU: Assigned-Tasks @@map("notifications") } enum NotificationCategory { NOTIFICATION // System/Admin-Benachrichtigung (read-only) REMINDER // Persoenliche Erinnerung (self-created) TASK // Actionable Task mit Status-Tracking APPROVAL // Genehmigungsworkflow (approve/reject) } enum NotificationPriority { LOW NORMAL HIGH URGENT } enum TaskStatus { OPEN IN_PROGRESS DONE DISMISSED } ``` ### Broadcast-Model (fuer Gruppen-Notifications) ```prisma model NotificationBroadcast { id String @id @default(cuid()) senderId String title String body String? link String? category NotificationCategory @default(NOTIFICATION) priority NotificationPriority @default(NORMAL) channel String @default("in_app") // -- Targeting -- targetType String // "user" | "role" | "project" | "orgUnit" | "all" targetValue String? // Role-Name, Project-ID, OrgUnit-ID, oder null fuer "all" // -- Scheduling -- scheduledAt DateTime? // null = sofort sentAt DateTime? recipientCount Int @default(0) createdAt DateTime @default(now()) sender User @relation(fields: [senderId], references: [id]) @@index([senderId]) @@index([scheduledAt, sentAt]) @@map("notification_broadcasts") } ``` ### Task-Action Registry (Enterprise-Pattern) Maschinenlesbare Aktionen ermoeglichen dem AI-Assistenten, Tasks direkt zu erledigen: ```typescript // packages/api/src/lib/task-actions.ts const TASK_ACTION_REGISTRY: Record = { "approve_vacation": { permission: "manageVacations", execute: ... }, "reject_vacation": { permission: "manageVacations", execute: ... }, "fill_demand": { permission: "manageAllocations", execute: ... }, "confirm_allocation":{ permission: "manageAllocations", execute: ... }, "review_budget": { permission: "manageProjects", execute: ... }, }; ``` Format: `"action_name:entity_id"` — einfach parsbar, erweiterbar. --- ## Betroffene Pakete & Dateien | Paket | Dateien | Art | |-------|---------|-----| | `packages/db` | `prisma/schema.prisma` | edit — Notification erweitern, Enums, Broadcast-Model | | `packages/shared` | `src/types/notification.ts` | create — Typen, Enums, Zod-Schemas | | `packages/shared` | `src/types/enums.ts` | edit — re-exportieren | | `packages/api` | `src/router/notification.ts` | edit — Task-CRUD, Reminder-CRUD, Broadcast, Targeting | | `packages/api` | `src/router/index.ts` | edit — ggf. neuen Router registrieren | | `packages/api` | `src/router/assistant-tools.ts` | edit — neue Tools: list_tasks, execute_task_action, etc. | | `packages/api` | `src/router/assistant.ts` | edit — TOOL_PERMISSION_MAP + System-Prompt | | `packages/api` | `src/sse/event-bus.ts` | edit — neue Event-Types | | `packages/api` | `src/lib/email.ts` | edit — Notification-Email-Templates | | `packages/api` | `src/lib/notification-targeting.ts` | create — Recipient-Aufloesung | | `packages/api` | `src/lib/task-actions.ts` | create — Action-Registry | | `packages/api` | `src/lib/reminder-scheduler.ts` | create — Reminder-Dispatcher | | `apps/web` | `src/components/notifications/NotificationBell.tsx` | edit — Tabs, Task-Badge | | `apps/web` | `src/components/notifications/NotificationCenter.tsx` | create — Full-Page | | `apps/web` | `src/components/notifications/ReminderModal.tsx` | create | | `apps/web` | `src/components/notifications/BroadcastModal.tsx` | create | | `apps/web` | `src/components/notifications/TaskCard.tsx` | create | | `apps/web` | `src/components/dashboard/widgets/TaskWidget.tsx` | create | | `apps/web` | `src/app/(app)/notifications/page.tsx` | create | | `apps/web` | `src/app/(app)/admin/notifications/page.tsx` | create | | `apps/web` | `src/components/layout/AppShell.tsx` | edit — Nav-Links | | `apps/web` | `src/hooks/useTimelineSSE.ts` | edit — Task-Events | --- ## Task-Liste (atomare Schritte) ### Phase N.1 — Datenmodell & Shared Types - [ ] **Task 1:** Shared-Typen erstellen -> `packages/shared/src/types/notification.ts` - NotificationCategory, NotificationPriority, TaskStatus Enums - CreateReminderSchema, CreateBroadcastSchema, UpdateTaskStatusSchema (Zod) - TaskAction Interface - [ ] **Task 2:** Prisma-Schema erweitern -> `packages/db/prisma/schema.prisma` - Notification-Model: category, priority, taskStatus, taskAction, assigneeId, dueDate, completedAt, completedBy, remindAt, recurrence, nextRemindAt, sourceId, senderId, channel, link, updatedAt - Enums: NotificationCategory, NotificationPriority, TaskStatus - Model: NotificationBroadcast - User-Relations: taskAssignee, notificationSender, broadcasts - Indexes: [userId, category, taskStatus], [nextRemindAt], [assigneeId, taskStatus] - [ ] **Task 3:** `pnpm db:push` + Dev-Server neu starten ### Phase N.2 — API: Router + Targeting + Scheduler - [ ] **Task 4:** SSE Event-Types erweitern -> `packages/api/src/sse/event-bus.ts` - TASK_ASSIGNED, TASK_COMPLETED, TASK_STATUS_CHANGED, REMINDER_DUE, BROADCAST_SENT - Emit-Helper: emitTaskAssigned(), emitTaskCompleted(), emitReminderDue() - [ ] **Task 5:** Notification-Router erweitern -> `packages/api/src/router/notification.ts` - list: Filter nach category, taskStatus, priority - listTasks (protectedProcedure): offene Tasks + zugewiesene Tasks - taskCounts (protectedProcedure): Counts nach Status - updateTaskStatus (protectedProcedure): OPEN->IN_PROGRESS->DONE/DISMISSED - createReminder (protectedProcedure): eigene Erinnerung anlegen - updateReminder / deleteReminder (protectedProcedure) - createBroadcast (managerProcedure): Targeted Notification an Gruppe - listBroadcasts (managerProcedure) - createTask (managerProcedure): Task fuer User/Gruppe - assignTask (managerProcedure): Task zuweisen - delete (protectedProcedure): eigene Notifications loeschen - [ ] **Task 6:** Broadcast-Targeting -> `packages/api/src/lib/notification-targeting.ts` (create) - resolveRecipients(targetType, targetValue, db): User-IDs aufloesen - "user" -> einzelner User - "role" -> alle User mit SystemRole - "project" -> Ressourcen mit aktiver Allokation -> verknuepfte User - "orgUnit" -> Ressourcen in OrgUnit -> verknuepfte User - "all" -> alle aktiven User - [ ] **Task 7:** Email-Templates -> `packages/api/src/lib/email.ts` (edit) - sendNotificationEmail(userId, notification): HTML mit Title, Body, Deep-Link - sendTaskEmail(userId, task): Template mit Task-Details + Action-Link - [ ] **Task 8:** Task-Action-Registry -> `packages/api/src/lib/task-actions.ts` (create) - Registry-Pattern: action_name -> { permission, execute(entityId, ctx) } - Initiale Actions: approve_vacation, reject_vacation, fill_demand, confirm_allocation - [ ] **Task 9:** Reminder-Scheduler -> `packages/api/src/lib/reminder-scheduler.ts` (create) - Intervall (60s): WHERE nextRemindAt <= NOW() - Fuer jeden faelligen Reminder: In-App Notification + optional Email - nextRemindAt neu berechnen oder null setzen - Catch-up bei Start (ueberfaellige sofort ausloesen) ### Phase N.3 — AI Assistant Integration - [ ] **Task 10:** Neue Tool-Definitionen -> `packages/api/src/router/assistant-tools.ts` - list_tasks: offene Tasks/Approvals mit Filter - get_task_detail: Details inkl. verknuepfter Entity - update_task_status: Status aendern - execute_task_action: maschinenlesbare Aktion ausfuehren - create_reminder: Erinnerung anlegen - create_task_for_user: Task fuer anderen User (Manager-only) - send_broadcast: Notification an Gruppe (Manager-only) - [ ] **Task 11:** Tool-Executors implementieren -> `packages/api/src/router/assistant-tools.ts` - execute_task_action: parst taskAction-String, dispatcht an Action-Registry - Permission-Check pro Action (nicht pauschal) - [ ] **Task 12:** Permission-Map + Prompt -> `packages/api/src/router/assistant.ts` - TOOL_PERMISSION_MAP erweitern - System-Prompt: Tasks/Reminders als Faehigkeit beschreiben ### Phase N.4 — Frontend - [ ] **Task 13:** NotificationBell erweitern -> `apps/web/src/components/notifications/NotificationBell.tsx` - Zweiter Badge: Task-Count (orange) neben Notification-Count (rot) - Tabs: "Alle" | "Tasks" | "Erinnerungen" - Task-Items mit Quick-Actions (Done/Dismiss) - Link zu "/notifications" - [ ] **Task 14:** TaskCard-Komponente -> `apps/web/src/components/notifications/TaskCard.tsx` (create) - Titel, Body, Due-Date, Priority-Badge, Entity-Link - Aktionen: "Start" / "Done" / "Dismiss" - Approval-Variante: "Approve" / "Reject" - Priority-farbcodiert (URGENT=rot, HIGH=orange, NORMAL=blau, LOW=grau) - [ ] **Task 15:** ReminderModal -> `apps/web/src/components/notifications/ReminderModal.tsx` (create) - Titel, Body, Datum/Uhrzeit, Wiederholung (keine/taeglich/woechentlich/monatlich) - Optional: Entity-Verknuepfung (Projekt/Ressource Dropdown) - [ ] **Task 16:** BroadcastModal -> `apps/web/src/components/notifications/BroadcastModal.tsx` (create) - Manager/Admin-only - Targeting: Dropdown (Alle/Rolle/Projekt/OrgUnit) + Wert-Auswahl - Inhalt: Titel, Body, Priority, Kategorie - Kanal: In-App / Email / Beides - Scheduling: Sofort / Zeitgesteuert - Vorschau: "Wird an X Empfaenger gesendet" - [ ] **Task 17:** NotificationCenter -> `apps/web/src/app/(app)/notifications/page.tsx` (create) - Tabs: Alle | Notifications | Tasks | Reminders | Approvals - Filter: Status, Priority, Zeitraum - Bulk: "Alle lesen", "Alle erledigt" - "Neue Erinnerung" Button - [ ] **Task 18:** TaskWidget -> `apps/web/src/components/dashboard/widgets/TaskWidget.tsx` (create) - Kompakte Liste offener Tasks (max 5-7) - Sortiert: Priority -> Due-Date - Quick-Actions: Done/Dismiss - Footer: "X offene Tasks — Alle anzeigen" - In Widget-Registry eintragen - [ ] **Task 19:** Admin Broadcast-Seite -> `apps/web/src/app/(app)/admin/notifications/page.tsx` (create) - Liste gesendeter Broadcasts - "Neue Benachrichtigung senden" Button - Statistiken: gesendet/gelesen pro Broadcast - [ ] **Task 20:** AppShell Navigation -> `apps/web/src/components/layout/AppShell.tsx` (edit) - "Notifications" fuer alle Rollen - "Broadcast" unter Admin (ADMIN/MANAGER) - [ ] **Task 21:** SSE-Hook -> `apps/web/src/hooks/useTimelineSSE.ts` (edit) - Auf TASK_ASSIGNED, TASK_COMPLETED, REMINDER_DUE reagieren - React-Query invalidieren: notification.listTasks, notification.taskCounts ### Phase N.5 — Auto-Tasks & Audit - [ ] **Task 22:** Automatische Task-Erzeugung bei Business-Events - vacation.create -> Task "Urlaubsantrag genehmigen" an Manager (APPROVAL) - Ueberallokation -> Task "Ueberallokation aufloesen" an Manager - Projekt-Deadline < 30 Tage + offene Demands -> Task "Demands besetzen" - demand.create -> Task "Demand besetzen" an Manager - [ ] **Task 23:** Audit-Trail -> `packages/api/src/lib/audit.ts` (create) - logTaskAction(taskId, userId, action, details) - completedBy: "ai-assistant" fuer AI-erledigte Tasks --- ## Abhaengigkeiten ``` Task 1 (Shared Types) ---+ Task 2 (Schema) ---------+--> Task 3 (db:push) | Task 3 --> Task 4 (SSE) | Task 3 --> Task 5 (Router)| Task 3 --> Task 6 (Targeting) Task 3 --> Task 7 (Email) | Task 3 --> Task 8 (Actions)| | Task 5 + 6 --> Task 9 (Scheduler) Task 5 + 8 --> Task 10-12 (AI) | Task 5 --> Task 13-21 (Frontend, parallel moeglich) Task 5 --> Task 22 (Auto-Tasks) ``` **Parallel:** - Task 4 + 5 + 6 + 7 + 8 (verschiedene Dateien) - Task 13-21 (verschiedene Dateien, 13+14 vor 17+18 empfohlen) **Sequentiell:** - Task 1 -> 2 -> 3 (Schema) - Task 5 -> 10 -> 11 (Router -> Tools -> Executors) --- ## Akzeptanzkriterien - [ ] `pnpm db:push` ohne Fehler - [ ] `pnpm --filter @planarchy/api exec tsc --noEmit` — 0 Errors - [ ] `pnpm --filter @planarchy/web exec tsc --noEmit` — 0 Errors - [ ] `pnpm test:unit` — alle Tests gruen - [ ] User kann eigene Erinnerung anlegen (Datum, Wiederholung, Entity) - [ ] Admin/Manager kann Broadcast an Rolle/Projekt/OrgUnit senden - [ ] Broadcast erzeugt individuelle Notifications pro Empfaenger - [ ] Tasks im Dashboard-Widget, sortiert nach Priority + Due-Date - [ ] Task-Status aenderbar ueber UI (Open -> In Progress -> Done/Dismissed) - [ ] AI-Assistent kann list_tasks aufrufen und offene Tasks anzeigen - [ ] AI-Assistent kann execute_task_action ausfuehren (z.B. Urlaub genehmigen) - [ ] Erledigte Tasks zeigen completedBy (User oder "AI-Assistent") - [ ] Email-Versand bei channel "email" oder "both" - [ ] SSE-Events invalidieren React-Query-Caches - [ ] Reminder-Scheduler erzeugt puenktlich Notifications - [ ] RBAC: User sehen nur eigene; Manager zugewiesene; Admin Broadcasts --- ## Risiken & offene Fragen ### Risiken 1. **Reminder-Scheduler Zuverlaessigkeit**: Node.js-setInterval kann bei Restart verpassen. Mitigation: Catch-up bei Start (alle ueberfaelligen sofort ausloesen). 2. **Broadcast-Skalierung**: "An alle" mit 500 Usern = 500 Rows. Mitigation: Batch-Insert (createMany). 3. **Task-Action-Sicherheit**: Permissions pro Action pruefen, nicht pauschal. Mitigation: Action-Registry mit Permission pro Handler. 4. **Schema-Migration**: Neue Felder nullable oder mit Default -> bestehende Notifications funktionieren weiter. ### Offene Fragen 1. **Scheduler**: setInterval im SSE-Handler oder separater Worker/Cron? Empfehlung: setInterval (reicht fuer <1000 User) 2. **Task-Delegation**: User duerfen Tasks an andere weiterdelegieren? Empfehlung: Ja (Manager-only) 3. **Retention**: Wie lange alte Notifications aufbewahren? Empfehlung: 90 Tage Auto-Cleanup 4. **Recurring Tasks**: Tasks wiederkehrend wie Reminders? Empfehlung: Phase 2 5. **Approval-Chains**: Mehrstufige Genehmigung? Empfehlung: Phase 2, erstmal einstufig