Action Reasons¶
Overview¶
The Action Reasons feature provides a configurable system for managing predefined reasons that admins can select when performing contract workflow actions. Instead of relying solely on free-text explanations, admins can choose from context-specific reasons when:
- Voiding/Cancelling a contract (
contract_void) - Requesting changes to a contract (
contract_changes_requested)
This feature improves consistency in workflow communications and provides better analytics on why contracts are voided or require changes.
Key Features¶
- Context-aware reasons: Reasons are organized by context (e.g., contract void, changes requested)
- Admin-managed: Full CRUD operations through the Admin Console settings page
- Drag-and-drop reordering: Customize the display order of reasons
- Enable/disable toggle: Temporarily hide reasons without deleting them
- Extensible design: Additional contexts can be added without schema changes
Architecture¶
┌─────────────────────────────────────────────────────────────┐
│ Admin Console │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Action Reasons Settings Page │ │
│ │ (/settings/action-reasons) │ │
│ │ - Create/Edit/Delete reasons │ │
│ │ - Drag-and-drop reordering │ │
│ │ - Enable/disable toggle │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Partner Contract List │ │
│ │ - Reason dropdown in Void/Request Changes panels │ │
│ │ - Reason ID sent with action requests │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Partner Service │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ActionReasonsModule │ │
│ │ - ActionReasonsController │ │
│ │ - ActionReasonsService │ │
│ │ - DTOs and Entity │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ PostgreSQL │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ action_reasons table │ │
│ │ - id, context, slug, name, description │ │
│ │ - display_order, enabled, timestamps │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ partner_contracts table │ │
│ │ - void_reason_id (FK) │ │
│ │ - changes_requested_reason_id (FK) │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
API Reference¶
Endpoints¶
All endpoints are prefixed with /api/partners/admin/action-reasons
| Method | Endpoint | Description |
|---|---|---|
| GET | / |
List reasons by context |
| GET | /:id |
Get a single reason by ID |
| POST | / |
Create a new reason |
| PATCH | /:id |
Update an existing reason |
| DELETE | /:id |
Delete a reason |
| PUT | /reorder |
Bulk reorder reasons within a context |
Query Parameters¶
| Parameter | Type | Description |
|---|---|---|
context |
string | Filter by context (e.g., contract_void) |
includeDisabled |
string | Set to "true" to include disabled reasons |
Request/Response Examples¶
List Reasons¶
Response:
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"context": "contract_void",
"slug": "compliance-issue",
"name": "Compliance Issue",
"description": "Contract voided due to regulatory compliance concerns",
"display_order": 0,
"enabled": true,
"created_at": "2026-01-26T10:00:00.000Z",
"updated_at": "2026-01-26T10:00:00.000Z"
}
]
Create Reason¶
POST /api/partners/admin/action-reasons
Content-Type: application/json
{
"context": "contract_void",
"slug": "partner-request",
"name": "Partner Request",
"description": "Voided at partner's request"
}
Update Reason¶
PATCH /api/partners/admin/action-reasons/550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json
{
"name": "Updated Name",
"enabled": false
}
Reorder Reasons¶
PUT /api/partners/admin/action-reasons/reorder
Content-Type: application/json
{
"context": "contract_void",
"ids": [
"550e8400-e29b-41d4-a716-446655440001",
"550e8400-e29b-41d4-a716-446655440000",
"550e8400-e29b-41d4-a716-446655440002"
]
}
Data Model¶
ActionReason Entity¶
interface ActionReason {
id: string; // UUID primary key
context: string; // Context identifier (e.g., 'contract_void')
slug: string; // URL-friendly unique identifier within context
name: string; // Display name
description: string | null; // Optional description
display_order: number; // Sort order (0-based)
enabled: boolean; // Whether reason is available for selection
created_at: Date;
updated_at: Date;
}
Available Contexts¶
| Context | Description |
|---|---|
contract_void |
Reasons for voiding/cancelling a contract |
contract_changes_requested |
Reasons for requesting changes to a contract |
Frontend Integration¶
Admin Console - Settings Page¶
Location: /settings/action-reasons
The Action Reasons settings page provides:
- Tab navigation: Switch between different contexts (Void Reasons, Change Reasons)
- Reason list: Drag-and-drop sortable list with inline controls
- Create/Edit dialog: Modal form for creating or editing reasons
- Delete confirmation: Safety dialog before permanent deletion
Contract Actions Integration¶
When voiding a contract or requesting changes, the admin can:
- Select a predefined reason from a dropdown
- Provide additional context in the free-text comment field
- Submit the action with both the reason ID and comment
The reason ID is stored in partner_contracts.void_reason_id or partner_contracts.changes_requested_reason_id.
Development¶
Project Structure¶
services/partner-service/src/modules/action-reasons/
├── action-reasons.controller.ts # HTTP endpoints
├── action-reasons.service.ts # Business logic
├── action-reasons.module.ts # NestJS module
├── dto/
│ ├── create-action-reason.dto.ts
│ ├── update-action-reason.dto.ts
│ └── reorder-action-reasons.dto.ts
└── entities/
└── action-reason.entity.ts # TypeScript interface
Adding a New Context¶
To add a new context (e.g., for document rejection):
-
Add the context constant to
action-reason.entity.ts: -
Add the context to the frontend's
partner.service.ts -
Add a new tab in
ActionReasonsPage.tsx -
Update the relevant workflow to use the new context
Validation Rules¶
- slug: Required, 1-100 chars, lowercase alphanumeric with hyphens/underscores only
- name: Required, 1-255 chars
- description: Optional
- display_order: Optional (auto-incremented if not provided), must be >= 0
- context + slug: Must be unique (database constraint)
Internationalization¶
The feature supports full i18n through the admin-console's translation system. Translation keys are located in frontends/admin-console/src/i18n/locales/en.json under settings.actionReasons.
Future Extensions¶
The action_reasons table is designed for extensibility. Potential future use cases:
| Context | Workflow | Current Field |
|---|---|---|
document_rejection |
Partner document review | verification_reason |
service_proposal_rejection |
Service proposal approval | review_message |
service_text_rejection |
Service text approval | admin_note |
contract_proposal_rejection |
Contract proposal approval | review_message |
task_dismissal |
Admin task management | (new field) |
See Also¶
- Admin Tutorial: Managing Action Reasons - Step-by-step guide for admins
- Action Reasons Agent Context - Technical reference for AI agents
- Partner Service Overview - Service documentation
- Smart Contracts Architecture - Contract workflow documentation