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
213 lines
25 KiB
Markdown
213 lines
25 KiB
Markdown
# Contract Template Overhaul & Client Assignment Alignment Plan
|
||
|
||
## Summary
|
||
This plan restructures the contracts domain so that `contracts` and `contract_lines` represent reusable templates, while `client_contracts` and `client_contract_lines` continue to hold tenant-specific instances. The work spans backend schema changes, domain service updates, UI flow adjustments for both the contract template wizard and the client contract wizard, and a data migration to decouple template-only fields from client-specific values.
|
||
|
||
## Goals
|
||
- Treat `contracts` / `contract_lines` as tenant-scoped templates that omit client-specific commercial terms (rates, quantities, bucket settings, etc.).
|
||
- Ensure `client_contracts` and `client_contract_lines` own all mutable billing terms and lifecycle metadata used for invoicing.
|
||
- Provide a streamlined Contract Template Wizard that mirrors the client contract wizard but skips per-client pricing fields.
|
||
- Allow the Client Contract Wizard to bootstrap from a selected contract template, pre-filling compatible sections while prompting for client-specific details.
|
||
- Migrate existing data so that all commercial terms live on `client_contract_lines` (with fallbacks for empty values).
|
||
- Keep billing engine, reporting, and integrations functional during the transition.
|
||
|
||
## Non-Goals
|
||
- Overhauling the service catalog or invoicing engine beyond required interface changes.
|
||
- Introducing new billing models or pricing logic.
|
||
- Building multi-tenant contract sharing across different Alga tenants.
|
||
|
||
## Stakeholders
|
||
- Billing & Finance product owners
|
||
- Frontend billing dashboard team
|
||
- Backend billing platform team
|
||
- QA & Test Automation team
|
||
|
||
## High-Level Timeline
|
||
1. **Phase 0 – Discovery & Alignment (1 week)**
|
||
2. **Phase 1 – Schema Preparation & Migrations (1.5 weeks)**
|
||
3. **Phase 2 – Backend Domain Updates (2 weeks)**
|
||
4. **Phase 3 – Frontend Template Wizard & Client Wizard Enhancements (2 weeks)**
|
||
5. **Phase 4 – Data Migration & Backfill (1 week)**
|
||
6. **Phase 5 – QA, Rollout, & Monitoring (1 week)**
|
||
|
||
Total estimated duration: ~8.5 weeks including buffer.
|
||
|
||
---
|
||
|
||
## Phase 0 – Discovery & Alignment
|
||
**Goals:** Validate assumptions about current contracts usage, document edge cases, and align on template vs. client instance semantics.
|
||
|
||
- Inventory existing tables/fields using DB diagrams and confirm ownership (e.g. `contracts`, `contract_lines`, `contract_line_mappings`, `client_contracts`, `client_contract_lines`, `client_contract_line_service_configurations`).
|
||
- Review Knex migrations in `server/migrations` (start with files containing `contract`/`billing` naming) to capture current columns, composite keys, and sequences on each related table.
|
||
- Map multi-tenant helpers referenced by migrations (e.g., `server/src/lib/db/admin.ts`, `server/src/lib/db/knexfile.ts`, `shared/db/index.ts`) to understand how schema helpers are invoked during tenant provisioning.
|
||
- Document any triggers, row level security policies, and dependent views/materialized views defined in SQL files (see `server/migrations/*cleanup_billing_to_contracts.cjs` and `cleanup_obsolete_email_tables.sql` for precedent).
|
||
- Review backend usage patterns:
|
||
- Run `rg "client_contract"` and `rg "contract_lines"` across `server/src/lib/api/services`, `server/src/lib/billing`, and `ee/server/src/lib` to list the service entrypoints, DTOs, and utilities that currently rely on template pricing data.
|
||
- Trace how the REST/Next.js routes obtain contract data (e.g., `server/src/app/api/v1/contracts`, enterprise overrides under `ee/server/src/app/api`) and note which serializers expect price fields on `contracts` vs. `client_contracts`.
|
||
- Summarize how integration and E2E suites seed contract data through helpers in `server/src/test/integration`, `server/src/test/e2e`, and scripts such as `server/scripts/create-tenant.ts` and `server/scripts/seed-templates.js` that provision default billing records.
|
||
- Capture UI flows:
|
||
- Walk through `ContractWizard.tsx`, `ContractDetail.tsx`, and billing dashboard routes to catalog inputs that currently bind to template pricing, quantities, or bucket settings.
|
||
- Note feature flags, context providers, and state containers (`Contracts.tsx` wizard state, billing feature flags) that determine whether a template can be selected during client contract creation.
|
||
- Produce a conclusive spec doc (append to this plan) enumerating which fields should remain on template tables, including an explicit mapping of “template column → client instance column” plus validation rules for missing data.
|
||
- Align with stakeholders on acceptance criteria and rollout checkpoints; schedule reviews with Billing PM, finance, and QA to confirm migration sequencing and sign-off expectations.
|
||
|
||
### Phase 0 Progress Log (2025-02-14)
|
||
- [x] **Inventory current schema surface**
|
||
- `contracts` table stores template metadata today (`contract_name`, `billing_frequency`, activation flags) with tenant-scoped PKs and indexes (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:166-183`).
|
||
- `contract_lines` and supporting config tables retain pricing knobs such as base rates, overtime multipliers, and bucket limits (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:400-936`).
|
||
- Client instance data is split across `client_contracts` (start/end dates, active state) and `client_contract_lines` (per-client assignments with timestamps) (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:240-569`).
|
||
- Multi-tenant enforcement relies on shared `addTenantForeignKey` helper; no triggers or RLS rules are defined for these tables in current migrations (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:1214-1246`).
|
||
- [x] **Review backend usage patterns**
|
||
- REST entry points live under Next routes (`server/src/app/api/v1/contracts/route.ts`, `server/src/app/api/v1/contract-lines/*`) backed by `ApiContractLineController`, which exposes CRUD, template copy, and client assignment flows (`server/src/lib/api/controllers/ApiContractLineController.ts:1-210`).
|
||
- `createContractFromWizard` persists pricing, rate tiers, and bucket settings directly onto template tables before seeding client assignments (`server/src/lib/actions/contractWizardActions.ts:80-260`).
|
||
- Reporting and billing pipelines pull amounts from `contract_line_fixed_config`, `contract_line_services`, and fall back to `contract_line_mappings.custom_rate`, so template-vs-instance separation must preserve these call sites (`server/src/lib/reports/definitions/contracts/expiration.ts:60-96`).
|
||
- Test helpers in `server/test-utils/billingTestHelpers.ts:520-640` seed both template and client tables, mirroring production expectations for pricing fields.
|
||
- [x] **Capture current UI flows**
|
||
- `ContractWizard` collects client-facing pricing inputs (base rates, quantities, usage rates, bucket overlays) and posts them through `createContractFromWizard`, reinforcing that templates currently own monetary fields (`server/src/components/billing-dashboard/contracts/ContractWizard.tsx:23-210`).
|
||
- Contract list surfaces (`server/src/components/billing-dashboard/contracts/Contracts.tsx:300-360`) and rate dialogs (`server/src/components/billing-dashboard/contracts/ContractPlanRateDialog.tsx:12-72`) expect per-line pricing to be editable on template entities.
|
||
- [x] **Template field ownership spec**
|
||
- Captured a column-by-column mapping for core tables plus proposed client-instance counterparts under “Template vs Instance Field Ownership”.
|
||
- [ ] **Stakeholder alignment**
|
||
- Schedule finance/QA/billing sync once ownership matrix is stable; confirm rollout checkpoints and validation requirements.
|
||
|
||
### Template vs Instance Field Ownership
|
||
| Table | Column / Concern | Current Role | Proposed Owner | Notes / Follow-ups |
|
||
| --- | --- | --- | --- | --- |
|
||
| `contracts` | `contract_name`, `contract_description`, `billing_frequency`, `is_active`, timestamps (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:166-227`) | Wizard defaults + feature gating | Template | Keep columns; add `template_metadata` JSON for guidance strings and UI hints. |
|
||
| `client_contracts` | `client_id`, `start_date`, `end_date`, `is_active`, `contract_id`, timestamps (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:240-284`) | Client lifecycle | Client instance | Add `template_contract_id` FK + `created_from_template_version` to track template revisions. |
|
||
| `contract_line_mappings` | `display_order`, `custom_rate`, timestamps (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:300-345`) | Associates template contracts↔lines & overrides | Mixed | Keep ordering on template. Move `custom_rate` into `client_contract_line_pricing` table keyed by `client_contract_line_id`. |
|
||
| `contract_lines` | `contract_line_name`, `description`, `contract_line_type`, `service_category`, activation flags (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:400-468`) | Template scaffolding | Template | Preserve; add `is_template` flag (Phase 1). |
|
||
| `contract_lines` | `billing_frequency`, overtime/after-hours columns (`enable_overtime`, `overtime_rate`, etc.) | Currently shared defaults but billable | Client instance | Copy into `client_contract_line_terms` (new) linked to `client_contract_line_id`; template retains optional suggested defaults stored in `contract_line_template_terms`. |
|
||
| `contract_line_fixed_config` | `base_rate`, `enable_proration`, `billing_cycle_alignment` (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:470-522`) | Controls fixed-fee pricing | Client instance | Duplicate structure into `client_contract_line_fixed_config`; template table keeps nullable default columns only. |
|
||
| `contract_line_services` | `service_id`, `quantity`, `custom_rate` (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:790-838`) | Bundled services + rate overrides | Client instance | Create `client_contract_services` keyed by `client_contract_line_id`; template table keeps `service_id` + `default_role` style metadata (`quantity` -> `default_quantity`, `custom_rate` -> remove). |
|
||
| `contract_line_service_configuration` | `configuration_type`, `custom_rate`, `quantity` (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:840-894`) | Service-specific config (Fixed/Bucket/Usage) | Client instance | Introduce `client_contract_service_configuration` keyed by `client_contract_service_id`; template table retains `configuration_type` + optional metadata only. |
|
||
| `contract_line_service_bucket_config` | `total_minutes`, `overage_rate`, `allow_rollover` (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:960-1010`) | Bucket sizing & overage pricing | Client instance | New `client_contract_service_bucket_config`; templates store defaults in `contract_line_service_defaults` JSON. |
|
||
| `contract_line_service_fixed_config` | `base_rate` (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:1012-1060`) | Fixed rate overrides | Client instance | Move to `client_contract_service_fixed_config`; template retains default guidance. |
|
||
| `contract_line_service_hourly_config` | `minimum_billable_time`, overtime multipliers, etc. (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:1062-1114`) | Hourly behavior | Client instance | New `client_contract_service_hourly_config`; template table trimmed to recommended values. |
|
||
| `contract_line_service_hourly_configs` | `hourly_rate`, `minimum_billable_time` (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:1116-1152`) | Hourly tier matrix | Client instance | Mirror table `client_contract_service_hourly_tiers` (per `config_id` + rate). Templates keep structural tiers without dollar amounts. |
|
||
| `contract_line_service_rate_tiers` | Tier pricing ladder (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:1154-1194`) | Usage tier pricing | Client instance | Move rate fields to `client_contract_service_rate_tiers`; templates retain `min/max_quantity`. |
|
||
| `contract_line_service_usage_config` | `unit_of_measure`, `enable_tiered_pricing`, `base_rate`, `minimum_usage` (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:1196-1244`) | Usage pricing baseline | Mixed | Keep descriptive fields (`unit_of_measure`, `enable_tiered_pricing`) on template; relocate `base_rate`, `minimum_usage` to client usage config table. |
|
||
| `contract_line_discounts` | Discount linkages (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:896-940`) | Template-level discount association | Mixed | Maintain template associations for suggestion; create `client_contract_line_discounts` for actual applied discounts per client. |
|
||
| `client_contract_lines` | `client_id`, `contract_line_id`, `start_date`, `is_active`, timestamps (`server/migrations/20251008000001_rename_billing_to_contracts.cjs:520-569`) | Client assignment roster | Client instance | Add `template_contract_line_id`, `billing_frequency`, `is_customized`, monetary columns or FK out to new pricing tables. |
|
||
|
||
#### Client Instance Table Additions
|
||
- **`client_contract_line_terms`**: (`client_contract_line_id` PK/FK, `billing_frequency`, `enable_overtime`, `overtime_rate`, `overtime_threshold`, `enable_after_hours_rate`, `after_hours_multiplier`). Values copied from `contract_lines` defaults during migration; future writes require these fields for billing engine parity.
|
||
- **`client_contract_services`**: (`client_contract_service_id` uuid, `client_contract_line_id`, `service_id`, `quantity`, `rate_cents`, `effective_date`, timestamps). Supersedes `contract_line_services` pricing data for clients; templates keep a slim `contract_template_services` table with `default_quantity`/`default_role`.
|
||
- **`client_contract_service_configuration`** tree:
|
||
- `client_contract_service_configuration` (mirrors schema of `contract_line_service_configuration` minus template defaults; keyed by `client_contract_service_id`).
|
||
- `client_contract_service_bucket_config`, `client_contract_service_fixed_config`, `client_contract_service_hourly_config`, `client_contract_service_hourly_tiers`, `client_contract_service_rate_tiers`, `client_contract_service_usage_config` matching existing template tables but referencing `client_contract_service_configuration_id`.
|
||
- **`client_contract_line_pricing`**: (`client_contract_line_id`, `source_template_contract_line_id`, `custom_rate_cents`, `source_contract_line_mapping_id`, `notes`). Receives data from `contract_line_mappings.custom_rate`.
|
||
- **`client_contract_line_discounts`**: (`client_contract_line_id`, `discount_id`, `applied_rate`, `start_date`, `end_date`) to represent actual discount applications, distinct from template recommendations.
|
||
- **`contract_line_template_terms`**: New template companion storing optional defaults for term-related fields stripped from `contract_lines` (mirrors columns added to `client_contract_line_terms` but nullable).
|
||
|
||
#### Cross-System Considerations
|
||
- **Billing engine** (`server/src/lib/billing/billingEngine.ts:409-470`): Update all joins to reference `client_contract_*` tables for pricing, ensuring totals never pull from template columns.
|
||
- **Reporting** (`server/src/lib/reports/definitions/contracts/expiration.ts:60-96`, `.../revenue.ts:45-85`): Redirect rate lookups to `client_contract_line_pricing` and corresponding client config tables.
|
||
- **Test fixtures** (`server/test-utils/billingTestHelpers.ts:520-640`): Extend helper APIs to seed both template defaults and client-specific pricing, aligned with new schema.
|
||
- **Historical data**: For closed contracts, persist original `contract_id`/`contract_line_id` associations via new `template_*` foreign keys to support audits without keeping legacy rate columns on templates.
|
||
|
||
## Phase 1 – Schema Preparation & Migrations
|
||
**Goals:** Add new columns/constraints to support template semantics and prepare for data migration.
|
||
|
||
- Draft ERD updates showing final relationships.
|
||
- Database migrations (Knex + SQL):
|
||
- Add `is_template` boolean flags to `contracts` and `contract_lines` (default `true`, enforced via check to keep backward compatibility during migration).
|
||
- Introduce `template_contract_id` FK on `client_contracts` (nullable) referencing `contracts.id` to track origin template.
|
||
- Introduce `template_contract_line_id` FK on `client_contract_lines` referencing `contract_lines.id`.
|
||
- Create template companion tables (`contract_line_template_terms`, `contract_template_services`, `contract_line_service_defaults`) to store recommended values separated from instance pricing.
|
||
- Add nullable JSONB column `template_metadata` to `contracts` for wizard hints (e.g. recommended payment cadence, notes).
|
||
- Introduce client-instance tables (`client_contract_line_terms`, `client_contract_services`, `client_contract_service_configuration` and child tables, `client_contract_line_pricing`, `client_contract_line_discounts`) mirroring the template schema but keyed to `client_contract_line_id`.
|
||
- Update existing template tables to drop or rename monetary fields:
|
||
- Convert `contract_line_services.quantity` → `default_quantity`, remove `custom_rate`.
|
||
- Remove rate columns from `contract_line_service_*` tables or mark nullable defaults pending migration.
|
||
- Drop `contract_line_mappings.custom_rate` once client pricing table is populated.
|
||
- Create forward migration scripts under `server/migrations` (e.g., `YYYYMMDDHHMM_contract_template_overhaul.cjs`), run locally with `npm run migrate`, and document verification queries for teardown.
|
||
- Write migration rollback strategy and add to `ee/docs/plans/...` appendix.
|
||
|
||
**Phase 1 Status – 2025-02-14**
|
||
- [x] Drafted initial Knex migration (`server/migrations/20250214090000_contract_templates_phase1.cjs`) that introduces template flags, template metadata JSON, and scaffolds client-specific tables for pricing/config cloning.
|
||
- [ ] Update existing migrations/services to remove legacy pricing fields once data migration completes (tracked in Phase 4).
|
||
- [ ] Align migration with rip-and-replace approach (no dual-write): adjust contract assignment services once data backfill happens.
|
||
|
||
## Phase 2 – Backend Domain Updates
|
||
**Goals:** Ensure services treat templates as blueprints and client contracts as concrete instances.
|
||
|
||
- Update repositories/services:
|
||
- `server/src/lib/api/services/ContractService.ts` → expose APIs to manage template contracts (CRUD) without pricing fields.
|
||
- `server/src/lib/api/services/ClientContractService.ts` → accept optional `templateContractId` and clone relevant lines into `client_contract_lines` with new pricing inputs.
|
||
- `server/src/lib/api/services/ContractLineService.ts` → ensure template lines handle service attachment and metadata only.
|
||
- `server/src/lib/billing/billingEngine.ts` and related modules → confirm all billing amounts come from `client_contract_lines`.
|
||
- Adjust DTOs/interfaces under `server/src/interfaces/billing.interfaces.ts` to distinguish `ContractTemplate` vs `ClientContract` payloads.
|
||
- Implement cloning utilities in `server/src/lib/billing/utils/templateClone.ts` (new file) to copy template scaffolding into client contract context.
|
||
- Update validation logic to forbid setting pricing on template endpoints; add API errors.
|
||
- Ensure service catalog linkage remains consistent (e.g., `plan_service_configuration` usage if applicable).
|
||
- Extend unit/integration tests:
|
||
- New tests in `server/src/test/unit/contracts` verifying template CRUD.
|
||
- Adjust existing tests in `server/src/test/integration/api/storageHandlers.test.ts` and `server/src/test/e2e/api/services.e2e.test.ts` to use client contract rates only.
|
||
|
||
**Phase 2 Status – 2025-02-14**
|
||
- [x] Implemented `cloneTemplateContractLine` utility and integrated it with API and server-action entry points for client contract assignments (`ContractLineService.assignPlanToClient`, client contract apply/add flows). Assignments now populate the new `client_contract_*` tables directly (rip-and-replace path).
|
||
- [x] Updated shared interfaces/schemas to expose template linkage fields consumed by the revised services.
|
||
- [ ] Update billing engine/report consumers to rely on `client_contract_line_pricing` and related tables (pending once data migration completes).
|
||
|
||
## Phase 3 – Frontend Template Wizard & Client Wizard Enhancements
|
||
**Goals:** Provide UX for managing templates and applying them when creating client contracts.
|
||
|
||
- Create Contract Template Wizard:
|
||
- New component `server/src/components/billing-dashboard/contracts/ContractTemplateWizard.tsx` based on `ContractWizard.tsx` but omitting rate/quantity inputs.
|
||
- Update routing in `BillingDashboard.tsx` to expose template management section.
|
||
- Add API hooks in `server/src/components/billing-dashboard/contracts/hooks.ts` for template CRUD (`useCreateContractTemplate`, `useUpdateContractTemplate`).
|
||
- Ensure UI surfaces template metadata (line types, services) with ability to add/remove lines and attach services.
|
||
- Update existing `ContractWizard.tsx` to support selecting a template:
|
||
- Add initial step that lists templates via new API.
|
||
- On template selection, pre-fill line items, services, default descriptions.
|
||
- Prompt user to enter client-specific pricing/quantities before finalizing.
|
||
- Handle optional template metadata hints (e.g., recommended billing cadence) in the UI.
|
||
- Split the contract detail surface into dedicated components:
|
||
- [x] `ContractTemplateDetail.tsx` focused on template metadata, line composition, and recommended usage notes.
|
||
- [ ] `ClientContractDetail.tsx` focused on client-specific terms (billing cycles, PO info, assignments) with clear linkage back to the originating template.
|
||
- Update routing so the Billing Dashboard chooses the appropriate detail component based on whether the record is a template or a client assignment, and provide navigation between the two where relevant.
|
||
- Refresh jest/react-testing-library coverage for wizards (`server/src/components/billing-dashboard/contracts/__tests__/`).
|
||
|
||
## Phase 4 – Data Migration & Backfill
|
||
**Goals:** Move existing pricing data from templates to client contracts and link instances to their originating templates.
|
||
|
||
- [x] Author migration script in `server/scripts/contract-template-decoupling.ts`:
|
||
- For each `client_contract` referencing a `contract_id`, set `template_contract_id`.
|
||
- For each `client_contract_line`, set `template_contract_line_id`.
|
||
- Copy pricing fields from template tables into new client-instance tables: `contract_line_fixed_config.base_rate`, `contract_line_services.quantity/custom_rate`, `contract_line_service_bucket_config.total_minutes/overage_rate`, hourly configs, usage configs, and discount links.
|
||
- Populate `client_contract_line_pricing` using data from `contract_line_mappings.custom_rate` and fixed-config fallbacks; ensure historical overrides preserved.
|
||
- Null out or remove template pricing columns once client data is populated, leaving only optional defaults.
|
||
- Provide dry-run mode and logging (tenant ID, contract ID counts).
|
||
- Write verification queries (appendix) to ensure no non-null pricing remains on templates.
|
||
- Coordinate deployment window; run migration in staging then production.
|
||
|
||
## Phase 5 – QA, Rollout, & Monitoring
|
||
**Goals:** Validate functionality end-to-end and ensure stability after launch.
|
||
|
||
- Manual QA checklist:
|
||
- Create new template, apply to new client contract, confirm pricing only captured in client contract.
|
||
- Update template and ensure existing client contracts unaffected.
|
||
- Regression test billing runs/invoice generation.
|
||
- Automation updates:
|
||
- Extend Playwright flow `ee/server/src/__tests__/integration/contract-wizard-happy-path.playwright.test.ts` to cover template selection.
|
||
- Update Cypress/Playwright dashboards (if any) to reflect new UI navigation.
|
||
- Monitoring:
|
||
- Add logs/metrics in contract creation endpoints to monitor template usage.
|
||
- Add alert if billing engine encounters template pricing (should be null).
|
||
- Launch plan:
|
||
- Enable feature flag `billing.contractTemplatesV2` for internal tenants first.
|
||
- Roll out to all tenants after one billing cycle.
|
||
|
||
## Appendix
|
||
- **Schema Change Checklist:**
|
||
- Add Knex migration files covering forward changes and matching rollback scripts.
|
||
- Create SQL migrations for production deployment (`shared/db/migrations/20251020120000_contract_template_overhaul.sql`).
|
||
- Add rollback scripts in `shared/db/migrations/rollback/`.
|
||
- **Documentation:**
|
||
- Update `docs/billing.md` and `docs/overview.md` sections on contracts.
|
||
- Add how-to guide under `ee/docs/guides/contract-templates.md` once implemented.
|
||
- **Decisions (2025-02-14):**
|
||
- No third-party integrations currently ingest template pricing fields. Code search across `sdk/*`, `shared/**/*`, and enterprise services shows `contract_line_mappings.custom_rate` is only read by internal billing engines, reports, and UI controllers (`server/src/lib/reports/definitions/contracts/*.ts`, `server/src/lib/api/services/ContractLineService.ts`). Safe to migrate pricing without breaking external consumers; document in release notes for partners.
|
||
- Contract template metadata will include a `recommended_services` array (service IDs plus optional notes) alongside UI hint fields in `template_metadata`. Wizard will surface these recommendations when initializing client contracts, while actual service bundling remains client-specific via `client_contract_services`.
|