feat(seed): load first-visit demo data from a committed bundle, not hardcoded Rust (PMS-651) #448

Merged
nrupard merged 1 commit from feat/PMS-651-data-driven-seed into main 2026-07-13 22:16:13 +02:00
Owner

What

PMS-651 backend slice: make first-visit demo seeding data-driven. The demo content (company / contact / ticket names, titles, descriptions) moves out of hardcoded Rust literals in src/modules/seed/data.rs into a committed, compile-time-embedded src/modules/seed/demo_seed.json bundle. data.rs maps the bundle into the same Create*Request DTOs and seeds through the real service methods.

Design decision (the ticket-config wrinkle)

The Story asks to seed "via the restore path." That path (data_transfer, PMS-648) is raw wipe-and-replace (jsonb_populate_recordset + id-remap), and tickets.status_id / priority_id / queue_id are NOT NULL FKs into per-tenant config (migrations/005_tickets.sql:103-108) that only create_ticket fills. To seed tickets through the raw import, the demo bundle would have to be a full tenant snapshot (all config + own_company + entities), regenerated on every config-default change and wiping the fresh tenant's just-created config on restore. That is fragile.

Per the design call on PMS-651, this slice uses a data-driven, create-only service-layer load instead (PMS-621's original vision): correct per-tenant config FKs via create_ticket, non-destructive, and the demo set is now editable without touching Rust. It intentionally does not reuse the wipe-replace restore path.

AC status

  • AC3 (data.rs hardcoded rows are no longer the seed source) - the bundle is the source; the load path is the service layer, not the restore path (relaxed per the design decision).
  • AC4 (guards unchanged) - ensure_demo_seeded / seed_rows untouched: demo_seeded CAS, emptiness check, shared-landing-tenant exclusion, MOKOSH_DEMO_SEED kill switch all intact.
  • AC5 (clean non-zQA dataset) - the bundle is the PMS-629 clean baseline; the PMS-629 assertion still guards it.
  • AC7 (tests) - seed output is unchanged, so tests/seed_demo.rs (fresh-tenant counts, idempotency, PMS-239 exclusion, non-empty-tenant skip) still covers a clean seed on a fresh DB; a new data.rs unit test guards that the embedded bundle parses to the expected shape.

Frontend (AC1/AC6) is delivered by MAPPS-364; API (AC1/AC2) by PMS-647/648.

Testing

just pre-commit green (fmt / clippy -D / compile --all-targets / unit incl the new bundle-parse test / doc). The seed_demo integration tests run in the Integration job.

#PMS-651

## What PMS-651 backend slice: make first-visit demo seeding data-driven. The demo content (company / contact / ticket names, titles, descriptions) moves out of hardcoded Rust literals in `src/modules/seed/data.rs` into a committed, compile-time-embedded `src/modules/seed/demo_seed.json` bundle. `data.rs` maps the bundle into the same `Create*Request` DTOs and seeds through the real service methods. ## Design decision (the ticket-config wrinkle) The Story asks to seed "via the restore path." That path (`data_transfer`, PMS-648) is raw wipe-and-replace (`jsonb_populate_recordset` + id-remap), and `tickets.status_id` / `priority_id` / `queue_id` are **NOT NULL** FKs into per-tenant config (`migrations/005_tickets.sql:103-108`) that only `create_ticket` fills. To seed tickets through the raw import, the demo bundle would have to be a **full tenant snapshot** (all config + own_company + entities), regenerated on every config-default change and **wiping the fresh tenant's just-created config** on restore. That is fragile. Per the design call on PMS-651, this slice uses a **data-driven, create-only service-layer load** instead (PMS-621's original vision): correct per-tenant config FKs via `create_ticket`, non-destructive, and the demo set is now editable without touching Rust. It intentionally does not reuse the wipe-replace restore path. ## AC status - [x] AC3 (data.rs hardcoded rows are no longer the seed source) - the bundle is the source; the load path is the service layer, not the restore path (relaxed per the design decision). - [x] AC4 (guards unchanged) - `ensure_demo_seeded` / `seed_rows` untouched: `demo_seeded` CAS, emptiness check, shared-landing-tenant exclusion, `MOKOSH_DEMO_SEED` kill switch all intact. - [x] AC5 (clean non-zQA dataset) - the bundle is the PMS-629 clean baseline; the PMS-629 assertion still guards it. - [x] AC7 (tests) - seed output is unchanged, so `tests/seed_demo.rs` (fresh-tenant counts, idempotency, PMS-239 exclusion, non-empty-tenant skip) still covers a clean seed on a fresh DB; a new `data.rs` unit test guards that the embedded bundle parses to the expected shape. Frontend (AC1/AC6) is delivered by MAPPS-364; API (AC1/AC2) by PMS-647/648. ## Testing `just pre-commit` green (fmt / clippy -D / compile --all-targets / unit incl the new bundle-parse test / doc). The `seed_demo` integration tests run in the Integration job. #PMS-651
feat(seed): load first-visit demo data from a committed bundle, not hardcoded Rust (PMS-651)
All checks were successful
E2E / Playwright against staging (pull_request) Successful in 36s
Check / fmt + clippy + build + tests (pull_request) Successful in 1m34s
Integration / integration tests (pull_request) Successful in 5m28s
Create release / Gate (release-branch merges only) (pull_request) Successful in 1s
Create release / Create release from merged PR (pull_request) Has been skipped
1c0c120ccf
Moves the demo seed content (company / contact / ticket names, titles, descriptions) out of hardcoded Rust literals in src/modules/seed/data.rs into a committed, compile-time-embedded src/modules/seed/demo_seed.json bundle. data.rs now maps that bundle into the same Create*Request DTOs and seeds through the real service methods, so ensure_demo_seeded / seed_rows and every guard (demo_seeded CAS, emptiness check, shared-landing-tenant exclusion, MOKOSH_DEMO_SEED kill switch) are unchanged, and tickets still get the tenant's per-tenant NOT-NULL config FKs (status/priority/queue) from create_ticket.

Design decision (see PMS-651): this uses a data-driven, create-only service-layer load, NOT the wipe-and-replace data_transfer restore path. Restoring a demo bundle through that path would require the bundle to be a full tenant snapshot (config included, since tickets.status_id/priority_id/queue_id are NOT NULL FKs the raw jsonb_populate_recordset load cannot resolve), regenerated on every config-default change and wiping the fresh tenant's just-created config. The service-layer loader avoids that fragility while still making the seed data-driven (PMS-621's original vision); the demo set can now change without touching Rust.

The seed output is unchanged (one "Acme Corporation (Demo)" company, two contacts, three tickets, tagged demo), so the existing tests/seed_demo.rs integration tests and the PMS-629 clean-baseline assertion still cover a clean seed on a fresh database. A new unit test guards that the embedded bundle parses to the expected shape so a malformed edit fails in CI, not at seed time.

#PMS-651
nrupard deleted branch feat/PMS-651-data-driven-seed 2026-07-13 22:16: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!448
No description provided.