Hermes 284313f908
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
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

1938 lines
153 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Scratchpad — Contract Auto-Renewal and Renewals Queue
- Plan slug: `contract-auto-renewal-and-renewals-queue`
- Created: `2026-02-21`
## What This Is
Rolling implementation memory for renewal settings + actionable renewals queue + automation ticketing.
## Decisions
- (2026-02-21) Build an **actionable queue** (not read-only report).
- (2026-02-21) Ship **both** dashboard entry and full queue page (`Client Contracts` widget + `Renewals` tab).
- (2026-02-21) Primary operational date is **renewal decision due date**.
- (2026-02-21) Due-date behavior is configurable with **tenant defaults + optional per-contract override**.
- (2026-02-21) Default automation target at due date: **create internal ticket**.
- (2026-02-21) Minimum queue actions for v1: `Mark renewing`, `Mark non-renewing`, `Create renewal draft`, `Snooze`.
- (2026-02-21) Default queue horizon: **90 days**, grouped `0-30`, `31-60`, `61-90`.
- (2026-02-21) Queue includes **fixed-term + evergreen anniversaries**.
- (2026-02-21) `Mark renewing` should **auto-create renewal draft** and open it.
- (2026-02-21) Release approach: **single release** scope.
- (2026-02-21) Automation runtime note: support **pg-boss for on-prem** and **Temporal for hosted/EE**.
## Discoveries / Constraints
- (2026-02-21) Runtime selection already exists in `server/src/lib/jobs/JobRunnerFactory.ts` with config/env-based choice and fallback behavior; default is pg-boss unless configured otherwise.
- (2026-02-21) Existing scheduled jobs in `server/src/lib/jobs/initializeScheduledJobs.ts` explicitly branch for enterprise/temporal behavior in some paths; renewal automation should follow same compatibility pattern.
- (2026-02-21) Contract lifecycle already emits `CONTRACT_CREATED` and `CONTRACT_RENEWAL_UPCOMING` in both `packages/clients/src/actions/clientContractActions.ts` and `packages/billing/src/actions/contractWizardActions.ts`.
- (2026-02-21) `CONTRACT_RENEWAL_UPCOMING` computation today is window-based (`DEFAULT_CONTRACT_RENEWAL_UPCOMING_WINDOW_DAYS = 30`) in `shared/workflow/streams/domainEventBuilders/contractEventBuilders.ts`; queue design requires broader 90-day horizon and due-date semantics.
- (2026-02-21) Existing contract expiration report is currently `end_date`-driven (`packages/billing/src/actions/contractReportActions.ts`, `server/src/lib/reports/definitions/contracts/expiration.ts`).
- (2026-02-21) Billing settings already provide tenant defaults in `default_billing_settings` with client override pattern in `client_billing_settings`; actions in `packages/billing/src/actions/billingSettingsActions.ts` and shared helpers in `shared/billingClients/billingSettings.ts` are reusable design patterns.
- (2026-02-21) Billing UI insertion points are clear:
- tabs config: `packages/billing/src/components/billing-dashboard/billingTabsConfig.ts`
- tab content host: `packages/billing/src/components/billing-dashboard/BillingDashboard.tsx`
- queue/widget host: `packages/billing/src/components/billing-dashboard/contracts/ClientContractsTab.tsx`
- wizard basics: `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx`
- (2026-02-21) Contract assignment data shape in `server/src/interfaces/contract.interfaces.ts` is assignment-level and suitable for renewal metadata on `IClientContract`.
## Commands / Runbooks
- (2026-02-21) Inspect billing dashboard contract files:
- `rg -n "ContractWizard|ClientContractsTab|billingTabsConfig|ContractBasicsStep" packages/billing/src/components/billing-dashboard`
- (2026-02-21) Inspect runtime selection + scheduling:
- `rg -n "JobRunnerFactory|initializeScheduledJobs|EDITION|JOB_RUNNER_TYPE" server/src/lib/jobs`
- (2026-02-21) Inspect contract renewal event publishing:
- `rg -n "CONTRACT_RENEWAL_UPCOMING|computeContractRenewalUpcoming" packages/billing packages/clients shared/workflow`
- (2026-02-21) Validate plan artifacts:
- `python3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/validate_plan.py ee/docs/plans/2026-02-21-contract-auto-renewal-and-renewals-queue`
## Links / References
- Key plan path: `ee/docs/plans/2026-02-21-contract-auto-renewal-and-renewals-queue`
- Runtime selection: `server/src/lib/jobs/JobRunnerFactory.ts`
- Scheduled job init: `server/src/lib/jobs/initializeScheduledJobs.ts`
- Job scheduler infra: `server/src/lib/jobs/jobScheduler.ts`
- Renewal event builders: `shared/workflow/streams/domainEventBuilders/contractEventBuilders.ts`
- Contract wizard save path: `packages/billing/src/actions/contractWizardActions.ts`
- Client contract actions: `packages/clients/src/actions/clientContractActions.ts`
- Billing settings actions: `packages/billing/src/actions/billingSettingsActions.ts`
- Billing settings shared helpers: `shared/billingClients/billingSettings.ts`
- Billing dashboard tabs host: `packages/billing/src/components/billing-dashboard/BillingDashboard.tsx`
- Client contracts tab: `packages/billing/src/components/billing-dashboard/contracts/ClientContractsTab.tsx`
- Wizard basics step: `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx`
## Implementation Log
- (2026-02-21) Completed `F001`.
- Added renewal fields to `ContractWizardData` in `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.tsx`:
- `renewal_mode?: 'none' | 'manual' | 'auto'`
- `notice_period_days?: number`
- `renewal_term_months?: number`
- `use_tenant_renewal_defaults?: boolean`
- Rationale: establish typed wizard-state shape early so subsequent UI rendering, defaults/hydration, validation, and submission features can build on stable field names.
- (2026-02-21) Completed `T001`.
- Added `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts`.
- Test covers type-level contract for the four renewal fields and validates the allowed `renewal_mode` domain values.
- Runbook:
- `npx vitest run packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts`
- (2026-02-21) Completed `F002`.
- Added `createDefaultContractWizardData()` in `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.tsx`.
- Renewal defaults for new contracts now initialize as:
- `renewal_mode: 'manual'`
- `notice_period_days: 30`
- `renewal_term_months: undefined`
- `use_tenant_renewal_defaults: true`
- Updated wizard initialization/reset paths to use the shared factory, keeping default behavior deterministic across first render, open/reset, and edit-merge flows.
- (2026-02-21) Completed `T002`.
- Extended `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts` with default-state assertions using `createDefaultContractWizardData()`.
- Validates default renewal state for new contracts: mode `manual`, notice `30`, no term months, tenant-default toggle enabled.
- (2026-02-21) Completed `F003`.
- Extended `DraftContractWizardData` in `packages/billing/src/actions/contractWizardActions.ts` with renewal fields.
- Updated `getDraftContractForResume` to hydrate renewal settings from `client_contracts`:
- normalized `renewal_mode` (`none|manual|auto`)
- sanitized integer `notice_period_days` (non-negative)
- sanitized positive integer `renewal_term_months`
- hydrated `use_tenant_renewal_defaults` when boolean
- Rationale: resumed drafts now carry renewal metadata into `editingContract` so wizard state merge can restore renewal settings.
- (2026-02-21) Completed `T003`.
- Added `packages/billing/src/actions/contractWizardActions.renewalDraftResumeWiring.test.ts`.
- Test validates:
- renewal fields are present on `DraftContractWizardData`,
- `getDraftContractForResume` returns hydrated renewal values,
- numeric renewal values are sanitized before payload return.
- (2026-02-21) Completed `F004`.
- Added `buildInitialContractWizardData(editingContract)` in `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.tsx`.
- Edit-mode initialization now explicitly normalizes renewal fields during hydration:
- validates `renewal_mode` domain,
- normalizes non-negative `notice_period_days`,
- normalizes positive `renewal_term_months`,
- preserves explicit boolean `use_tenant_renewal_defaults`.
- Wired both initial state and open-effect initialization to use this shared edit-hydration path.
- (2026-02-21) Completed `T004`.
- Extended `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts`.
- Added assertions proving edit hydration path uses `buildInitialContractWizardData(editingContract)` and renewal normalization helpers for mode/notice/term.
- (2026-02-21) Completed `F005`.
- Added a fixed-term renewal UI container to `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx`.
- New `Renewal Settings` card renders only when `data.end_date` is present (`data-automation-id=\"renewal-settings-fixed-term-card\"`).
- (2026-02-21) Completed `T005`.
- Added `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.renewalCards.test.ts`.
- Test asserts fixed-term card conditional wiring on `data.end_date` and verifies the automation id/heading token.
- (2026-02-21) Completed `F006`.
- Added evergreen variant UI in `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx`.
- New `Evergreen Review Settings` card renders when `data.end_date` is absent (`data-automation-id=\"renewal-settings-evergreen-card\"`).
- (2026-02-21) Completed `T006`.
- Extended `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.renewalCards.test.ts` with evergreen-card assertions.
- Verifies absent-end-date branch and `renewal-settings-evergreen-card` wiring.
- (2026-02-21) Completed `F007`.
- Added renewal mode selector UI to both fixed-term and evergreen renewal cards in `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx`.
- Options now explicitly include `none`, `manual`, and `auto`, bound to `data.renewal_mode`.
- (2026-02-21) Completed `T007`.
- Extended `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.renewalCards.test.ts`.
- Added assertions for `renewalModeOptions` values (`none|manual|auto`) and `updateData` binding back to `renewal_mode`.
- (2026-02-21) Completed `F008`.
- Added `Notice Period (Days)` input to both renewal cards in `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx`.
- Input is conditionally rendered only when renewal mode is enabled (`manual` or `auto`), with non-negative integer coercion on change.
- (2026-02-21) Completed `T008`.
- Extended `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.renewalCards.test.ts` with notice-period assertions.
- Confirms `isRenewalEnabled` gate and both notice input IDs (`fixed` and `evergreen`) are present in the renewal-enabled branch.
- (2026-02-21) Completed `F009`.
- Added auto-renew specific `Renewal Term (Months)` inputs to fixed-term and evergreen renewal cards in `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx`.
- Input is gated by `isAutoRenew` and writes sanitized positive integer values to `renewal_term_months`.
- (2026-02-21) Completed `F010`.
- Confirmed auto-renew term controls are hidden unless `effectiveRenewalMode === 'auto'` via `isAutoRenew` conditional rendering in `ContractBasicsStep.tsx`.
- (2026-02-21) Completed `T009`.
- Extended `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.renewalCards.test.ts` with auto-term wiring assertions.
- Verifies both term input IDs and positive-integer assignment path for `renewal_term_months`.
- (2026-02-21) Completed `T010`.
- Added explicit `isAutoRenew` gating assertions in `ContractBasicsStep.renewalCards.test.ts`.
- Verifies auto-specific term controls are conditionally rendered only in `auto` mode.
- (2026-02-21) Completed `F011`.
- Added step-0 wizard validation in `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.tsx`:
- if `end_date` is set and `renewal_mode` is missing, progression is blocked with inline error.
- (2026-02-21) Completed `F012`.
- Added notice-period validation bounds in `ContractWizard.tsx` (`MIN_NOTICE_PERIOD_DAYS=0`, `MAX_NOTICE_PERIOD_DAYS=3650`).
- Step-0 validation now requires notice period to be an integer and within bounds whenever renewal mode is enabled.
- (2026-02-21) Completed `F013`.
- Added step-0 validation rule in `ContractWizard.tsx` requiring `renewal_term_months` to be a positive integer when provided.
- (2026-02-21) Completed `F014`.
- Renewal validation errors from step-0 rules (`F011`-`F013`) now surface through the wizards existing inline step error panel before progression.
- (2026-02-21) Completed `T011`.
- Extended `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts` with assertions for required renewal mode when `end_date` is set.
- (2026-02-21) Completed `T012`.
- Marked covered by the same `ContractWizard.renewalFields.test.ts` additions that assert notice-period integer/bounds validation wiring.
- (2026-02-21) Completed `T013`.
- Marked covered by existing `ContractWizard.renewalFields.test.ts` assertions for positive renewal-term validation when value is provided.
- (2026-02-21) Completed `T014`.
- Marked covered by existing `ContractWizard.renewalFields.test.ts` assertion that inline step error rendering (`errors[currentStep]`) is present for renewal validation failures.
- (2026-02-21) Completed `F015`.
- Extended `ContractBasicsStep` summary alert to include renewal preview fields:
- renewal mode label,
- notice period (for renewal-enabled modes),
- renewal term months (auto-renew mode).
- (2026-02-21) Completed `F016`.
- Extended `ReviewContractStep` “Contract Basics” card to preview renewal fields before submit:
- renewal mode,
- notice period,
- renewal term (auto mode).
- (2026-02-21) Completed `F017`.
- Added renewal fields to `ClientContractWizardSubmission` (`packages/billing/src/actions/contractWizardActions.ts`).
- Updated `buildSubmissionData()` in `ContractWizard.tsx` to include renewal mode, notice period, renewal term, and tenant-default toggle in outgoing wizard payload.
- (2026-02-21) Completed `F018`.
- Updated `createClientContractFromWizard` insert path for `client_contracts` to persist renewal fields.
- Added schema-compat guards (`hasColumn`) so renewal columns are written when available without breaking pre-migration environments.
- (2026-02-21) Completed `T015`.
- Extended `ContractBasicsStep.renewalCards.test.ts` to assert renewal mode/notice/term rows are present in the Contract Basics summary preview.
- (2026-02-21) Completed `T016`.
- Added `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ReviewContractStep.renewalPreview.test.ts`.
- Test covers renewal preview rows and mode-gated rendering conditions in the review step.
- (2026-02-21) Completed `T017`.
- Extended `ContractWizard.renewalFields.test.ts` to assert `buildSubmissionData()` includes all renewal fields in outgoing wizard payload.
- (2026-02-21) Completed `T018`.
- Extended `contractWizardActions.renewalDraftResumeWiring.test.ts` to assert draft/client save path writes renewal fields into `client_contracts` with schema-guarded `hasColumn` checks.
- (2026-02-21) Completed `F019`.
- Extended tenant default billing settings model surface in `packages/billing/src/actions/billingSettingsActions.ts` and `server/src/interfaces/billing.interfaces.ts` with renewal-default fields (including default renewal mode) using schema-guarded writes for compatibility.
- (2026-02-21) Completed `F020`.
- Included `defaultNoticePeriodDays` mapping (`default_notice_period_days`) in tenant default billing settings model and guarded write path.
- (2026-02-21) Completed `F021`.
- Included `renewalDueDateActionPolicy` mapping (`renewal_due_date_action_policy`) with normalized fallback in tenant billing settings model.
- (2026-02-21) Completed `F022`.
- Included tenant default renewal ticket board field mapping (`renewal_ticket_board_id`) in billing settings model/read-write path.
- (2026-02-21) Completed `F023`.
- Included tenant default renewal ticket status field mapping (`renewal_ticket_status_id`) in billing settings model/read-write path.
- (2026-02-21) Completed `F024`.
- Included tenant default renewal ticket priority field mapping (`renewal_ticket_priority`) in billing settings model/read-write path.
- (2026-02-21) Completed `F025`.
- Included tenant default renewal ticket assignee field mapping (`renewal_ticket_assignee_id`) in billing settings model/read-write path.
- (2026-02-21) Completed `F026`.
- `getDefaultBillingSettings` now returns renewal default fields (mode, notice days, due-date policy, ticket routing defaults) with deterministic fallbacks.
- (2026-02-21) Completed `F027`.
- `updateDefaultBillingSettings` now writes renewal default fields via schema-guarded update/insert payloads.
- (2026-02-21) Completed `T019`.
- Added `packages/billing/src/actions/billingSettingsActions.renewalDefaultsWiring.test.ts` and marked renewal-mode model coverage.
- (2026-02-21) Completed `T020`.
- Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for `defaultNoticePeriodDays`.
- (2026-02-21) Completed `T021`.
- Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for `renewalDueDateActionPolicy`.
- (2026-02-21) Completed `T022`.
- Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for `renewalTicketBoardId`.
- (2026-02-21) Completed `T023`.
- Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for `renewalTicketStatusId`.
- (2026-02-21) Completed `T024`.
- Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for `renewalTicketPriority`.
- (2026-02-21) Completed `T025`.
- Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for `renewalTicketAssigneeId`.
- (2026-02-21) Completed `T026`.
- Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for `getDefaultBillingSettings` renewal default response mapping.
- (2026-02-21) Completed `T027`.
- Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for schema-guarded renewal default persistence in update writes.
- (2026-02-21) Completed `T028`.
- Extended renewal UI/source tests to assert `Use Tenant Renewal Defaults` toggle controls and payload field wiring (`use_tenant_renewal_defaults`).
- (2026-02-21) Completed `T029`.
- Covered by `ContractWizard.renewalFields.test.ts` assertions that tenant defaults are applied in submission resolution when toggle is enabled.
- (2026-02-21) Completed `T030`.
- Covered by `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts` assertion:
- `prefers explicit contract override values when tenant defaults are disabled`.
- Validation run:
- `cd server && npx vitest run --coverage.enabled=false ../packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts`
- (2026-02-21) Completed `T031`.
- Covered by `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts` assertion:
- `uses deterministic fallback precedence for partial override/default state`.
- Validation run:
- `cd server && npx vitest run --coverage.enabled=false ../packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts`
- (2026-02-21) Completed `F028`.
- Added explicit `Use Tenant Renewal Defaults` toggle controls to both fixed-term and evergreen renewal settings cards in `ContractBasicsStep.tsx`, bound to `use_tenant_renewal_defaults`.
- (2026-02-21) Completed `F029`.
- Updated `buildSubmissionData()` in `ContractWizard.tsx` to resolve renewal mode + notice period from tenant defaults when `use_tenant_renewal_defaults` is enabled.
- (2026-02-21) Completed `F030`.
- Submission resolution now prefers explicit contract-level renewal values when `use_tenant_renewal_defaults` is disabled.
- (2026-02-21) Completed `F031`.
- Implemented deterministic renewal fallback order in submission resolution:
- explicit contract values (when overrides enabled),
- tenant defaults,
- hard defaults (`manual`, `30`).
- (2026-02-21) Completed `F032`.
- Extended contract-assignment read APIs to expose normalized/effective renewal settings in both shared and clients data-access layers:
- `shared/billingClients/clientContracts.ts`
- `packages/clients/src/models/clientContract.ts`
- Added schema-guarded tenant-default joins (`default_billing_settings`) for read paths and computed:
- `effective_renewal_mode`
- `effective_notice_period_days`
- Added type surface fields on `IClientContract` in:
- `packages/types/src/interfaces/contract.interfaces.ts`
- `server/src/interfaces/contract.interfaces.ts`
- Validation run:
- `npm -w @alga-psa/shared run typecheck`
- `npm -w @alga-psa/clients run typecheck`
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts`
- (2026-02-21) Completed `F033`.
- Added fixed-term `decision_due_date` computation in assignment normalization paths:
- `shared/billingClients/clientContracts.ts`
- `packages/clients/src/models/clientContract.ts`
- Formula implemented with date-only semantics for fixed-term contracts:
- `decision_due_date = end_date - effective_notice_period_days`
- Added `decision_due_date` to contract interfaces:
- `packages/types/src/interfaces/contract.interfaces.ts`
- `server/src/interfaces/contract.interfaces.ts`
- Expanded test coverage in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`.
- (2026-02-21) Completed `F034`.
- Added evergreen annual-review anchor computation based on contract start-date anniversary rules.
- New shared helper:
- `computeNextEvergreenReviewAnchorDate` in `shared/billingClients/clientContracts.ts`
- Exposed normalized field on active evergreen assignments:
- `evergreen_review_anchor_date`
- Mirrored logic in clients model read normalization for parity:
- `packages/clients/src/models/clientContract.ts`
- Expanded tests in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`.
- (2026-02-21) Completed `F035`.
- Added evergreen `decision_due_date` computation from annual anchor minus effective notice period.
- New shared helper:
- `computeEvergreenDecisionDueDate` in `shared/billingClients/clientContracts.ts`
- Applied in both read normalization paths (shared + clients model) so evergreen assignments now expose date-only `decision_due_date`.
- Expanded deterministic date-math coverage in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`.
- (2026-02-21) Completed `F036`.
- Confirmed and codified date-only normalization for `decision_due_date` math using `normalizeDateOnly` + UTC midnight subtraction paths.
- Added regression test proving timestamp `end_date` inputs are normalized to date-only before subtraction:
- `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`
- (2026-02-21) Completed `F037`.
- Confirmed `decision_due_date` recalculates from current assignment state when fixed-term `end_date` changes.
- Added regression coverage:
- `recomputes fixed-term decision_due_date when end_date changes`
- in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`
- (2026-02-21) Completed `F038`.
- Confirmed fixed-term `decision_due_date` recalculates when notice period changes.
- Added regression coverage:
- `recomputes fixed-term decision_due_date when notice period changes`
- in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`
- (2026-02-21) Completed `F039`.
- Made `decision_due_date` generation renewal-mode-aware in read normalization:
- mode `none` suppresses due date generation for non-evergreen entries.
- Added regression coverage for mode transitions:
- `recomputes decision_due_date when renewal mode changes between none/manual/auto`
- in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`
- (2026-02-21) Completed `F040`.
- Confirmed evergreen `decision_due_date` recomputes when anniversary anchor basis changes (start-date basis change).
- Added deterministic coverage:
- `recomputes evergreen decision_due_date when anniversary anchor basis changes`
- in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`
- (2026-02-21) Completed `F041`.
- Added lifecycle suppression in due-date normalization:
- no `decision_due_date` generation for inactive, terminated, or expired assignment/contract lifecycle state.
- Included `contract_status` from joined contract reads in shared/clients assignment APIs to enforce lifecycle gating.
- Added regression test:
- `skips decision_due_date generation for inactive/terminated assignments`
- in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`
- (2026-02-21) Completed `F042`.
- Verified suppression path for `renewal_mode = none` when no evergreen anchor is available (e.g. fixed-term assignment) remains enforced.
- Covered by existing regression test:
- `recomputes decision_due_date when renewal mode changes between none/manual/auto`
- in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`
- (2026-02-21) Completed `F043`.
- Added derived per-cycle dedupe key in read normalization:
- `renewal_cycle_key` (`fixed-term:<end_date>` or `evergreen:<anchor_date>`)
- Exposed in both shared and clients assignment APIs plus contract interfaces.
- Added regression coverage:
- `creates one renewal_cycle_key per computed contract cycle for deduplication`
- in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`
- (2026-02-21) Completed `F044`.
- Added deterministic dedupe guard for active assignment rows by composite key:
- `tenant + client_contract_id + renewal_cycle_key`
- Applied dedupe in list read APIs:
- `shared/billingClients/clientContracts.ts`
- `packages/clients/src/models/clientContract.ts`
- Added regression test:
- `deduplicates active rows by tenant + client_contract_id + renewal_cycle_key`
- in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`
- (2026-02-21) Completed `F045`.
- Added explicit cycle boundary fields in normalization:
- `renewal_cycle_start`
- `renewal_cycle_end`
- Fixed-term boundaries map directly to assignment `start_date`/`end_date`.
- Evergreen boundaries now use annual cycle bounds helper:
- `computeEvergreenCycleBounds` in `shared/billingClients/clientContracts.ts`
- Added deterministic coverage in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`.
- (2026-02-21) Completed `F046`.
- Added derived `days_until_due` field to assignment normalization and contract interfaces.
- New date-only helper:
- `computeDaysUntilDate` in `shared/billingClients/clientContracts.ts`
- Added deterministic coverage for positive/negative day deltas and normalized row field presence in:
- `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`
- (2026-02-21) Completed `F047`.
- Added clamp bounds to `days_until_due` derivation to preserve overdue visibility while preventing extreme negative/positive corruption:
- `MAX_ABSOLUTE_DAYS_UNTIL_DUE = 36500`
- Applied in shared and clients normalization helpers.
- Added deterministic clamp coverage in:
- `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`
- (2026-02-21) Completed `F048`.
- Added `renewals` tab value to billing tab union/config metadata in:
- `packages/billing/src/components/billing-dashboard/billingTabsConfig.ts`
- Added tab definition (`label=Renewals`, `href=/msp/billing?tab=renewals`) and icon mapping.
- Added coverage:
- `packages/billing/tests/billingTabsConfig.renewals.test.ts`
- (2026-02-21) Completed `F049`.
- Added `Tabs.Content value=\"renewals\"` route to billing dashboard tab host in:
- `packages/billing/src/components/billing-dashboard/BillingDashboard.tsx`
- Added initial placeholder content for the renewals route host.
- Added route-wiring coverage:
- `packages/billing/tests/BillingDashboard.renewalsRoute.test.ts`
- (2026-02-21) Completed `F050`.
- Added dedicated renewals queue page component:
- `packages/billing/src/components/billing-dashboard/contracts/RenewalsQueueTab.tsx`
- Updated `BillingDashboard` renewals route to render `<RenewalsQueueTab />`.
- Added component + wiring coverage:
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- `packages/billing/tests/BillingDashboard.renewalsRoute.test.ts`
- (2026-02-21) Completed `F051`.
- Added server action to load renewal queue rows:
- `packages/billing/src/actions/renewalsQueueActions.ts`
- Renewals page now calls `listRenewalQueueRows()` on mount via `useEffect` and renders loading/empty/error/data states.
- Exported renewals queue actions via:
- `packages/billing/src/actions/index.ts`
- Added wiring coverage:
- `packages/billing/tests/renewalsQueueActions.wiring.test.ts`
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- (2026-02-21) Completed `F052`.
- Added default 90-day horizon behavior to renewals queue loading:
- `DEFAULT_RENEWALS_HORIZON_DAYS = 90` in `renewalsQueueActions.ts`
- server-side filtering for `days_until_due` in range `[0, horizonDays]`
- Updated renewals UI copy to indicate default horizon window.
- Extended wiring coverage in:
- `packages/billing/tests/renewalsQueueActions.wiring.test.ts`
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- (2026-02-21) Completed `F053`.
- Added renewals queue bucket quick filters in `RenewalsQueueTab`:
- `All`, `0-30 Days`, `31-60 Days`, `61-90 Days`
- Implemented client-side bucket filtering against `days_until_due`.
- Extended component coverage in:
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- (2026-02-21) Completed `F054`.
- Added owner filter UI + behavior in `RenewalsQueueTab`:
- owner options derive from queue row `assigned_to` values with `unassigned` fallback.
- Extended queue row shape from server action with `assigned_to`.
- Added wiring coverage updates in:
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- `packages/billing/tests/renewalsQueueActions.wiring.test.ts`
- (2026-02-21) Completed `F055`.
- Added queue status mapping + filter support for:
- `pending`, `renewing`, `non_renewing`, `snoozed`, `completed`
- Added status filter UI + filtering behavior in `RenewalsQueueTab`.
- Extended action/component wiring coverage in:
- `packages/billing/tests/renewalsQueueActions.wiring.test.ts`
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- (2026-02-21) Completed `F056`.
- Added renewal mode filter support in queue UI for:
- `none`, `manual`, `auto`
- Queue row mapping already includes `effective_renewal_mode`; UI filtering now applies this dimension.
- Extended action/component wiring coverage in:
- `packages/billing/tests/renewalsQueueActions.wiring.test.ts`
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- (2026-02-21) Completed `F057`.
- Added contract type filter support in queue UI for:
- `fixed-term`, `evergreen`
- Filter operates on queue row `contract_type`.
- Extended component wiring coverage in:
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- (2026-02-21) Completed `F058`.
- Enforced default queue sort by `decision_due_date` ascending in renewals list action.
- Sorting now occurs after normalization/horizon filtering in:
- `packages/billing/src/actions/renewalsQueueActions.ts`
- Added wiring coverage update in:
- `packages/billing/tests/renewalsQueueActions.wiring.test.ts`
- (2026-02-21) Completed `F059`.
- Added days-remaining visual badge state logic in queue rows:
- `overdue`, `due-soon`, `upcoming`
- Rendering now surfaces overdue and due-soon emphasis states via row badge styles.
- Added component coverage update in:
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- (2026-02-21) Completed `F060`.
- Added `Upcoming Renewals` summary widget to `ClientContractsTab` with queue-derived total count.
- Widget data source now loads via `listRenewalQueueRows()` during tab fetch flow.
- Added coverage:
- `packages/billing/tests/ClientContractsTab.upcomingRenewalsWidget.test.ts`
- (2026-02-21) Completed `F061`.
- Updated `Upcoming Renewals` widget to display 90-day bucket counts:
- `0-30`, `31-60`, `61-90`
- Counts now derive from renewal queue row `days_until_due`.
- Added coverage update in:
- `packages/billing/tests/ClientContractsTab.upcomingRenewalsWidget.test.ts`
- (2026-02-21) Completed `F062`.
- Added widget-to-queue navigation with preserved bucket context in:
- `packages/billing/src/components/billing-dashboard/contracts/ClientContractsTab.tsx`
- Bucket count badges now route to:
- `/msp/billing?tab=renewals&bucket=0-30|31-60|61-90`
- Added queue hydration from URL bucket query param in:
- `packages/billing/src/components/billing-dashboard/contracts/RenewalsQueueTab.tsx`
- Added/updated coverage in:
- `packages/billing/tests/ClientContractsTab.upcomingRenewalsWidget.test.ts`
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/ClientContractsTab.upcomingRenewalsWidget.test.ts tests/RenewalsQueueTab.component.test.ts`
- (2026-02-21) Completed `F063`.
- Added queue-to-widget refresh wiring in billing dashboard:
- `packages/billing/src/components/billing-dashboard/BillingDashboard.tsx`
- `BillingDashboard` now increments `renewalsQueueRefreshTrigger` when renewals queue refreshes after mutation pathways.
- Passed refresh trigger into `ClientContractsTab` so upcoming renewals bucket counts are recomputed.
- `RenewalsQueueTab` now accepts `onQueueMutationComplete` and emits it after successful queue row reloads:
- `packages/billing/src/components/billing-dashboard/contracts/RenewalsQueueTab.tsx`
- Added wiring coverage in:
- `packages/billing/tests/BillingDashboard.renewalsRoute.test.ts`
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts`
- (2026-02-21) Completed `F064`.
- Defined centralized renewal queue status enum in shared contract interfaces:
- `packages/types/src/interfaces/contract.interfaces.ts`
- `server/src/interfaces/contract.interfaces.ts`
- Added renewal work-item interface model (`IClientContractRenewalWorkItem`) with `status: RenewalWorkItemStatus`.
- Updated queue row model/status normalization to consume `RenewalWorkItemStatus` from shared types:
- `packages/billing/src/actions/renewalsQueueActions.ts`
- Updated wiring coverage:
- `packages/billing/tests/renewalsQueueActions.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts tests/RenewalsQueueTab.component.test.ts`
- `npm -w @alga-psa/server run typecheck` (workspace alias not present in root workspaces)
- (2026-02-21) Completed `F065`.
- Added queue mutation action to transition pending work items to renewing:
- `markRenewalQueueItemRenewing(clientContractId)` in `packages/billing/src/actions/renewalsQueueActions.ts`
- Transition behavior:
- validates required `clientContractId`
- enforces tenant-scoped active row lookup
- requires current status to resolve as `pending`
- updates status to `renewing` and writes `updated_at`
- Added mutation response payload shape:
- `RenewalQueueMutationResult`
- Added/updated wiring coverage:
- `packages/billing/tests/renewalsQueueActions.wiring.test.ts`
- `packages/billing/tests/renewalsQueueActions.markRenewing.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts tests/renewalsQueueActions.markRenewing.wiring.test.ts`
- (2026-02-21) Completed `F066`.
- Added queue mutation action to transition pending work items to non-renewing:
- `markRenewalQueueItemNonRenewing(clientContractId)` in `packages/billing/src/actions/renewalsQueueActions.ts`
- Transition behavior mirrors mark-renewing safeguards:
- validates required `clientContractId`
- verifies status column availability
- enforces tenant-scoped active row lookup
- requires current status to resolve as `pending`
- updates status to `non_renewing` and writes `updated_at`
- Added wiring coverage:
- `packages/billing/tests/renewalsQueueActions.markNonRenewing.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewing.wiring.test.ts`
- (2026-02-21) Completed `F067`.
- Added renewal draft action for eligible queue entries:
- `createRenewalDraftForQueueItem(clientContractId)` in `packages/billing/src/actions/renewalsQueueActions.ts`
- Action behavior:
- requires non-empty `clientContractId`
- resolves eligible statuses to `pending|renewing` only
- creates a new draft contract + draft client contract assignment
- reuses existing linked draft when `created_draft_contract_id` is already present and valid
- links original row via `created_draft_contract_id` when column exists
- Added response type:
- `RenewalDraftCreationResult`
- Added wiring coverage:
- `packages/billing/tests/renewalsQueueActions.createDraft.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewing.wiring.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts`
- (2026-02-21) Completed `F068`.
- Added snooze mutation action:
- `snoozeRenewalQueueItem(clientContractId, snoozedUntil)` in `packages/billing/src/actions/renewalsQueueActions.ts`
- Action behavior:
- validates required `clientContractId` + `snoozedUntil`
- verifies `status` + `snoozed_until` columns exist
- normalizes `snoozed_until` to date-only (`YYYY-MM-DD`)
- blocks snoozing from terminal statuses (`completed`, `non_renewing`)
- updates status to `snoozed` and returns `RenewalSnoozeResult`
- Added wiring coverage:
- `packages/billing/tests/renewalsQueueActions.snooze.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.snooze.wiring.test.ts tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewing.wiring.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts`
- (2026-02-21) Completed `F069`.
- Added assign-owner mutation action:
- `assignRenewalQueueItemOwner(clientContractId, assignedTo)` in `packages/billing/src/actions/renewalsQueueActions.ts`
- Action behavior:
- validates required `clientContractId`
- allows `assignedTo` as user id string or `null` (unassign)
- verifies `status` + `assigned_to` columns exist
- updates `assigned_to` with tenant-scoped row filtering
- returns `RenewalAssignmentResult` with current status + updated timestamp
- Added wiring coverage:
- `packages/billing/tests/renewalsQueueActions.assignOwner.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.assignOwner.wiring.test.ts tests/renewalsQueueActions.snooze.wiring.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts`
- (2026-02-21) Completed `F070`.
- Added automatic unsnooze transition during queue list refresh in:
- `packages/billing/src/actions/renewalsQueueActions.ts`
- Behavior:
- checks `status` + `snoozed_until` columns
- moves eligible rows from `snoozed` to `pending` when `snoozed_until <= today`
- clears `snoozed_until` and updates `updated_at`
- Added wiring coverage:
- `packages/billing/tests/renewalsQueueActions.unsnooze.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.unsnooze.wiring.test.ts tests/renewalsQueueActions.wiring.test.ts tests/renewalsQueueActions.snooze.wiring.test.ts`
- (2026-02-21) Completed `F071`.
- Added actor audit persistence helper flow in renewal queue actions:
- `resolveActorUserId(user)`
- `withActionActor(updateData, hasLastActionByColumn, actorUserId)`
- User-initiated queue mutations now persist `last_action_by` when column exists:
- `markRenewalQueueItemRenewing`
- `markRenewalQueueItemNonRenewing`
- `createRenewalDraftForQueueItem`
- `snoozeRenewalQueueItem`
- `assignRenewalQueueItemOwner`
- Added wiring coverage:
- `packages/billing/tests/renewalsQueueActions.actorAudit.wiring.test.ts`
- Updated wiring expectations for mark actions:
- `packages/billing/tests/renewalsQueueActions.markRenewing.wiring.test.ts`
- `packages/billing/tests/renewalsQueueActions.markNonRenewing.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewing.wiring.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts tests/renewalsQueueActions.snooze.wiring.test.ts tests/renewalsQueueActions.assignOwner.wiring.test.ts`
- (2026-02-21) Completed `F072`.
- Added timestamp audit persistence helper in renewal queue actions:
- `withActionTimestamp(updateData, hasLastActionAtColumn, actionAt)`
- User-initiated queue mutations now persist `last_action_at` when column exists:
- `markRenewalQueueItemRenewing`
- `markRenewalQueueItemNonRenewing`
- `createRenewalDraftForQueueItem`
- `snoozeRenewalQueueItem`
- `assignRenewalQueueItemOwner`
- Added wiring coverage:
- `packages/billing/tests/renewalsQueueActions.timestampAudit.wiring.test.ts`
- Updated wiring expectations for mark/actor tests:
- `packages/billing/tests/renewalsQueueActions.markRenewing.wiring.test.ts`
- `packages/billing/tests/renewalsQueueActions.markNonRenewing.wiring.test.ts`
- `packages/billing/tests/renewalsQueueActions.actorAudit.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewing.wiring.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts tests/renewalsQueueActions.snooze.wiring.test.ts tests/renewalsQueueActions.assignOwner.wiring.test.ts`
- (2026-02-21) Completed `F073`.
- Added optional queue action note support across mutation actions:
- `markRenewalQueueItemRenewing(..., note?)`
- `markRenewalQueueItemNonRenewing(..., note?)`
- `createRenewalDraftForQueueItem(..., note?)`
- `snoozeRenewalQueueItem(..., note?)`
- `assignRenewalQueueItemOwner(..., note?)`
- Added note helpers:
- `normalizeActionNote(note)`
- `withActionNote(updateData, hasLastActionNoteColumn, note)`
- Mutations now persist `last_action_note` when column exists and note is non-empty.
- Added wiring coverage:
- `packages/billing/tests/renewalsQueueActions.noteAudit.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.noteAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewing.wiring.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts tests/renewalsQueueActions.snooze.wiring.test.ts tests/renewalsQueueActions.assignOwner.wiring.test.ts`
- (2026-02-21) Completed `F074`.
- Added explicit completed-status guard in automatic unsnooze pending-transition path:
- `packages/billing/src/actions/renewalsQueueActions.ts`
- Unsnooze update now includes:
- `.andWhereNot('status', 'completed')`
- This ensures completed work items never implicitly transition back to pending without an explicit reopen flow.
- Updated coverage:
- `packages/billing/tests/renewalsQueueActions.unsnooze.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.unsnooze.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts`
- (2026-02-21) Completed `F075`.
- Added explicit override guard to renewing transition:
- `markRenewalQueueItemRenewing` now rejects `previousStatus === 'non_renewing'` with an override-required error.
- This preserves strict non-renewal intent unless a dedicated override flow is implemented.
- Updated wiring coverage:
- `packages/billing/tests/renewalsQueueActions.markRenewing.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewing.wiring.test.ts`
- (2026-02-21) Completed `F076`.
- Added future-date enforcement for snooze action validation:
- `snoozeRenewalQueueItem` now rejects `snoozedUntil <= today`
- Added explicit error path:
- `Snooze target date must be in the future`
- Updated wiring coverage:
- `packages/billing/tests/renewalsQueueActions.snooze.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.snooze.wiring.test.ts tests/renewalsQueueActions.unsnooze.wiring.test.ts`
- (2026-02-21) Completed `F077`.
- Added row-level action availability model based on effective queue status:
- `RenewalQueueAction` union
- `getAvailableActionsForStatus(status)` in `packages/billing/src/actions/renewalsQueueActions.ts`
- `listRenewalQueueRows` now returns `available_actions` for each row.
- Renewals queue UI now surfaces available actions per row:
- `Actions: {row.available_actions.join(', ')}` in `packages/billing/src/components/billing-dashboard/contracts/RenewalsQueueTab.tsx`
- Updated coverage:
- `packages/billing/tests/renewalsQueueActions.wiring.test.ts`
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts tests/RenewalsQueueTab.component.test.ts`
- (2026-02-21) Completed `F078`.
- Added queue row action controls for:
- `Mark renewing`
- `Mark non-renewing`
- Implemented optimistic in-flight UI behavior in `RenewalsQueueTab`:
- per-row pending state map (`pendingRowActions`)
- immediate optimistic status/action updates before server response
- in-row pending indicator (`Updating action...`)
- action buttons disabled while row mutation is in-flight
- Mutation handlers call server actions:
- `markRenewalQueueItemRenewing`
- `markRenewalQueueItemNonRenewing`
- Updated coverage:
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts`
- (2026-02-21) Completed `F079`.
- Added targeted row refresh helper after successful mutation responses:
- `refreshQueueRowFromServer(clientContractId)` in `RenewalsQueueTab`
- Success path now refreshes only the affected row from server state:
- `await refreshQueueRowFromServer(rowId)`
- Fallback path still supports full refresh when row cannot be resolved.
- Updated coverage:
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/RenewalsQueueTab.component.test.ts`
- (2026-02-21) Completed `F080`.
- Extended renewal queue row model with draft linkage:
- `created_draft_contract_id?: string | null` in `RenewalQueueRow`
- Queue list action now maps draft linkage field from row source:
- `created_draft_contract_id: (row as any).created_draft_contract_id ?? null`
- Renewals queue UI now shows linked draft id when present:
- `Draft contract: {row.created_draft_contract_id}`
- Updated coverage:
- `packages/billing/tests/renewalsQueueActions.wiring.test.ts`
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts`
- (2026-02-21) Completed `F081`.
- Extended renewal queue row model with ticket linkage:
- `created_ticket_id?: string | null` in `RenewalQueueRow`
- Queue list action now maps ticket linkage:
- `created_ticket_id: (row as any).created_ticket_id ?? null`
- Renewals queue UI now shows linked ticket id when present:
- `Ticket: {row.created_ticket_id}`
- Updated coverage:
- `packages/billing/tests/renewalsQueueActions.wiring.test.ts`
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts tests/RenewalsQueueTab.component.test.ts`
- (2026-02-21) Completed `F082`.
- Added activation-confirmed completion action:
- `completeRenewalQueueItemForActivation(clientContractId, activatedContractId?, note?)`
- in `packages/billing/src/actions/renewalsQueueActions.ts`
- Completion rules:
- source work item must be `renewing`
- target renewal contract must exist with `status = active`
- on success, work item transitions to `completed` with audit metadata
- Added result type:
- `RenewalCompletionResult`
- Added wiring coverage:
- `packages/billing/tests/renewalsQueueActions.completeOnActivation.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.completeOnActivation.wiring.test.ts tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts`
- (2026-02-21) Completed `F083`.
- Added non-renewal finalization completion action:
- `completeRenewalQueueItemForNonRenewal(clientContractId, note?)`
- in `packages/billing/src/actions/renewalsQueueActions.ts`
- Completion rules:
- source work item must be `non_renewing`
- on success, work item transitions to `completed` with audit metadata
- Added wiring coverage:
- `packages/billing/tests/renewalsQueueActions.completeNonRenewal.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.completeNonRenewal.wiring.test.ts tests/renewalsQueueActions.completeOnActivation.wiring.test.ts`
- (2026-02-21) Completed `F084`.
- Added a scheduled renewal queue processor job handler:
- `processRenewalQueueHandler(data)` in `server/src/lib/jobs/handlers/processRenewalQueueHandler.ts`
- scans active contracts whose `decision_due_date` falls within `today..horizonDays`
- defaults horizon to `90` days and validates `tenantId`
- Registered new job name and scheduling helpers:
- pg-boss handler registration in `server/src/lib/jobs/index.ts`
- recurring scheduling helper `scheduleRenewalQueueProcessingJob(...)`
- tenant startup scheduling hook in `server/src/lib/jobs/initializeScheduledJobs.ts` (daily at `0 5 * * *`)
- abstraction-layer handler registration + available handler list in `server/src/lib/jobs/registerAllHandlers.ts`
- Added wiring test under included Vitest paths:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F085`.
- Extended renewal queue processor to upsert work-item state for newly eligible cycles:
- processor now loads active contract assignments, normalizes effective renewal state, and filters by computed `decision_due_date` within `today..horizon`
- upserts `decision_due_date`, `renewal_cycle_start`, `renewal_cycle_end`, and `renewal_cycle_key` when drift/new cycle is detected
- resets cycle-scoped linkage fields (`created_ticket_id`, `created_draft_contract_id`) when cycle key rolls
- normalizes unknown/invalid statuses (or cycle changes) back to `pending`
- Updated wiring coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F086`.
- Scheduled renewal processing now explicitly resolves tenant default due-date action policy:
- reads `default_billing_settings.renewal_due_date_action_policy` when available
- normalizes policy (`queue_only | create_ticket`) with deterministic fallback to `create_ticket`
- During upsert, processor applies tenant policy to work-item rows when contract-level policy column exists:
- updates `client_contracts.renewal_due_date_action_policy` to tenant effective value
- tracks policy distribution in logs (`queueOnlyPolicyCount`, `createTicketPolicyCount`)
- Updated wiring coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F087`.
- Scheduled renewal processing now applies contract-level due-date policy overrides with deterministic precedence:
- resolve `use_tenant_renewal_defaults` (default `true`)
- resolve contract-level policy from `client_contracts.renewal_due_date_action_policy` when valid
- compute effective policy as:
- tenant policy when `use_tenant_renewal_defaults = true`
- contract override when defaults are disabled and explicit contract policy exists
- tenant fallback when override is missing/invalid
- Processor now logs override utilization:
- `contractOverridePolicyCount`
- Updated wiring coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F088`.
- Added due-date ticket automation execution in renewal processor:
- computes `shouldCreateTicketAtDueDate` for eligible rows where:
- effective policy is `create_ticket`
- decision due date is due (`<= today`)
- no `created_ticket_id` is already linked
- builds renewal-context title/description payloads
- uses configured renewal routing defaults (board/status/priority/assignee) when present
- Processor now persists ticket linkage on success:
- `updates.created_ticket_id = createdTicketId`
- Added direct ticket-creation fallback path for resilience when workflow action execution is unavailable.
- Updated wiring coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F089`.
- Integrated renewal ticket automation with workflow runtime business action path:
- initializes runtime v2 action registry (`initializeWorkflowRuntimeV2`)
- resolves and invokes `tickets.create@v1` from `getActionRegistryV2`
- validates both input and output schemas via registered action definitions
- Retained direct-ticket fallback path when runtime action execution is unavailable/fails to keep automation robust.
- Updated wiring coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F090`.
- Added renewal ticket title builder with explicit client + contract context:
- `buildRenewalTicketTitle(row, decisionDueDate)`
- title shape: `Renewal Decision Due {date}: {clientName} / {contractName}`
- Renewal automation now uses this title for both workflow-action and direct-fallback ticket creation paths.
- Updated wiring coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F091`.
- Added renewal ticket description builder with due-date + renewal-settings context:
- `buildRenewalTicketDescription(row, normalized, decisionDueDate)`
- includes decision due date, effective renewal mode, effective notice period, and cycle key metadata
- Renewal automation now uses this description for workflow-action and direct-fallback ticket creation paths.
- Updated wiring coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F092`.
- Renewal ticket routing now uses effective defaults with tenant/contract precedence:
- tenant defaults from `default_billing_settings`:
- `renewal_ticket_board_id`
- `renewal_ticket_status_id`
- `renewal_ticket_priority`
- `renewal_ticket_assignee_id`
- optional contract-level overrides from `client_contracts` are applied when `use_tenant_renewal_defaults = false`
- deterministic fallback to tenant defaults for any missing contract-level routing values
- Added processor visibility metric:
- `routingOverrideAppliedCount`
- Updated wiring coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F093`.
- Renewal processor now persists ticket linkage on successful automation:
- captures ticket id from workflow-action/direct-fallback creation result
- writes `created_ticket_id` on the client-contract renewal work item update payload
- This makes ticket linkage visible in queue APIs/UI and supports downstream idempotency checks.
- Updated wiring coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F094`.
- Added deterministic renewal ticket idempotency key builder:
- shape: `renewal-ticket:{tenantId}:{clientContractId}:{cycleKey}`
- Processor now uses this idempotency key for:
- workflow runtime `tickets.create` invocation input (`idempotency_key`)
- direct fallback ticket attributes (`idempotency_key`) for duplicate-detection context
- Updated wiring coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F095`.
- Added duplicate-prevention lookup before renewal ticket creation:
- checks existing `tickets` rows for matching `attributes.idempotency_key`
- if found, links existing ticket id to work item and skips create path
- Both workflow and direct ticket creation paths now receive shared ticket attributes including idempotency metadata.
- Added processor metric:
- `duplicateTicketSkipCount`
- Updated wiring coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F096`.
- Renewal processor now records automation failures on work items when ticket creation fails:
- reads optional `client_contracts.automation_error` column
- writes failure reason on create-path errors
- records missing-routing-defaults as explicit automation error for `create_ticket` policy
- clears `automation_error` when ticket creation succeeds
- Added processor metric:
- `automationErrorCount`
- Updated wiring coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F097`.
- Added manual retry queue action for failed renewal ticket automation:
- `retryRenewalQueueTicketCreation(clientContractId)` in `packages/billing/src/actions/renewalsQueueActions.ts`
- Retry action behavior:
- validates work item + due-date eligibility
- resolves effective due-date policy and routing defaults with tenant/contract precedence
- reuses cycle idempotency key to avoid duplicates
- links existing idempotent ticket when present
- otherwise re-attempts ticket creation and updates `created_ticket_id` / `automation_error`
- Exposed `automation_error` in renewal queue row payload model.
- Updated coverage:
- `packages/billing/tests/renewalsQueueActions.retryTicket.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.retryTicket.wiring.test.ts tests/renewalsQueueActions.wiring.test.ts`
- (2026-02-21) Completed `F098`.
- Queue-only policy behavior is enforced in both automation paths:
- scheduled processor only enters ticket-create path when `effectiveDueDateActionPolicy === 'create_ticket'`
- manual retry action returns without creating tickets when effective policy is `queue_only`
- This preserves queue visibility/workflow without forcing ticket side effects.
- Updated coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- `packages/billing/tests/renewalsQueueActions.retryTicket.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.retryTicket.wiring.test.ts tests/renewalsQueueActions.wiring.test.ts`
- (2026-02-21) Completed `F099`.
- Updated contract renewal-upcoming domain-event builders/schemas for queue-compatible semantics:
- expanded default window from 30 to 90 days
- `computeContractRenewalUpcoming` now supports decision-due date and renewal cycle key inputs
- payload now includes:
- `decisionDueDate`
- `daysUntilDecisionDue`
- `renewalCycleKey`
- Updated event publishers in:
- `packages/billing/src/actions/contractWizardActions.ts`
- `packages/clients/src/actions/clientContractActions.ts`
- `CONTRACT_RENEWAL_UPCOMING` idempotency keys now prefer cycle-key/decision-due identity where available.
- Added wiring coverage:
- `packages/billing/tests/contractRenewalUpcomingEvent.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `npm -w @alga-psa/clients run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/renewalsQueueActions.retryTicket.wiring.test.ts`
- Note:
- direct execution of `shared/workflow/streams/domainEventBuilders/__tests__/contractEventBuilders.test.ts` under current Vitest include globs returned “No test files found”; wiring assertions were added in billing tests to cover this change.
- (2026-02-21) Completed `F100`.
- Confirmed evergreen renewal queue generation path in scheduled processor:
- processor normalizes each contract with `normalizeClientContract` (which computes evergreen annual-cycle decision dates)
- upserts normalized cycle boundaries and cycle key:
- `renewal_cycle_start`
- `renewal_cycle_end`
- `renewal_cycle_key`
- includes evergreen entries whenever computed decision due date is within the processing horizon
- Updated coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npm run typecheck`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F101`.
- Added explicit per-row contract type badge rendering in Renewals queue UI:
- evergreen rows now show `Evergreen` badge
- fixed-term rows show `Fixed-term` badge
- Implemented in:
- `packages/billing/src/components/billing-dashboard/contracts/RenewalsQueueTab.tsx`
- Added component wiring assertions:
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/RenewalsQueueTab.component.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F102`.
- Added evergreen cycle anchor detail to renewal queue rows.
- Queue row model now surfaces:
- `evergreen_cycle_anchor_date` (from `evergreen_review_anchor_date`, fallback `renewal_cycle_end`)
- UI now renders evergreen-only row detail:
- `Evergreen anchor: <date>`
- Updated wiring coverage:
- `packages/billing/tests/RenewalsQueueTab.component.test.ts`
- `packages/billing/tests/renewalsQueueActions.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F103`.
- Confirmed evergreen entries share the same mark-renewing transition path as fixed-term entries:
- queue action availability is status-driven (`pending` includes `mark_renewing`)
- mark-renewing mutation path has no contract-type/end-date gate
- Added dedicated wiring coverage:
- `packages/billing/tests/renewalsQueueActions.markRenewingEvergreen.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markRenewingEvergreen.wiring.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F104`.
- Confirmed evergreen entries share the same mark-non-renewing transition path as fixed-term entries:
- queue action availability remains status-driven
- mark-non-renewing mutation path has no contract-type/end-date gate
- Added dedicated wiring coverage:
- `packages/billing/tests/renewalsQueueActions.markNonRenewingEvergreen.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.markNonRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewingEvergreen.wiring.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F105`.
- Confirmed create-renewal-draft action supports evergreen entries:
- mutation eligibility is status-driven (`pending` / `renewing`)
- draft assignment creation logic supports null `end_date` (evergreen) while preserving start-date semantics
- Added dedicated wiring coverage:
- `packages/billing/tests/renewalsQueueActions.createDraftEvergreen.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.createDraft.wiring.test.ts tests/renewalsQueueActions.createDraftEvergreen.wiring.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F106`.
- Confirmed evergreen cycle rollover semantics in scheduled renewal processing:
- when cycle key advances, processor treats it as a new cycle (`cycleChanged`)
- status normalization reopens work item to `pending`
- updated cycle key is persisted and cycle-change counters increment
- Added explicit rollover wiring coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- `cd server && npm run typecheck`
- (2026-02-21) Completed `F107`.
- Added cycle-level deduplication guard in scheduled renewal processing to prevent duplicate handling of the same contract/cycle period:
- dedupe identity: `client_contract_id + cycleKey` (fallback to `decision_due_date`)
- duplicate entries are skipped and counted in processor metrics
- This hardens evergreen annual-cycle processing against duplicate row inputs from upstream query/join behavior.
- Updated coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- `cd server && npm run typecheck`
- (2026-02-21) Completed `F108`.
- Added regression coverage confirming evergreen decision due date uses contract-level notice-period override when tenant defaults are disabled.
- Covered both branches:
- tenant defaults enabled => tenant notice period drives evergreen decision date
- tenant defaults disabled => contract override notice period drives evergreen decision date
- Updated coverage:
- `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F109`.
- Updated `ClientContractsTab` upcoming-renewals widget bucketing to explicitly include both contract types:
- `fixed-term`
- `evergreen`
- Added explicit widget wiring coverage to ensure evergreen entries are included in bucket counts.
- Updated files:
- `packages/billing/src/components/billing-dashboard/contracts/ClientContractsTab.tsx`
- `packages/billing/tests/ClientContractsTab.upcomingRenewalsWidget.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F110`.
- Extended expiration-report action payload to include `decision_due_date` alongside `end_date` when present.
- Updated `ContractExpiration` type and query mapping in:
- `packages/billing/src/actions/contractReportActions.ts`
- Added wiring coverage:
- `packages/billing/tests/contractReportActions.expiration.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F111`.
- Extended expiration-report rows to include `renewal_mode`.
- Updated report contract type in:
- `packages/billing/src/actions/contractReportActions.ts`
- Expanded wiring coverage:
- `packages/billing/tests/contractReportActions.expiration.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F112`.
- Extended expiration-report rows to include renewal queue state when present (`queue_status` from `client_contracts.status`).
- Updated files:
- `packages/billing/src/actions/contractReportActions.ts`
- `packages/billing/tests/contractReportActions.expiration.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F113`.
- Preserved existing fixed-term expiration inclusion semantics while adding renewal metadata:
- expiration rows still key off `end_date` presence
- no hard requirement for `renewal_mode` to be set
- Added explicit compatibility coverage in:
- `packages/billing/tests/contractReportActions.expiration.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F114`.
- Preserved expiration-report sort compatibility for existing consumers:
- primary ordering remains `cc.end_date ASC`
- dedupe key remains based on contract/client/end-date identity
- Added explicit compatibility assertions in:
- `packages/billing/tests/contractReportActions.expiration.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F115`.
- Extended report summary payload with `atRiskDecisionCount` for dashboard consumption.
- At-risk metric now counts active client-contract assignments with `decision_due_date` in the next 90 days.
- Updated files:
- `packages/billing/src/actions/contractReportActions.ts`
- `packages/billing/tests/contractReportActions.summary.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.summary.wiring.test.ts tests/contractReportActions.expiration.wiring.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F116`.
- Updated Contract Reports expiration tab copy to reference renewal decisions in addition to expirations.
- Updated UX copy in:
- `packages/billing/src/components/billing-dashboard/reports/ContractReports.tsx`
- Added wiring coverage:
- `packages/billing/tests/ContractReports.expirationCopy.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/ContractReports.expirationCopy.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/contractReportActions.expiration.wiring.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F117`.
- Updated expiration-report row construction so legacy `auto_renew` display derives from effective renewal mode values.
- Effective renewal mode now resolves with tenant-default precedence logic:
- honors `use_tenant_renewal_defaults`
- falls back deterministically between contract/tenant/default (`manual`)
- `auto_renew` now maps to `effectiveRenewalMode === 'auto'`.
- Updated files:
- `packages/billing/src/actions/contractReportActions.ts`
- `packages/billing/tests/contractReportActions.expiration.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false`
- `npm -w @alga-psa/billing run typecheck`
- (2026-02-21) Completed `F118`.
- Confirmed renewal scheduled processor registration in the on-prem pg-boss scheduled initialization path:
- tenant loop schedules `process-renewal-queue` via `scheduleRenewalQueueProcessingJob(tenantId, 90, cron)`
- includes both first-schedule and singleton-already-scheduled handling logs
- Updated coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- `cd server && npm run typecheck`
- (2026-02-21) Completed `F119`.
- Added Temporal runner coverage proving renewal scheduled processing can be registered as a recurring Temporal workflow:
- schedules `process-renewal-queue` with tenant + horizon payload
- validates Temporal schedule action carries renewal job name/data
- Updated coverage:
- `ee/server/src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`
- Validation:
- `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`
- Note:
- `npm --prefix ee/server run test:unit -- src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts` executes the full unit suite in this workspace and currently surfaces unrelated pre-existing failures in other unit files; targeted execution of the modified test passes.
- (2026-02-21) Completed `F120`.
- Confirmed renewal processing uses a shared core handler callable from both runtime adapters:
- legacy pg-boss registration path (`index.ts`) calls `processRenewalQueueHandler`
- centralized handler registry (`registerAllHandlers.ts`) also calls the same handler for Temporal/runner abstraction execution
- `initializeJobRunner.ts` bridges registered handlers into runner implementations
- Updated coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- `cd server && npm run typecheck`
- (2026-02-21) Completed `F121`.
- Added parity coverage confirming queue-creation payload shape is equivalent across runner paths:
- pg-boss scheduling uses `process-renewal-queue` with `{ tenantId, horizonDays }`
- Temporal recurring workflow action forwards `jobName`, `tenantId`, and `data` through `genericJobWorkflow`
- Updated coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- `cd server && npm run typecheck`
- (2026-02-21) Completed `F122`.
- Added runtime-parity coverage confirming ticket idempotency behavior is shared across runner paths because both execute the same renewal processor core:
- shared idempotency key construction
- duplicate-ticket lookup by idempotency attribute
- shared duplicate-skip semantics
- Updated coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- `cd server && npm run typecheck`
- (2026-02-21) Completed `F123`.
- Added wiring coverage confirming runtime selection stays in `JobRunnerFactory` and renewal business logic remains runner/edition agnostic:
- runner type resolution via config/env (`JOB_RUNNER_TYPE`)
- renewal processor contains no edition/runtime branching
- Updated coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- `cd server && npm run typecheck`
## Open Questions
- Should renewal ticket defaults be a brand-new billing settings card, or an extension of existing default ticket settings patterns?
- Should evergreen annual review use contract start-date anniversary or configurable anchor date in v1?
- Should renewal status transitions hard-lock contract activation behavior, or remain advisory with warnings in v1?
- (2026-02-21) Completed `F124`.
- Added explicit runtime-fallback coverage confirming Temporal bootstrap failures gracefully fall back to pg-boss when fallback is enabled.
- Assertions verify:
- Temporal path attempted first for EE/runtime selection
- fallback gate checks `config?.fallbackToPgBoss !== false`
- fallback execution calls `createPgBossRunner(config)`
- Temporal bootstrap/import failures remain surfaced and handled by fallback branch
- Updated coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F125`.
- Added tenant-scope parity coverage across pg-boss and Temporal renewal runtime paths.
- Assertions verify:
- scheduler payload requires and forwards tenant id for renewal processing
- renewal processor enforces tenant id and scopes reads/writes by tenant
- Temporal runner enforces tenant id in job data and propagates tenant scope into workflow/job persistence
- Updated coverage:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F126`.
- Enforced billing read authorization on renewals queue list endpoint.
- `listRenewalQueueRows` now gates access via `hasPermission(user, 'billing', 'read')` and throws `Permission denied: Cannot read renewals queue` when unauthorized.
- Updated files:
- `packages/billing/src/actions/renewalsQueueActions.ts`
- `packages/billing/tests/renewalsQueueActions.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F127`.
- Enforced billing update authorization on all renewals queue mutation endpoints.
- Added shared guard `requireBillingUpdatePermission(user)` and applied it to:
- `markRenewalQueueItemRenewing`
- `markRenewalQueueItemNonRenewing`
- `createRenewalDraftForQueueItem`
- `snoozeRenewalQueueItem`
- `assignRenewalQueueItemOwner`
- `completeRenewalQueueItemForActivation`
- `completeRenewalQueueItemForNonRenewal`
- `retryRenewalQueueTicketCreation`
- Updated files:
- `packages/billing/src/actions/renewalsQueueActions.ts`
- `packages/billing/tests/renewalsQueueActions.permissions.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts tests/renewalsQueueActions.permissions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F128`.
- Enforced billing settings update authorization on renewal default writes.
- `updateDefaultBillingSettings` now requires `hasPermission(user, 'billing_settings', 'update')` and rejects unauthorized callers.
- Updated files:
- `packages/billing/src/actions/billingSettingsActions.ts`
- `packages/billing/tests/billingSettingsActions.renewalPermissions.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/billingSettingsActions.renewalPermissions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F129`.
- Added explicit wiring coverage that renewal work-item read paths are tenant-scoped by default.
- Coverage asserts tenant filtering across list/read query builders in renewals queue actions.
- Updated file:
- `packages/billing/tests/renewalsQueueActions.tenantReads.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.tenantReads.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F130`.
- Added wiring coverage that renewal work-item mutation/write paths remain tenant-filtered by default.
- Coverage checks tenant-scoped update/insert/lookup clauses in renewals queue action writes.
- Updated file:
- `packages/billing/tests/renewalsQueueActions.tenantWrites.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.tenantWrites.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F131`.
- Enhanced renewal transition auditing to capture action metadata (`last_action`) alongside actor/timestamp/note.
- Added `withActionLabel(...)` and `last_action` column checks across mutation paths so transitions now record action labels such as:
- `mark_renewing`, `mark_non_renewing`, `create_renewal_draft`, `snooze`, `assign_owner`, `complete_after_activation`, `complete_after_non_renewal`
- Updated files:
- `packages/billing/src/actions/renewalsQueueActions.ts`
- `packages/billing/tests/renewalsQueueActions.transitionAudit.wiring.test.ts`
- `packages/billing/tests/renewalsQueueActions.actorAudit.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F132`.
- Added automation-linkage audit metadata in renewal processor when due-date ticket linkage succeeds.
- When a ticket is linked, handler now records (when columns exist):
- `last_action = 'system_ticket_automation_linked'`
- `last_action_by = null` (system actor)
- `last_action_at = nowIso`
- Updated files:
- `server/src/lib/jobs/handlers/processRenewalQueueHandler.ts`
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F133`.
- Added explicit draft-linkage audit coverage ensuring renewal draft creation linkage persists with actor/timestamp metadata.
- Coverage validates draft link persistence and action metadata chain (`withActionLabel` + `withActionActor` + `withActionTimestamp`).
- Updated file:
- `packages/billing/tests/renewalsQueueActions.createDraftAudit.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.createDraft.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F134`.
- Added explicit cross-tenant identifier rejection in queue mutation validation:
- owner assignment now rejects `assignedTo` user IDs found only in another tenant
- activation completion now rejects `activatedContractId` values belonging to another tenant
- Added explicit error paths for cross-tenant and not-in-tenant owner identifiers.
- Updated files:
- `packages/billing/src/actions/renewalsQueueActions.ts`
- `packages/billing/tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.assignOwner.wiring.test.ts tests/renewalsQueueActions.completeOnActivation.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F135`.
- Added note sanitization prior to persistence/render for renewal queue action notes.
- `normalizeActionNote` now sanitizes input by stripping HTML tags, removing angle brackets/control chars, normalizing whitespace, and trimming.
- Updated files:
- `packages/billing/src/actions/renewalsQueueActions.ts`
- `packages/billing/tests/renewalsQueueActions.noteSanitization.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.noteAudit.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T032`.
- Verified effective renewal settings exposure in contract assignment read paths.
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T033`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T034`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T035`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T036`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T037`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T038`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T039`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T040`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T041`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T042`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T043`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T044`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T045`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T046`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T047`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false`
- (2026-02-21) Completed `T048`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T049`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T050`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T051`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T052`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T053`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T054`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T055`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T056`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T057`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T058`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T059`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T060`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/ClientContractsTab.upcomingRenewalsWidget.test.ts tests/BillingDashboard.renewalsRoute.test.ts --coverage=false`
- (2026-02-21) Completed `T061`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/ClientContractsTab.upcomingRenewalsWidget.test.ts tests/BillingDashboard.renewalsRoute.test.ts --coverage=false`
- (2026-02-21) Completed `T062`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/ClientContractsTab.upcomingRenewalsWidget.test.ts tests/BillingDashboard.renewalsRoute.test.ts --coverage=false`
- (2026-02-21) Completed `T063`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/ClientContractsTab.upcomingRenewalsWidget.test.ts tests/BillingDashboard.renewalsRoute.test.ts --coverage=false`
- (2026-02-21) Completed `T064`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T065`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T066`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T067`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T068`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T069`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T070`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T071`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T072`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T073`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T074`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T075`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T076`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T077`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T078`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T079`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T080`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T081`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T082`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T083`.
- Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`
- (2026-02-21) Completed `T084`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T085`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T086`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T087`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T088`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T089`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T090`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T091`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T092`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T093`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T094`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T095`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T096`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T097`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T098`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T099`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T100`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T101`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T102`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T103`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T104`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T105`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T106`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T107`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T108`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T109`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false`
- (2026-02-21) Completed `T110`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T111`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T112`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T113`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T114`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T115`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T116`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T117`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T118`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`
- (2026-02-21) Completed `T119`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`
- (2026-02-21) Completed `T120`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`
- (2026-02-21) Completed `T121`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`
- (2026-02-21) Completed `T122`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`
- (2026-02-21) Completed `T123`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`
- (2026-02-21) Completed `T124`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`
- (2026-02-21) Completed `T125`.
- Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`
- (2026-02-21) Completed `T126`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T127`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T128`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T129`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T130`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T131`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T132`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T133`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T134`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T135`.
- Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T136`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T137`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T138`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T139`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T140`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T141`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T142`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T143`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T144`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T145`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T146`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T147`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T148`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T149`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T150`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T151`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T152`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T153`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T154`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T155`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T156`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T157`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T158`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T159`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T160`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T161`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T162`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T163`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T164`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T165`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T166`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T167`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T168`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T169`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T170`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T171`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T172`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T173`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T174`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T175`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T176`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T177`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T178`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T179`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T180`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T181`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T182`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T183`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T184`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T185`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T186`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T187`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T188`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T189`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T190`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T191`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T192`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T193`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T194`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T195`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T196`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T197`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T198`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T199`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T200`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T201`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T202`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T203`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T204`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T205`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T206`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T207`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T208`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T209`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T210`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T211`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T212`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T213`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T214`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T215`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T216`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T217`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T218`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T219`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T220`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T221`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T222`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T223`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T224`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T225`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T226`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T227`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T228`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T229`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T230`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T231`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T232`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T233`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T234`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T235`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T236`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T237`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T238`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T239`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T240`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T241`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T242`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `T243`.
- Validation: consolidated renewal billing/server/ee suites executed and passing in this session.
- (2026-02-21) Completed `F136`.
- Added migration:
- `server/migrations/202602211100_add_contract_renewal_queue_status_audit_columns.cjs`
- Migration adds renewal queue status/audit columns on `client_contracts`:
- `status`, `snoozed_until`, `assigned_to`, `last_action`, `last_action_by`, `last_action_at`, `last_action_note`
- Added queue-status check constraint:
- `client_contracts_renewal_status_check` (`pending|renewing|non_renewing|snoozed|completed`)
- Added tenant-scoped actor FKs (null-on-delete):
- `client_contracts_assigned_to_fkey` (`tenant`, `assigned_to`) -> `users(tenant, user_id)`
- `client_contracts_last_action_by_fkey` (`tenant`, `last_action_by`) -> `users(tenant, user_id)`
- Migration is idempotent and Citus-safe (`ensureSequentialMode`, guarded column/constraint checks).
- Validation:
- `node -c server/migrations/202602211100_add_contract_renewal_queue_status_audit_columns.cjs`
- (2026-02-21) Completed `F137`.
- Added migration:
- `server/migrations/202602211105_add_contract_renewal_cycle_columns.cjs`
- Migration adds renewal-cycle fields on `client_contracts`:
- `decision_due_date`
- `renewal_cycle_start`
- `renewal_cycle_end`
- `renewal_cycle_key`
- Migration remains idempotent and Citus-safe with guarded column checks.
- Validation:
- `node -c server/migrations/202602211105_add_contract_renewal_cycle_columns.cjs`
- (2026-02-21) Completed `F138`.
- Added migration:
- `server/migrations/202602211110_add_contract_renewal_automation_columns.cjs`
- Migration adds renewal automation linkage/policy columns on `client_contracts`:
- `created_ticket_id`, `automation_error`, `renewal_due_date_action_policy`
- `renewal_ticket_board_id`, `renewal_ticket_status_id`, `renewal_ticket_priority`, `renewal_ticket_assignee_id`
- `created_draft_contract_id`
- Added policy check constraint:
- `client_contracts_renewal_due_date_action_policy_check` (`queue_only|create_ticket`)
- Migration remains idempotent and Citus-safe with guarded column/constraint checks.
- Validation:
- `node -c server/migrations/202602211110_add_contract_renewal_automation_columns.cjs`
- (2026-02-21) Completed `F139`.
- Added migration:
- `server/migrations/202602211115_add_contract_renewal_config_columns.cjs`
- Migration adds renewal configuration columns on `client_contracts`:
- `renewal_mode`, `notice_period_days`, `renewal_term_months`, `use_tenant_renewal_defaults`
- Added DB constraints aligned to wizard/server validation rules:
- `client_contracts_renewal_mode_check` (`none|manual|auto`)
- `client_contracts_notice_period_days_check` (`>= 0`)
- `client_contracts_renewal_term_months_check` (`NULL OR > 0`)
- Migration remains idempotent and Citus-safe with guarded column/constraint checks.
- Validation:
- `node -c server/migrations/202602211115_add_contract_renewal_config_columns.cjs`
- (2026-02-21) Completed `F140`.
- Added migration:
- `server/migrations/202602211120_add_default_billing_renewal_columns.cjs`
- Migration adds renewal defaults/policy columns on `default_billing_settings`:
- `default_renewal_mode`, `default_notice_period_days`, `renewal_due_date_action_policy`
- `renewal_ticket_board_id`, `renewal_ticket_status_id`, `renewal_ticket_priority`, `renewal_ticket_assignee_id`
- Added DB constraints for default value domains:
- `default_billing_settings_default_renewal_mode_check`
- `default_billing_settings_default_notice_period_days_check`
- `default_billing_settings_renewal_due_date_action_policy_check`
- Migration remains idempotent and Citus-safe with guarded column/constraint checks.
- Validation:
- `node -c server/migrations/202602211120_add_default_billing_renewal_columns.cjs`
- (2026-02-21) Completed `F141`.
- Added backfill migration:
- `server/migrations/202602211125_backfill_active_client_contract_renewal_defaults.cjs`
- Backfill scope:
- active fixed-term `client_contracts` rows (`is_active=true`, joined `contracts.status='active'`, `end_date IS NOT NULL`)
- Backfill behavior (only when target fields are missing):
- sets deterministic defaults: `renewal_mode='manual'`, `notice_period_days=30`, `use_tenant_renewal_defaults=true`
- computes initial fixed-term cycle fields:
- `decision_due_date = end_date - notice_period_days`
- `renewal_cycle_start = start_date::date`
- `renewal_cycle_end = end_date::date`
- `renewal_cycle_key = fixed-term:<end_date>`
- preserves existing non-null values via `COALESCE` to avoid overwriting already-migrated data
- Migration is intentionally non-reversible (data backfill).
- Validation:
- `node -c server/migrations/202602211125_backfill_active_client_contract_renewal_defaults.cjs`
- (2026-02-21) Completed `F142`.
- Added migration:
- `server/migrations/202602211130_add_contract_renewal_indexes_constraints.cjs`
- Added renewal queue performance indexes on `client_contracts` for common filters/sorts:
- `idx_client_contracts_renewal_due_status` (`tenant`, `decision_due_date`, `status`) partial active+due-date-not-null
- `idx_client_contracts_renewal_owner_status` (`tenant`, `assigned_to`, `status`) partial active
- `idx_client_contracts_renewal_mode_type` (`tenant`, `renewal_mode`, `end_date`) partial active
- `idx_client_contracts_renewal_snooze` (`tenant`, `status`, `snoozed_until`) partial active
- Added cycle dedupe uniqueness index:
- `ux_client_contracts_active_cycle_key` (`tenant`, `client_contract_id`, `renewal_cycle_key`) partial active+cycle-key-not-null
- Migration remains Citus-safe and guarded by column existence checks.
- Validation:
- `node -c server/migrations/202602211130_add_contract_renewal_indexes_constraints.cjs`
- (2026-02-21) Completed `F143`.
- Added renewal schema-readiness guard in queue actions:
- `packages/billing/src/actions/renewalsQueueActions.ts`
- `assertRenewalSchemaReady(knex)` now validates required renewal columns on:
- `client_contracts`
- `default_billing_settings`
- all renewals queue endpoints now fail fast with actionable migration guidance when required schema is missing.
- Added renewal schema-readiness enforcement in scheduled automation:
- `server/src/lib/jobs/handlers/processRenewalQueueHandler.ts`
- processor now throws actionable error listing missing renewal columns/tables instead of silently skipping.
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `cd server && npm run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `F144`.
- Removed required-column compatibility branching in strict migrated-schema paths:
- `packages/billing/src/actions/renewalsQueueActions.ts`
- queue list/load now uses direct migrated-schema fields for unsnooze + tenant-default joins.
- queue mutation/update helpers now write action audit fields directly (no per-column optional branch).
- retry-ticket flow now uses direct migrated-schema policy/routing fields.
- `server/src/lib/jobs/handlers/processRenewalQueueHandler.ts`
- post-guard processing now assumes migrated columns exist and applies direct policy/cycle/ticket updates.
- direct tenant-default selection list + default settings join used in all renewal processor reads.
- Updated strict-mode wiring assertions:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Validation:
- `npm -w @alga-psa/billing run typecheck`
- `cd server && npm run typecheck`
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts --coverage=false`
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T244`.
- Added migration coverage for renewal queue status/audit columns on `client_contracts` in:
- `server/src/test/unit/migrations/contractRenewalMigrations.test.ts`
- Assertions cover required status/audit columns and status domain constraint wiring from migration `202602211100_add_contract_renewal_queue_status_audit_columns.cjs`.
- Validation:
- `cd server && npx vitest run src/test/unit/migrations/contractRenewalMigrations.test.ts --coverage=false`
- (2026-02-21) Completed `T245`.
- Extended migration coverage for renewal-cycle columns in:
- `server/src/test/unit/migrations/contractRenewalMigrations.test.ts`
- Assertions verify `decision_due_date`, `renewal_cycle_start`, `renewal_cycle_end`, and `renewal_cycle_key` add/drop wiring in migration `202602211105_add_contract_renewal_cycle_columns.cjs`.
- Validation:
- `cd server && npx vitest run src/test/unit/migrations/contractRenewalMigrations.test.ts --coverage=false`
- (2026-02-21) Completed `T246`.
- Extended migration coverage for renewal automation/policy linkage columns on `client_contracts` in:
- `server/src/test/unit/migrations/contractRenewalMigrations.test.ts`
- Assertions verify ticket link, routing override, automation error, and policy-check constraint wiring from `202602211110_add_contract_renewal_automation_columns.cjs`.
- Validation:
- `cd server && npx vitest run src/test/unit/migrations/contractRenewalMigrations.test.ts --coverage=false`
- (2026-02-21) Completed `T247`.
- Extended migration coverage for renewal default/policy columns on `default_billing_settings` in:
- `server/src/test/unit/migrations/contractRenewalMigrations.test.ts`
- Assertions verify default renewal mode/notice/policy columns, ticket-routing default fields, and policy/validation constraints from `202602211120_add_default_billing_renewal_columns.cjs`.
- Validation:
- `cd server && npx vitest run src/test/unit/migrations/contractRenewalMigrations.test.ts --coverage=false`
- (2026-02-21) Completed `T248`.
- Extended migration coverage for renewal backfill behavior in:
- `server/src/test/unit/migrations/contractRenewalMigrations.test.ts`
- Assertions verify data backfill SQL initializes deterministic renewal defaults/cycle fields and scopes updates to active fixed-term rows joined to active contracts.
- Validation:
- `cd server && npx vitest run src/test/unit/migrations/contractRenewalMigrations.test.ts --coverage=false`
- (2026-02-21) Completed `T249`.
- Added strict-schema integration wiring test for renewals queue listing in:
- `packages/billing/tests/renewalsQueueActions.schemaReadiness.integration.test.ts`
- Coverage verifies `listRenewalQueueRows` enforces `assertRenewalSchemaReady(knex)` and uses migrated-schema query path without legacy missing-column fallback branches.
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.schemaReadiness.integration.test.ts --coverage=false`
- Constraint note:
- runtime-import action tests currently hit workspace package entry-resolution failures for `@alga-psa/db`; migration/strict-schema integration coverage is therefore implemented via source-level wiring assertions (same style as existing renewal wiring suites).
- (2026-02-21) Completed `T250`.
- Extended strict-schema integration wiring coverage for snooze mutation in:
- `packages/billing/tests/renewalsQueueActions.schemaReadiness.integration.test.ts`
- Assertions verify migrated-schema snooze path writes `status='snoozed'`, `snoozed_until`, and action audit metadata (`last_action`/actor/timestamp/note chain).
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.schemaReadiness.integration.test.ts --coverage=false`
- (2026-02-21) Completed `T251`.
- Extended strict-schema integration wiring coverage for mark-renewing mutation in:
- `packages/billing/tests/renewalsQueueActions.schemaReadiness.integration.test.ts`
- Assertions verify pending-only transition to `renewing` plus actor/timestamp audit persistence in migrated-schema path.
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.schemaReadiness.integration.test.ts --coverage=false`
- (2026-02-21) Completed `T252`.
- Extended renewal job integration wiring coverage in:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Added assertions that `processRenewalQueueHandler` computes/persists `decision_due_date`, `renewal_cycle_start`, `renewal_cycle_end`, and `renewal_cycle_key` for eligible rows.
- Validation:
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T253`.
- Extended renewal job integration wiring coverage in:
- `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts`
- Added assertions that ticket automation under `create_ticket` uses tenant+contract+cycle idempotency identity and duplicate lookup/linking so at most one ticket is linked per cycle.
- Validation:
- `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`
- (2026-02-21) Completed `T254`.
- Extended strict-schema integration wiring coverage for guard-failure path in:
- `packages/billing/tests/renewalsQueueActions.schemaReadiness.integration.test.ts`
- Assertions verify `assertRenewalSchemaReady` fails fast with actionable missing-column error text instructing migration execution.
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.schemaReadiness.integration.test.ts --coverage=false`
- (2026-02-21) Completed `T255`.
- Extended strict-schema integration wiring coverage for guard-pass operational path in:
- `packages/billing/tests/renewalsQueueActions.schemaReadiness.integration.test.ts`
- Assertions verify all renewals queue endpoints invoke `assertRenewalSchemaReady(knex)` and no longer rely on legacy missing-column fallback branches in strict migrated-schema mode.
- Validation:
- `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.schemaReadiness.integration.test.ts --coverage=false`