At a Glance
Owner: Any workflow approver · Table: none — projection over workflow state · Workflow: read-only inbox · Upstream: purchase-request, purchase-order, purchase-order/credit-note · Aggregated personal inbox of documents awaiting the signed-in user's action.

My Approval (/procurement/approval) is the per-user inbox aggregating every workflow stage assigned to the signed-in user across approvable documents — primarily Purchase Requests, but also POs, Credit Notes, and any module the workflow engine gates. Where each module shows all its documents, My Approval shows only the slice the current user must act on right now. The page is read-and-act only — it owns no persisted entity and is a projection over workflow state held on each source document.
Used by any HOD / Procurement Manager / Finance Controller who appears in a stage's approver list · No write-back to a local table — every action calls the source document's API.
| Task | Where | Notes |
|---|---|---|
| See pending items | Procurement → My Approval | Sorted by last_action_at_date desc by default |
| Approve a PR / PO / CN | Row → Approve | Calls source-doc API; row drops off on success |
| Send back a PO (or PR) | Row → Send Back | Routes to workflow_previous_stage; required for "fix-and-resubmit" |
| Reject | Row → Reject | Terminates the source doc workflow |
| Bulk approve | Multi-select → Approve selected | Fans out one transaction per row |
| Inspect history | Expand row | Renders workflow_history JSON entries |
| Symptom / Message | Cause | Action |
|---|---|---|
| Row missing from inbox | Signed-in user not in user_action.execute[] on the doc's current stage |
Check stage configuration in system-config/workflow |
| "409 Conflict" on approve | A peer in the same execute[] already acted; engine has advanced the stage |
UI auto-refreshes — re-check the inbox |
| Action buttons disabled | Source document's posting period has closed | Reopen the period or void the document (finance) |
| Row appears but cannot act | deleted_at set on the source out-of-band |
Refresh — the row should drop off |
| Cross-tenant doc shown | (Cannot happen) | All queries scoped by active tenant context |
workflow_history lives on the source.409 Conflict because workflow_current_stage has advanced. UI re-queries and the row drops off.deleted_at IS NOT NULL on the source are excluded.user_action.execute[]. No additional role check at this layer — the engine resolved roles to user-ids when it wrote the array.There is no tb_my_approval table. The page is a query / view backed by the workflow-state columns embedded in every approvable document. It scans those documents and surfaces the subset whose active stage matches the signed-in user.
For every approvable document type (PR, PO, CN, store requisition, etc.), the same column shape is queried:
| Column on source table | Purpose in My Approval |
|---|---|
workflow_id |
Identifies which workflow definition gates this document. |
workflow_current_stage |
The stage matched against the user's role / membership. |
workflow_previous_stage, workflow_next_stage |
Used to render Send-Back targets and the "next approver" preview. |
workflow_history (JSON) |
[{stage, action, message, by:{id,name}, at}, …] — audit trail rendered on row expansion. |
user_action (JSON) |
{ execute: [{id}, …] } — the authoritative filter: row appears only if signed-in user's id is in this array. |
last_action, last_action_at_date, last_action_by_id, last_action_by_name |
Most recent transition — shown on the row. |
doc_status (per-module enum) |
Surface-level filter — only in_progress (or equivalent "awaiting action" status) is listed. |
Identical column shape on tb_purchase_request, tb_purchase_order, tb_credit_note, and other approvable tables. The page issues a parallel query per document type and unions the rows.
user_action.execute[] arrayPopulated by the workflow engine on each stage transition based on stage configuration in system-config/workflow:
execute[].A user sees a row iff their id is in execute[] for the doc's workflow_current_stage. Once any peer acts, the engine recomputes for the next stage and the row drops off.
The inbox has no own status — behaviour is entirely a projection:
execute[] with the signed-in user's id.Approve / reject / send-back invoke the same backend endpoints as each module's detail page — the inbox is purely a routing convenience. Bulk approve fans out one transaction per row. No fields on the inbox row itself are editable. The inbox owns no posting effect.
user_action.execute[].tb_purchase_request, tb_purchase_order, tb_credit_note, etc. — ../carmen-turborepo-backend-v2/packages/prisma-shared-schema-tenant/prisma/schema.prisma (workflow_* and user_action block replicated on each approvable model; CN example at lines 358-376).../carmen-inventory-frontend/app/(root)/procurement/approval/.../carmen/docs/business-analysis/my-approvals-ba.md; approver experience in ../carmen/docs/purchase-request-management/PR-User-Experience.md.