fix(tenants): seed lookup config for tenants reached off the PSA path #222

Merged
nrupard merged 2 commits from feat/pms-288-seed-lookup-config-on-placement into main 2026-06-13 20:14:11 +02:00
Owner

Summary

Seeds the PSA per-tenant lookup/config set for tenants a user is placed into off the PSA creation path, so ticket creation no longer 500s with CONFIGURATION_ERROR. Closes PMS-288.

create_tenant and ensure_personal_tenant seed at creation, but place_bunyip_user only calls ensure_personal_tenant for brand-new or default-tenant-stuck users. A user already placed elsewhere - an invite into an auth/SSO-created org tenant, or an existing placement in a manually-created tenant - is not re-homed and never triggers the seed. That tenant has no default ticket_statuses row and no ticket_sequences row, so POST /api/v1/tickets 500s (surfaced by the E2E suite).

Change

  • TenantService::ensure_default_config(tenant_id) (new, public): idempotently seeds the per-tenant sequences (ON CONFLICT on the tenant_id PK, under the tenant GUC like create_tenant) and the lookup/config set (copy_default_config, which early-returns when already seeded). copy_default_config alone is insufficient - it does not seed ticket_sequences, which next_ticket_number requires (tickets/service.rs:113-129).
  • place_bunyip_user (auth/middleware.rs): calls ensure_default_config(target) once target is resolved, covering the invite and existing-placement branches the current code misses. No-op for the already-seeded personal-tenant branch and for already-seeded tenants. Best-effort: a seed failure is logged, not fatal to the request.

Tests (both fail on the pre-fix code)

  • ensure_default_config_seeds_off_psa_tenant_idempotently (tests/tenants.rs): a bare org tenant gains a default ticket status + a sequence row; a second call adds no duplicates.
  • placement_seeds_off_psa_target_tenant_so_tickets_create (tests/bunyip_login.rs): a user placed in a manually-created unseeded org tenant can create a ticket end-to-end (exercises both the default-status lookup and next_ticket_number).

Verification

  • Both new tests pass against postgres:18.2-alpine.
  • cargo fmt --all --check clean; cargo clippy --bin mokosh-server --test tenants --test bunyip_login clean.

Notes

Interim staging unblock (the one-off SQL seed of the three ticket lookups) is no longer needed once this deploys - any tenant a user lands in is seeded on the authenticated request. Relates to PMS-287 (the create_tenant kind fix); distinct code path.

## Summary Seeds the PSA per-tenant lookup/config set for tenants a user is placed into off the PSA creation path, so ticket creation no longer 500s with `CONFIGURATION_ERROR`. Closes PMS-288. `create_tenant` and `ensure_personal_tenant` seed at creation, but `place_bunyip_user` only calls `ensure_personal_tenant` for brand-new or default-tenant-stuck users. A user already placed elsewhere - an invite into an auth/SSO-created org tenant, or an existing placement in a manually-created tenant - is not re-homed and never triggers the seed. That tenant has no default `ticket_statuses` row and no `ticket_sequences` row, so `POST /api/v1/tickets` 500s (surfaced by the E2E suite). ## Change - `TenantService::ensure_default_config(tenant_id)` (new, public): idempotently seeds the per-tenant sequences (`ON CONFLICT` on the `tenant_id` PK, under the tenant GUC like `create_tenant`) **and** the lookup/config set (`copy_default_config`, which early-returns when already seeded). `copy_default_config` alone is insufficient - it does not seed `ticket_sequences`, which `next_ticket_number` requires (`tickets/service.rs:113-129`). - `place_bunyip_user` (`auth/middleware.rs`): calls `ensure_default_config(target)` once `target` is resolved, covering the invite and existing-placement branches the current code misses. No-op for the already-seeded personal-tenant branch and for already-seeded tenants. Best-effort: a seed failure is logged, not fatal to the request. ## Tests (both fail on the pre-fix code) - `ensure_default_config_seeds_off_psa_tenant_idempotently` (`tests/tenants.rs`): a bare org tenant gains a default ticket status + a sequence row; a second call adds no duplicates. - `placement_seeds_off_psa_target_tenant_so_tickets_create` (`tests/bunyip_login.rs`): a user placed in a manually-created unseeded org tenant can create a ticket end-to-end (exercises both the default-status lookup and `next_ticket_number`). ## Verification - Both new tests pass against postgres:18.2-alpine. - `cargo fmt --all --check` clean; `cargo clippy --bin mokosh-server --test tenants --test bunyip_login` clean. ## Notes Interim staging unblock (the one-off SQL seed of the three ticket lookups) is no longer needed once this deploys - any tenant a user lands in is seeded on the authenticated request. Relates to PMS-287 (the `create_tenant` `kind` fix); distinct code path.
fix(tenants): seed lookup config for tenants reached off the PSA path
Some checks failed
E2E / Playwright against staging (pull_request) Failing after 38s
Check / fmt + clippy + compile + tests (pull_request) Failing after 2m33s
74adb16db5
A user can be placed into a tenant that never ran copy_default_config - an invite into an auth/SSO-created org tenant, or an existing placement in a manually-created tenant. create_tenant and ensure_personal_tenant seed at creation, but the bunyip placement path only calls ensure_personal_tenant for brand-new or default-tenant-stuck users; a user already placed elsewhere is not re-homed and never triggers the seed. Such a tenant has no default ticket status and no ticket_sequences row, so ticket creation 500s with CONFIGURATION_ERROR (surfaced by the E2E suite).

Add TenantService::ensure_default_config(tenant_id): idempotently seed the per-tenant sequences (ON CONFLICT on the tenant_id PK, under the tenant GUC like create_tenant) plus the lookup/config set (copy_default_config, which early-returns when already seeded). copy_default_config alone is not enough - it does not seed ticket_sequences, which next_ticket_number requires.

Call it from place_bunyip_user once target is resolved, covering the invite and existing-placement branches the current code misses; it is a no-op for the already-seeded personal-tenant branch and for already-seeded tenants. Best-effort: a seed failure is logged, not fatal to the request.

Tests: ensure_default_config_seeds_off_psa_tenant_idempotently (seeds a bare tenant's default status + sequence, idempotent on re-run) and placement_seeds_off_psa_target_tenant_so_tickets_create (a user placed in a manually-created unseeded org tenant can create a ticket end-to-end). Both fail on the pre-fix code.

#PMS-288
perf(tenants): cheap-guard the per-request sequence seed
Some checks failed
E2E / Playwright against staging (pull_request) Failing after 35s
Create release / Create release from merged PR (pull_request) Has been skipped
Check / fmt + clippy + compile + tests (pull_request) Failing after 3m7s
e0daef1381
ensure_default_config runs on the per-request bunyip auth path
(place_bunyip_user), so the already-seeded common case must stay cheap.
The sequence step opened a write transaction + two INSERT ... ON CONFLICT
on every call; only the copy_default_config step was guarded by its
EXISTS early-return. Add a cheap `SELECT EXISTS(ticket_sequences)` and
skip the write transaction when the sequence row is already present, so
steady state is a couple of SELECTs and no write tx. The inserts keep
ON CONFLICT DO NOTHING so a concurrent first-request race stays
idempotent even when the cheap guard lets both callers through.

#PMS-288
nrupard deleted branch feat/pms-288-seed-lookup-config-on-placement 2026-06-13 20:14:11 +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!222
No description provided.