## Relevant Files ### New Files - `ondeck/src/lib/renewal-group-recommendations.ts` - Pure TS recommendation engine: groups policies by expiration window, calculates renewal dates per rule. - `ondeck/src/lib/renewal-group-recommendations.test.ts` - Unit tests for the recommendation engine. - `ondeck/src/app/(dashboard)/manager/setup/page.tsx` - New Client Setup Queue page (server component). - `ondeck/src/app/(dashboard)/manager/setup/[clientId]/page.tsx` - Setup Wizard page for a specific client (server component, fetches client + policies). - `ondeck/src/components/renewal-groups/setup-wizard.tsx` - Main wizard client component with state, drag-and-drop orchestration, advocate selector, and save logic. - `ondeck/src/components/renewal-groups/group-card.tsx` - Droppable group card showing policies, inline name editor, renewal date picker, rule selector, and default-group radio. - `ondeck/src/components/renewal-groups/policy-chip.tsx` - Draggable policy pill used inside group cards and the unassigned policies tray. - `ondeck/src/app/api/clients/setup-queue/route.ts` - GET: returns unconfigured clients (missing `renewalDate` or `claimsAdvocate`). - `ondeck/src/app/api/clients/[id]/setup/route.ts` - POST: persists wizard output (groups, renewalDate, claimsAdvocate, notes, setupCompletedAt). PUT: saves draft. - `ondeck/src/app/api/admin/renewal-settings/route.ts` - GET/PUT: reads and writes global renewal group defaults from `app_settings`. - `ondeck/src/app/(dashboard)/admin/renewal-settings/page.tsx` - Admin Panel page for global defaults (grouping window, renewal date rule). ### Modified Files - `ondeck/prisma/schema.prisma` - Add `setupCompletedAt DateTime?` to `Client`; add new `AppSetting` model for key-value settings store. - `ondeck/src/app/(dashboard)/layout.tsx` - Add badge on Manager nav item showing count of unconfigured clients. - `ondeck/src/app/(dashboard)/manager/page.tsx` - Add "New Client Setup" summary card linking to the queue page. - `ondeck/src/app/(dashboard)/clients/[id]/page.tsx` - Pass `setupCompletedAt` and policies to `ClientDetail`; add "Edit Setup" button for Manager/Admin. - `ondeck/src/components/clients/client-detail.tsx` - Render "Edit Setup" button that navigates to the wizard for the current client. - `ondeck/src/app/(dashboard)/admin/page.tsx` - Add "Renewal Groups" section linking to the new settings page. ### Notes - Unit tests should be placed alongside source files (e.g., `renewal-group-recommendations.ts` and `renewal-group-recommendations.test.ts` in the same directory). - Run tests with `npx jest src/lib/renewal-group-recommendations`. - After any `schema.prisma` change, run `npx prisma migrate dev --name ` and `npx prisma generate`. - `@dnd-kit/core`, `@dnd-kit/sortable`, and `@dnd-kit/utilities` are already installed. --- ## Tasks - [x] 1.0 Database & Schema - [x] 1.1 Add `setupCompletedAt DateTime? @map("setup_completed_at")` field to the `Client` model in `prisma/schema.prisma`. - [x] 1.2 Add a new `AppSetting` model to `prisma/schema.prisma` with fields `key String @id`, `value String @db.Text`, `updatedAt DateTime @updatedAt`. Map to table `app_settings`. - [x] 1.3 Run `npx prisma migrate dev --name add_setup_completed_at_and_app_settings` to create and apply the migration. (Used `prisma db push` due to pre-existing schema drift.) - [x] 1.4 Run `npx prisma generate` to update the Prisma client. - [x] 1.5 Seed two default rows into `app_settings`: `renewal_group_window_days = "90"` and `renewal_group_date_rule = "nearest-to-year-start"`. - [x] 2.0 Recommendation Engine - [x] 2.1 Create `src/lib/renewal-group-recommendations.ts`. Define and export the input types: `PolicyInput { policyId: string; expirationDate: Date }` and `RecommendationConfig { windowDays: number; rule: 'nearest-to-year-start' | 'earliest' | 'latest' }`. - [x] 2.2 Implement the grouping algorithm: sort policies by `expirationDate`, then use a sliding-window approach to cluster policies whose dates fall within `windowDays` of each other into the same group. - [x] 2.3 Implement the `renewalDate` calculation for each group based on `config.rule`: `nearest-to-year-start` picks the expiration date with the lowest day-of-year value; `earliest` picks the minimum; `latest` picks the maximum. All results are `expirationDate + 1 day`. - [x] 2.4 Handle standalone policies (groups of size 1) — they are valid output and their `renewalDate` is simply `expirationDate + 1`. - [x] 2.5 Policies with a `null` expiration date must be excluded from grouping and returned separately as `ungroupable: PolicyInput[]`. - [x] 2.6 Write unit tests in `renewal-group-recommendations.test.ts` covering: basic 90-day grouping, cross-year-boundary grouping, all three date rules, standalone policy, null-date exclusion, and empty input. (12/12 pass) - [x] 3.0 New Client Setup Queue - [x] 3.1 Create `src/app/api/clients/setup-queue/route.ts` — GET handler that queries clients where `claimsAdvocateId IS NULL OR setupCompletedAt IS NULL`, including policy count, earliest/latest expiration dates, and `createdAt`. Returns sorted by `createdAt ASC`. - [x] 3.2 Create `src/app/(dashboard)/manager/setup/page.tsx` — server component that fetches the queue via Prisma and renders a table/list of unconfigured clients. Restrict to Manager/Admin roles; redirect others. - [x] 3.3 Each queue row must show: client name (linked to wizard), policy count, earliest expiry, latest expiry, days in queue (today − `createdAt`). - [x] 3.4 Add a "Days in queue" warning: highlight rows where `daysInQueue > 5` in amber, `> 10` in red. - [x] 3.5 Update `src/components/layout/nav-bar.tsx` to fetch the unconfigured client count client-side and show a numeric badge on the Manager nav link when count > 0. - [x] 3.6 Update `src/app/(dashboard)/manager/page.tsx` and `manager-page-client.tsx` to add a "New Client Setup" summary card showing the queue count and a link to `/manager/setup`. - [x] 4.0 Setup Wizard UI - [x] 4.1 Create `src/app/(dashboard)/manager/setup/[clientId]/page.tsx` — server component that fetches the client, all its policies, existing policy groups, Claims-dept users, and global settings. Passes all data to ``. - [x] 4.2 Create `src/components/renewal-groups/setup-wizard.tsx` — client component with full state management. - [x] 4.3 On mount, if no existing groups, auto-run the recommendation engine. If existing groups already exist, load them directly. - [x] 4.4 Render a top toolbar in the wizard: `windowDays` number input, `rule` select dropdown, and a "Re-run Recommendations" button with dirty-state confirmation dialog. - [x] 4.5 Create `src/components/renewal-groups/policy-chip.tsx` — `useDraggable` component with no-expiry warning. - [x] 4.6 Create `src/components/renewal-groups/group-card.tsx` — `useDroppable` card with inline name editor, rule selector, live renewal date, manual override, notes, and default-group star. - [x] 4.7 Render an "Unassigned Policies" tray at the bottom of the wizard. - [x] 4.8 Implement policy drag-and-drop via `@dnd-kit/core`. - [x] 4.9 Add group management: "Add Group" button, trash icon to delete, "Split" context action on each chip. - [x] 4.10 Add Claims Advocate selector (filtered to Claims dept). "Save & Complete" disabled if no advocate. - [x] 4.11 Single-default-group rule with star radio buttons; hidden when only one group. - [x] 4.12 "Save & Complete" — validates, calls POST, navigates to client detail on success. - [x] 4.13 "Save as Draft" — calls PUT, shows toast, keeps `setupCompletedAt` null. - [x] 4.14 Breadcrumb/back link to the queue page at the top of the wizard. - [x] 5.0 API Routes - [x] 5.1 Create `src/app/api/clients/[id]/setup/route.ts` — POST handler with Prisma transaction: upsert groups, update policy assignments, set client fields including `setupCompletedAt`. - [x] 5.2 PUT handler on same route for draft saves (omits `setupCompletedAt`). - [x] 5.3 Both handlers protected: return `403` if not Manager or Admin. - [x] 5.4 Create `src/app/api/admin/renewal-settings/route.ts` — GET/PUT with Admin-only write guard. - [x] 5.5 `setup-queue/route.ts` accepts `?count=true` query param returning `{ count: number }`. - [x] 6.0 Admin Panel — Global Settings - [x] 6.1 Create `src/app/(dashboard)/admin/renewal-settings/page.tsx` — server component reading settings and rendering ``. - [x] 6.2 Settings form: number input for window days (1–365) and select for date rule. - [x] 6.3 On save, calls `PUT /api/admin/renewal-settings`. Shows success/error toast. - [x] 6.4 Updated `src/app/(dashboard)/admin/page.tsx` with a "Renewal Groups" card linking to `/admin/renewal-settings`. - [x] 7.0 Re-open Wizard from Client Detail - [x] 7.1 Updated `src/app/(dashboard)/clients/[id]/page.tsx` to pass `setupCompletedAt` and `canManageSetup` props. - [x] 7.2 Updated `src/components/clients/client-detail.tsx` to render "Edit Setup" / "Complete Setup" button for Manager/Admin. - [x] 7.3 Wizard loads existing `PolicyGroup` data when re-opened and shows a re-configure banner. - [x] 7.4 API POST handler deletes removed groups (DB groups not in payload) inside the same transaction.