Initial commit: OnDeck project

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
lorentz 2026-02-18 13:20:52 +00:00
commit b036a93da2
139 changed files with 33198 additions and 0 deletions

16
dev/.postgres Normal file
View file

@ -0,0 +1,16 @@
# PostgreSQL Connection Details for OnDeck Database
# Connection String
DATABASE_URL=postgresql://ondeck_user:ondeck_password_2026!@localhost:5432/ondeck
# Individual Connection Parameters
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=ondeck
POSTGRES_USER=ondeck_user
POSTGRES_PASSWORD=ondeck_password_2026!
# Alternative Formats
# SQLAlchemy: postgresql+psycopg2://ondeck_user:ondeck_password_2026!@localhost:5432/ondeck
# JDBC: jdbc:postgresql://localhost:5432/ondeck?user=ondeck_user&password=ondeck_password_2026!
# Node.js: postgres://ondeck_user:ondeck_password_2026!@localhost:5432/ondeck

4
dev/.sql Normal file
View file

@ -0,0 +1,4 @@
server: 63.89.3.224
database: A1100080D1
user: 1100080_RO
password: iYi=14AxQh@7%oXkA[]9

416
dev/DATABASE_REFERENCE.md Normal file
View file

@ -0,0 +1,416 @@
# AFW Database Reference
**Server:** 63.89.3.224
**Database:** A1100080D1
---
## Departments
| ShortName | GLDeptCode | Full Name |
|-----------|------------|-----------|
| Dept0 | 000 | 00-Administration |
| Dept1 | 001 | 01-Commercial Lines |
| Dept2 | 002 | 02-Private Client |
| Dept3 | 003 | 03-Surety |
| Dept4 | 004 | 04-Group Benefits |
| Dept5 | 005 | 05-Life Insurance |
| Dept6 | 006 | 06-Retirement Benefits |
| Dept7 | 007 | DC Operations |
| Dept8 | 008 | 08-Select Commercial |
| Dept9 | 009 | 09-Transportation |
| Dept10 | 010 | 10-Real Estate/HealthCare |
| Dept11 | 011 | Streamline Captive |
| Dept12 | 012 | 12-Construction |
---
## Key Tables
### AFW_BasicPolInfo
Core policy information table.
| Column | Type | Description |
|--------|------|-------------|
| PolId | uniqueidentifier | Primary key - Policy ID |
| CustId | uniqueidentifier | Foreign key to AFW_Customer |
| PolNo | varchar(25) | Policy number |
| ShortPolNo | varchar(25) | Short policy number |
| PolEffDate | datetime | Policy effective date |
| PolExpDate | datetime | Policy expiration date |
| PolType | char(1) | Policy type |
| PolSubType | char(1) | Policy sub-type (P=Policy) |
| PolTypeLOB | varchar(150) | Line of business |
| Status | char(1) | Policy status (D=Deleted) |
| CoCode | varchar(3) | Parent company code |
| WritingCoCode | varchar(3) | Writing company code |
| ExecCode | varchar(3) | Executive/Producer code |
| CsrCode | varchar(3) | CSR code |
| BrokerCode | varchar(3) | Broker code |
| GLDivCode | varchar(3) | GL Division code |
| GLDeptCode | varchar(3) | GL Department code |
| GLBrnchCode | char(3) | GL Branch code |
| GLGrpCode | char(3) | GL Group code |
| BillMethod | varchar(1) | Billing method code |
| TypeOfBus | smallint | Type of business code |
| RenewalRptFlag | char(1) | Renewal/Status flag |
| IsContinuous | char(1) | Continuous policy flag |
| IsFinanced | varchar(1) | Financed flag |
| FullTermPremium | money | Full term premium amount |
| ChangedBy | varchar(3) | Last modified by |
| ChangedDate | datetime | Last modified date |
| EnteredDate | datetime | Entry date |
### AFW_Customer
Customer/insured information.
| Column | Type | Description |
|--------|------|-------------|
| CustId | uniqueidentifier | Primary key - Customer ID |
| CustNo | int | Customer number |
| FirmNameCust | varchar(75) | Firm/customer name |
| LastName | varchar(51) | Last name (individual) |
| FirstName | varchar(50) | First name (individual) |
| Addr1 | varchar(75) | Address line 1 |
| Addr2 | varchar(75) | Address line 2 |
| City | varchar(30) | City |
| State | char(2) | State code |
| ZipCode | varchar(9) | ZIP code |
| TypeCust | char(1) | Customer type |
| EMail | varchar(150) | Email address |
| BusPhone | varchar(7) | Business phone |
| ANotId | uniqueidentifier | Notation ID |
| Prod1Code | char(3) | Producer code |
| CsrCode | char(3) | CSR code |
| GLDivCode | char(3) | GL Division code |
| GLDeptCode | char(3) | GL Department code |
| Active | char(1) | Active status |
### AFW_Company
Insurance company/carrier information.
| Column | Type | Description |
|--------|------|-------------|
| CoId | uniqueidentifier | Primary key - Company ID |
| CoCode | char(3) | Company code |
| Name | varchar(75) | Company full name |
| ShortName | varchar(6) | Company short name |
| Type | char(1) | Company type |
| Status | char(1) | Status |
| NAIC | varchar(6) | NAIC code |
| ParentCoCode | char(3) | Parent company code |
### AFW_GeneralLedgerDepartment
Department lookup table.
| Column | Type | Description |
|--------|------|-------------|
| GLDeptCode | char(3) | Primary key - Department code |
| Name | varchar(25) | Department full name |
| ShortName | char(6) | Department short name (Dept1, Dept2, etc.) |
| Status | char(1) | Status |
| IsHide | char(1) | Hidden flag |
### AFW_Employee
Employee/personnel information.
| Column | Type | Description |
|--------|------|-------------|
| EmpCode | varchar(3) | Primary key - Employee code |
| LastName | varchar(20) | Last name |
| FirstName | varchar(16) | First name |
| MiddleName | varchar(11) | Middle name |
| ShortName | varchar(6) | Short name |
| Title | varchar(64) | Job title |
| EMail | varchar(150) | Email address |
| Status | char(1) | Status |
| IsRep | char(1) | Is representative flag |
| IsProd | char(1) | Is producer flag |
| EmpSupervisorCode | varchar(3) | Supervisor employee code |
| DefaultGLDivCode | char(3) | Default GL Division |
| DefaultGLDeptCode | char(3) | Default GL Department |
### AFW_PolicyPersonnel
Links policies to additional personnel (reps, executives).
| Column | Type | Description |
|--------|------|-------------|
| PolId | uniqueidentifier | Policy ID |
| PolPId | uniqueidentifier | Policy Personnel ID |
| EmpCode | char(3) | Employee code |
| EmpType | char(1) | Employee type (R=Rep, P=Producer/Exec) |
| IsPrimary | char(1) | Is primary flag (Y/N) |
| Percentage | float | Commission percentage |
| FlatAmount | money | Flat commission amount |
| Position | smallint | Position/order |
| EnteredDate | datetime | Entry date |
### AFW_PRCode
Lookup/reference codes table.
| Column | Type | Description |
|--------|------|-------------|
| AttrCode | char(3) | Attribute code (category) |
| Code | varchar(10) | Code value |
| Description | varchar(150) | Description |
| SortNo | smallint | Sort order |
| IsHide | char(1) | Hidden flag |
---
## Lookup Values (AFW_PRCode)
### Type of Business (AttrCode = 'TB')
| Code | Description |
|------|-------------|
| 0 | All |
| 1 | Personal Lines |
| 2 | Commercial Lines |
| 3 | Non Property & Casualty |
| 4 | Benefits |
| 5 | Life |
| 6 | Health |
| 7 | Financial Services |
### Billing Method (AttrCode = 'BM')
| Code | Description |
|------|-------------|
| A | Agency bill |
| F | 1st Installment Agency Bill, Remaining Direct Bill |
| P | Direct bill |
### Policy Status/Renewal Flag (AttrCode = 'PF')
| Code | Description |
|------|-------------|
| A | Active |
| C | Cancelled |
| E | Expired |
| N | Non-Renewed |
| R | Renewed |
| W | Rewritten |
| T | Not taken |
| I | Include |
| Q | Quote |
---
## Employee Assignment to Policies
Employees can be assigned to policies in two ways: **Primary Assignment** (direct fields on the policy) and **Additional Personnel** (via the AFW_PolicyPersonnel table).
### Primary Assignment (AFW_BasicPolInfo)
Every policy has three primary employee fields:
| Field | Role | Description |
|-------|------|-------------|
| `ExecCode` | **Executive/Producer** | Primary producer/account executive responsible for the policy |
| `CsrCode` | **CSR** | Customer Service Representative handling day-to-day service |
| `BrokerCode` | **Broker** | External broker (optional, can be NULL) |
These are required fields (except BrokerCode) and link to `AFW_Employee.EmpCode`.
```sql
-- Example: Get primary personnel for a policy
SELECT
bp.PolNo,
exec.LastName + ', ' + exec.FirstName AS Executive,
csr.LastName + ', ' + csr.FirstName AS CSR,
broker.LastName + ', ' + broker.FirstName AS Broker
FROM AFW_BasicPolInfo bp
INNER JOIN AFW_Employee exec ON exec.EmpCode = bp.ExecCode
INNER JOIN AFW_Employee csr ON csr.EmpCode = bp.CsrCode
LEFT JOIN AFW_Employee broker ON broker.EmpCode = bp.BrokerCode
```
### Additional Personnel (AFW_PolicyPersonnel)
Policies can have additional personnel assignments beyond the primary exec/csr/broker. These are stored in `AFW_PolicyPersonnel`.
#### Employee Types (EmpType)
| Code | Description | Usage |
|------|-------------|-------|
| `P` | **Producer/Executive** | Additional executives, account managers |
| `R` | **Representative** | Additional CSRs, service reps |
| `B` | **Broker** | Additional brokers |
| `T` | **Sales Center Rep** | Telemarketing/sales center staff |
#### Primary vs Additional
| IsPrimary | Meaning |
|-----------|---------|
| `Y` | Primary person of this type for the policy |
| `N` | Additional/secondary person of this type |
A policy can have:
- One primary Producer (`EmpType='P'`, `IsPrimary='Y'`)
- Multiple additional Producers (`EmpType='P'`, `IsPrimary='N'`)
- One primary Rep (`EmpType='R'`, `IsPrimary='Y'`)
- Multiple additional Reps (`EmpType='R'`, `IsPrimary='N'`)
#### Commission Fields
| Field | Description |
|-------|-------------|
| `Method` | Commission method: `A`=Amount/Percentage, `P`=Percentage only |
| `Percentage` | Commission split percentage |
| `FlatAmount` | Flat commission amount |
| `FeeMethod` | Fee calculation method |
| `FeePercentage` | Fee percentage |
| `ProductionCreditSplitPercentage` | Production credit split % |
| `IsSuspended` | Whether commission is suspended |
```sql
-- Example: Get all personnel for a policy with their types
SELECT
pp.EmpType,
CASE pp.EmpType
WHEN 'P' THEN 'Producer/Exec'
WHEN 'R' THEN 'Representative'
WHEN 'B' THEN 'Broker'
WHEN 'T' THEN 'Sales Center Rep'
END AS RoleDescription,
pp.IsPrimary,
emp.LastName + ', ' + emp.FirstName AS Name,
pp.Percentage AS CommissionPct
FROM AFW_PolicyPersonnel pp
INNER JOIN AFW_Employee emp ON emp.EmpCode = pp.EmpCode
WHERE pp.PolId = @PolId
ORDER BY pp.EmpType, pp.IsPrimary DESC, pp.Position
```
### Customer-Level Personnel (AFW_CustAddPersonnel)
Customers can also have default personnel assignments that may cascade to new policies.
| Column | Description |
|--------|-------------|
| `CustId` | Customer ID |
| `EmpCode` | Employee code |
| `TypeOfEmp` | Employee type (`P`=Producer, `R`=Rep) |
| `TypeOfBus` | Type of business this applies to |
| `IsPrimary` | Primary flag |
### Employee Role Flags (AFW_Employee)
Employees have role flags indicating their capabilities:
| Flag | Description |
|------|-------------|
| `IsRep` | Can be assigned as a Representative |
| `IsProd` | Can be assigned as a Producer |
| `IsTeleMarketer` | Telemarketing role |
| `IsOther` | Other role type |
Common combinations:
- `IsRep=Y, IsProd=Y` - Can serve as both producer and rep (most common)
- `IsRep=N, IsProd=Y` - Producer only
- `IsRep=Y, IsProd=N` - Rep/CSR only
### Query: Get All Personnel for a Policy (Full)
```sql
-- Primary personnel from AFW_BasicPolInfo
SELECT
'Primary Exec' AS Assignment,
bp.ExecCode AS EmpCode,
exec.LastName + ', ' + exec.FirstName AS Name
FROM AFW_BasicPolInfo bp
INNER JOIN AFW_Employee exec ON exec.EmpCode = bp.ExecCode
WHERE bp.PolId = @PolId
UNION ALL
SELECT
'Primary CSR' AS Assignment,
bp.CsrCode,
csr.LastName + ', ' + csr.FirstName
FROM AFW_BasicPolInfo bp
INNER JOIN AFW_Employee csr ON csr.EmpCode = bp.CsrCode
WHERE bp.PolId = @PolId
UNION ALL
-- Additional personnel from AFW_PolicyPersonnel
SELECT
CASE
WHEN pp.EmpType = 'P' AND pp.IsPrimary = 'Y' THEN 'Add''l Exec (Primary)'
WHEN pp.EmpType = 'P' AND pp.IsPrimary = 'N' THEN 'Add''l Exec'
WHEN pp.EmpType = 'R' AND pp.IsPrimary = 'Y' THEN 'Add''l Rep (Primary)'
WHEN pp.EmpType = 'R' AND pp.IsPrimary = 'N' THEN 'Add''l Rep'
WHEN pp.EmpType = 'B' THEN 'Add''l Broker'
END AS Assignment,
pp.EmpCode,
emp.LastName + ', ' + emp.FirstName
FROM AFW_PolicyPersonnel pp
INNER JOIN AFW_Employee emp ON emp.EmpCode = pp.EmpCode
WHERE pp.PolId = @PolId
```
---
## Key Views
| View Name | Description |
|-----------|-------------|
| AFW_PolicyBizVw | Policy business summary view |
| AFW_PolicyVw | Full policy view |
| AFW_PolicyShortVw | Abbreviated policy view |
| AFW_CustomerShortVw | Abbreviated customer view |
| AFW_EmployeeVw | Employee view |
| AFW_CompanyVw | Company view |
| AFW_BrokerVw | Broker view |
| AFW_BusinessUnitVw | Business unit view |
| AFW_InvoiceTransactionVw | Invoice transaction view |
| AFW_PolicyTransactionFactVw | Policy transaction fact view |
---
## Common Query Patterns
### Filter by Department
```sql
INNER JOIN AFW_GeneralLedgerDepartment
ON AFW_GeneralLedgerDepartment.GLDeptCode = AFW_BasicPolInfo.GLDeptCode
WHERE AFW_GeneralLedgerDepartment.ShortName IN ('Dept1', 'Dept8', 'Dept9')
```
### Get Policy Status Description
```sql
INNER JOIN AFW_PRCode RenewalRptFlag
ON RenewalRptFlag.Code = AFW_BasicPolInfo.RenewalRptFlag
AND RenewalRptFlag.AttrCode = 'PF'
```
### Get Employee Formatted Name
```sql
AFW_Employee.LastName + ', ' + AFW_Employee.FirstName AS FormattedName
```
### Filter Active Policies (Exclude Deleted)
```sql
WHERE AFW_BasicPolInfo.Status != 'D'
AND PolSubType = 'P'
```
---
## Table Relationships
```
AFW_Customer (CustId)
└── AFW_BasicPolInfo (CustId) ──┬── AFW_Company [ParentCompany] (CoCode)
├── AFW_Company [WritingCompany] (WritingCoCode)
├── AFW_GeneralLedgerDepartment (GLDeptCode)
├── AFW_Employee [ExecCode] (EmpCode)
├── AFW_Employee [CsrCode] (EmpCode)
├── AFW_PRCode [TypeOfBusiness] (TypeOfBus, AttrCode='TB')
├── AFW_PRCode [BillMethod] (BillMethod, AttrCode='BM')
├── AFW_PRCode [Status] (RenewalRptFlag, AttrCode='PF')
└── AFW_PolicyPersonnel (PolId)
└── AFW_Employee (EmpCode)
```

61
dev/create-prd.mdc Normal file
View file

@ -0,0 +1,61 @@
---
description:
globs:
alwaysApply: false
---
# Rule: Generating a Product Requirements Document (PRD)
## Goal
To guide an AI assistant in creating a detailed Product Requirements Document (PRD) in Markdown format, based on an initial user prompt. The PRD should be clear, actionable, and suitable for a junior developer to understand and implement the feature.
## Process
1. **Receive Initial Prompt:** The user provides a brief description or request for a new feature or functionality.
2. **Ask Clarifying Questions:** Before writing the PRD, the AI *must* ask clarifying questions to gather sufficient detail. The goal is to understand the "what" and "why" of the feature, not necessarily the "how" (which the developer will figure out).
3. **Generate PRD:** Based on the initial prompt and the user's answers to the clarifying questions, generate a PRD using the structure outlined below.
4. **Save PRD:** Save the generated document as `prd-[feature-name].md` inside the `/tasks` directory.
## Clarifying Questions (Examples)
The AI should adapt its questions based on the prompt, but here are some common areas to explore:
* **Problem/Goal:** "What problem does this feature solve for the user?" or "What is the main goal we want to achieve with this feature?"
* **Target User:** "Who is the primary user of this feature?"
* **Core Functionality:** "Can you describe the key actions a user should be able to perform with this feature?"
* **User Stories:** "Could you provide a few user stories? (e.g., As a [type of user], I want to [perform an action] so that [benefit].)"
* **Acceptance Criteria:** "How will we know when this feature is successfully implemented? What are the key success criteria?"
* **Scope/Boundaries:** "Are there any specific things this feature *should not* do (non-goals)?"
* **Data Requirements:** "What kind of data does this feature need to display or manipulate?"
* **Design/UI:** "Are there any existing design mockups or UI guidelines to follow?" or "Can you describe the desired look and feel?"
* **Edge Cases:** "Are there any potential edge cases or error conditions we should consider?"
## PRD Structure
The generated PRD should include the following sections:
1. **Introduction/Overview:** Briefly describe the feature and the problem it solves. State the goal.
2. **Goals:** List the specific, measurable objectives for this feature.
3. **User Stories:** Detail the user narratives describing feature usage and benefits.
4. **Functional Requirements:** List the specific functionalities the feature must have. Use clear, concise language (e.g., "The system must allow users to upload a profile picture."). Number these requirements.
5. **Non-Goals (Out of Scope):** Clearly state what this feature will *not* include to manage scope.
6. **Design Considerations (Optional):** Link to mockups, describe UI/UX requirements, or mention relevant components/styles if applicable.
7. **Technical Considerations (Optional):** Mention any known technical constraints, dependencies, or suggestions (e.g., "Should integrate with the existing Auth module").
8. **Success Metrics:** How will the success of this feature be measured? (e.g., "Increase user engagement by 10%", "Reduce support tickets related to X").
9. **Open Questions:** List any remaining questions or areas needing further clarification.
## Target Audience
Assume the primary reader of the PRD is a **junior developer**. Therefore, requirements should be explicit, unambiguous, and avoid jargon where possible. Provide enough detail for them to understand the feature's purpose and core logic.
## Output
* **Format:** Markdown (`.md`)
* **Location:** `/tasks/`
* **Filename:** `prd-[feature-name].md`
## Final instructions
1. Do NOT start implementing the PRD
2. Make sure to ask the user clarifying questions
3. Take the user's answers to the clarifying questions and improve the PRD

64
dev/generate-tasks.mdc Normal file
View file

@ -0,0 +1,64 @@
---
description:
globs:
alwaysApply: false
---
# Rule: Generating a Task List from a PRD
## Goal
To guide an AI assistant in creating a detailed, step-by-step task list in Markdown format based on an existing Product Requirements Document (PRD). The task list should guide a developer through implementation.
## Output
- **Format:** Markdown (`.md`)
- **Location:** `/tasks/`
- **Filename:** `tasks-[prd-file-name].md` (e.g., `tasks-prd-user-profile-editing.md`)
## Process
1. **Receive PRD Reference:** The user points the AI to a specific PRD file
2. **Analyze PRD:** The AI reads and analyzes the functional requirements, user stories, and other sections of the specified PRD.
3. **Phase 1: Generate Parent Tasks:** Based on the PRD analysis, create the file and generate the main, high-level tasks required to implement the feature. Use your judgement on how many high-level tasks to use. It's likely to be about 5. Present these tasks to the user in the specified format (without sub-tasks yet). Inform the user: "I have generated the high-level tasks based on the PRD. Ready to generate the sub-tasks? Respond with 'Go' to proceed."
4. **Wait for Confirmation:** Pause and wait for the user to respond with "Go".
5. **Phase 2: Generate Sub-Tasks:** Once the user confirms, break down each parent task into smaller, actionable sub-tasks necessary to complete the parent task. Ensure sub-tasks logically follow from the parent task and cover the implementation details implied by the PRD.
6. **Identify Relevant Files:** Based on the tasks and PRD, identify potential files that will need to be created or modified. List these under the `Relevant Files` section, including corresponding test files if applicable.
7. **Generate Final Output:** Combine the parent tasks, sub-tasks, relevant files, and notes into the final Markdown structure.
8. **Save Task List:** Save the generated document in the `/tasks/` directory with the filename `tasks-[prd-file-name].md`, where `[prd-file-name]` matches the base name of the input PRD file (e.g., if the input was `prd-user-profile-editing.md`, the output is `tasks-prd-user-profile-editing.md`).
## Output Format
The generated task list _must_ follow this structure:
```markdown
## Relevant Files
- `path/to/potential/file1.ts` - Brief description of why this file is relevant (e.g., Contains the main component for this feature).
- `path/to/file1.test.ts` - Unit tests for `file1.ts`.
- `path/to/another/file.tsx` - Brief description (e.g., API route handler for data submission).
- `path/to/another/file.test.tsx` - Unit tests for `another/file.tsx`.
- `lib/utils/helpers.ts` - Brief description (e.g., Utility functions needed for calculations).
- `lib/utils/helpers.test.ts` - Unit tests for `helpers.ts`.
### Notes
- Unit tests should typically be placed alongside the code files they are testing (e.g., `MyComponent.tsx` and `MyComponent.test.tsx` in the same directory).
- Use `npx jest [optional/path/to/test/file]` to run tests. Running without a path executes all tests found by the Jest configuration.
## Tasks
- [ ] 1.0 Parent Task Title
- [ ] 1.1 [Sub-task description 1.1]
- [ ] 1.2 [Sub-task description 1.2]
- [ ] 2.0 Parent Task Title
- [ ] 2.1 [Sub-task description 2.1]
- [ ] 3.0 Parent Task Title (may not require sub-tasks if purely structural or configuration)
```
## Interaction Model
The process explicitly requires a pause after generating parent tasks to get user confirmation ("Go") before proceeding to generate the detailed sub-tasks. This ensures the high-level plan aligns with user expectations before diving into details.
## Target Audience
Assume the primary reader of the task list is a **junior developer** who will implement the feature.

292
dev/mvp.md Normal file
View file

@ -0,0 +1,292 @@
# OnDeck (Horizon)
## Policy Renewal Workflow System
### Functional Requirements Review (With User Feedback)
---
## Purpose of This Document
This document describes what **OnDeck** will do for your team. It incorporates stakeholder feedback directly into the functional requirements so the final system reflects real operational needs.
Stakeholders were asked to:
- Answer questions highlighted in yellow
- Confirm decisions highlighted in green
- Suggest changes or additions
User responses are embedded inline below.
---
## What is OnDeck?
OnDeck is a web application that automatically creates and tracks renewal tasks for insurance policies. It integrates with **AMS360** to pull client, policy, and staff data, then generates tasks at the appropriate time based on configurable rules.
---
## Key Benefits
- Automatic task creation based on policy expiration dates
- Consistent renewal workflows across departments
- Clear visibility into task ownership and overdue work
- Full audit trail for compliance
- Microsoft 365 single sign-on
---
## 1. User Roles & Permissions
OnDeck supports four user roles with different access levels:
| Role | Capabilities |
|-----|-------------|
| **Admin** | Full system access: user management, configuration, reporting, audit logs, data sync |
| **Manager** | View all clients/tasks, assign work, manage templates, run reports, view audit logs |
| **Account Executive (AE)** | View/update assigned clients and tasks, mark tasks complete |
| **Claims** | View client info and manage claims-related tasks only |
> ❓ **QUESTION:** Are these four roles sufficient?
> 💬 **USER RESPONSE:**
> Yes, these four roles are sufficient for the MVP. Additional roles or more granular permissions can be evaluated after rollout once usage patterns are clearer.
---
> ❓ **QUESTION:** Who should have Admin access?
> 💬 **USER RESPONSE:**
> Likely Kristie Lulich and Tyler Lyster, though final determination should be deferred to Tyler.
---
> ✅ **DECISION NEEDED:** Role assignment method
> 💬 **USER RESPONSE:**
> Roles should be assigned based on Microsoft 365 security groups. The more automation, the better.
---
### Authentication
- Users authenticate using existing Microsoft 365 credentials
- No separate password required
- First login automatically creates an OnDeck account and links it to the AMS360 employee record
---
## 2. Departments
OnDeck organizes work by department. Each policy and task template is associated with a department.
### Default Departments
- Personal Lines
- Commercial Lines
- Claims
- Benefits
- Other
> ❓ **QUESTION:** Should all 13 AMS360 departments be synced?
> 💬 **USER RESPONSE:**
> Recommendation is to start with **Commercial Lines** and **Claims**. Personal Lines could be added later, but may not be needed initially due to other technologies in use.
---
> ❓ **QUESTION:** Should task templates be department-specific?
> 💬 **USER RESPONSE:**
> Yes initially. In the future, tasks should be usable across departments if needed.
---
## 3. Data from AMS360
OnDeck syncs data from AMS360 on a scheduled basis.
### Data Synced
| Data Type | Description |
|---------|-------------|
| Employees | Active employees become users with name, email, department |
| Clients | Active customers with contact and producer info |
| Policies | Expiration date, carrier, department, assigned reps (up to 2 reps + 2 execs) |
### Sync Schedule
- Nightly sync at **2:00 AM**
- Manual sync available to Admins
> ✅ **DECISION:** Is nightly sync acceptable?
> 💬 **USER RESPONSE:**
> Yes, no issues anticipated with a 2:00 AM sync.
---
> ❓ **QUESTION:** Should policy date ranges be restricted?
> 💬 **USER RESPONSE:**
> No. Tasks occur year-round. Ideally include all current policies. Historical policies may be useful in the future.
---
## 4. Task Templates
Task templates define renewal workflows and generate tasks automatically.
### Template Attributes
- Name
- Description
- Department
- Timing (pre/post renewal)
- Days offset
- Priority
- Optional client designation
### Example Templates
| Task | Timing | Offset | Priority | Department |
|----|------|--------|---------|-----------|
| Order Loss Runs | Pre | -90 | Medium | Commercial |
| Review Coverage | Pre | -60 | High | Commercial |
| Send Renewal Quote | Pre | -30 | High | Commercial |
| Confirm Renewal | Pre | -7 | Urgent | Commercial |
| Issue Certificates | Post | +3 | Medium | Commercial |
---
> ❓ **QUESTION:** Provide standard renewal templates
> 💬 **USER RESPONSE:**
> This information exists in the Claims database.
---
> ❓ **QUESTION:** Do client designations require different tasks?
> 💬 **USER RESPONSE:**
> Differences exist mainly for **SHAPE** and **SHAPE2**, primarily impacting Claims. AEs generally follow the same workflow. Future enhancement could support à la carte or tiered services.
---
## 5. Task Workflow
### Task Statuses
| Status | Meaning |
|------|--------|
| Not Started | Task created, work not begun |
| In Progress | Task actively being worked |
| Completed | Task finished (user + timestamp recorded) |
| Blocked | Waiting on external dependency |
| N/A | Not applicable (reason required) |
| Cancelled | Voided (reason required) |
> ❓ **QUESTION:** Are these statuses sufficient?
> 💬 **USER RESPONSE:**
> Generally yes, but preference is to avoid N/A and Cancelled by improving assignment accuracy at the policy/client level.
---
### Task Assignment
> ❓ **QUESTION:** How should tasks be initially assigned?
> 💬 **USER RESPONSE:**
> Automatically based on predefined parameters (policy producer/AE or claims owner). Managers must be able to reassign.
---
> ❓ **QUESTION:** Single owner or multiple assignees?
> 💬 **USER RESPONSE:**
> Single owner per task to ensure accountability. Managers can reassign as needed.
---
## 6. Multiple Policies per Client
Clients may have multiple policies renewing together or separately.
### Proposed Behavior
- Default: one task set per client
- Options:
- Group policies
- Split policies
- Exclude policies
> ✅ **DECISION:** Default task grouping
> 💬 **USER RESPONSE:**
> One task set per client is correct, with smarter assignment logic to minimize manual adjustments.
---
> ❓ **QUESTION:** Policy exclusion reasons?
> 💬 **USER RESPONSE:**
> Defer to Tyler. Generally unclear why a policy would be excluded.
---
> ❓ **QUESTION:** Should excluded policies remain visible?
> 💬 **USER RESPONSE:**
> Yes, with a visual indicator.
---
## 7. Notifications & Alerts
### Alert Types
- Overdue tasks
- Tasks due today
- New assignments
- System issues (Admins only)
### Delivery Methods
- In-app
- Email
- Microsoft Teams
> ✅ **DECISION:** Teams notification targeting
> 💬 **USER RESPONSE:**
> Notifications should be sent to **individual users**, not shared channels.
---
> ❓ **QUESTION:** Overdue reminder frequency?
> 💬 **USER RESPONSE:**
> Weekly consolidated summary to reduce notification fatigue.
---
> ❓ **QUESTION:** Additional notification triggers?
> 💬 **USER RESPONSE:**
> - Policy renewal completion with carrier
> - Client transition into SHAPE / SHAPE2 (notify management)
> Task creation for SHAPE/SHAPE2 should occur after management assignment.
---
## 8. Audit Trail & Compliance
### Logged Events
- User identity
- Before/after values
- Timestamp
- Sign-in attempts
Audit logs are immutable and exportable.
---
> ❓ **QUESTION:** Audit log retention period?
> 💬 **USER RESPONSE:**
> 18 months is sufficient. Can be extended later if required.
---
> ❓ **QUESTION:** Need specific compliance reports?
> 💬 **USER RESPONSE:**
> No dedicated compliance reports needed for MVP. Standard task/status reporting is sufficient.
---
## Summary of Confirmed Direction
- MVP roles confirmed
- Microsoft 365based role automation preferred
- Initial focus on Commercial + Claims
- Single-task ownership model
- Weekly overdue summaries
- One task set per client by default
- 18-month audit retention
The Shape designation is already in use by AMS360, Shape2 has yet to be defined in AMS but will be similar to Shape

View file

@ -0,0 +1,621 @@
# OnDeck - PRD Input Document
## Project Overview
**Project Name:** OnDeck - Policy Renewal Workflow Management System
**Client Type:** Insurance Brokerage
**Purpose:** Streamline policy renewal workflows by centralizing client and policy data from AMS360, enabling custom client classifications, personnel assignments, and department-specific task management tied to policy renewal dates.
---
## 1. Problem Statement
Insurance brokerages managing large policy portfolios face challenges coordinating renewal activities across departments. Currently:
- Client and policy data lives in AMS360 with no custom workflow layer
- No systematic way to assign internal designations or classifications to clients
- Renewal tasks are tracked manually or in disconnected systems
- No visibility into workload distribution or deadline compliance across teams
- Personnel assignments to clients aren't centrally managed
**Goal:** Create OnDeck - a unified web application that syncs AMS360 data, adds custom metadata layers, and provides renewal-based task management with dashboards for workload visibility.
---
## 2. User Personas & Roles
### 2.1 Role Definitions
| Role | Description | Key Permissions |
|------|-------------|-----------------|
| **Admin** | System administrators, IT staff | Full access: user management, sync configuration, all data, system settings |
| **Manager** | Department leads, supervisors | View all department data, assign tasks, manage personnel assignments, view all dashboards |
| **Account Executive** | Handles client relationships, renewals | View assigned clients, manage own tasks, update client info, view personal dashboard |
| **Claims** | Claims department staff | View assigned clients, manage claims-related tasks, limited client edit |
### 2.2 Authorization Model
**Dual-layer approach:**
1. **Entra ID Groups → Base Role Mapping**
- Entra Group membership determines initial role assignment
- Example: `SG-OnDeck-Admins` → Admin role
- MFA enforced via Entra Conditional Access policies
2. **In-App Granular Permissions**
- Fine-grained permissions within roles
- Client-level access assignments (primary/additional personnel)
- Department-based data filtering
- Custom permission overrides when needed
---
## 3. Functional Requirements
### 3.1 Authentication & Authorization
#### 3.1.1 Entra ID Integration
- **SSO via Entra ID** using MSAL.js or NextAuth.js Azure AD provider
- **Token claims must include:** `groups`, `preferred_username`, `name`, `oid`
- **Group-to-role mapping** configurable by Admin
- **Leverage existing MFA** - no additional MFA implementation needed
- **Session management:** Configurable timeout, refresh token handling
#### 3.1.2 In-App Permission System
- Permission sets per role (CRUD matrix)
- Ability to assign individuals to specific clients (overrides department-level access)
- Audit log of permission changes
- Admin UI for managing Entra Group → Role mappings
### 3.2 AMS360 Data Sync Engine
#### 3.2.1 Sync Configuration
- **Frequency:** Daily automated sync (configurable time window)
- **Method:** Direct SQL connection to AMS360 database
- **Direction:** One-way (AMS360 → Local Postgres)
- **Entities to sync:**
- Clients (customer master data)
- Policies (policy details, renewal dates, coverage info)
#### 3.2.2 Sync Behavior
- **Initial load:** Full sync of all active clients and policies
- **Incremental sync:** Based on `ModifiedDate` or equivalent timestamp fields
- **Conflict handling:** AMS360 is source of truth for synced fields
- **Sync logging:** Record sync runs, row counts, errors
- **Manual trigger:** Admin can initiate on-demand sync
#### 3.2.3 Data Mapping (AMS360 → Local)
```
AMS360 Client → local.clients
- CustomerID → ams_customer_id (unique key for sync)
- CustomerName → name
- Address fields → address_*
- Phone/Email → contact_*
- Producer → producer_code
- (other relevant fields TBD based on AMS360 schema)
AMS360 Policy → local.policies
- PolicyID → ams_policy_id (unique key for sync)
- CustomerID → client_id (FK to local.clients)
- PolicyNumber → policy_number
- EffectiveDate → effective_date
- ExpirationDate → expiration_date (THIS IS THE RENEWAL DATE)
- PolicyType → policy_type
- Carrier → carrier_name
- Premium → premium_amount
- Status → status
```
### 3.3 Client Management (Custom Data Layer)
#### 3.3.1 Custom Client Fields (Local Only)
These fields are NOT synced from AMS360 - they are managed entirely in the app:
| Field | Type | Description |
|-------|------|-------------|
| `shape` | FK to shapes table | Primary designation (user-defined) |
| `shape2` | FK to shapes table | Secondary designation (user-defined) |
| `primary_personnel_id` | FK to users | Primary account owner (Entra user) |
| `notes` | Text | Internal notes |
| `custom_fields` | JSONB | Extensible custom field storage |
#### 3.3.2 Shape/Designation Management
- Admin-configurable list of Shape values
- Each shape has: `id`, `name`, `description`, `color` (for UI), `active`
- Shapes can be deactivated but not deleted (preserve historical data)
- Clients can have one Shape and one Shape2 (both optional)
#### 3.3.3 Personnel Assignment
- **Primary Personnel:** One Entra user designated as primary owner
- **Additional Personnel:** Zero or more Entra users with access
- Personnel dropdown populated from Entra ID users (synced or on-demand lookup)
- Assignment changes logged for audit
### 3.4 Task/Action Management
#### 3.4.1 Task Definition
Tasks represent actions to be taken relative to policy renewal dates.
**Task Properties:**
| Field | Type | Description |
|-------|------|-------------|
| `id` | UUID | Primary key |
| `title` | String | Task name |
| `description` | Text | Detailed instructions |
| `department` | Enum | Personal Lines, Commercial Lines, Claims, etc. |
| `timing` | Enum | `PRE_RENEWAL` or `POST_RENEWAL` |
| `days_offset` | Integer | Days before (negative) or after (positive) renewal |
| `due_date` | Date | Calculated: policy.expiration_date + days_offset |
| `status` | Enum | `NOT_STARTED`, `IN_PROGRESS`, `COMPLETED`, `BLOCKED`, `CANCELLED` |
| `priority` | Enum | `LOW`, `MEDIUM`, `HIGH`, `URGENT` |
| `client_id` | FK | Associated client |
| `policy_id` | FK | Associated policy (optional - can be client-level) |
| `assigned_users` | Many-to-many | One or more Entra users |
| `created_by` | FK | User who created |
| `created_at` | Timestamp | |
| `updated_at` | Timestamp | |
| `completed_at` | Timestamp | When status changed to COMPLETED |
| `completed_by` | FK | User who completed |
#### 3.4.2 Task Templates
- **Department-based templates:** Predefined task sets per department
- Templates define: title, description, timing, days_offset, default priority
- When a policy approaches renewal, tasks can be auto-generated from templates
- Admin can manage templates per department
**Example Template:**
```
Department: Personal Lines
Template Name: "Standard Auto Renewal"
Tasks:
1. Review coverage limits (PRE_RENEWAL, -45 days)
2. Contact client for updates (PRE_RENEWAL, -30 days)
3. Submit renewal to carrier (PRE_RENEWAL, -21 days)
4. Send renewal docs to client (POST_RENEWAL, +3 days)
```
#### 3.4.3 Task Assignment
- Tasks can be assigned to one or more users
- Assignment can be manual or auto-assigned to client's primary personnel
- Bulk task assignment for efficiency
- Reassignment with audit trail
#### 3.4.4 Task Lifecycle
```
NOT_STARTED → IN_PROGRESS → COMPLETED
BLOCKED → IN_PROGRESS → COMPLETED
Any status → CANCELLED (with reason)
```
### 3.5 Dashboards & Reporting
#### 3.5.1 Personal Dashboard (Account Executive, Claims)
- **My Tasks:** Filtered to assigned tasks
- Overdue (red highlight)
- Due today
- Due this week
- Upcoming (next 30 days)
- **My Clients:** Quick access to assigned clients
- **Quick Stats:**
- Tasks completed this week/month
- Overdue task count
- Upcoming renewals count
#### 3.5.2 Manager Dashboard
- **Team Overview:**
- Workload distribution (tasks per team member)
- Completion rates by user
- Overdue tasks by user
- **Department Metrics:**
- Tasks by status (pie/bar chart)
- Renewal timeline (upcoming 90 days)
- SLA compliance (% tasks completed on time)
- **Drill-down capability:** Click to see individual user details
#### 3.5.3 Admin Dashboard
- All Manager dashboard features, plus:
- **System Health:**
- Last sync time, status, row counts
- Error logs
- User activity summary
- **Cross-department views**
#### 3.5.4 KPIs to Track
| KPI | Calculation | Visualization |
|-----|-------------|---------------|
| Tasks Completed | Count by period | Line chart (trend) |
| Tasks Overdue | Count where due_date < today AND status not COMPLETED | Number + list |
| Upcoming Renewals | Policies expiring in next 30/60/90 days | Count + calendar view |
| Workload per Person | Active tasks assigned per user | Bar chart |
| On-Time Completion Rate | (Completed on/before due_date) / Total completed | Percentage |
| Avg Days to Complete | Mean(completed_at - created_at) | Number |
---
## 4. Data Architecture
### 4.1 Database Schema (PostgreSQL)
```sql
-- Entra user cache (synced from Entra or populated on first login)
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
entra_oid VARCHAR(36) UNIQUE NOT NULL, -- Entra Object ID
email VARCHAR(255) UNIQUE NOT NULL,
display_name VARCHAR(255),
department VARCHAR(100),
is_active BOOLEAN DEFAULT true,
last_login_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Role definitions
CREATE TABLE roles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(50) UNIQUE NOT NULL, -- Admin, Manager, Account Executive, Claims
description TEXT,
permissions JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMP DEFAULT NOW()
);
-- Entra Group to Role mapping
CREATE TABLE entra_group_role_mappings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
entra_group_id VARCHAR(36) NOT NULL, -- Entra Group Object ID
entra_group_name VARCHAR(255),
role_id UUID REFERENCES roles(id),
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(entra_group_id)
);
-- User role assignments (can override group-based roles)
CREATE TABLE user_roles (
user_id UUID REFERENCES users(id),
role_id UUID REFERENCES roles(id),
assigned_by UUID REFERENCES users(id),
assigned_at TIMESTAMP DEFAULT NOW(),
PRIMARY KEY (user_id, role_id)
);
-- Shape/Designation definitions
CREATE TABLE shapes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(100) NOT NULL,
description TEXT,
color VARCHAR(7), -- Hex color for UI
is_active BOOLEAN DEFAULT true,
display_order INTEGER,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Clients (synced from AMS360 + custom fields)
CREATE TABLE clients (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- AMS360 synced fields
ams_customer_id VARCHAR(50) UNIQUE NOT NULL,
name VARCHAR(255) NOT NULL,
address_line1 VARCHAR(255),
address_line2 VARCHAR(255),
city VARCHAR(100),
state VARCHAR(50),
zip_code VARCHAR(20),
phone VARCHAR(50),
email VARCHAR(255),
producer_code VARCHAR(50),
ams_created_at TIMESTAMP,
ams_modified_at TIMESTAMP,
-- Custom fields (local only)
shape_id UUID REFERENCES shapes(id),
shape2_id UUID REFERENCES shapes(id),
primary_personnel_id UUID REFERENCES users(id),
notes TEXT,
custom_fields JSONB DEFAULT '{}',
-- Metadata
last_synced_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Additional personnel assignments for clients
CREATE TABLE client_personnel (
client_id UUID REFERENCES clients(id) ON DELETE CASCADE,
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
assigned_at TIMESTAMP DEFAULT NOW(),
assigned_by UUID REFERENCES users(id),
PRIMARY KEY (client_id, user_id)
);
-- Policies (synced from AMS360)
CREATE TABLE policies (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- AMS360 synced fields
ams_policy_id VARCHAR(50) UNIQUE NOT NULL,
client_id UUID REFERENCES clients(id) ON DELETE CASCADE,
policy_number VARCHAR(100),
policy_type VARCHAR(100),
effective_date DATE,
expiration_date DATE NOT NULL, -- This is the RENEWAL DATE
carrier_name VARCHAR(255),
premium_amount DECIMAL(12, 2),
status VARCHAR(50),
ams_created_at TIMESTAMP,
ams_modified_at TIMESTAMP,
-- Metadata
last_synced_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Index for renewal date queries
CREATE INDEX idx_policies_expiration ON policies(expiration_date);
CREATE INDEX idx_policies_client ON policies(client_id);
-- Department enum
CREATE TYPE department_type AS ENUM (
'PERSONAL_LINES',
'COMMERCIAL_LINES',
'CLAIMS',
'BENEFITS',
'OTHER'
);
-- Task timing enum
CREATE TYPE task_timing AS ENUM ('PRE_RENEWAL', 'POST_RENEWAL');
-- Task status enum
CREATE TYPE task_status AS ENUM (
'NOT_STARTED',
'IN_PROGRESS',
'COMPLETED',
'BLOCKED',
'CANCELLED'
);
-- Task priority enum
CREATE TYPE task_priority AS ENUM ('LOW', 'MEDIUM', 'HIGH', 'URGENT');
-- Task templates (department-based)
CREATE TABLE task_templates (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
description TEXT,
department department_type NOT NULL,
timing task_timing NOT NULL,
days_offset INTEGER NOT NULL, -- Negative = before renewal, Positive = after
default_priority task_priority DEFAULT 'MEDIUM',
is_active BOOLEAN DEFAULT true,
display_order INTEGER,
created_by UUID REFERENCES users(id),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Tasks (actual task instances)
CREATE TABLE tasks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title VARCHAR(255) NOT NULL,
description TEXT,
department department_type NOT NULL,
timing task_timing NOT NULL,
days_offset INTEGER NOT NULL,
due_date DATE NOT NULL,
status task_status DEFAULT 'NOT_STARTED',
priority task_priority DEFAULT 'MEDIUM',
client_id UUID REFERENCES clients(id) ON DELETE CASCADE,
policy_id UUID REFERENCES policies(id) ON DELETE SET NULL,
template_id UUID REFERENCES task_templates(id), -- If generated from template
created_by UUID REFERENCES users(id),
completed_at TIMESTAMP,
completed_by UUID REFERENCES users(id),
cancelled_reason TEXT,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Task assignments (many-to-many)
CREATE TABLE task_assignments (
task_id UUID REFERENCES tasks(id) ON DELETE CASCADE,
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
assigned_at TIMESTAMP DEFAULT NOW(),
assigned_by UUID REFERENCES users(id),
PRIMARY KEY (task_id, user_id)
);
-- Indexes for task queries
CREATE INDEX idx_tasks_due_date ON tasks(due_date);
CREATE INDEX idx_tasks_status ON tasks(status);
CREATE INDEX idx_tasks_client ON tasks(client_id);
CREATE INDEX idx_tasks_department ON tasks(department);
-- Sync log
CREATE TABLE sync_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
sync_type VARCHAR(50) NOT NULL, -- 'clients', 'policies', 'full'
started_at TIMESTAMP NOT NULL,
completed_at TIMESTAMP,
status VARCHAR(50) NOT NULL, -- 'running', 'completed', 'failed'
rows_processed INTEGER DEFAULT 0,
rows_inserted INTEGER DEFAULT 0,
rows_updated INTEGER DEFAULT 0,
error_message TEXT,
triggered_by UUID REFERENCES users(id) -- NULL if scheduled
);
-- Audit log
CREATE TABLE audit_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id),
action VARCHAR(100) NOT NULL,
entity_type VARCHAR(50) NOT NULL,
entity_id UUID,
old_values JSONB,
new_values JSONB,
ip_address INET,
user_agent TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_audit_logs_user ON audit_logs(user_id);
CREATE INDEX idx_audit_logs_entity ON audit_logs(entity_type, entity_id);
CREATE INDEX idx_audit_logs_created ON audit_logs(created_at);
```
### 4.2 AMS360 Connection Requirements
- **Connection type:** SQL Server (typically)
- **Credentials:** Read-only service account recommended
- **Network:** May require VPN or firewall rules
- **Tables to query:** (Exact names depend on AMS360 version)
- Customer table
- Policy table
- (Reference AMS360 data dictionary for exact schema)
---
## 5. Technical Architecture
### 5.1 Recommended Stack
| Layer | Technology | Rationale |
|-------|------------|-----------|
| **Frontend** | React + TypeScript | Familiarity, strong ecosystem |
| **UI Framework** | Tailwind CSS + shadcn/ui | Modern, accessible components |
| **State Management** | TanStack Query | Server state caching, mutations |
| **Backend** | Node.js + Express or Next.js API Routes | JavaScript consistency |
| **ORM** | Prisma or Drizzle | Type-safe database access |
| **Database** | PostgreSQL | Robust, JSONB support |
| **Auth** | MSAL.js + NextAuth.js (Azure AD provider) | Native Entra integration |
| **Sync Engine** | Node.js service + node-mssql | AMS360 SQL connection |
| **Scheduler** | node-cron or external (systemd timer) | Daily sync trigger |
| **Hosting** | Docker on Linux server | Your standard deployment |
### 5.2 Authentication Flow
```
1. User navigates to app
2. App redirects to Entra ID login (MSAL.js)
3. User authenticates + MFA (per Entra CA policies)
4. Entra returns ID token + access token
5. Token includes group claims
6. App backend:
a. Validates token
b. Looks up entra_oid in users table (create if first login)
c. Resolves roles from group claims + user_roles table
d. Creates session
7. Frontend receives user context with permissions
```
### 5.3 Sync Engine Architecture
```
┌─────────────────┐ ┌──────────────────┐
│ AMS360 DB │ ──SQL── │ Sync Service │
│ (SQL Server) │ │ (Node.js) │
└─────────────────┘ └────────┬─────────┘
┌────────▼─────────┐
│ PostgreSQL │
│ (Local DB) │
└──────────────────┘
Sync Process:
1. Cron triggers sync at configured time
2. Sync service connects to AMS360 (read-only)
3. Queries records modified since last sync
4. Upserts into local Postgres (match on ams_*_id)
5. Logs sync results
6. Closes connections
```
---
## 6. Non-Functional Requirements
### 6.1 Security
- All traffic over HTTPS
- Entra ID MFA enforced via Conditional Access
- Database credentials in environment variables / secrets manager
- Read-only AMS360 connection
- RBAC enforced at API layer
- Audit logging for sensitive operations
- Session timeout configurable (default: 8 hours)
### 6.2 Performance
- Dashboard queries < 2 seconds
- Sync should complete within 1 hour for typical data volumes
- Pagination on all list endpoints (default 50, max 100)
- Database indexes on frequently queried fields
### 6.3 Availability
- Daily sync window during off-hours (e.g., 2 AM)
- Sync failures should not affect app availability
- Sync retry logic (3 attempts with backoff)
### 6.4 Data Integrity
- Foreign key constraints enforced
- Soft deletes where appropriate
- Sync never deletes local records (mark inactive if removed from AMS360)
---
## 7. MVP Scope vs. Future Phases
### Phase 1 - MVP
- [ ] Entra ID authentication with group-based roles
- [ ] AMS360 daily sync (Clients + Policies)
- [ ] Client list with custom fields (Shape, Shape2, Primary Personnel)
- [ ] Basic task management (CRUD, assignment, status)
- [ ] Personal dashboard (my tasks, overdue, upcoming)
- [ ] Admin: Shape management, sync trigger
### Phase 2
- [ ] Task templates per department
- [ ] Auto-generation of tasks from templates based on renewal dates
- [ ] Manager dashboard with team metrics
- [ ] Bulk operations (assign, update status)
- [ ] Email notifications for overdue tasks
### Phase 3
- [ ] Advanced reporting / export
- [ ] Calendar view for renewals
- [ ] Additional personnel assignments
- [ ] Custom fields beyond Shape/Shape2
- [ ] API for external integrations
---
## 8. Open Questions / Decisions Needed
1. **AMS360 access:** Who provides credentials? Any data restrictions?
2. **Departments:** Are the listed departments (Personal Lines, Commercial, Claims, Benefits) complete?
3. **Task auto-generation:** Should tasks auto-generate when policy enters renewal window, or manual trigger?
4. **Notifications:** Email? In-app only? Teams integration?
5. **Mobile:** Responsive web sufficient, or native app needed?
6. **Hosting:** On-prem server or cloud (Azure)?
---
## 9. Glossary
| Term | Definition |
|------|------------|
| **AMS360** | Agency Management System by Vertafore - source of client/policy data |
| **Shape/Shape2** | Custom client designations defined by the brokerage |
| **Renewal Date** | Policy expiration date - triggers workflow tasks |
| **Pre-Renewal Task** | Action to be completed before policy expires |
| **Post-Renewal Task** | Action to be completed after policy renews |
| **Primary Personnel** | Main user responsible for a client |
| **Entra ID** | Microsoft's identity platform (formerly Azure AD) |
---
*Document Version: 1.0*
*Created: January 2025*
*Last Updated: January 2025*

38
dev/process-task-list.mdc Normal file
View file

@ -0,0 +1,38 @@
---
description:
globs:
alwaysApply: false
---
# Task List Management
Guidelines for managing task lists in markdown files to track progress on completing a PRD
## Task Implementation
- **One sub-task at a time:** Do **NOT** start the next subtask until you ask the user for permission and they say “yes” or "y"
- **Completion protocol:**
1. When you finish a **subtask**, immediately mark it as completed by changing `[ ]` to `[x]`.
2. If **all** subtasks underneath a parent task are now `[x]`, also mark the **parent task** as completed.
- Stop after each subtask and wait for the users goahead.
## Task List Maintenance
1. **Update the task list as you work:**
- Mark tasks and subtasks as completed (`[x]`) per the protocol above.
- Add new tasks as they emerge.
2. **Maintain the “Relevant Files” section:**
- List every file created or modified.
- Give each file a oneline description of its purpose.
## AI Instructions
When working with task lists, the AI must:
1. Regularly update the task list file after finishing any significant work.
2. Follow the completion protocol:
- Mark each finished **subtask** `[x]`.
- Mark the **parent task** `[x]` once **all** its subtasks are `[x]`.
3. Add newly discovered tasks.
4. Keep “Relevant Files” accurate and up to date.
5. Before starting work, check which subtask is next.
6. After implementing a subtask, update the file and then pause for user approval.

17
dev/shapetasks.csv Normal file
View file

@ -0,0 +1,17 @@
Task,DaysAfterRenewal,DaysPriorToNextRenewal,AppliesTo,Active
SHAPE Onboarding Checklist (required after first renewal or when changing carriers),30,335,Shape,Yes
Claim Review,90,275,Shape,Yes
Review reserves and negotiate adjustments where applicable,120,245,Shape,Yes
Claim Review,180,185,Shape,Yes
Project experience modification factor; send to Account Executive,215,150,Shape,Yes
Request 120 day loss runs,245,120,Shape,Yes
Assist with captive claims worksheet (if applicable),245,120,Shape,Yes
Prepare loss summary/analysis for internal pre-renewal meeting,260,105,Shape,Yes
Request 90 day loss runs,275,90,Shape,Yes
Claim Review (can be included with client pre-renewal meeting if attending),275,90,Shape,Yes
SHAPE Onboarding Checklist (if requested or changing carriers),30,335,Shape2,Yes
Request 120 day loss runs,245,120,Shape2,Yes
Assist with captive claims worksheet (if applicable),245,120,Shape2,Yes
Prepare loss summary/analysis for internal pre-renewal meeting,260,105,Shape2,Yes
Claim Review in conjunction with 120 day loss summary.  Confirm if being marketed.,260,105,Shape2,Yes
Request 90 day loss runs (if being marketed),275,90,Shape2,Yes
1 Task DaysAfterRenewal DaysPriorToNextRenewal AppliesTo Active
2 SHAPE Onboarding Checklist (required after first renewal or when changing carriers) 30 335 Shape Yes
3 Claim Review 90 275 Shape Yes
4 Review reserves and negotiate adjustments where applicable 120 245 Shape Yes
5 Claim Review 180 185 Shape Yes
6 Project experience modification factor; send to Account Executive 215 150 Shape Yes
7 Request 120 day loss runs 245 120 Shape Yes
8 Assist with captive claims worksheet (if applicable) 245 120 Shape Yes
9 Prepare loss summary/analysis for internal pre-renewal meeting 260 105 Shape Yes
10 Request 90 day loss runs 275 90 Shape Yes
11 Claim Review (can be included with client pre-renewal meeting if attending) 275 90 Shape Yes
12 SHAPE Onboarding Checklist (if requested or changing carriers) 30 335 Shape2 Yes
13 Request 120 day loss runs 245 120 Shape2 Yes
14 Assist with captive claims worksheet (if applicable) 245 120 Shape2 Yes
15 Prepare loss summary/analysis for internal pre-renewal meeting 260 105 Shape2 Yes
16 Claim Review in conjunction with 120 day loss summary.  Confirm if being marketed. 260 105 Shape2 Yes
17 Request 90 day loss runs (if being marketed) 275 90 Shape2 Yes