diff --git a/dev/Horizon issues and Next Steps.docx b/dev/Horizon issues and Next Steps.docx
new file mode 100644
index 0000000..2afc0bf
Binary files /dev/null and b/dev/Horizon issues and Next Steps.docx differ
diff --git a/dev/Seubert-Claims-LukeBillman.md b/dev/Seubert-Claims-LukeBillman.md
new file mode 100644
index 0000000..462ea24
--- /dev/null
+++ b/dev/Seubert-Claims-LukeBillman.md
@@ -0,0 +1,147 @@
+## Key Outcomes
+
+The meeting resolved critical issues with disappearing tasks and established a comprehensive solution for handling client renewal dates. All tasks prior to April 1, 2026 will be marked complete to clear historical backlog, and a new client-level renewal date field will be implemented to ensure consistent task generation across different renewal group configurations.
+## Decisions Made
+
+### Task Visibility and Historical Data
+
+- **Mark all tasks before April 1, 2026 as complete** to eliminate the backlog of 599+ overdue tasks that were causing confusion across user dashboards
+- **Standardize overdue task definition** across all system views (tasks page, manager page, and workload page) to mean: past the due date, not marked as N/A or completed, with no lower bound restriction
+
+### Client Renewal Date Logic
+
+- **Add a "Client Renewal" date field** at the client level that will be editable by managers and serve as the source of truth for client-level tasks
+- **Implement automatic date suggestion logic** using the following priority: (1) default/starred group renewal date, (2) if only one group exists, use that group's date, (3) if only individual policies exist, use policy date
+- **Allow manual override** of the suggested client renewal date during client setup to accommodate complex scenarios like transportation clients with multiple renewal groups
+
+### Meeting Cadence
+
+- **Establish weekly or bi-weekly recurring meetings** short-term to ensure system issues are addressed promptly
+- **Explore adding in-app functionality** for submitting change requests or bug reports that can be quickly triaged as either bugs for immediate fixes or design issues requiring meetings
+
+## Issues Resolved
+
+### Disappearing Tasks Problem
+
+- **Root cause identified**: Original 7-day visibility window was removed to address initial backlog, but this caused legitimate overdue tasks to accumulate without being hidden
+- **Dashboard inconsistencies**: Task counts differed between primary dashboard and task dashboard due to three different overdue definitions being applied across different system views
+- **Example case**: Mimi showed 599 past due tasks in one view but only 2 in another view
+
+### JG Contracting Renewal Task Generation Failure
+
+- **Problem**: Client with January 1, 2027 renewal wasn't generating expected claim review tasks in April and August 2026
+- **Root cause**: System was following the June 30 renewal date of a single unassigned policy instead of the January 1 date of the main renewal group containing the bulk of policies
+- **Why it happened**: System used "nearest to year start" logic (default date rule) which selected June 30 as closer to year start than January 1, applying this to client-level tasks
+- **Evidence**: Client-level tasks appeared at 275 days before June 30 (September 28) and 90 days before June 30 (April 1), confirming they followed the wrong renewal date
+
+### Group Numbering Confusion
+
+- **Issue**: JG Contracting's single renewal group was labeled "Group 2" instead of "Group 1"
+- **Explanation**: Group functionality and UI were built on different days, causing inconsistent labeling logic
+
+## Technical Implementation Details
+
+### Task Status Update Execution
+
+- **Bulk update completed**: 3,292 tasks with due date before April 1, 2026 and status "not started" were marked as completed
+- **Logging implemented**: Bulk changes are now logged to track why large numbers of tasks changed status
+- **Potential issue identified**: Some tasks that were previously marked complete after April 1 may have been reset to "not started" - requires investigation
+
+### Task Source Tracking
+
+- **New icon added**: Small settings icon appears next to policies on the right side of the screen to show where tasks originated from
+- **Helps debugging**: Allows users to trace which renewal date or policy group generated specific tasks
+
+### Client Renewal Date Field Implementation
+
+- **Location**: Will appear in the client setup screen alongside existing renewal group configuration
+- **Label**: "Client Renewal" to allow future reuse for other purposes beyond just tasking
+- **Behavior**: Auto-populated by logic on client creation but editable by managers at any time
+- **No automatic overwriting**: Once set, the date won't change automatically unless a specific triggering action occurs
+
+## Complex Scenarios Addressed
+
+### Transportation Clients with Multiple Renewal Groups
+
+- **Use case**: Clients with auto and motor truck cargo renewing 1/1, but AUCAC and truck broker liability renewing 3/1
+- **Challenge**: System must allow selection of which group's renewal date should drive client-level tasks
+- **Solution**: Manager can manually select the appropriate renewal date during setup, typically following the "big line" (highest premium policy)
+
+### Single Policy vs. Multiple Groups
+
+- **Single policy scenario**: If client has only one policy with no groups, system will use that policy's renewal date
+- **Multiple groups scenario**: System will follow the starred/default group's renewal date
+- **Override capability**: Regardless of automatic selection, managers can change the client renewal date if business logic dictates otherwise
+
+## Pending Confirmation
+
+- **Task reset investigation needed**: Verify whether tasks completed after April 1, 2026 were incorrectly reset to "not started" during the bulk update
+- **Sync date range behavior**: Confirm that policy syncs only capture policies within the specified date range (e.g., a policy starting 8/1/25 expiring 8/1/26 would be missed if sync runs for 1/1/26-12/31/26)
+
+## Technical Specifications
+
+### Overdue Task Definition (Standardized)
+
+- **Criteria**: Task is overdue if all of the following are true:
+ - Due date is before today
+ - Status is NOT "N/A"
+ - Status is NOT "Completed"
+ - No lower bound date restriction (perpetual visibility)
+
+### Task Generation Logic Hierarchy
+
+1. **Client-level tasks**: Follow the client renewal date field
+2. **Group-level tasks**: Follow their specific group's renewal date
+3. **Policy-level tasks**: Follow individual policy renewal dates
+
+### Default Date Rule Logic (Pre-Fix)
+
+- **Original behavior**: Selected renewal date nearest to start of year across all policies and groups
+- **Problem**: Did not account for which policies/groups were primary or contained bulk of coverage
+- **New behavior**: Will populate suggested client renewal date but allow override
+
+## Action Items
+
+- **Lawrence**: Implement client renewal date field in client setup screen with auto-population logic and manual override capability
+- **Lawrence**: Investigate and resolve task reset issue where completed tasks after 4/1 may have been changed to "not started"
+- **Lawrence**: Update sync date range to clearly indicate which policies will be captured based on effective/expiration dates
+- **Luke**: Set up weekly or bi-weekly recurring meeting with Lawrence to review ongoing system issues
+- **Luke**: Review task counts across all users to verify the April 1 bulk completion resolved dashboard inconsistencies
+
+## Open Questions
+
+### Task Visibility After Bulk Update
+
+- Why are some tasks showing different statuses than expected after the bulk completion of pre-April 1 tasks?
+- Are there any completed tasks from April 2026 onwards that were incorrectly reset?
+
+### Sync Functionality
+
+- Does the sync date range need to be adjusted to capture policies with effective dates before the sync year but expiration dates within it?
+- Should sync default dates be modified to be more inclusive of cross-year policies?
+
+## System Behavior Notes
+
+### Task Page vs. Dashboard Discrepancies (Pre-Fix)
+
+- **Tasks page**: Counted all overdue tasks with no lower bound
+- **Manager page**: Used configurable overdue window (last 30 days only)
+- **Workload KPI**: Counted all tasks including unassigned ones
+- **Result**: Same user could see vastly different overdue counts depending on which view they accessed
+
+### Renewal Group Star Functionality
+
+- **Purpose**: Star indicates the default renewal group that should drive client-level task generation
+- **Previous assumption**: System was following starred groups for client-level tasks
+- **Actual behavior**: System was using "nearest to year start" logic instead, ignoring the star designation
+
+### Policy Sync Date Range Default
+
+- **Current behavior**: Sync defaults to current calendar year (1/1/26 - 12/31/26)
+- **Limitation**: Policies with effective dates in previous year but expiration in current year will be missed unless date range is manually adjusted
+
+## Next Meeting
+
+- **Frequency**: Weekly or bi-weekly to be scheduled
+- **Topics**: Continue working through system functionality issues and enhancements
+- **Participants**: Luke, Lawrence, potentially Dawn and Christy as needed
diff --git a/dev/audit-logging-fix-plan.md b/dev/audit-logging-fix-plan.md
new file mode 100644
index 0000000..ea585cb
--- /dev/null
+++ b/dev/audit-logging-fix-plan.md
@@ -0,0 +1,108 @@
+# Audit Logging Fix Plan
+_Scheduled: after hours_
+
+## Problem
+
+Two code paths can change a task's status without capturing the **previous** status in the audit log:
+
+1. **`POST /api/tasks/[id]/notes`** — When a user adds a note and simultaneously changes task status, the audit entry is `TASK_NOTE_ADDED` with only `statusChange: `. The old status is never recorded.
+2. **`src/lib/shape-import/run-import.ts`** — SHAPE import directly calls `prisma.task.update()` and `prisma.task.create()` with `COMPLETED`/`NA` status. Zero per-task audit entries.
+
+The notes-route gap is the most operationally urgent because users are actively using it daily. The import gap is lower risk (import is a rare admin operation).
+
+---
+
+## Fix 1 — Notes Route: Capture Old Status (Priority: High)
+
+**File:** `src/app/api/tasks/[id]/notes/route.ts`
+
+### What to change
+
+The task is already fetched before the note is written (to check assignment). Add the old status to the audit log, and emit a **separate** `TASK_STATUS_CHANGED` entry when a status change accompanies the note.
+
+```ts
+// After fetching task (line ~42), old status is already available as task.status
+
+if (status && ['COMPLETED', 'NOT_STARTED', 'IN_PROGRESS'].includes(status)) {
+ await prisma.task.update({ ... }) // existing logic, unchanged
+
+ // ADD: dedicated status-change audit entry
+ await prisma.auditLog.create({
+ data: {
+ userId,
+ action: 'TASK_STATUS_CHANGED',
+ entityType: 'Task',
+ entityId: id,
+ oldValues: { status: task.status },
+ newValues: { status, source: 'note' },
+ },
+ })
+}
+
+// Existing TASK_NOTE_ADDED entry — update to include oldStatus too
+await prisma.auditLog.create({
+ data: {
+ userId,
+ action: 'TASK_NOTE_ADDED',
+ entityType: 'Task',
+ entityId: id,
+ oldValues: { status: task.status }, // ADD this
+ newValues: { noteId: note.id, statusChange: status ?? null },
+ },
+})
+```
+
+### Verification after deploy
+```sql
+-- Confirm old status is now captured
+SELECT old_values->>'status', new_values->>'status', new_values->>'source', created_at
+FROM audit_logs
+WHERE action = 'TASK_STATUS_CHANGED'
+ORDER BY created_at DESC
+LIMIT 10;
+```
+
+---
+
+## Fix 2 — PATCH Route: Confirm old_values.status is always set (Priority: Medium)
+
+**File:** `src/app/api/tasks/[id]/route.ts`
+
+The `TASK_UPDATED` entries already capture `oldValues: { status: task.status }`, but only when a status field is present in the request body. Verify the task is always fetched before the update (it is — line ~30 fetches `task`). No code change needed; just confirm via spot-check.
+
+```sql
+-- Spot-check: any TASK_UPDATED entries missing old_values.status
+SELECT COUNT(*) FROM audit_logs
+WHERE action = 'TASK_UPDATED'
+ AND old_values->>'status' IS NULL;
+```
+
+---
+
+## Fix 3 — SHAPE Import: Per-task Audit Logging (Priority: Low)
+
+**File:** `src/lib/shape-import/run-import.ts`
+
+This is a bulk operation run rarely by admins. The `ShapeImportRun` table already records run-level stats. Acceptable to leave per-task audit logging out for now given the volume (hundreds of tasks per run would bloat the audit table).
+
+**Recommendation:** Add a summary `SHAPE_IMPORT_TASK_SUMMARY` audit entry per import run that records counts by status (created COMPLETED, created NOT_STARTED, updated, skipped). Already partially done via `ImportStats`.
+
+---
+
+## Deployment Steps
+
+1. Apply Fix 1 to `notes/route.ts`
+2. TypeScript check: `npx tsc --noEmit`
+3. Commit: `git commit -m "Fix: capture old status in task notes audit log"`
+4. Push + deploy: `docker compose -f /opt/stacks/horizon/docker-compose.yml up -d --build`
+5. Run verification queries above to confirm
+6. Optionally apply Fix 3 summary entry to shape import
+
+---
+
+## Notes
+
+- No DB schema changes required — `old_values` and `new_values` are already `jsonb` columns.
+- No migration needed.
+- Zero downtime deploy (standard Next.js container rebuild).
+- Fix 1 is safe to apply during off-hours with no user impact.
diff --git a/ondeck/src/app/(dashboard)/clients/[id]/page.tsx b/ondeck/src/app/(dashboard)/clients/[id]/page.tsx
index 05ff44c..d29b9d5 100644
--- a/ondeck/src/app/(dashboard)/clients/[id]/page.tsx
+++ b/ondeck/src/app/(dashboard)/clients/[id]/page.tsx
@@ -66,6 +66,7 @@ export default async function ClientDetailPage({
OR: [
{ policyGroupId: null },
{ policyGroup: { renewalDate: { gte: cutoff } } },
+ { status: { notIn: ['COMPLETED', 'CANCELLED', 'NA'] } },
],
AND: [
{
diff --git a/ondeck/src/app/(dashboard)/manager/setup/page.tsx b/ondeck/src/app/(dashboard)/manager/setup/page.tsx
index 9030d9d..d18d618 100644
--- a/ondeck/src/app/(dashboard)/manager/setup/page.tsx
+++ b/ondeck/src/app/(dashboard)/manager/setup/page.tsx
@@ -30,28 +30,40 @@ export default async function SetupQueuePage() {
redirect('/dashboard')
}
- const clients = await prisma.client.findMany({
- where: {
- designation: { name: { in: ['Shape', 'Shape 2'] } },
- policies: { some: {} },
- OR: [
- { claimsAdvocateId: null },
- { setupCompletedAt: null },
- ],
- },
- select: {
- id: true,
- name: true,
- createdAt: true,
- claimsAdvocateId: true,
- setupCompletedAt: true,
- policies: {
- select: { expirationDate: true },
+ const DEAD_STATUSES = ['Cancelled', 'Expired', 'Non-Renewed', 'Rewritten', 'Not taken']
+
+ const [clients, skippedCount] = await Promise.all([
+ prisma.client.findMany({
+ where: {
+ designation: { name: { in: ['Shape', 'Shape 2'] } },
+ policies: { some: { status: { notIn: DEAD_STATUSES } } },
+ OR: [
+ { claimsAdvocateId: null },
+ { setupCompletedAt: null },
+ ],
},
- _count: { select: { policies: true } },
- },
- orderBy: { createdAt: 'asc' },
- })
+ select: {
+ id: true,
+ name: true,
+ createdAt: true,
+ claimsAdvocateId: true,
+ setupCompletedAt: true,
+ policies: {
+ where: { status: { notIn: DEAD_STATUSES } },
+ select: { expirationDate: true },
+ },
+ _count: { select: { policies: { where: { status: { notIn: DEAD_STATUSES } } } } },
+ },
+ orderBy: { createdAt: 'asc' },
+ }),
+ prisma.client.count({
+ where: {
+ designation: { name: { in: ['Shape', 'Shape 2'] } },
+ OR: [{ claimsAdvocateId: null }, { setupCompletedAt: null }],
+ NOT: { policies: { some: { status: { notIn: DEAD_STATUSES } } } },
+ },
+ }),
+ ])
const now = new Date()
@@ -85,6 +97,11 @@ export default async function SetupQueuePage() {
New Client Setup
Clients that need a claims advocate or renewal group configuration.
+ {skippedCount > 0 && (
+
+ ({skippedCount} skipped — no active policies)
+
+ )}