Improving Frontend-Backend Workflow Alignment
This document provides recommendations for improving the alignment between frontend and backend workflow implementations in the PRS system.
Current Challenges
The PRS system currently faces several challenges related to frontend-backend workflow alignment:
- Inconsistent Status Representation:
- Frontend and backend use different status values
- Status mapping is scattered across multiple components
-
No centralized status constants
-
No Central Workflow Management:
- Status transitions are handled independently in frontend and backend
- No shared validation logic between frontend and backend
-
Workflow rules are duplicated across components
-
Optimistic Updates Without Validation:
- Frontend may update UI before backend confirms status change
- No rollback mechanism if backend rejects status change
-
Potential for inconsistent state
-
Incomplete Permission Checks:
- Frontend may show actions that backend would reject
- Permission checks are not consistently applied
-
No centralized permission management
-
Zustand Store and Database Synchronization:
- Zustand stores in frontend don't properly synchronize with backend database status fields
- Local state may become out of sync with server state
- No clear mechanism for handling concurrent updates
Recommendations Without Code Changes
The following recommendations can be implemented without immediate code changes:
1. Document Status Mapping
Create a comprehensive status mapping document that maps backend status values to frontend display values:
| Markdown |
|---|
| # Status Mapping
## Requisition Workflow
| Backend Status | Frontend Display | CSS Class |
|---------------|------------------|-----------|
| draft | Draft | draft |
| submitted | For Approval | for_approval |
| approved | Approved | approved |
| rejected | Rejected | rejected |
| ... | ... | ... |
|
2. Create Workflow Transition Matrix
Document all valid state transitions for each workflow:
| Markdown |
|---|
| # Workflow Transition Matrix
## Requisition Workflow
| Current State | Valid Next States | Required Permissions | Frontend Actions |
|---------------|-------------------|----------------------|------------------|
| draft | submitted | submit_requisition | Submit button |
| submitted | approved, rejected | approve_requisition | Approve/Reject buttons |
| ... | ... | ... | ... |
|
3. Document API Contract
Create a clear API contract document for all status transition endpoints:
| Markdown |
|---|
| # API Contract
## Requisition Workflow
### PUT /v1/requisitions/submit
- **Required State**: draft
- **Resulting State**: submitted
- **Required Permissions**: submit_requisition
- **Frontend Component**: SubmitRequisitionButton
- **React Query Invalidation**: ['requisition'], ['requisitions']
|
4. Create Testing Scenarios
Document comprehensive testing scenarios for workflow transitions:
| Markdown |
|---|
| # Testing Scenarios
## Requisition Workflow
1. **Submit Requisition**:
- Create a draft requisition
- Add items
- Submit the requisition
- Verify status changes to "submitted"
- Verify approvers are notified
|
Implementation Roadmap
Once you're ready to implement changes, consider this phased approach:
Phase 1: Standardize Status Representation
- Create Shared Status Constants:
- Define a single source of truth for status values
-
Ensure consistent naming between frontend and backend
-
Centralize Status Mapping:
- Create a central status mapping utility
- Update all UI components to use this utility
Phase 2: Improve State Synchronization
- Implement a Workflow State Service:
- Create a service to manage workflow state
-
Handle status transitions consistently
-
Enhance Error Handling:
- Add proper error handling for status transitions
- Implement rollback for failed transitions
Phase 3: Add Frontend Validation
- Implement Pre-submission Validation:
- Add validation before sending status updates
-
Disable actions that would be rejected by backend
-
Enhance Permission Checks:
- Implement consistent permission checks
- Align frontend and backend permissions
Specific Implementation Recommendations
1. Create a Status Constants Module
Create a shared module for status constants:
| JavaScript |
|---|
| // src/constants/statusConstants.js
export const REQUISITION_STATUS = Object.freeze({
DRAFT: 'draft',
SUBMITTED: 'submitted',
APPROVED: 'approved',
REJECTED: 'rejected',
// ...
});
export const CANVASS_STATUS = Object.freeze({
DRAFT: 'draft',
FOR_APPROVAL: 'for_approval',
APPROVED: 'approved',
REJECTED: 'rejected',
// ...
});
export const PO_STATUS = Object.freeze({
FOR_PO_REVIEW: 'for_po_review',
FOR_PO_APPROVAL: 'for_po_approval',
FOR_DELIVERY: 'for_delivery',
REJECT_PO: 'reject_po',
CANCELLED_PO: 'cancelled_po',
// ...
});
|
2. Create a Status Display Utility
Create a utility for consistent status display:
| JavaScript |
|---|
| // src/utils/statusUtils.js
import { REQUISITION_STATUS, CANVASS_STATUS, PO_STATUS } from '../constants/statusConstants';
const STATUS_DISPLAY_MAP = {
[REQUISITION_STATUS.DRAFT]: 'Draft',
[REQUISITION_STATUS.SUBMITTED]: 'For Approval',
[REQUISITION_STATUS.APPROVED]: 'Approved',
[REQUISITION_STATUS.REJECTED]: 'Rejected',
// ...
[CANVASS_STATUS.DRAFT]: 'CS Draft',
[CANVASS_STATUS.FOR_APPROVAL]: 'For CS Approval',
// ...
[PO_STATUS.FOR_PO_REVIEW]: 'For PO Review',
[PO_STATUS.FOR_PO_APPROVAL]: 'For PO Approval',
// ...
};
const STATUS_CLASS_MAP = {
[REQUISITION_STATUS.DRAFT]: 'draft',
[REQUISITION_STATUS.SUBMITTED]: 'for_approval',
[REQUISITION_STATUS.APPROVED]: 'approved',
[REQUISITION_STATUS.REJECTED]: 'rejected',
// ...
};
export const getStatusDisplay = (status) => STATUS_DISPLAY_MAP[status] || status;
export const getStatusClass = (status) => STATUS_CLASS_MAP[status] || 'default';
|
3. Create a Workflow Validation Utility
Create a utility for workflow validation:
| JavaScript |
|---|
| // src/utils/workflowUtils.js
import { REQUISITION_STATUS, CANVASS_STATUS, PO_STATUS } from '../constants/statusConstants';
const REQUISITION_TRANSITIONS = {
[REQUISITION_STATUS.DRAFT]: [REQUISITION_STATUS.SUBMITTED],
[REQUISITION_STATUS.SUBMITTED]: [REQUISITION_STATUS.APPROVED, REQUISITION_STATUS.REJECTED],
[REQUISITION_STATUS.APPROVED]: [REQUISITION_STATUS.ASSIGNING],
// ...
};
export const isValidTransition = (currentStatus, nextStatus, workflowType) => {
let transitionMap;
switch (workflowType) {
case 'requisition':
transitionMap = REQUISITION_TRANSITIONS;
break;
case 'canvass':
transitionMap = CANVASS_TRANSITIONS;
break;
case 'purchaseOrder':
transitionMap = PO_TRANSITIONS;
break;
default:
return false;
}
return transitionMap[currentStatus]?.includes(nextStatus) || false;
};
|
4. Enhance React Query Mutations
Enhance React Query mutations with proper error handling and invalidation:
| JavaScript |
|---|
| // src/hooks/useSubmitRequisition.js
import { useMutation, useQueryClient } from 'react-query';
import { submitRequisition } from '../api/requisitionApi';
import { REQUISITION_STATUS } from '../constants/statusConstants';
import { isValidTransition } from '../utils/workflowUtils';
export const useSubmitRequisition = () => {
const queryClient = useQueryClient();
return useMutation(
(requisition) => {
// Pre-validation
if (!isValidTransition(requisition.status, REQUISITION_STATUS.SUBMITTED, 'requisition')) {
throw new Error('Invalid status transition');
}
return submitRequisition(requisition);
},
{
onSuccess: (data) => {
// Invalidate relevant queries
queryClient.invalidateQueries(['requisition']);
queryClient.invalidateQueries(['requisitions']);
// Show success message
toast.success('Requisition submitted successfully');
},
onError: (error) => {
// Show error message
toast.error(`Failed to submit requisition: ${error.message}`);
}
}
);
};
|
Conclusion
By implementing these recommendations, you can improve the alignment between frontend and backend workflow implementations in the PRS system. This will lead to:
- More Consistent User Experience: Users will see consistent status information and available actions
- Fewer Errors: Validation will prevent invalid status transitions
- Better Maintainability: Centralized workflow management will make the code easier to maintain
- Improved Reliability: Proper error handling will make the system more robust
Remember that these changes should be implemented incrementally, with thorough testing at each step to ensure that existing functionality is not broken.