4.4 KiB
4.4 KiB
Cost Breakup Table Architecture
Overview
This document describes the enhanced architecture for storing cost breakups in the Dealer Claim Management system. Instead of storing cost breakups as JSONB arrays, we now use a dedicated relational table for better querying, reporting, and data integrity.
Architecture Decision
Previous Approach (JSONB)
- Storage: Cost breakups stored as JSONB array in
dealer_proposal_details.cost_breakup - Limitations:
- Difficult to query individual cost items
- Hard to update specific items
- Not ideal for reporting and analytics
- No referential integrity
New Approach (Separate Table)
- Storage: Dedicated
dealer_proposal_cost_itemstable - Benefits:
- Better querying and filtering capabilities
- Easier to update individual cost items
- Better for analytics and reporting
- Maintains referential integrity
- Supports proper ordering of items
Database Schema
Table: dealer_proposal_cost_items
CREATE TABLE dealer_proposal_cost_items (
cost_item_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
proposal_id UUID NOT NULL REFERENCES dealer_proposal_details(proposal_id) ON DELETE CASCADE,
request_id UUID NOT NULL REFERENCES workflow_requests(request_id) ON DELETE CASCADE,
item_description VARCHAR(500) NOT NULL,
amount DECIMAL(15, 2) NOT NULL,
item_order INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
Indexes:
idx_proposal_cost_items_proposal_idonproposal_ididx_proposal_cost_items_request_idonrequest_ididx_proposal_cost_items_proposal_orderon(proposal_id, item_order)
Backward Compatibility
The system maintains backward compatibility by:
- Dual Storage: Still saves cost breakups to JSONB field for backward compatibility
- Smart Retrieval: When fetching proposal details:
- First tries to get cost items from the new table
- Falls back to JSONB field if table is empty
- Migration: Automatically migrates existing JSONB data to the new table during migration
API Response Format
The API always returns cost breakups as an array, regardless of storage method:
{
"proposalDetails": {
"proposalId": "uuid",
"costBreakup": [
{
"description": "Item 1",
"amount": 10000
},
{
"description": "Item 2",
"amount": 20000
}
],
"costItems": [
{
"costItemId": "uuid",
"itemDescription": "Item 1",
"amount": 10000,
"itemOrder": 0
}
]
}
}
Implementation Details
Saving Cost Items
When a proposal is submitted:
- Save proposal details to
dealer_proposal_details(with JSONB for backward compatibility) - Delete existing cost items for the proposal (if updating)
- Insert new cost items into
dealer_proposal_cost_itemstable - Items are ordered by
itemOrderfield
Retrieving Cost Items
When fetching proposal details:
- Query
dealer_proposal_detailswithincludeforcostItems - If cost items exist in the table, use them
- If not, fall back to parsing JSONB
costBreakupfield - Always return as a normalized array format
Migration
The migration (20251210-create-proposal-cost-items-table.ts):
- Creates the new table
- Creates indexes for performance
- Migrates existing JSONB data to the new table automatically
- Handles errors gracefully (doesn't fail if migration of existing data fails)
Model Associations
DealerProposalDetails.hasMany(DealerProposalCostItem, {
as: 'costItems',
foreignKey: 'proposalId',
sourceKey: 'proposalId'
});
DealerProposalCostItem.belongsTo(DealerProposalDetails, {
as: 'proposal',
foreignKey: 'proposalId',
targetKey: 'proposalId'
});
Benefits for Frontend
- Consistent Format: Always receives cost breakups as an array
- No Changes Required: Frontend code doesn't need to change
- Better Performance: Can query specific cost items if needed
- Future Extensibility: Easy to add features like:
- Cost item categories
- Approval status per item
- Historical tracking of cost changes
Future Enhancements
Potential future improvements:
- Add
categoryfield to cost items - Add
approved_amountvsrequested_amountfor budget approval workflows - Add
notesfield for item-level comments - Add audit trail for cost item changes
- Add
is_approvedflag for individual item approval