Assignments Workflow
1. Executive Summary
Purpose
The assignments workflow provides the mechanism by which UTA staff are connected to the entities they are accountable for — whether those are long-lived organizational entities (departments, clients, buyers, deals, sales items, payment terms) or transient financial work items (cash receipts, cash receipt splits, outbound payments). There are two structurally different kinds of assignment: a responsibility establishes lasting single-owner accountability for a business entity and resolves upward through a four-level organizational hierarchy when no direct owner exists; a task tracks a specific piece of work that needs to be done against a transactional entity, progresses through a forward-only status lifecycle, and may have multiple concurrent holders. Together these two mechanisms ensure that every open receivable, unprocessed receipt, and pending payment can be traced to a responsible person, and that ad-hoc work is explicitly handed off rather than silently dropped.
Scope
Covered:
- Creating and transferring responsibility assignments for departments, clients, buyers, deals, meta-data pairs, sales items, and payment terms
- Creating, updating, and progressing task assignments for cash receipts, cash receipt splits, and payment items
- Viewing all assignments for a given person (By Person view)
- Viewing the responsibility chain and tasks for a specific entity (By Entity view)
- Identifying unassigned entities with open receivables or work needing attention (Unassigned view)
- Hierarchy resolution: automatically determining the accountable person by walking up from the most specific entity to the broadest when no direct assignment exists
- Full audit trail via
assignment_history
Not covered (documented separately):
- Cash receipt processing — see Cash Receipts Workflow
- Worksheet lifecycle — see Worksheets Workflow
- Settlement and payment processing — see Settlements Workflow and Payments Workflow
- Billing item and deal management — see Billing Items Workflow and Deals Workflow
Key Objectives
- Ensure every open billing item can be traced to a responsible UTA staff member, either through a direct assignment or through the hierarchy fallback chain.
- Provide a unified work queue so individuals can see all tasks and responsibilities assigned to them in one place.
- Surface unassigned entities to supervisors so ownership gaps are detected and corrected quickly.
- Maintain a tamper-resistant audit trail of every assignment creation, transfer, and status change.
2. Process Overview
flowchart TD
A[Open Assignments screen] --> B{Choose view}
B --> |By Person| C[Select person]
B --> |By Entity| D[Select entity type & entity]
B --> |Unassigned| E[Browse unassigned entities]
C --> F[View responsibilities + tasks]
F --> G{Action needed?}
G --> |Transfer responsibility| H[Open Transfer dialog]
G --> |Progress task status| I[Update task status]
G --> |Edit task| J[Edit title / assignee / due date]
G --> |View history| K[Open History dialog]
H --> L[Service: transferResponsibility]
I --> M[Service: updateTaskStatus]
J --> N[Service: updateTask]
D --> O[Load responsibility chain + tasks]
O --> P{Hierarchy gap?}
P --> |Yes, assign| Q[Open Assign Responsibility dialog]
P --> |Yes, transfer| R[Open Transfer dialog]
O --> S[View entity tasks]
S --> T[Progress or cancel tasks]
E --> U[Load unassigned summary counts]
U --> V[Select entity type]
V --> W[View unassigned list]
W --> X{Quick assign?}
X --> |Quick assign person selected| Y[One-click assign responsibility or task]
X --> |No| Z[Open Assign/Create Task dialog]
Y & Z --> AA[assignment created / refreshed]
subgraph New Assignment
AB[Open Assign Responsibility dialog] --> AC[Select person + entity type + entity]
AC --> AD[Service: createResponsibility]
AE[Open Create Task dialog] --> AF[Title + person + entity type + entity + due date]
AF --> AG[Service: createTask]
endWalkthrough
Enter the Assignments screen — The screen loads at
/assignmentswith three tabs: By Person, By Entity, and Unassigned. An "Assign" dropdown in the header allows creating a new Responsibility or Task from any tab.By Person view — The user selects a person from the dropdown. The system loads all active responsibilities and all tasks (filtered to
OPEN,WORKING,WAITINGby default) for that person in two separate tables. Summary counts show how many responsibilities, open tasks, working tasks, and waiting tasks the person holds. From this view the user can transfer a responsibility, progress a task status, edit a task, or view the audit history for any assignment.By Entity view — The user selects an entity type and then searches for a specific entity. The system loads the full responsibility chain for that entity (all hierarchy levels from L1 Department to L4 Sales Item / Payment Term, showing who is assigned at each level and who the effective responsible person is) together with a list of active tasks against that entity. The user can assign or transfer responsibility at any chain level and create or progress tasks.
Unassigned view — The system displays summary counts of unassigned entities across all nine entity types. The user selects an entity type (e.g.,
CLIENT,DEAL,CASH_RECEIPT) and optionally filters by department or coverage level. The table shows entities that have no active assignment and still need attention (open receivables for responsibility types; unprocessed receipts/splits or pending/failed payments for task types). The user can assign inline via a quick-assign person selector or open a dialog.Create Responsibility — User selects entity type and specific entity via autocomplete, selects the responsible person, and saves. The service validates that no active responsibility already exists for that entity before creating the record.
Transfer Responsibility — User opens the Transfer dialog for an existing responsibility, selects the new person, and optionally enters a reason. The service deactivates the old assignment and creates a new one, recording both a
DEACTIVATEDhistory entry on the old record and aREASSIGNEDentry on the new record.Create Task — User enters a title, selects the entity type and specific entity, selects an assignee, and optionally sets a due date. Tasks are always initialized to
OPEN. Multiple tasks can exist for the same entity simultaneously.Progress Task Status — Assignees use inline action buttons (Start, Complete, Pause, Resume) or the status dropdown to move a task through its lifecycle:
OPEN→WORKING→COMPLETE(orWAITING→WORKING→COMPLETE). Each transition records aSTATUS_CHANGEDhistory entry.Sibling cancellation — When a task is completed, the caller may invoke sibling cancellation to cancel all other active tasks for the same entity, preventing duplicate work.
3. Business Rules
3.1 Exactly One Active Responsibility Per Entity
Business rule: At any point in time, exactly one active responsibility may exist for a given entity. Attempting to directly create a second responsibility for an entity that already has one is rejected; the Transfer procedure must be used instead.
Foundation reference: One-active-responsibility-per-entity constraint — enforced at the application layer in createResponsibility Step 1 (check for existing active record).
Workflow context: The Assign Responsibility dialog returns an error when the service rejects a duplicate creation: "An active responsibility already exists for this entity. Use transfer instead." In the By Entity chain panel, a level that already has an owner shows only a "Transfer" button — there is no second "Assign" button at that level.
3.2 Responsibility Transfer Uses Deactivate-Then-Create Pattern
Business rule: Transferring a responsibility does not update the existing assignment row in place. Instead it deactivates the old record (assignment.is_active_ind set to false) and creates a new one, preserving the full chain of ownership in immutable history.
Foundation reference: Transfer Responsibility procedure
Workflow context: The Transfer dialog shows the current assignee's name alongside the entity context so the user confirms they are transferring the correct record. The new assignee selector explicitly excludes the current assignee to prevent self-transfer. The dialog description reads "The current assignment will be deactivated and a new one created."
3.3 Task Status Transitions Are Forward-Only
Business rule: A task can only move forward through its status lifecycle (OPEN → WORKING → COMPLETE; WORKING ↔ WAITING). Once a task reaches COMPLETE or CANCELLED, no further transitions are permitted.
Foundation reference: Task status transition rules — the allowed matrix is enforced in updateTaskStatus Step 1 before any write occurs.
Workflow context: The inline action buttons presented to the user always reflect the current status: only valid next actions are shown. A task in COMPLETE or CANCELLED status shows no action buttons. An attempt to call an invalid transition returns an error toast.
3.4 Multiple Tasks Are Allowed Per Entity
Business rule: Unlike responsibilities, multiple task assignments can be created for the same entity simultaneously. This supports scenarios where several users are independently working on the same receipt, split, or payment.
Foundation reference: Task multiplicity — no uniqueness check is performed during task creation.
Workflow context: The By Entity view shows all active tasks for an entity in a table so supervisors can see concurrent assignments. The Unassigned tab removes a task entity from the list only when the entity has at least one active non-terminal task assignment.
3.5 Hierarchy Resolution Walks From Most Specific to Broadest
Business rule: When the system needs to identify the responsible person for an entity, it checks for a direct assignment first, then walks up the four-level hierarchy until it finds a match. The resolution order is: Level 4 (Sales Item, Payment Term) → Level 3 (Meta-Data Pair, Deal) → Level 2 (Client, Buyer) → Level 1 (Department). The first match found is the effective responsible person.
Foundation reference: Hierarchy Resolution Walk-Up
Workflow context: The Responsibility Chain panel in the By Entity view shows every level in the hierarchy for the selected entity, highlights the effective level with a green indicator, and shows the resolved user name at the bottom. Unassigned entities in the Unassigned tab show a "Coverage" badge indicating the nearest ancestor level that has an assignment (e.g., "via Client", "via Dept", "Unowned").
3.6 Task-Level Entities Do Not Participate in the Hierarchy
Business rule: CASH_RECEIPT, CASH_RECEIPT_SPLIT, and PAYMENT entity types are used only for task assignments. They do not appear in the responsibility hierarchy chain. Responsibility hierarchy resolution applies only to the organizational levels (Department, Client, Buyer, Deal, Meta-Data Pair, Sales Item, Payment Term).
Foundation reference: entity_type_cd code master values
3.7 Sibling Cancellation Is Explicit, Not Automatic
Business rule: Completing a task does not automatically cancel sibling tasks. Sibling cancellation is a separate, explicitly invoked operation. The caller decides whether to trigger it after marking a task COMPLETE.
Foundation reference: Cancel Sibling Tasks procedure
NOTE
PoC Artifact: In the PoC, sibling cancellation is available as a server action (cancelSiblingTasks) but the UI does not explicitly prompt the user to cancel siblings after completing a task. The production system should expose a clear "Cancel sibling tasks?" confirmation after task completion.
3.8 Assignment History Is Immutable
Business rule: Every create, transfer, status change, and cancellation produces exactly one row in assignment_history. These records are never updated or deleted.
Foundation reference: assignment_history table definition
Workflow context: The History dialog (accessible from the task row overflow menu in the By Person view) shows all history entries in reverse chronological order, with action_cd, status transitions, user-to-user transfers, timestamps, and any comment text.
3.9 Unassigned Entities Filter to "Needs Attention" Only
Business rule: The Unassigned tab does not list every entity without an assignment — it lists only those that have open work needing attention. For responsibility types this means entities with at least one open billing item with a positive REV balance. For task types (cash receipts and splits) this means entities whose worksheet status is not fully approved or whose applied amount does not equal the receipt/split amount. For payment tasks this means payments in WAITING, PENDING, or FAILED status.
Foundation reference: Unassigned Entities by Type query — "needs work" determination per entity type.
4. Data Access & Operations References
4.1 Queries Used
| Operation | Foundation Doc | Purpose in This Workflow |
|---|---|---|
getAssignmentById | Get Assignment by ID | Load a specific assignment when opening the Transfer dialog from the By Entity chain panel. |
getAssignmentDisplayById | Get Assignment Display by ID | Enrich assignment records with assignee name and email for display. |
getAssignmentsForUser | Get Assignments for User | Load all responsibilities and tasks for the selected person in the By Person view. |
getAssignmentsForEntity | Get Assignments for Entity | Load all tasks for a selected entity in the By Entity view. |
findActiveResponsibility | Find Active Responsibility | Check for an existing active responsibility before creating a new one; used per-level in chain resolution. |
findSiblingTasks | Find Sibling Tasks | Identify other active tasks for the same entity when performing sibling cancellation. |
resolveResponsibleUser | Hierarchy Resolution Walk-Up | Determine the effective responsible person for an entity by walking up the hierarchy. |
buildResponsibilityChain | Responsibility Chain | Build the full per-level responsibility picture for the By Entity chain panel. |
getHistoryForAssignment | Get History for Assignment | Populate the History dialog with enriched audit trail entries. |
getUnassignedEntitiesByType | Unassigned Entities by Type | Populate the Unassigned tab data table for the selected entity type. |
getUnassignedSummary | Unassigned Summary | Load the summary chip counts on mount in the Unassigned tab. |
4.2 Procedures Used
| Operation | Foundation Doc | Trigger in This Workflow |
|---|---|---|
createResponsibility | Create Responsibility Assignment | User submits the Assign Responsibility dialog (from header dropdown, By Entity assign button, or Unassigned tab assign button). |
transferResponsibility | Transfer Responsibility Assignment | User submits the Transfer Responsibility dialog (from By Person "Transfer" button or By Entity chain "Transfer" button). |
createTask | Create Task Assignment | User submits the Create Task dialog (from header dropdown, By Entity "Create Task" button, Unassigned tab "Assign Task" button, or quick-assign). |
updateTaskStatus | Update Task Status | User clicks Start / Complete / Pause / Resume action buttons or selects a status from the status dropdown on a task row. |
updateTask | Update Task Fields | User submits the Edit Task dialog (from the overflow menu on a task row in the By Person view). |
cancelSiblingTasks | Cancel Sibling Tasks | Explicitly invoked after a task is completed via the cancelSiblingTasks server action. |
resolveResponsibilityChain | Responsibility Chain Resolution | Triggered when the user selects an entity in the By Entity tab to load the full hierarchy chain. |
5. Key User Actions
5.1 Assign Responsibility
Preconditions:
- No active responsibility exists for the target entity. (If one exists, the Transfer action must be used instead.)
- A valid entity type and specific entity must be selected.
- A person to assign must be selected.
Procedure reference: Create Responsibility Assignment
Steps:
- User opens the "Assign Responsibility" dialog from the "Assign" dropdown in the page header, from an "Assign" button in the By Entity chain panel, or from an "Assign" button in the Unassigned tab.
- User selects the assignee from the person dropdown.
- User selects the entity type (e.g.,
CLIENT (L2),DEAL (L3)). If the dialog was opened from a chain or unassigned row, entity type and entity are pre-filled and locked. - User searches for and selects the specific entity via the autocomplete field. For
META_DATA_PAIRentity types the user enters a meta type code and meta value manually. - User clicks "Assign Responsibility". The service checks for an existing active responsibility and rejects with an error if one is found; otherwise it inserts the new
assignmentrow and itsASSIGNEDhistory entry.
Postconditions:
- New
assignmentrow withassignment_type_cd='RESPONSIBILITY',is_active_ind=true,assigned_to_user_id= selected user. - New
assignment_historyrow withaction_cd='ASSIGNED',to_user_id= selected user. - Success toast; dialog closes; parent view refreshes.
UI trigger: "Assign Responsibility" item in the "Assign" dropdown. Visible always in the page header. "Assign" button in the Responsibility Chain panel: visible for hierarchy levels that have no current assignment. "Assign" button in the Unassigned tab responsibility rows: visible for all unassigned responsibility-type entities.
5.2 Transfer Responsibility
Preconditions:
- An active
RESPONSIBILITYassignment (assignment.is_active_ind=true) must exist for the entity. - The new assignee must differ from
assignment.assigned_to_user_id.
Procedure reference: Transfer Responsibility Assignment
Steps:
- User clicks the "Transfer" button on a responsibility row in the By Person view, or the "Transfer" button on a populated level in the By Entity chain panel.
- The Transfer Responsibility dialog opens showing the current entity context and the current assignee's name.
- User selects the new assignee (the current assignee is excluded from the dropdown).
- User optionally enters a transfer reason in the text area.
- User clicks "Transfer". The service deactivates the old assignment, records a
DEACTIVATEDhistory entry, creates the new assignment, and records aREASSIGNEDhistory entry.
Postconditions:
- Old
assignmentrow:is_active_ind=false. - New
assignment_historyrow on old assignment:action_cd='DEACTIVATED',from_user_id= previous owner. - New
assignmentrow:is_active_ind=true,assigned_to_user_id= new owner. - New
assignment_historyrow on new assignment:action_cd='REASSIGNED',from_user_id= previous owner,to_user_id= new owner. - Success toast; dialog closes; parent view refreshes.
UI trigger: "Transfer" button in the By Person responsibilities table. Visible for every active responsibility row. "Transfer" button inside each populated level row in the Responsibility Chain panel: visible when assignment is not null at that level.
5.3 Create Task
Preconditions:
- A task title must be provided (minimum 1 character).
- An assignee must be selected.
- An entity type and specific entity must be identified.
Procedure reference: Create Task Assignment
Steps:
- User opens the "Create Task" dialog from the "Assign" → "Create Task" dropdown, from the "Create Task" button in the By Entity tasks section, or from the "Assign Task" button in the Unassigned tab for task-type entities.
- User enters a task title. When pre-filled from the Unassigned tab, the title defaults to "Clear Cash Receipt", "Clear Cash Split", or "Process Payment" based on entity type.
- User selects the assignee.
- User selects the entity type and specific entity (pre-filled and locked when launched from context).
- User optionally sets a due date (
assignment.end_dt). - User clicks "Create Task". The service inserts the new
assignmentrow (task_status_cdinitialized to'OPEN') and itsASSIGNEDhistory entry.
Postconditions:
- New
assignmentrow withassignment_type_cd='TASK',task_status_cd='OPEN',is_active_ind=true,assigned_to_user_id= selected user. - New
assignment_historyrow withaction_cd='ASSIGNED',to_user_id= selected user. - Success toast; dialog closes; parent view refreshes.
UI trigger: "Create Task" item in the "Assign" dropdown (always visible). "Create Task" button in the By Entity tasks section (visible when an entity is selected). "Assign Task" button in Unassigned tab task-type rows. Quick-assign path: if a person is selected in "Quick Assign To", clicking "Assign Task" creates the task immediately without opening the dialog.
5.4 Update Task Status
Preconditions:
assignment.assignment_type_cd='TASK'.- Requested transition must be valid per the task status state machine.
- Task must not be in a terminal state (
COMPLETEorCANCELLED).
Procedure reference: Update Task Status
Steps:
- User clicks an inline action button (Start / Complete / Pause / Resume) or selects a status from the status dropdown on the task row.
- The service validates the transition against the allowed matrix, updates
assignment.task_status_cd, and inserts aSTATUS_CHANGEDhistory entry.
Postconditions:
assignment.task_status_cdupdated to the new status.- New
assignment_historyrow withaction_cd='STATUS_CHANGED',from_status_cd= previous status,to_status_cd= new status. - Success toast; task row reflects new status.
UI trigger: "Start Working" (play icon) — visible when task_status_cd = 'OPEN'. "Complete" (check icon) and "Pause" (pause icon) — visible when task_status_cd = 'WORKING'. "Resume" (play icon) — visible when task_status_cd = 'WAITING'. Status dropdown — clickable on any non-terminal status badge. "Cancel Task" in overflow menu — visible for OPEN, WORKING, or WAITING statuses.
5.5 Edit Task
Preconditions:
assignment.assignment_type_cd='TASK'.- A non-empty task title and an assignee must be provided.
Procedure reference: Update Task Fields
Steps:
- User selects "Edit Task" from the overflow menu on a task row in the By Person view.
- The Edit Task dialog opens pre-populated with current
assignment.task_title,assignment.assigned_to_user_id, andassignment.end_dt. Entity type and entity are displayed read-only and cannot be changed. - User modifies the title, assignee, and/or due date.
- User clicks "Save Changes". The service updates the editable fields. If the assignee changed, a
REASSIGNEDhistory entry is recorded.
Postconditions:
assignmentrow updated with newtask_title,assigned_to_user_id, and/orend_dt.- If assignee changed: new
assignment_historyrow withaction_cd='REASSIGNED',from_user_id= old assignee,to_user_id= new assignee. - If only title or due date changed: no history entry is created.
UI trigger: "Edit Task" item in the overflow (three-dot) menu on task rows in the By Person view. Visible for all task assignments.
NOTE
PoC Artifact: Title and due date changes do not produce a history entry in the PoC. The production system should audit all field changes for compliance.
5.6 View Assignment History
Preconditions:
- An
assignmentrecord must exist.
Procedure reference: Get History for Assignment
Steps:
- User selects "View History" from the overflow menu on a task row in the By Person view.
- The History dialog loads all
assignment_historyrows for the selected assignment in reverse chronological order, enriched withfrom_user_name,to_user_name, andaction_by_user_name. - Each entry shows
action_cd, status transitions, user-to-user moves, the acting user's name, the timestamp (action_dt), and anycomment_text.
Postconditions:
- No data is mutated. Read-only display.
UI trigger: "View History" item in the overflow menu on task rows in the By Person view. Visible for all task assignments.
5.7 Quick Assign (Unassigned Tab)
Preconditions:
- A person must be selected in the "Quick Assign To" selector in the Unassigned tab.
- The target entity must appear in the unassigned list for the selected entity type.
Procedure reference: For responsibility types: Create Responsibility Assignment. For task types: Create Task Assignment.
Steps:
- User selects a person in the "Quick Assign To" dropdown. The assign buttons in the table change visual style to indicate quick-assign mode is active.
- User clicks "Assign" (responsibility types) or "Assign Task" (task types) on a row.
- The system creates the assignment immediately without opening a dialog. For task types, a default title is used ("Clear Cash Receipt", "Clear Cash Split", or "Process Payment").
- The row disappears from the unassigned list; summary chip counts update.
Postconditions:
- Same postconditions as "Assign Responsibility" (5.1) or "Create Task" (5.3) depending on entity type.
- Success toast with entity display name.
UI trigger: "Assign" / "Assign Task" buttons in the Unassigned table rows. When no Quick Assign person is selected, the same buttons open the full dialog instead.
6. Permissions & Role-Based Access
NOTE
PoC Artifact: The PoC does not implement role-based access control on the Assignments screens. All authenticated users can perform all actions. The table below describes the intended production access model based on the role definitions and the nature of each action.
| Action | CASH_MANAGER | CASH_PROCESSOR | SETTLEMENT_APPROVER | IT |
|---|---|---|---|---|
| View assignments (By Person, By Entity, Unassigned) | Yes | Yes | Yes | Yes |
| Assign responsibility (any entity type) | — | — | — | Yes |
| Transfer responsibility | — | — | — | Yes |
| Create task (any entity type) | Yes | Yes | Yes | Yes |
| Update task status | Yes | Yes | Yes | Yes |
| Edit task (title, assignee, due date) | Yes | Yes | Yes | Yes |
| View assignment history | Yes | Yes | Yes | Yes |
| Quick assign (Unassigned tab) | Yes | Yes | Yes | Yes |
| Cancel sibling tasks | Yes | Yes | Yes | Yes |
Field-level restrictions:
- The entity type and specific entity on a task assignment cannot be changed after creation; only
task_title,assigned_to_user_id, andend_dtare editable. - Responsibility assignment and transfer are restricted to IT/Admin in the intended production model, reflecting that changing long-lived ownership of clients, deals, and departments is an administrative act rather than a daily operational one.
7. Integration Points
7.1 Upstream
| Source | Data Provided | Mechanism |
|---|---|---|
| Cash Receipts workflow | cash_receipt.cash_receipt_id and cash_receipt_split.cash_receipt_split_id used as entity keys for task assignments | Polymorphic FK via assignment.entity_id when entity_type_cd = 'CASH_RECEIPT' or 'CASH_RECEIPT_SPLIT' |
| Worksheets workflow | cash_receipt_worksheet.worksheet_status_cd used in the "needs work" determination for unassigned receipts and splits | LEFT JOIN in unassigned gap-detection query |
| Settlements / Payments workflow | payment_item.payment_item_id used as entity key for payment task assignments; payment_item.payment_execution_status_cd used to filter actionable payments | Polymorphic FK via assignment.entity_id when entity_type_cd = 'PAYMENT' |
| Deals and Bookings | deal.deal_reference, revenue_items.sales_item_ref, billing_item.payment_term_ref used as string-based entity keys for Level 3 and Level 4 responsibility assignments | assignment.entity_reference |
| Parties | party.party_id used as entity key for CLIENT and BUYER responsibility assignments | assignment.entity_id |
| Departments | department.department_id used as entity key for DEPARTMENT responsibility assignments | assignment.entity_id |
| Billing Items | billing_item and billing_item_detail used in REV balance calculation for unassigned gap detection | JOIN in open_rev_details CTE across billing_item, billing_item_detail, cash_receipt_application, cash_receipt_application_deduction |
7.2 Downstream
| Consumer | Data Consumed | Mechanism |
|---|---|---|
| Cash Receipts workflow | Active assignment records for CASH_RECEIPT and CASH_RECEIPT_SPLIT entity types — used to identify who is responsible for processing a receipt or split | FK lookup via assignment.entity_id |
| Payments workflow | Active assignment records for PAYMENT entity type — used to identify who is following up on pending or failed payments | FK lookup via assignment.entity_id |
| System-wide hierarchy resolution | Active RESPONSIBILITY assignments at all four hierarchy levels — consulted whenever any downstream service needs to route work or notifications to the correct staff member | resolveResponsibleUser service call |
7.3 External Integrations
No external integrations for this workflow. Assignment data is entirely internal to the Client Processing system.
8. Functional Screen Requirements
8.1 Assignments Main Screen
Route: /assignments
Data loading:
- No initial server-side data fetch on page load. All data is loaded client-side upon tab selection or person/entity selection.
Header Region
The page header shows the page title and an "Assign" dropdown for creating new assignments.
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Page title "Assignments" | Static | No | Always visible |
| "Assign" dropdown button | Static | No | Always visible |
| "Assign Responsibility" menu item | Static | No | Always visible in dropdown |
| "Create Task" menu item | Static | No | Always visible in dropdown |
Tab Region
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| "By Person" tab | Static | No | Always visible |
| "By Entity" tab | Static | No | Always visible |
| "Unassigned" tab | Static | No | Always visible |
Conditional display:
- Active tab content is rendered below the tab list. All three tabs are always visible; content loads only for the active tab.
8.2 By Person Tab
Route: /assignments (active tab: By Person)
Data loading:
getAssignmentsForUser— Get Assignments for User — called twice in parallel when a person is selected: once withassignmentTypeCd = 'RESPONSIBILITY'andisActiveInd = true; once withassignmentTypeCd = 'TASK'.
Person Selector Region
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Person dropdown | All active users from users table | Yes | Always visible |
| "N Resp" summary chip | Computed: responsibilities.length | No | Visible once a person is selected |
| "N Open" summary chip | Computed: tasks where task_status_cd = 'OPEN' | No | Visible once a person is selected |
| "N Working" summary chip | Computed: tasks where task_status_cd = 'WORKING' | No | Visible once a person is selected |
| "N Waiting" summary chip | Computed: tasks where task_status_cd = 'WAITING' | No | Visible only when waitingCount > 0 |
Responsibilities Table
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Level | assignment.entity_type_cd (rendered as a badge) | No | Always in table |
| Entity | assignment.entity_reference or #assignment.entity_id | No | Always in table |
| Since | assignment.created_dt | No | Always in table |
| Transfer button | — | No (action) | Always in table |
Grid features:
- Sortable columns: none (PoC)
- Filters: none
- Row selection: none
- Pagination: no (max 300px height with scroll)
Conditional display:
- Responsibilities table is visible when a person is selected and
responsibilities.length > 0. - "No responsibilities assigned" placeholder shown when the responsibilities list is empty.
- "+ Assign" button visible at the top right of the section when a person is selected.
Tasks Table
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Status | assignment.task_status_cd (clickable dropdown) | Yes | Always in table |
| Task | assignment.task_title | No | Always in table |
| Entity | assignment.entity_type_cd badge + entity key (with hyperlink for certain types) | No | Always in table |
| Due | assignment.end_dt | No | Always in table; shown in red with warning indicator when overdue |
| Age | Computed: days since assignment.created_dt | No | Always in table |
| Action buttons | — | No (actions) | Context-dependent by task_status_cd |
| Overflow menu | — | No (actions) | Always in table |
Grid features:
- Sortable columns: none (PoC)
- Filters: status multi-select; defaults to
['OPEN', 'WORKING', 'WAITING'] - Row selection: none
- Pagination: yes when
filteredTasks.length > 20
Conditional display:
- "Start Working" (play icon) button visible when
assignment.task_status_cd='OPEN'. - "Complete" (check icon) and "Pause" (pause icon) buttons visible when
assignment.task_status_cd='WORKING'. - "Resume" (play icon) button visible when
assignment.task_status_cd='WAITING'. - "Cancel Task" menu item in overflow visible when
task_status_cdIN ('OPEN','WORKING','WAITING'). - "Edit Task" and "View History" always present in overflow menu.
- Entity link:
CLIENTlinks to/clients/{entityId};SALES_ITEMandPAYMENT_TERMlink to/revenue?salesItemRef=...;CASH_RECEIPT_SPLITresolves a worksheet link asynchronously. - "+ Task" button visible at the top right of the tasks section when a person is selected.
8.3 By Entity Tab
Route: /assignments (active tab: By Entity)
Data loading:
getResponsibilityChain— Responsibility Chain Resolution — triggered when an entity is selected.getAssignmentsForEntity— Get Assignments for Entity — triggered in parallel with chain load.
Entity Selector Region
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Entity type dropdown | Static list of all 10 entity types | Yes | Always visible |
| Entity autocomplete / search field | Searches the appropriate table per entity type | Yes | Visible once an entity type is selected |
Responsibility Chain Panel
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Level badge | assignment.entity_type_cd | No | One row per resolved hierarchy level |
| Entity label | Resolved from parent entity tables (department.department_name, party.display_name, deal.deal_name, etc.) | No | One row per resolved hierarchy level |
| Assignee name | assignment.assigned_to_user_name (joined from users) | No | Visible when assignment is not null at this level |
| "(none)" indicator | Static | No | Visible when no active responsibility at this level |
| "Transfer" button | — | No (action) | Visible when assignment is not null at this level |
| "Assign" button | — | No (action) | Visible when assignment is null at this level |
| Effective responsible person summary | Computed: most specific level with an active assignment | No | Always visible at the bottom of the chain panel |
Conditional display:
- Chain panel visible when an entity is selected and chain data is loaded.
- The level row holding the effective assignment is highlighted distinctly (green left border).
- "No responsible person found" message shown when all levels are unassigned.
- "No hierarchy data available for this entity type" shown for task-level entity types.
Tasks Section (By Entity)
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Status | assignment.task_status_cd (badge only) | No | Always in table |
| Task | assignment.task_title | No | Always in table |
| Assignee | assignment.assigned_to_user_name | No | Always in table |
| Due | assignment.end_dt | No | Always in table |
| Action buttons | — | No (actions) | Context-dependent by task_status_cd |
Grid features:
- Sortable columns: none (PoC)
- Filters: only active tasks shown (
task_status_cdNOT IN'COMPLETE','CANCELLED') - Row selection: none
- Pagination: yes when
activeTasks.length > 20
Conditional display:
- Tasks section visible when an entity is selected.
- "No active tasks for this entity" placeholder when the list is empty.
- "Create Task" button always visible at top right of tasks section when an entity is selected.
- Action buttons follow the same rules as the By Person tasks table.
8.4 Unassigned Tab
Route: /assignments (active tab: Unassigned)
Data loading:
getUnassignedSummary— Unassigned Summary — loaded on tab mount.getUnassignedEntitiesByType— Unassigned Entities by Type — loaded when entity type, department filter, or coverage level changes.
Summary Chips Region
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Responsibility type chips (Department, Client, Buyer, Deal, Sales Item, Payment Term) | getUnassignedSummary count per entity_type_cd | No (clickable filter) | Always visible after summary loads |
| Task type chips (Cash Receipt, Cash Split, Payment) | getUnassignedSummary count per entity_type_cd | No (clickable filter) | Always visible after summary loads |
Clicking a chip sets the active entity type and reloads the data table.
Filters Region
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Entity Type dropdown | Static list of all entity types | Yes | Always visible |
| Filter by Department autocomplete | department table search | Yes | Visible for CLIENT, BUYER, DEAL, SALES_ITEM, PAYMENT_TERM entity types |
| Quick Assign To person selector | All active users | Yes | Always visible |
| Coverage filter chips | Static per entity type | Yes | Visible when coverage options exist for the selected entity type |
Unassigned Entities Table — Responsibility Types
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Entity | Entity display name from the appropriate source table; assignment.entity_reference shown as sub-label | No | Always in table |
| Department | department.department_name resolved via billing_item | No | Visible for non-DEPARTMENT entity types |
| Coverage | Computed: nearest_assignment_level, nearest_assignment_entity_type_cd, nearest_assigned_user_name | No | Visible for non-DEPARTMENT entity types |
| Open Items | Computed: COUNT(DISTINCT billing_item_id) with positive REV balance | No | Always in table |
| Open Amount | Computed: SUM(rev_balance) across open billing item details | No | Always in table |
| Assign button | — | No (action) | Always in table |
Unassigned Entities Table — Task Types (Cash Receipts, Splits)
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Receipt / Split | cash_receipt.cash_receipt_ref or Split #{cash_receipt_split_id} | No | Always in table |
| Deposit Date | cash_receipt.deposit_dt | No | Always in table |
| Amount | cash_receipt.net_receipt_amt or cash_receipt_split.split_amt | No | Always in table |
| Applied | Computed: sum of cash_receipt_application.cash_receipt_amt_applied on active worksheets | No | Always in table |
| Balance | Computed: Amount − Applied | No | Always in table; highlighted amber when > $0.005 |
| Worksheet | cash_receipt_worksheet.worksheet_status_cd (worst status across splits) | No | Always in table |
| Coverage | Computed: nearest responsible ancestor via reference-based coverage | No | Always in table |
| Assign Task button | — | No (action) | Always in table |
Unassigned Entities Table — Task Types (Payments)
| Field / Column | Source | Editable? | Condition |
|---|---|---|---|
| Payment | payment_item.payment_item_id | No | Always in table |
| Pay Date | payment_item scheduled or creation date | No | Always in table |
| Amount | payment_item.payment_amt | No | Always in table |
| Status | payment_item.payment_execution_status_cd | No | Always in table |
| Origin | Derived from payment_item.payment_item_type_cd (Settlement, Ledger, Refund, Other) | No (clickable — opens payment detail drawer) | Always in table |
| Payment Party | party.display_name for payment_item.party_id | No | Always in table |
| Client | Client party display name | No | Always in table |
| Deal | deal.deal_name | No | Always in table |
| Coverage | Computed: nearest responsible ancestor | No | Always in table |
| Department | department.department_name | No | Always in table |
| Assign Task button | — | No (action) | Always in table |
Grid features (all Unassigned tables):
- Sortable columns: none (PoC; server sorts by
open_receivable_amountdescending for responsibility types; by entity date descending for task types) - Filters: entity type selector, optional department filter, optional coverage level chips
- Row selection: none
- Pagination: enabled when
results.length > 20
Conditional display:
- "No unassigned [entity type]s needing attention" placeholder when no results match the selected type and filters.
- When coverage filter is active and no results match, placeholder appends "matching this coverage filter".
- When Quick Assign person is selected, "Assign" / "Assign Task" buttons change to filled style to indicate active quick-assign mode.
- Clicking the Origin cell on a payment row opens a Payment Execution Drawer showing full payment detail.
9. Additional Diagrams
Task Status State Machine
stateDiagram-v2
[*] --> OPEN : Task created (task_status_cd = 'OPEN')
OPEN --> WORKING : Begin work
OPEN --> CANCELLED : Cancel before starting
WORKING --> WAITING : Blocked on dependency
WORKING --> COMPLETE : Finish
WORKING --> CANCELLED : Abandon
WAITING --> WORKING : Unblocked / Resume
WAITING --> CANCELLED : Abandon
COMPLETE --> [*] : Terminal
CANCELLED --> [*] : TerminalResponsibility Lifecycle
stateDiagram-v2
[*] --> Active : createResponsibility\nassignment.is_active_ind = true
Active --> Inactive : transferResponsibility\nis_active_ind set to false\nnew assignment created with is_active_ind = true
Inactive --> [*] : Preserved for auditHierarchy Resolution Sequence
sequenceDiagram
participant UI as User / System
participant Svc as AssignmentService
participant DB as Database
UI->>Svc: resolveResponsibleUser(salesItemRef, dealRef, clientId, deptId)
Svc->>DB: findActiveResponsibility(SALES_ITEM, salesItemRef)
DB-->>Svc: null (no match)
Svc->>DB: findActiveResponsibility(DEAL, dealRef)
DB-->>Svc: null (no match)
Svc->>DB: findActiveResponsibility(CLIENT, clientId)
DB-->>Svc: assignment row (match found)
Svc-->>UI: resolved_from_entity_type_cd = 'CLIENT', resolved_from_level = 2, assigned_to_user_id = 7
Note over Svc: Short-circuits -- DEPARTMENT level not queried10. Cross-References
| Document | Relationship |
|---|---|
| Assignments Data Model | Defines the assignment and assignment_history tables, all code master values (assignment_type_cd, entity_type_cd, task_status_cd, action_cd), status lifecycles, and validation constraints used throughout this workflow. |
| Assignments Queries | Specifies all data retrieval operations: CRUD lookups, hierarchy resolution queries, gap-detection queries with REV balance and coverage level calculations, and the unassigned summary query. |
| Assignments Procedures | Specifies all data mutation operations: create/transfer responsibility, create/update/cancel tasks, hierarchy resolution walk-up, and responsibility chain resolution. |
| Cash Receipts Workflow | Task assignments for CASH_RECEIPT and CASH_RECEIPT_SPLIT entity types are created when receipts or splits need processing work. The Unassigned tab surfaces these entities using worksheet status and applied-amount data from the Cash Receipts domain. |
| Worksheets Workflow | Worksheet status (D, P, T, A, R) and current_item_ind drive the "needs work" determination for unassigned cash receipt and split entities in the Unassigned tab. |
| Settlements Workflow | Task assignments for PAYMENT entity type are created when payment items need follow-up. payment_item.payment_execution_status_cd determines which payment entities surface in the Unassigned tab. |
| Billing Items Workflow | The REV balance calculation in gap-detection queries derives from billing_item and billing_item_detail; open billing items determine which responsibility-type entities appear in the Unassigned tab. |
| Deals Workflow | Deal, sales item, and payment term identifiers form the Level 3 and Level 4 entity keys for responsibility assignments. The four-level responsibility hierarchy reflects the deal structure. |
11. Gherkin Scenarios
Feature: Assignments - Responsibility Management
Scenario: Assign responsibility to a department for the first time
Given no active assignment exists where assignment.entity_type_cd = 'DEPARTMENT'
AND assignment.entity_id = 42 AND assignment.is_active_ind = true
And user "Sarah Chen" has user_id = 7 in the users table
When a supervisor opens the Assign Responsibility dialog and selects
entity type "Department (L1)", department "Music Department" (department_id = 42),
and assignee "Sarah Chen"
And the supervisor clicks "Assign Responsibility"
Then a new assignment row is created with assignment_type_cd = 'RESPONSIBILITY',
entity_type_cd = 'DEPARTMENT', entity_id = 42, assigned_to_user_id = 7,
is_active_ind = true
And a new assignment_history row is created with action_cd = 'ASSIGNED', to_user_id = 7
And "Music Department" no longer appears in the Unassigned tab for DEPARTMENT
Scenario: Transfer responsibility when accountable person changes
Given an active assignment exists where assignment.assignment_id = 'abc-123',
entity_type_cd = 'CLIENT', entity_id = 501, assigned_to_user_id = 7,
is_active_ind = true
And user "James Park" has user_id = 12 in the users table
When a supervisor opens the Transfer dialog for assignment 'abc-123',
selects new assignee "James Park", and enters reason "Sarah on leave"
And the supervisor clicks "Transfer"
Then assignment 'abc-123' is updated to is_active_ind = false
And a new assignment_history row is inserted for 'abc-123' with
action_cd = 'DEACTIVATED', from_user_id = 7, comment_text = 'Sarah on leave'
And a new assignment row is created with entity_type_cd = 'CLIENT',
entity_id = 501, assigned_to_user_id = 12, is_active_ind = true
And a new assignment_history row is inserted for the new assignment with
action_cd = 'REASSIGNED', from_user_id = 7, to_user_id = 12
Scenario: Reject duplicate responsibility creation
Given an active assignment exists where entity_type_cd = 'DEAL',
entity_reference = 'DEAL-2024-001', is_active_ind = true, assigned_to_user_id = 7
When a user attempts to create a new responsibility for
entity_type_cd = 'DEAL' and entity_reference = 'DEAL-2024-001'
Then the service rejects the operation with error
"An active responsibility already exists for this entity. Use transfer instead."
And no new assignment row is created
Scenario: Self-transfer rejected
Given an active assignment exists where assignment.assignment_id = 'abc-123',
assigned_to_user_id = 7, is_active_ind = true
When user 7 attempts to transfer assignment 'abc-123' to new_user_id = 7
Then the service rejects the operation
And assignment 'abc-123' remains unchanged with is_active_ind = true,
assigned_to_user_id = 7
Feature: Assignments - Task Management
Scenario: Create and progress a cash receipt task through to completion
Given cash_receipt with cash_receipt_id = 1001 has posting_status_cd = 'U'
and no active task assignment exists for entity_type_cd = 'CASH_RECEIPT',
entity_id = 1001
And user "Alex Rivera" has user_id = 5
When a cash manager opens the Create Task dialog for receipt 1001 from the
Unassigned tab, selects assignee "Alex Rivera", and submits with
task_title = 'Clear Cash Receipt' and end_dt = '2026-03-05'
Then a new assignment row is created with assignment_type_cd = 'TASK',
entity_type_cd = 'CASH_RECEIPT', entity_id = 1001, assigned_to_user_id = 5,
task_status_cd = 'OPEN', end_dt = '2026-03-05'
And receipt 1001 no longer appears in the Unassigned tab for CASH_RECEIPT
When "Alex Rivera" clicks the "Start Working" button on the task
Then assignment.task_status_cd is updated to 'WORKING'
And a new assignment_history row is inserted with action_cd = 'STATUS_CHANGED',
from_status_cd = 'OPEN', to_status_cd = 'WORKING'
When "Alex Rivera" clicks the "Complete" button on the task
Then assignment.task_status_cd is updated to 'COMPLETE'
And a new assignment_history row is inserted with action_cd = 'STATUS_CHANGED',
from_status_cd = 'WORKING', to_status_cd = 'COMPLETE'
Scenario: Task paused while waiting for external information
Given a task assignment with assignment_id = 'task-789', task_status_cd = 'WORKING',
entity_type_cd = 'CASH_RECEIPT_SPLIT', entity_id = 55
When the assignee clicks "Pause" on the task
Then assignment.task_status_cd is updated to 'WAITING'
And a new assignment_history row is inserted with action_cd = 'STATUS_CHANGED',
from_status_cd = 'WORKING', to_status_cd = 'WAITING'
When the external dependency resolves and the assignee clicks "Resume"
Then assignment.task_status_cd is updated to 'WORKING'
And a new assignment_history row is inserted with action_cd = 'STATUS_CHANGED',
from_status_cd = 'WAITING', to_status_cd = 'WORKING'
Scenario: Invalid task status transition rejected
Given a task assignment with assignment_id = 'task-456', task_status_cd = 'COMPLETE'
When a user attempts to transition the task to status 'OPEN'
Then the service rejects the operation
And assignment.task_status_cd remains 'COMPLETE'
And no assignment_history row is inserted
Scenario: Multiple concurrent tasks on same entity with sibling cancellation
Given cash_receipt with cash_receipt_id = 2002 has two active task assignments:
task-A with task_status_cd = 'WORKING' assigned to user 3
task-B with task_status_cd = 'OPEN' assigned to user 5
When task-A is completed (task_status_cd updated to 'COMPLETE')
Then task-B still has task_status_cd = 'OPEN' (unaffected without explicit cancellation)
When cancelSiblingTasks is invoked with assignment_id = 'task-A'
Then task-B is updated to task_status_cd = 'CANCELLED'
And a new assignment_history row is inserted for task-B with
action_cd = 'CANCELLED', from_status_cd = 'OPEN', to_status_cd = 'CANCELLED'
Scenario: Edit task reassigns to a different person
Given a task assignment with assignment_id = 'task-999',
task_title = 'Review deposit', assigned_to_user_id = 3
When a supervisor opens the Edit Task dialog and changes the assignee to user_id = 8
And submits the form
Then assignment.assigned_to_user_id is updated to 8
And a new assignment_history row is inserted with action_cd = 'REASSIGNED',
from_user_id = 3, to_user_id = 8
Scenario: Edit task title only produces no history entry
Given a task assignment with assignment_id = 'task-999',
task_title = 'Review deposit', assigned_to_user_id = 3
When a supervisor edits only the task_title to 'Review deposit - urgent'
without changing the assignee
Then assignment.task_title is updated to 'Review deposit - urgent'
And no new assignment_history row is inserted for this change
Feature: Assignments - Hierarchy Resolution
Scenario: Resolve responsible person via hierarchy walk-up when direct assignment missing
Given the following active responsibility assignments exist:
| entity_type_cd | entity_key | assigned_to_user_id |
| DEPARTMENT | entity_id = 10 | 2 |
| CLIENT | entity_id = 501 | 7 |
And no active assignment exists for entity_type_cd = 'DEAL'
AND entity_reference = 'DEAL-2024-007'
And deal 'DEAL-2024-007' belongs to client_id = 501 and department_id = 10
When resolveResponsibleUser is called with
dealReference = 'DEAL-2024-007', clientId = 501, departmentId = 10
Then the service checks DEAL level and finds no match
Then the service checks CLIENT level and finds assignment where entity_id = 501,
assigned_to_user_id = 7
And the service returns resolved_from_entity_type_cd = 'CLIENT',
resolved_from_level = 2, assigned_to_user_id = 7
And the DEPARTMENT level is not queried (short-circuit on first match)
Scenario: Fully unowned entity shows correct Unassigned tab badge
Given a department with department_id = 99 has open billing items
with positive rev_balance
And no active assignment exists for entity_type_cd = 'DEPARTMENT',
entity_id = 99, assignment_type_cd = 'RESPONSIBILITY', is_active_ind = true
When the Unassigned tab loads for entity type DEPARTMENT
Then department 99 appears in the results with nearest_assignment_level = 0
And the Coverage badge displays "Unowned"
Scenario: Unassigned deal shows coverage badge for ancestor client assignment
Given a deal entity_reference = 'DEAL-2024-010' has no active deal-level responsibility
And the parent client (entity_id = 600) has an active responsibility
assigned to user_id = 9 (display name "Maria Torres")
When the Unassigned tab loads for entity type DEAL
Then deal 'DEAL-2024-010' appears in the results
with nearest_assignment_level = 2 and nearest_assignment_entity_type_cd = 'CLIENT'
And the Coverage badge displays "via Client (Maria Torres)"
Feature: Assignments - Unassigned Gap Detection
Scenario: Cash receipt disappears from Unassigned tab after task assigned
Given cash_receipt with cash_receipt_id = 3003 has posting_status_cd != 'V'
and the worst worksheet status rank < 4 (needs work)
And no active task assignment exists for entity_type_cd = 'CASH_RECEIPT',
entity_id = 3003 where task_status_cd NOT IN ('COMPLETE', 'CANCELLED')
When a cash manager selects "Alex Rivera" in Quick Assign To and clicks
"Assign Task" on cash_receipt 3003
Then a new assignment row is created with entity_type_cd = 'CASH_RECEIPT',
entity_id = 3003, assigned_to_user_id = 5, task_status_cd = 'OPEN',
task_title = 'Clear Cash Receipt'
And cash_receipt 3003 no longer appears in the Unassigned CASH_RECEIPT list
And the CASH_RECEIPT summary chip count decrements by 1
Scenario: Failed payment appears in Unassigned payment task list
Given payment_item with payment_item_id = 7777 has
payment_execution_status_cd = 'FAILED'
And no active task assignment exists for entity_type_cd = 'PAYMENT',
entity_id = 7777 where task_status_cd NOT IN ('COMPLETE', 'CANCELLED')
When the Unassigned tab loads for entity type PAYMENT
Then payment 7777 appears in the results with statusCd = 'FAILED'
And an "Assign Task" button is visible on the row