feat(auth): migrate calendar + sla + contracts to TenantId (PMS-139 sweep batch 3) #161

Merged
longjacksonle merged 1 commit from feat/pms-139-sweep-calendar-sla-contracts into main 2026-06-11 13:55:12 +02:00

What

Batch 3 of the PMS-139 typed-tenant sweep: migrate calendar, sla, and contracts from bare Uuid tenant ids to the TenantId newtype.

How

  • Handlers derive the scope via u.tenant() (the TenantScoped trait, now imported in each routes.rs); every public service method and module-local helper takes tenant_id: TenantId.
  • The transparent newtype encodes/decodes/Displays as its inner Uuid, so .bind(tenant_id) binds and %tenant_id tracing render unchanged - no .get() needed at the SQL layer.
  • The only unwraps are the nine audit_write call sites in contracts, which use tenant_id.get() transitionally until the audit hub is swept last.
  • Cross-tenant workers (calendar reminder, sla sweep, contract lifecycle) are untouched: they read tenant ids off DB-projected rows (ReminderCandidate/ReminderRow/sweep rows) as Uuid and dispatch through the notifications/audit hubs, never calling a migrated method.
  • Direct-construction tests (tests/contracts.rs, tests/sla.rs) wrap literal tenant ids with TenantId::from_trusted(...), matching the batch-1 tests/rmm precedent.

Verification

  • cargo check --all-targets, cargo clippy --all-targets: clean.
  • cargo test --test contracts --test sla --test calendar_reminders --test sla_notify: 6 + 1 + 2 + 1 pass.
  • cargo test --doc: the compile_fail newtype guard still holds (2 pass / 3 ignored).

Progress: 8 of ~17 modules migrated (reports, rmm, time_tracking, assets, projects, calendar, sla, contracts). ~9 remain; the audit_write / notifications::dispatch / TicketService hubs are swept last.

🤖 Generated with Claude Code

## What Batch 3 of the PMS-139 typed-tenant sweep: migrate `calendar`, `sla`, and `contracts` from bare `Uuid` tenant ids to the `TenantId` newtype. ## How - Handlers derive the scope via `u.tenant()` (the `TenantScoped` trait, now imported in each `routes.rs`); every public service method and module-local helper takes `tenant_id: TenantId`. - The transparent newtype encodes/decodes/Displays as its inner `Uuid`, so `.bind(tenant_id)` binds and `%tenant_id` tracing render unchanged - no `.get()` needed at the SQL layer. - The only unwraps are the nine `audit_write` call sites in contracts, which use `tenant_id.get()` transitionally until the audit hub is swept last. - Cross-tenant workers (calendar reminder, sla sweep, contract lifecycle) are untouched: they read tenant ids off DB-projected rows (`ReminderCandidate`/`ReminderRow`/sweep rows) as `Uuid` and dispatch through the notifications/audit hubs, never calling a migrated method. - Direct-construction tests (`tests/contracts.rs`, `tests/sla.rs`) wrap literal tenant ids with `TenantId::from_trusted(...)`, matching the batch-1 `tests/rmm` precedent. ## Verification - `cargo check --all-targets`, `cargo clippy --all-targets`: clean. - `cargo test --test contracts --test sla --test calendar_reminders --test sla_notify`: 6 + 1 + 2 + 1 pass. - `cargo test --doc`: the `compile_fail` newtype guard still holds (2 pass / 3 ignored). Progress: 8 of ~17 modules migrated (reports, rmm, time_tracking, assets, projects, calendar, sla, contracts). ~9 remain; the `audit_write` / `notifications::dispatch` / `TicketService` hubs are swept last. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(auth): migrate calendar + sla + contracts to TenantId (PMS-139 sweep batch 3)
Some checks failed
Check / fmt + clippy + compile + tests (pull_request) Failing after 12s
E2E (staging) / Playwright against staging (pull_request) Successful in 39s
Build OCI container / Build and push mokosh-api image (push) Successful in 3m16s
Create release / Create release from merged PR (pull_request) Has been skipped
b77e6718e0
Sweep batch 3 of the typed-tenant rollout. Handlers in calendar/sla/contracts now derive the scope via `u.tenant()` (the `TenantScoped` trait), and every public service method plus module-local helper takes `tenant_id: TenantId` instead of a bare `Uuid`, so a wrong-tenant id is a compile error rather than a silent cross-tenant read.

The transparent newtype encodes/decodes/Displays as its inner `Uuid`, so `.bind(tenant_id)` and `%tenant_id` tracing are unchanged. The only unwraps are at the not-yet-swept `audit_write` hub in contracts (nine call sites use `tenant_id.get()` transitionally) - those vanish when the audit hub is swept last.

Cross-tenant workers (calendar reminder, sla sweep, contract lifecycle) are untouched: they read tenant ids off DB-projected rows as `Uuid` and fan out through the notifications/audit hubs, never calling a migrated method. The calendar `ReminderCandidate`/`ReminderRow` projections keep their `Uuid` fields for the same reason.

Direct-construction tests (`tests/contracts.rs`, `tests/sla.rs`) wrap their literal tenant ids with `TenantId::from_trusted(...)`, matching the batch-1 `tests/rmm` precedent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/pms-139-sweep-calendar-sla-contracts 2026-06-11 13:55:13 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/mokosh-server!161
No description provided.