feat: enterprise notification & task management system

Phase N.1 — Data Model:
- Extend Notification model with category, priority, task fields (status, action,
  assignee, dueDate, completedAt/By), reminder fields (remindAt, recurrence,
  nextRemindAt), and targeting metadata (sourceId, senderId, channel)
- Add NotificationCategory, NotificationPriority, TaskStatus enums
- Add NotificationBroadcast model for group notifications
- Shared types with parseTaskAction()/buildTaskAction() helpers

Phase N.2 — API:
- Extend notification router: listTasks, taskCounts, updateTaskStatus,
  createReminder/update/delete/list, createBroadcast/listBroadcasts,
  createTask, assignTask, delete
- Broadcast targeting: resolve recipients by user/role/project/orgUnit/all
- Task-action registry: approve_vacation, reject_vacation, confirm_assignment
- Reminder scheduler: 60s poll interval, recurring support, catch-up on start
- SSE events: TASK_ASSIGNED, TASK_COMPLETED, TASK_STATUS_CHANGED,
  REMINDER_DUE, BROADCAST_SENT

Phase N.3 — AI Assistant:
- 7 new tools: list_tasks, get_task_detail, update_task_status,
  execute_task_action, create_reminder, create_task_for_user, send_broadcast
- execute_task_action dispatches to task-action registry with per-action
  permission checks, marks tasks as completed by AI

Phase N.4 — Frontend:
- Enhanced NotificationBell with task badge, tabs (All/Tasks/Reminders)
- TaskCard component with priority badges, due dates, action buttons
- ReminderModal for creating/editing personal reminders
- BroadcastModal for targeted group notifications (manager+)
- NotificationCenter full-page with 5 tabs and bulk actions
- TaskWidget dashboard widget showing open tasks
- Admin broadcast management page
- AppShell nav links for Notifications and Broadcasts
- SSE hook handlers for task/reminder events

Phase N.5 — Auto-Tasks:
- Vacation create → APPROVAL tasks for all managers
- Vacation approve/reject → mark approval tasks as DONE
- Demand create → TASK for managers to fill staffing needs

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
2026-03-18 11:51:49 +01:00
parent 093e13b88f
commit d0f04f13f8
26 changed files with 3404 additions and 54 deletions
+5
View File
@@ -53,6 +53,11 @@ export const SSE_EVENT_TYPES = {
ROLE_UPDATED: "role.updated",
ROLE_DELETED: "role.deleted",
NOTIFICATION_CREATED: "notification:created",
TASK_ASSIGNED: "task.assigned",
TASK_COMPLETED: "task.completed",
TASK_STATUS_CHANGED: "task.status_changed",
REMINDER_DUE: "reminder.due",
BROADCAST_SENT: "broadcast.sent",
PING: "ping",
} as const;
+1 -1
View File
@@ -7,7 +7,7 @@ export * from "./engine.js";
export * from "./staffing.js";
export * from "./vacation.js";
export * from "./role.js";
export type { Notification } from "./notification.js";
export * from "./notification.js";
export * from "./permissions.js";
export * from "./columns.js";
export * from "./dashboard.js";
+80
View File
@@ -1,3 +1,37 @@
// ─── Notification Category / Priority / TaskStatus ──────────────────────────
// Mirror Prisma enums for use in frontend/shared code
export type NotificationCategory =
| "NOTIFICATION"
| "REMINDER"
| "TASK"
| "APPROVAL";
export type NotificationPriority = "LOW" | "NORMAL" | "HIGH" | "URGENT";
export type TaskStatus = "OPEN" | "IN_PROGRESS" | "DONE" | "DISMISSED";
// ─── Task Action Helpers ────────────────────────────────────────────────────
export interface TaskActionDef {
action: string; // e.g. "approve_vacation"
entityId: string; // e.g. vacation ID
}
/** Parse a taskAction string like "approve_vacation:clxyz123" */
export function parseTaskAction(taskAction: string): TaskActionDef | null {
const idx = taskAction.indexOf(":");
if (idx < 0) return null;
return { action: taskAction.slice(0, idx), entityId: taskAction.slice(idx + 1) };
}
/** Build a taskAction string */
export function buildTaskAction(action: string, entityId: string): string {
return `${action}:${entityId}`;
}
// ─── Notification Interface ─────────────────────────────────────────────────
export interface Notification {
id: string;
userId: string;
@@ -8,4 +42,50 @@ export interface Notification {
entityType?: string | null;
readAt?: Date | null;
createdAt: Date;
updatedAt?: Date;
// Extended fields
category?: NotificationCategory;
priority?: NotificationPriority;
link?: string | null;
// Task fields
taskStatus?: TaskStatus | null;
taskAction?: string | null;
assigneeId?: string | null;
dueDate?: Date | null;
completedAt?: Date | null;
completedBy?: string | null;
// Reminder fields
remindAt?: Date | null;
recurrence?: string | null;
nextRemindAt?: Date | null;
// Targeting
sourceId?: string | null;
senderId?: string | null;
channel?: string;
}
// ─── Broadcast Interface ────────────────────────────────────────────────────
export interface NotificationBroadcast {
id: string;
senderId: string;
title: string;
body?: string | null;
link?: string | null;
category?: NotificationCategory;
priority?: NotificationPriority;
channel?: string;
targetType: string; // "user" | "role" | "project" | "orgUnit" | "all"
targetValue?: string | null;
scheduledAt?: Date | null;
sentAt?: Date | null;
recipientCount?: number;
createdAt: Date;
}