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:
@@ -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;
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user