Re_Backend/docs/UNIFIED_REQUEST_ARCHITECTURE.md

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_requests stores the core data (id, requestNumber, initiator, status, currentLevel).
  • Secondary Collection: dealer_claims stores the business-specific metadata (proposal, expenses, invoices, etc.) and is linked via requestId.

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 Check is added, the following levels shift, but their stepAction tags 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.proposal and DealerClaim.completion always hold the active/latest values.
  • The Revision Store: DealerClaim.revisions[] acts as an append-only audit trail.

Resubmission Flow:

  1. Request is rejected at Level 2/3/5.
  2. Workflow moves back to Level 1 or 4 (Dealer).
  3. Dealer edits the data.
  4. On Submit:
    • Backend takes the current proposal or completion data.
    • Pushes it into revisions with a timestamp and triggeredBy: 'SYSTEM_VERSION_SNAPSHOT'.
    • Overwrites the main object with the new data.
    • Advances the workflow.

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): WorkflowRequest remains light. It handles high-frequency queries like "My Pending Tasks" or "Recent Activity".
  • Business Index (Depth): DealerClaim holds 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:

  1. Performance: We don't bloat the main workflow_requests collection with hundreds of dealer-specific fields. This keeps "Total Request" counts and general listing extremely fast.
  2. Scalability: For deep filters (e.g., "Show all claims in South Region with expenses > 50k"), we query the dealer_claims collection first to get the requestIds, then fetch the workflow status. This is much faster than a massive $lookup on a single bloated collection.
  3. Clean KPIs: KPIs like "Budget vs Actual" are calculated directly from DealerClaim without 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' and stepPersona: '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.

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 WorkflowRequest collection structure is not being modified; we are only adding two optional metadata fields to the ApprovalLevel sub-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.