seubert-claims/tasks/tasks-prd-renewal-groups.md

92 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 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 <migration-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 `<SetupWizard />`.
- [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 `<RenewalSettingsForm />`.
- [x] 6.2 Settings form: number input for window days (1365) 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.