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
220 lines
11 KiB
Markdown
220 lines
11 KiB
Markdown
# PRD — Contract Auto-Renewal and Renewals Queue
|
|
|
|
- Slug: `contract-auto-renewal-and-renewals-queue`
|
|
- Date: `2026-02-21`
|
|
- Status: Draft
|
|
|
|
## Summary
|
|
Add first-class contract renewal management to Billing Contracts: renewal settings during contract setup, a dedicated actionable Renewals queue, and due-date automation that can create internal tickets. The system must support fixed-term and evergreen contracts, tenant defaults with optional per-contract override, and runtime compatibility for both on-prem (`pg-boss`) and hosted/EE (`Temporal`) automation execution.
|
|
|
|
## Problem
|
|
MSPs currently rely on `end_date` awareness and ad-hoc process to decide whether to renew or terminate contracts. This creates avoidable revenue leakage, missed non-renewal notices, and inconsistent ownership of renewal decisions.
|
|
|
|
Current contract surfaces support start/end dates and expiration reporting, but they do not support:
|
|
- explicit renewal behavior on each contract assignment,
|
|
- a single operational queue for upcoming renewal decisions,
|
|
- standardized queue actions (`renewing`, `non-renewing`, `create draft`, `snooze`),
|
|
- configurable due-date automation (ticket creation) with assignment defaults.
|
|
|
|
## Goals
|
|
1. Capture renewal intent and notice-window behavior at contract creation/edit time.
|
|
2. Compute and surface a single operational date (`decision_due_date`) for renewal work.
|
|
3. Provide an actionable Renewals queue with 90-day triage buckets and owner/status workflows.
|
|
4. Support tenant-level defaults with optional per-contract override.
|
|
5. Automatically create internal renewal tickets at due date when configured.
|
|
6. Support fixed-term contracts and evergreen annual-review flow in the same queue model.
|
|
7. Ship as one cohesive release spanning wizard, queue, actions, and automation.
|
|
|
|
## Non-goals
|
|
1. Sending customer-facing renewal quote emails from queue actions.
|
|
2. New billing/invoice pricing engines for renewal uplift or pro forma quoting.
|
|
3. Full CLM/legal document lifecycle features.
|
|
4. Replacing existing contract status model (`draft`, `active`, `terminated`, `expired`) in this release.
|
|
5. New feature-flag infrastructure or rollout orchestration beyond normal release controls.
|
|
|
|
## Users and Primary Flows
|
|
- Billing manager / account manager:
|
|
- sets renewal behavior during contract creation/edit,
|
|
- reviews upcoming decisions in queue,
|
|
- marks contracts renewing or non-renewing,
|
|
- snoozes decisions with explicit date.
|
|
- Service manager / coordinator:
|
|
- owns assigned renewal tasks,
|
|
- works queue by due-date buckets,
|
|
- opens renewal draft contracts from queue.
|
|
|
|
Primary flows:
|
|
1. Create fixed-term contract with end date, choose renewal behavior and notice period.
|
|
2. Create evergreen contract (no end date) with annual-review configuration.
|
|
3. Review queue by `0-30`, `31-60`, `61-90` decision windows.
|
|
4. Mark `renewing` and auto-create next-term draft contract.
|
|
5. Mark `non-renewing` and close renewal work item.
|
|
6. Snooze and assign renewal work item.
|
|
7. Due-date automation creates internal ticket when configured.
|
|
|
|
## UX / UI Notes
|
|
1. `Contract Basics` step (`ContractWizard`) gets a conditional `Renewal Settings` card:
|
|
- if `end_date` exists: fixed-term renewal settings.
|
|
- if `end_date` absent: evergreen annual review settings.
|
|
|
|
2. Billing gets a new top-level `Renewals` tab/page:
|
|
- queue table with filters + action menu,
|
|
- default horizon 90 days,
|
|
- bucket presets and owner filters.
|
|
|
|
3. `Client Contracts` tab gets an `Upcoming Renewals` summary widget:
|
|
- count by 0-30 / 31-60 / 61-90,
|
|
- quick entry into Renewals queue.
|
|
|
|
4. Queue actions in v1:
|
|
- `Mark renewing` (auto-create renewal draft and open editor),
|
|
- `Mark non-renewing`,
|
|
- `Create renewal draft`,
|
|
- `Snooze`.
|
|
|
|
5. Queue primary sort key is `decision_due_date` (not raw contract end date).
|
|
|
|
## Requirements
|
|
|
|
### Functional Requirements
|
|
|
|
#### FR1 — Contract Setup and Renewal Configuration
|
|
1. Capture renewal settings on client contract assignments in the contract wizard and edit flows.
|
|
2. Support renewal modes: `none`, `manual`, `auto`.
|
|
3. If fixed-term (`end_date` set), capture notice period and renewal term behavior.
|
|
4. If evergreen (`end_date` null), capture annual-review cadence and notice period.
|
|
5. Validate incompatible states in UI and server (e.g., auto-renew with missing term strategy when required).
|
|
|
|
#### FR2 — Tenant Defaults and Contract-Level Overrides
|
|
1. Add tenant defaults for renewal behavior and due-date automation target.
|
|
2. Support per-contract override toggle (`use tenant defaults` vs explicit override values).
|
|
3. Preserve deterministic fallback behavior when override values are partially unset.
|
|
|
|
#### FR3 — Renewal Decision Date Engine
|
|
1. Compute `decision_due_date` for each active client contract.
|
|
2. Fixed-term formula: `decision_due_date = end_date - notice_period_days`.
|
|
3. Evergreen formula: derive next anniversary window and subtract notice period days.
|
|
4. Recompute decision dates when contract dates/settings change.
|
|
5. Prevent duplicate active work items for the same contract renewal cycle.
|
|
|
|
#### FR4 — Renewals Queue and Dashboard Entry Points
|
|
1. Add `Renewals` Billing tab and queue page.
|
|
2. Add `Upcoming Renewals` widget in `Client Contracts` tab.
|
|
3. Queue must support filters: horizon, bucket, owner, status, renewal mode, fixed/evergreen.
|
|
4. Queue must show due-date centric columns and actions.
|
|
|
|
#### FR5 — Queue Actions and Renewal Workflow
|
|
1. Add queue statuses: `pending`, `renewing`, `non_renewing`, `snoozed`, `completed`.
|
|
2. Implement action transitions with actor + timestamp + optional note.
|
|
3. `Mark renewing` must auto-create draft renewal contract (per chosen product decision).
|
|
4. `Create renewal draft` must be available as explicit independent action.
|
|
5. `Snooze` must require a future target date.
|
|
|
|
#### FR6 — Automation and Ticket Creation
|
|
1. At `decision_due_date`, create/update queue work item if unresolved.
|
|
2. When tenant/contract policy says `create internal ticket`, create one ticket idempotently.
|
|
3. Store linkage from renewal work item to created ticket.
|
|
4. Ticket defaults (board/status/priority/assignee) must come from renewal automation settings.
|
|
|
|
#### FR7 — Evergreen Annual Review Flow
|
|
1. Include evergreen contracts in queue using annual review cycle date.
|
|
2. Support the same status/actions as fixed-term contracts.
|
|
3. After a cycle is completed, prepare next evergreen cycle work item.
|
|
|
|
#### FR8 — Reporting and Existing Surface Alignment
|
|
1. Align existing contract expiration reporting with renewal decision model.
|
|
2. Preserve existing expiration semantics while adding decision-due visibility.
|
|
3. Avoid regressions in existing `Contract Expiration Report` consumers.
|
|
|
|
#### FR9 — Runtime Compatibility (On-prem PG Boss vs Hosted/EE Temporal)
|
|
1. Renewal automation job path must support on-prem `pg-boss` runtime.
|
|
2. Renewal automation job path must support hosted/EE `Temporal` runtime.
|
|
3. Ensure behavior parity regardless of runtime (idempotency, ticket creation, retry semantics).
|
|
4. Respect existing runtime selection and fallback patterns (`JobRunnerFactory`).
|
|
|
|
#### FR10 — Permissions, Security, and Auditability
|
|
1. Restrict queue mutations to authorized billing users.
|
|
2. Ensure tenant isolation in all queue queries and actions.
|
|
3. Record auditable state transitions and key actor metadata.
|
|
|
|
### Non-functional Requirements
|
|
1. Queue list queries for default 90-day horizon should complete within existing Billing table UX expectations.
|
|
2. Renewal work-item creation and ticket automation must be idempotent across retries.
|
|
3. Runtime-independent behavior parity must be verified between `pg-boss` and `Temporal` paths.
|
|
4. All date handling must use existing date-only conventions for contract dates to avoid timezone drift.
|
|
|
|
## Data / API / Integrations
|
|
|
|
### Data model additions
|
|
1. `client_contracts` additions (assignment-level settings):
|
|
- `renewal_mode` (`none|manual|auto`)
|
|
- `notice_period_days` (int)
|
|
- `renewal_term_months` (nullable int)
|
|
- `use_tenant_renewal_defaults` (bool)
|
|
- evergreen cycle metadata (as needed for annual review computation)
|
|
|
|
2. `default_billing_settings` additions (tenant defaults):
|
|
- default renewal mode
|
|
- default notice period
|
|
- due-date action policy (`queue_only` or `create_ticket`)
|
|
- default ticket routing fields (board/status/priority/assignee)
|
|
|
|
3. New queue table (recommended): `client_contract_renewal_work_items`:
|
|
- work item identity + tenant + client_contract_id
|
|
- `decision_due_date`, `cycle_start`, `cycle_end`
|
|
- `status`, `assigned_to`, `snoozed_until`
|
|
- `created_ticket_id`, `created_draft_contract_id`
|
|
- `last_action`, `last_action_by`, `last_action_at`, note/reason fields
|
|
|
|
### API / action surfaces
|
|
1. Extend `ClientContractWizardSubmission` and related actions to include renewal settings.
|
|
2. New renewal queue actions:
|
|
- list/query queue
|
|
- mark renewing
|
|
- mark non-renewing
|
|
- create renewal draft
|
|
- snooze
|
|
- assign owner
|
|
|
|
3. Integrate with existing ticket creation action path (`tickets.create`) for automation side effects.
|
|
|
|
### Integrations
|
|
- Billing dashboard/tab composition.
|
|
- Contract wizard basics step.
|
|
- Existing event bus + workflow runtime event model.
|
|
- On-prem scheduled jobs via `pg-boss`.
|
|
- Hosted/EE automation via `Temporal`.
|
|
|
|
## Security / Permissions
|
|
1. Read queue: billing read permission.
|
|
2. Mutate queue actions: billing update permission.
|
|
3. Tenant defaults changes: billing settings update permission.
|
|
4. Ticket automation execution: system/service actor with tenant-scoped permission enforcement.
|
|
|
|
## Observability
|
|
No net-new observability framework is required for v1. Reuse existing audit/event patterns and existing job/runtime failure reporting surfaces. Track enough state in renewal work items to diagnose retries and failures without adding a separate telemetry subsystem.
|
|
|
|
## Rollout / Migration
|
|
1. Add schema migrations for new contract renewal columns, default settings fields, and queue table.
|
|
2. Backfill existing active fixed-term contracts with deterministic defaults (`manual`, default notice period, tenant default usage).
|
|
3. Do not auto-create queue/tickets for historical expired/terminated contracts.
|
|
4. Stage rollout sequence:
|
|
- deploy schema + read-compatible code,
|
|
- deploy write paths and queue UI,
|
|
- enable scheduled automation processing.
|
|
|
|
## Open Questions
|
|
1. Should renewal automation ticket defaults be separate from inbound-ticket defaults, or reuse them where unspecified?
|
|
2. What is the canonical evergreen anniversary anchor for contracts with manually edited start dates over time?
|
|
3. Do we require a hard block against activating renewal drafts until the original contract is marked renewing/non-renewing, or allow parallel status transitions?
|
|
|
|
## Acceptance Criteria (Definition of Done)
|
|
1. Contract wizard supports fixed-term and evergreen renewal settings and persists them per client contract assignment.
|
|
2. Billing has a functional Renewals queue tab with 90-day buckets and required actions.
|
|
3. `Client Contracts` includes upcoming-renewals summary widget linked to queue.
|
|
4. `Mark renewing` auto-creates and links a renewal draft contract.
|
|
5. Due-date automation creates at most one ticket per renewal cycle when policy is enabled.
|
|
6. On-prem (`pg-boss`) and hosted/EE (`Temporal`) execute equivalent renewal automation behavior.
|
|
7. Existing contract expiration report remains functional and reflects decision-date semantics where applicable.
|
|
8. Features/tests checklists are populated and traceable to this PRD.
|