Skip to content

feat(events): rename Programme* models to Event*/Template*#267

Merged
mindsers merged 9 commits into
mainfrom
feat/events/rename-programme-to-event
Jul 20, 2026
Merged

feat(events): rename Programme* models to Event*/Template*#267
mindsers merged 9 commits into
mainfrom
feat/events/rename-programme-to-event

Conversation

@mindsers

Copy link
Copy Markdown
Contributor

Summary

PR-B of the events data model refactor — pure symbol rename. No behavioural change. Follows PR #265 (EventKind → Template merge).

  • 10 Prisma models renamed to drop the Programme prefix and the misleading Assignment suffix. Tables now read as "EventTemplate describes the shape, EventPart is a materialised instance".
  • Field-name adjustments where the relation semantics improve (Event.parts reads better than Event.partAssignments; Member.eventPartsAsAssignee preserves the role hint the old partAssignments carried).
  • One data-preserving migration (20260720300000_rename_programme_to_event) — pure ALTER TABLE … RENAME TO, rewrites entityType strings on AuditLog + NotificationEvent so audit queries don't have to reason about two names forever. RLS policies survive automatically (bound to table OID, not name).

Deliberately kept

  • Programme in display-board — that's the domain vocabulary (the meeting programme rendered on the board), not a Prisma model reference.
  • programme_* i18n keys — the values reference the same domain concept in French/English, and the programme-templates.ndjson etc. archive names stay for backup-import compatibility.
  • File renames (programme-*.server.tsevent-*.server.ts) — deferred to a follow-up PR to keep this one focused on the model rename and reduce merge conflicts for branches open against main.

Test plan

  • pnpm test:typecheck — clean
  • pnpm test:unit — 2176 pass
  • pnpm test:integration — 265 pass, 1 skipped
  • pnpm test:lint — 0 errors
  • pnpm test:file-sizes, pnpm test:boundaries, pnpm test:server-barrel-exports, pnpm test:service-test-coverage — all pass
  • Staging DB sanity: SELECT tablename FROM pg_tables WHERE tablename LIKE 'Programme%' returns 0 rows
  • Staging DB sanity: SELECT DISTINCT \"entityType\" FROM \"AuditLog\" WHERE \"entityType\" LIKE 'Programme%' returns 0 rows
  • Staging DB sanity: SELECT tablename, policyname FROM pg_policies WHERE tablename IN ('EventTemplate','TemplatePart','TemplateServiceRole','EventPart','EventServiceRole','TemplateResponsible', ...) returns tenant_isolation on each renamed table
  • Staging UI: create an event via /programs/new, assign a part, release, verify email queues, verify dashboard "next meeting" renders

Follow-ups (not in scope)

  • File renames: app/features/events/server/programme-*.server.tsevent-*.server.ts, ProgrammeDocument.tsxEventDocument.tsx, etc.
  • Optional: rename data_transfer_entity_programme_* i18n keys + entity file names once we're comfortable breaking backup compatibility.

@mindsers
mindsers force-pushed the feat/events/rename-programme-to-event branch from c69532e to 7a52a99 Compare July 20, 2026 06:57
mindsers added 7 commits July 20, 2026 10:40
Prisma model rename map:
- ProgrammeTemplate                         → EventTemplate
- ProgrammeTemplatePart                     → TemplatePart
- ProgrammeTemplateServiceRole              → TemplateServiceRole
- ProgrammePartAssignment                   → EventPart
- ProgrammeServiceRoleAssignment            → EventServiceRole
- ProgrammeTemplateResponsible              → TemplateResponsible
- ProgrammeTemplatePartAllowedRole          → TemplatePartAllowedRole
- ProgrammePartAssignmentAllowedRole        → EventPartAllowedRole
- ProgrammeTemplateServiceRoleAllowedRole   → TemplateServiceRoleAllowedRole
- ProgrammeServiceRoleAssignmentAllowedRole → EventServiceRoleAllowedRole

Field-name adjustments:
- Event.partAssignments        → Event.parts
- Event.serviceRoleAssignments → Event.serviceRoles
- Member.partAssignments       → Member.eventPartsAsAssignee
- Member.partAssistantAssignments → Member.eventPartsAsAssistant
- Member.serviceRoleAssignments → Member.eventServiceRolesAsAssignee
- ExternalSpeaker.partAssignments → ExternalSpeaker.eventParts
- Role.allowedForPartAssignments → Role.allowedForEventParts
- Role.allowedForServiceRoleAssignments → Role.allowedForEventServiceRoles

Migration 20260720300000_rename_programme_to_event does pure
ALTER TABLE ... RENAME TO for the tables, renames every PK/FK/index
to Prisma's expected convention, and rewrites historical entityType
strings on AuditLog and NotificationEvent. RLS policies survive the
rename automatically (bound to table OID, not name — same as the
20260507 user_role_to_permission precedent).

Deliberately kept:
- Programme in display-board — the domain vocabulary (the meeting
  programme rendered on the board).
- programme_* i18n keys — values reference the same domain concept;
  NDJSON archive names stay for backup-import compatibility.
- File renames (programme-*.server.ts → event-*.server.ts) — deferred
  to a follow-up PR to keep this focused and reduce merge conflicts.
…ile renames

Applies the PR review findings on top of the initial model rename:
- migration `20260720400000_finish_programme_to_event_cleanup` renames the
  `assignmentId` FK columns on the two allowed-role join tables to
  `eventPartId` / `eventServiceRoleId`, and rewrites still-pending
  `NotificationEvent.debounceKey` rows so the post-rename debounce lookup
  keeps matching pre-deploy pending entries
- schema back-relations align with the new model names
  (`TemplatePart.eventParts`, `TemplateServiceRole.eventServiceRoles`,
  `Event.eventParts`, `Event.eventServiceRoles`)
- helper files renamed from `programme-*` / `Programme*` to `event-*` /
  `template-*` / `Event*` via `git mv`, with imports swept across the
  codebase and the guard scripts / biome overrides updated to match
- `ARCHIVE_VERSION` bumped 2.0 → 2.1 with a `rewriteLegacyEntityType` shim
  in the AuditLog importer so historical `Programme*` entityType strings
  become `Event*` / `Template*` on read; NDJSON archive filenames stay
  frozen for backward compatibility
- stale "programme assignments" comments and doc references updated to
  the new domain vocabulary, with a Programme-vs-Event section added to
  the architecture conventions doc
…dels

Rebase carry: the viewer-role tagging (#266) and part-role-labels (#268)
PRs shipped tests that reference `db.programme*` and `event.partAssignments`,
which are the pre-rename names. Retarget them at `db.eventPart` /
`db.templatePart` / `event.eventParts` so the suite stays green on top of
the Programme→Event rename.
…column

Two runtime callers still passed the old `assignmentId` name to Prisma
after the column rename to `eventPartId` / `eventServiceRoleId`:

- edit.tsx loader — read fails with `Unknown argument 'assignmentId'`
  when opening the event edit page, because the join-table where/select
  used the pre-rename column name.
- export-congregation.server.ts — writes the two `*-allowed-roles`
  NDJSON files. Selects `eventPartId` / `eventServiceRoleId` from the
  DB now and renames the field to `assignmentId` on serialize so the
  archive format stays byte-compatible with pre-2.1 importers.

Typecheck passed because both sites had no `select` narrowing that
tripped on the removed column at compile time — the failure only surfaced
at query planning time.
"Role" was overloaded — it named both permission roles (Role model) and
event assignment slots (ServiceRole model). Renaming the second one to
ServicePart aligns the family of join tables into a clean, symmetric
pattern:

  TemplatePart / EventPart               → meeting parts (talks, readings)
  TemplateServicePart / EventServicePart → service parts (sound, ushering)
  <Parent>AllowedRole                    → which Roles are allowed on that slot

Now "Role" unambiguously means permission role, and every AllowedRole
join table reads the same way.

Changes:
- Schema rename: TemplateServiceRole → TemplateServicePart, EventServiceRole
  → EventServicePart, and their two AllowedRole join tables. FK columns
  renamed to match (serviceRoleId → servicePartId, eventServiceRoleId →
  eventServicePartId).
- Field renames on Event, EventTemplate, Congregation, Member, Role.
- Migration `20260720500000_rename_service_role_to_service_part`: mirror
  of the Programme→Event one — table rename via ALTER preserves rows, FKs,
  and RLS policies (bound to OID). Also rewrites AuditLog / NotificationEvent
  entityType strings from `EventServiceRole` to `EventServicePart` and
  rebuilds pending debounceKeys so post-deploy notification cancellation
  keeps matching.
- Code sweep across ~70 files: Prisma model access, function names
  (updateServiceRoleAssignment → updateServicePartAssignment), types
  (ServiceRoleReleaseAssignment, ServiceRoleRow), local vars, and audit
  action enum (ServiceRoleAllowedRolesChanged →
  ServicePartAllowedRolesChanged).
- i18n keys stay `_service_role_*` — the user-facing "service role" copy
  in French/English is unchanged, and renaming the JSON keys is out of
  scope for this PR.
- NDJSON archive filenames stay frozen (`programme-service-role-assignments`
  etc.) for pre-2.1 archive backward compatibility, same principle as the
  Programme→Event rename.
Review flagged that the `rewriteLegacyEntityType` shim had wrong map
keys. My earlier ServiceRole→ServicePart sweep rewrote them
(`ProgrammeTemplateServiceRole` → `ProgrammeTemplateServicePart`,
`ProgrammeServiceRoleAssignment` → `ProgrammeServicePartAssignment`),
but real pre-2.1 archives store the original `ProgrammeTemplateServiceRole`
/ `ProgrammeServiceRoleAssignment` strings — never the interim names.
The colocated test mirrored the same wrong strings, so it locked in the
bug: every import of a pre-2.1 archive silently passed those two audit
strings through untouched and wrote dead entity names back into
`AuditLog.entityType`.

Fixes:
- Restore the original `Programme*ServiceRole*` keys in the map, so
  pre-2.1 archives map straight to the current `ServicePart` names.
- Add `EventServiceRole` → `EventServicePart` and `TemplateServiceRole`
  → `TemplateServicePart` for 2.1-era archives (exported between the
  two renames in this same PR).
- Rewrite the test to assert against the actual pre-2.1 strings and
  cover the 2.1 fallback too, with a comment referencing the old
  schema so future maintainers see why the keys look the way they do.

Also flush comment/doc rot the review surfaced:
- `architecture-conventions.md`: correct migration timestamp
  (`20260720300000` → `20260720350000`), rename stale
  `programmeAssignmentPolicy` / `assignServiceRole` references, mention
  the ServicePart follow-up migration and its rationale, extend the
  frozen-NDJSON note to list `programme-service-role-assignments.ndjson`.
- `notifications.md`: "service-role assignee" → "service-part assignee"
  in the release-fire paragraph.
- Migration `20260720400000` header: bump the sibling-migration
  timestamp and spell out the two actual pre-rename join-table names.
- `template-role.ts` header: drop "programme part or service-role
  assignment" for the current "event part or event service part"
  vocabulary.
- `days-off.tsx` inline comment: "service roles" → "event service parts".
Adds an integration test that seeds a synthetic archive with one row per
legacy `entityType` (pre-2.1 Programme* + 2.1-era ServiceRole*, plus a
current-name control), runs it through the real `importAuditLogs` path
against the live test DB, and asserts every persisted row carries the
current model name.

The colocated unit test for `rewriteLegacyEntityType` already covers the
mapping — but the review flagged that a same-authored unit test can lock
in a wrong mapping. This end-to-end round-trip proves the shim actually
rewrites entityTypes on the way into `AuditLog.entityType`, exercising
Prisma serialization + write path in one shot. It would have caught the
`ProgrammeTemplateServicePart` map-key bug at the branch level.
@mindsers
mindsers force-pushed the feat/events/rename-programme-to-event branch from 0ed318a to 52ac70e Compare July 20, 2026 08:43
mindsers added 2 commits July 20, 2026 11:44
Second-pass review flagged that the new integration test seeded every row
with `actorId: null`, leaving the `idMap.getOptional('user-accounts', ...)`
branch unexercised. If a future rename tweaks the FK remap, a legacy
archive that carries a real `actorId` would silently null out its actor
without any test failure to surface it.

Extends the test with three actor shapes on the same run:
- Row 0: mapped source actor → asserts target actor id round-trips.
- Middle rows: `actorId: null` → asserts null passes through untouched
  (the pre-existing case, still covered).
- Last row: source actorId not in `idMap` → asserts `getOptional`'s
  null fallback is what actually lands in the row (documenting the
  observed behavior).

Also refine two comments the reviewers surfaced:
- Drop the misleading "sort both by the LEGACY string" note — rows are
  ordered by `entityId` and `cases[i]` maps to `rows[i]` because the
  seed uses monotonic `id: 1000 + i`. State that up front instead.
- Tighten the shim's `TemplateServiceRole` / `EventServiceRole` entries
  comment: no released 2.1 archive can carry those strings (both
  renames ship in the same PR); they cover pre-merge / dev / preview
  archives produced between the two rename commits.
… rename

Six stale technical references caught in dev docs post-rename:

- architecture.md model catalog listed `ProgrammeTemplate` / `EventKind` /
  `ProgrammePartAssignment` / `ProgrammeServiceRoleAssignment` etc; now
  `EventTemplate` / `TemplatePart` / `TemplateServicePart` / `EventPart`
  / `EventServicePart` / `TemplateResponsible`. EventKind is gone (merged
  into EventTemplate in PR #265).
- architecture.md FK rule example used the old `ProgrammePartAssignment` /
  `ProgrammeServiceRoleAssignment` — now `EventPart` / `EventServicePart`.
- architecture-conventions.md import example imported the deleted
  `EventKind` symbol; now imports `EventTemplateKey`.
- coding-conventions.md `Setting and EventKind have compound unique keys`
  gotcha still cited the deleted `EventKind`. Real current set is
  `Setting`, `Role`, and `EventTemplate` (grep of schema.prisma
  confirmed).
- coding-conventions.md aggregate-doctrine reference to
  `ProgrammeAssignment` — now `EventPart` (the policy file's name).
- row-level-security.md tenant-scoped table list had every renamed
  model under its old name; refreshed to the current 12 Event/Template
  identifiers.
- data-transfer.md `ARCHIVE_VERSION` still said 2.0 — bumped narrative
  to 2.1 with the shim rationale. `1.0` archive description switched
  from "programme parts/service-roles" to "template parts / template
  service parts". Conflict-resolution table row for "Event kinds"
  renamed to "Event templates".

Product docs (`docs/product/*.md`) and self-hosting/managed docs use
"programme" as the domain word — those stay unchanged per the
user-facing vocabulary policy.
@mindsers
mindsers merged commit 74979e8 into main Jul 20, 2026
5 checks passed
@mindsers
mindsers deleted the feat/events/rename-programme-to-event branch July 20, 2026 09:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant