6.4 KiB
Analysis: Dealer Claim & Unified Request Architecture
This document analyzes the current architecture and proposes an efficient approach to unify Dealer Claims and Custom Requests while supporting specialized data capture and versioning.
Current State
Both Custom Requests and Dealer Claims are already "unified" at the base level:
- Primary Collection:
workflow_requestsstores the core data (id, requestNumber, initiator, status, currentLevel). - Secondary Collection:
dealer_claimsstores the business-specific metadata (proposal, expenses, invoices, etc.) and is linked viarequestId.
This architecture naturally supports showing both in the same list.
Proposed Efficient Approach
To make these two paths truly "inline" and handle specialized steps efficiently, we recommend a Metadata-Driven Activity System.
1. Unified Listing
The UI should continue to use the existing listWorkflows endpoints. The backend already returns templateType, which the frontend can use to decide which icon or detail view to render.
2. Specialized Step Identification (Dual-Tag System)
To handle dynamic level shifts and accurately recognize the purpose of each step, we use two categories of tags on each ApprovalLevel.
Category A: Action Tags (stepAction)
Defines what special behavior is required in this step.
DEALER_PROPOSAL: Show proposal submission form.EXPENSE_CAPTURE: Show expense document upload form.PROPOSAL_EVALUATION: Show evaluation tools for the initiator/manager.NONE: Standard approve/reject UI.
Category B: Persona Tags (stepPersona)
Defines who is acting in this step (role-based logic).
INITIATOR: Used when the initiator acts as an approver (e.g., evaluating a dealer proposal).DEPARTMENT_LEAD: Standard leadership approval.ADDITIONAL_APPROVER: Distinguishes steps added manually from the template.
How it works together:
| Level | Level Name | stepAction |
stepPersona |
UI Behavior |
|---|---|---|---|---|
| 1 | Dealer Proposal | DEALER_PROPOSAL |
DEALER |
Full Proposal Form |
| 2 | Initiator Review | PROPOSAL_EVALUATION |
INITIATOR |
Inline evaluation checklist |
| 3 | Lead Approval | NONE |
DEPARTMENT_LEAD |
Simple Approve/Reject |
| 3b | Extra Check | NONE |
ADDITIONAL_APPROVER |
Manual Approval UI |
- Dynamic Insertions: If
Extra Checkis added, the following levels shift, but theirstepActiontags remain, so the UI NEVER breaks. - Resubmission: Rejection logic targets the latest completed level with
stepAction: 'DEALER_PROPOSAL'.
3. Versioning & Iterations
The user's requirement to track previous proposals during resubmission is handled via the Snapshotted Revisions pattern:
- The Main Store:
DealerClaim.proposalandDealerClaim.completionalways hold the active/latest values. - The Revision Store:
DealerClaim.revisions[]acts as an append-only audit trail.
Resubmission Flow:
- Request is rejected at Level 2/3/5.
- Workflow moves back to Level 1 or 4 (Dealer).
- Dealer edits the data.
- On Submit:
- Backend takes the current
proposalorcompletiondata. - Pushes it into
revisionswith a timestamp andtriggeredBy: 'SYSTEM_VERSION_SNAPSHOT'. - Overwrites the main object with the new data.
- Advances the workflow.
- Backend takes the current
4. KPI & Deep Filtering Strategy (Hybrid Approach)
To support complex KPIs and high-performance filtering across thousands of requests, we use a Referential Flat Pattern:
- Workflow Index (Speed):
WorkflowRequestremains light. It handles high-frequency queries like "My Pending Tasks" or "Recent Activity". - Business Index (Depth):
DealerClaimholds the "Deep Data". We apply Mongoose/MongoDB indexes on fields like:dealer.region,dealer.state(for Geospatial/Regional KPIs).budgetTracking.utilizedBudget(for Financial KPIs).completion.expenses.category(for operational analysis).
The "Hybrid" Advantage:
- Performance: We don't bloat the main
workflow_requestscollection with hundreds of dealer-specific fields. This keeps "Total Request" counts and general listing extremely fast. - Scalability: For deep filters (e.g., "Show all claims in South Region with expenses > 50k"), we query the
dealer_claimscollection first to get therequestIds, then fetch the workflow status. This is much faster than a massive$lookupon a single bloated collection. - Clean KPIs: KPIs like "Budget vs Actual" are calculated directly from
DealerClaimwithout interfering with generic workflow TAT metrics.
5. Ad-Hoc & Additional Approver Handling
When a user manually adds an approver (Ad-hoc) to a Dealer Claim or Custom Flow:
- Tag Assignment: The new level is automatically tagged with
stepAction: 'NONE'andstepPersona: 'ADDITIONAL_APPROVER'. - UI Consistency: The frontend sees
stepAction: 'NONE'and renders the standard approval interface (comments + buttons). - Rejection Intelligence:
- If an Additional Approver rejects, the system looks back for the nearest anchor step (e.g.,
stepAction: 'DEALER_PROPOSAL'). - This prevents the workflow from getting "stuck" between two manually added levels if the business rule requires a return to the initiator or dealer.
- If an Additional Approver rejects, the system looks back for the nearest anchor step (e.g.,
6. Impact on Custom Flows & Compatibility
Zero Breaking Changes:
- Existing Custom Flows will default to
stepAction: 'NONE'. The UI behavior remains identical to the current state. - The
WorkflowRequestcollection structure is not being modified; we are only adding two optional metadata fields to theApprovalLevelsub-documents.
Future-Proofing:
- Custom Flows can now "unlock" specialized steps (like
PROPOSAL_EVALUATION) simply by updating their template metadata, without any backend code changes.
7. Implementation Strategy
| Feature | Custom Request Path | Dealer Claim Path |
|---|---|---|
| Listing | Unified listWorkflows |
Unified listWorkflows |
| Details View | Standard UI | Enhanced UI (tabs for Expenses/Proposal) |
| Logic | Generic approveRequest |
approveRequest + DealerClaimService hook |
| Versioning | Activity Logs only | Snapshotted Revisions for re-submissions |
Key Advantage
This approach avoids creating "two separate systems". It treats a Dealer Claim as a "Custom Request with a specific metadata payload". The UI remains cohesive, and the backend logic for TAT, notifications, and status transitions stays shared.