Skip to content

fix(seed): populate built-in role assignments in marketing seed (#252)#277

Merged
mindsers merged 1 commit into
mainfrom
fix/252-marketing-seed-role-assignments
Jul 21, 2026
Merged

fix(seed): populate built-in role assignments in marketing seed (#252)#277
mindsers merged 1 commit into
mainfrom
fix/252-marketing-seed-role-assignments

Conversation

@mindsers

Copy link
Copy Markdown
Contributor

Summary

Fixes #252. The marketing seed created publishers via raw prisma.member.create(...), bypassing the Member aggregate that calls syncBuiltInRoleAssignments. Seeded members ended up with zero MemberRoleAssignment rows, so the assign-part loader's fallback (built-in member role) returned no candidates and the speaker/reader/service-role comboboxes rendered empty.

Changes

  • app/database/seed-marketing.ts — seed the built-in Role rows after the congregation exists (fresh-DB safety, regardless of whether db:seed ran first) and call syncBuiltInRoleAssignments after each member.create.
  • app/shared/domain/built-in-roles.server.ts — scope the built-in Role lookup by congregationId. Production callers run inside an RLS scope (SET LOCAL app.congregation_id), so this is a no-op there. But callers that bypass RLS — seed scripts run as the DB owner — would otherwise match every congregation's built-in roles and write cross-tenant assignments. Discovered while verifying: without this, a member got each role ~10× (44 foreign-congregation assignments) on a multi-congregation dev DB.
  • scripts/check-aggregate-boundaries.ts — the flagged CI hole. Widen the write regex to catch prisma.member.* / prisma.attribution.* (not just db.*), and move the app/database/** seed exemption from prose in docs/development/architecture-conventions.md into actual enforcement. This is why the seed's bypass never tripped the boundary check.
  • Tests: unit case locking the congregation-scoped role lookup; boundary tests for prisma.-prefixed writes being flagged and app/database/** being exempt.

Verification

  • pnpm db:seed:marketing runs clean. Post-seed: marc.dupont@demo.unitae.app has exactly [baptized, brother, elder, member, publisher], 0 foreign-congregation assignments, 0 active demo members with empty roles, and all 45 publishers hold the member built-in role → resolveEligibleUserIds now returns 45 candidates (was []), so the comboboxes populate.
  • pnpm test:typecheck clean · pnpm test:aggregate-boundaries 1124 files, no violations · unit tests green (built-in-roles 17/17, boundary 16/16).

Note: the repo's test:boundaries (eslint-plugin-boundaries) is currently broken on main after #271 bumped the plugin to 7.0.2 (config key policiesrules); unrelated to this PR.

The marketing seed created publishers via raw prisma.member.create, bypassing
the Member aggregate that calls syncBuiltInRoleAssignments. Seeded members had
zero MemberRoleAssignment rows, so the assign-part loader's fallback (built-in
`member` role) returned no candidates and speaker/reader/service-role
comboboxes rendered empty.

- seed-marketing.ts: seed built-in Role rows after the congregation exists
  (fresh-DB safety) and call syncBuiltInRoleAssignments after each member
  create.
- built-in-roles.server.ts: scope the built-in Role lookup by congregationId.
  Production callers run inside an RLS scope so this is a no-op there, but
  callers that bypass RLS (seeds run as the DB owner) would otherwise match
  every congregation's built-in roles and write cross-tenant assignments.
- check-aggregate-boundaries.ts: widen the write regex to catch prisma.* (not
  just db.*) and move the app/database/** seed exemption from prose into
  enforcement — this is why the bypass never tripped the boundary check.
@mindsers
mindsers merged commit 0360e87 into main Jul 21, 2026
7 checks passed
@mindsers
mindsers deleted the fix/252-marketing-seed-role-assignments branch July 21, 2026 06:51
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.

bug(seed): marketing seed leaves members without role assignments — programme part comboboxes empty

1 participant