Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
239 lines
8.2 KiB
Markdown
239 lines
8.2 KiB
Markdown
# PRD — Resume Draft Contract
|
|
|
|
- Slug: `resume-draft-contract`
|
|
- Date: `2026-01-23`
|
|
- Status: Draft
|
|
|
|
## Summary
|
|
|
|
Enable users to save client contracts as drafts during the wizard flow and later resume configuring them. Add a dedicated "Drafts" tab in the contracts management area that displays all draft contracts with clear actions to resume editing or discard them.
|
|
|
|
## Problem
|
|
|
|
Currently, users creating complex client contracts through the 6-step wizard must complete the entire process in one session. If they:
|
|
- Get interrupted and close the browser
|
|
- Need to gather more information before completing
|
|
- Want to save work-in-progress for later
|
|
|
|
...they lose all their progress. While the backend already supports saving contracts with `status: 'draft'`, there's no clear UI path to find and resume these draft contracts. Drafts are mixed in with active contracts and there's no obvious "Resume" action.
|
|
|
|
## Goals
|
|
|
|
- Provide a dedicated "Drafts" tab in the Contracts management area to list all draft contracts
|
|
- Allow users to resume editing a draft contract, starting from Step 1 of the wizard
|
|
- Allow users to discard (delete) a draft contract with confirmation
|
|
- Show clear visual indication that contracts in the drafts tab are incomplete
|
|
- Preserve the existing "Save Draft" button functionality in the wizard
|
|
|
|
## Non-goals
|
|
|
|
- Auto-save functionality (manual save only)
|
|
- Smart resume to a specific step (always start at Step 1)
|
|
- Draft versioning or history
|
|
- Draft sharing or collaboration features
|
|
- Draft expiration or auto-cleanup
|
|
- Draft contracts for templates (templates already have their own draft system via `template_status`)
|
|
|
|
## Users and Primary Flows
|
|
|
|
### Persona: MSP Billing Administrator
|
|
|
|
**Flow 1: Saving a Draft**
|
|
1. User starts creating a new client contract via the wizard
|
|
2. User completes some steps but isn't ready to finalize
|
|
3. User clicks "Save Draft" button
|
|
4. System saves contract with `status: 'draft'` and confirms success
|
|
5. User can close the wizard
|
|
|
|
**Flow 2: Viewing Drafts**
|
|
1. User navigates to Contracts management area
|
|
2. User clicks on "Drafts" tab (alongside Templates and Client Contracts)
|
|
3. User sees list of all draft contracts with:
|
|
- Contract name
|
|
- Client name
|
|
- Created date
|
|
- Last modified date
|
|
- Actions (Resume, Discard)
|
|
|
|
**Flow 3: Resuming a Draft**
|
|
1. User clicks "Resume" action on a draft contract
|
|
2. Wizard opens at Step 1 (Contract Basics) with all saved data pre-populated
|
|
3. User can navigate through steps, reviewing/modifying as needed
|
|
4. User either:
|
|
- Saves as draft again (overwrites existing draft)
|
|
- Completes and activates the contract
|
|
|
|
**Flow 4: Discarding a Draft**
|
|
1. User clicks "Discard" action on a draft contract
|
|
2. Confirmation dialog appears: "Are you sure you want to discard this draft? This cannot be undone."
|
|
3. User confirms
|
|
4. Draft is deleted from the system
|
|
|
|
## UX / UI Notes
|
|
|
|
### Contracts Page Tabs
|
|
|
|
Add third tab to existing layout:
|
|
```
|
|
[Templates] [Client Contracts] [Drafts]
|
|
```
|
|
|
|
### Drafts Tab Content
|
|
|
|
- DataTable with columns:
|
|
- Contract Name
|
|
- Client
|
|
- Created
|
|
- Last Modified
|
|
- Actions (dropdown menu)
|
|
- Actions menu items:
|
|
- "Resume" - opens wizard with draft data
|
|
- "Discard" - shows confirmation, then deletes
|
|
- Empty state: "No draft contracts. Start creating a new contract to save as draft."
|
|
|
|
### Drafts Tab Visual Indicators
|
|
|
|
- Badge/count on tab showing number of drafts: `Drafts (3)`
|
|
- Optional: "Draft" badge next to contract name in list
|
|
|
|
### Resume Experience
|
|
|
|
- When resuming, wizard opens as a dialog/drawer (same as creating new)
|
|
- Step 1 pre-populated with saved draft data
|
|
- All subsequent steps also pre-populated
|
|
- "Save Draft" button updates the existing draft (not creating new)
|
|
- "Cancel" button closes without saving (confirmation if changes made)
|
|
- Completing wizard converts draft to active contract
|
|
|
|
### Discard Confirmation Dialog
|
|
|
|
```
|
|
Discard Draft Contract?
|
|
|
|
This will permanently delete the draft "{contract_name}" for {client_name}.
|
|
This action cannot be undone.
|
|
|
|
[Cancel] [Discard]
|
|
```
|
|
|
|
## Requirements
|
|
|
|
### Functional Requirements
|
|
|
|
**FR1: Drafts Tab**
|
|
- Add "Drafts" tab to the Contracts management area (third tab after Templates and Client Contracts)
|
|
- Tab shows count of draft contracts as badge
|
|
- Tab contains DataTable listing all draft contracts for the tenant
|
|
|
|
**FR2: Drafts List**
|
|
- Display contract name, client name, created date, last modified date
|
|
- Include actions dropdown with Resume and Discard options
|
|
- Support sorting by columns (default: last modified, descending)
|
|
- Support search/filter by contract name or client name
|
|
- Respect existing pagination patterns
|
|
|
|
**FR3: Resume Draft**
|
|
- "Resume" action opens the ContractWizard dialog
|
|
- Wizard loads with all saved draft data pre-populated
|
|
- User starts at Step 1 (Contract Basics)
|
|
- Existing "Save Draft" functionality updates the same draft
|
|
- Completing wizard activates the contract (changes `status` from `'draft'` to `'active'`)
|
|
|
|
**FR4: Discard Draft**
|
|
- "Discard" action shows confirmation dialog
|
|
- Confirming deletes the contract and all associated data
|
|
- Deletion uses existing `deleteContract` action
|
|
- List refreshes after successful deletion
|
|
|
|
**FR5: Backend Support**
|
|
- Create action to fetch draft contracts only: `getDraftContracts()`
|
|
- Ensure `updateContract` properly handles draft → active transition
|
|
- Ensure existing draft save in wizard properly updates (not creates new)
|
|
|
|
### Non-functional Requirements
|
|
|
|
- Drafts tab loads within acceptable time (<500ms for typical list sizes)
|
|
- Resume action loads wizard with data within acceptable time
|
|
- Delete operation completes within acceptable time with proper error handling
|
|
|
|
## Data / API / Integrations
|
|
|
|
### New Action Functions
|
|
|
|
```typescript
|
|
// In contractActions.ts or new draftContractActions.ts
|
|
|
|
// Fetch all draft contracts for the current tenant
|
|
export const getDraftContracts = withAuth(async (
|
|
user,
|
|
{ tenant }
|
|
): Promise<ContractWithClient[]> => {
|
|
const { knex } = await createTenantKnex();
|
|
return knex('contracts')
|
|
.join('client_contracts', 'contracts.contract_id', 'client_contracts.contract_id')
|
|
.join('companies', 'client_contracts.client_id', 'companies.company_id')
|
|
.where('contracts.tenant', tenant)
|
|
.where('contracts.status', 'draft')
|
|
.select(
|
|
'contracts.*',
|
|
'companies.company_name as client_name',
|
|
'client_contracts.client_id'
|
|
)
|
|
.orderBy('contracts.updated_at', 'desc');
|
|
});
|
|
|
|
// Get a single draft contract with full data for resuming
|
|
export const getDraftContractForResume = withAuth(async (
|
|
user,
|
|
{ tenant },
|
|
contractId: string
|
|
): Promise<ContractWizardData> => {
|
|
// Fetch contract, lines, services, configurations
|
|
// Transform to ContractWizardData format for wizard consumption
|
|
});
|
|
```
|
|
|
|
### Interface Updates
|
|
|
|
```typescript
|
|
// Add to contract.interfaces.ts if not present
|
|
interface ContractWithClient extends IContract {
|
|
client_name: string;
|
|
client_id: string;
|
|
}
|
|
```
|
|
|
|
### Wizard Updates
|
|
|
|
The ContractWizard already accepts `editingContract` prop — this will be used for resuming drafts. May need to enhance to handle full draft data reload.
|
|
|
|
## Security / Permissions
|
|
|
|
- Drafts follow existing contract permissions
|
|
- Users who can create contracts can save/resume drafts
|
|
- Users who can delete contracts can discard drafts
|
|
- All queries filter by tenant to maintain multi-tenant isolation
|
|
|
|
## Rollout / Migration
|
|
|
|
- No database migration required — `status: 'draft'` already exists
|
|
- Feature is additive — no breaking changes
|
|
- Existing drafts (if any) will appear in the new Drafts tab immediately
|
|
|
|
## Open Questions
|
|
|
|
None — key decisions resolved during planning phase.
|
|
|
|
## Acceptance Criteria (Definition of Done)
|
|
|
|
- [ ] "Drafts" tab appears in Contracts management alongside Templates and Client Contracts
|
|
- [ ] Drafts tab displays count badge showing number of drafts
|
|
- [ ] Drafts list shows contract name, client, created date, modified date, and actions
|
|
- [ ] "Resume" action opens wizard with draft data pre-populated at Step 1
|
|
- [ ] Saving draft again updates the existing draft (no duplicate creation)
|
|
- [ ] Completing the wizard from a resumed draft activates the contract
|
|
- [ ] "Discard" action shows confirmation dialog
|
|
- [ ] Confirming discard deletes the draft contract
|
|
- [ ] Empty state displays appropriately when no drafts exist
|
|
- [ ] List supports sorting and search/filter
|