docs: HANDOFF pass-56, Phase 4 notification breadth + migration 047
Adds an ARCHITECTURE section "Notification breadth: bookings, classes, forms" describing each new event type, the triggering action, the recipient rule, and the dedupe-key scheme. Updates Known Limitations #5 to reflect that booking + class + form notifications are no longer "not wired yet." API_REFERENCE: extends the Transactional notifications section with the shared enqueue helper, every new event type, its trigger and recipient, and the new members_with_permission RPC used for the forms.manage fan-out. DATABASE_SCHEMA + DB_SCHEMA_MAP: adds the migration 047 row and the new helper function to the helper-functions list. HANDOFF: pass-56 entry covers the four locked design forks, the four sub-phase commits, test growth (532 -> 565, +33 cases), state (local, inert post-deploy until owner provisions Resend + CRON_SECRET), the known fan-out volume tradeoff, and the remaining backlog.
This commit is contained in:
+2
-1
@@ -412,6 +412,7 @@ Default channels created by trigger on space INSERT: `general`, `announcements`,
|
||||
| 044 | `prevent_member_self_role_change` also blocks self-change of payment_status, payment_note, dues_paid_until, last_paid_at, last_payment_at, stripe_customer_id, joined_at (member could otherwise forge a dues-good signal via PostgREST). Service-client/privileged writes still bypass. No new table/column |
|
||||
| 045 | `class_signup_tx` / `class_cancel_tx` SECURITY DEFINER functions: capacity-decision+insert and cancel+waitlist-promote run under a per-session `pg_advisory_xact_lock` (concurrent signups can't over-enroll; concurrent cancels can't double-promote). Mirrors the pure computeSignupStatus/pickPromotion rule; RPC is runtime authority. No new table/column |
|
||||
| 046 | `user_has_role_in_space` + `user_has_permission` gated on `status IN ('current','late')` (RLS-layer defense-in-depth for D2): unverified/inactive can no longer exercise a role/permission via direct PostgREST. `get_user_space_ids` + `user_effective_roles` intentionally NOT gated (would break unverified self-reads / onboarding). No new table/column |
|
||||
| 047 | `members_with_permission(sid, perm)` SECURITY DEFINER, set-returning inverse of `user_has_permission` (same current/late gate, same admin shortcut + `space_role_permissions`/`user_effective_roles` fallback). Lets Phase 4 fan-outs (e.g. `form_submission_admin`) resolve permission holders in one query. No new table/column/policy |
|
||||
|
||||
---
|
||||
|
||||
@@ -452,4 +453,4 @@ Default channels created by trigger on space INSERT: `general`, `announcements`,
|
||||
|
||||
Column additions: `space_members.tier_id`, `onboarding_completed_at`, `onboarding_progress`; `secrets.encrypted_value`, `encryption_version`; `knowledge_base.render_markdown`, `is_meeting_minutes`, `meeting_date`; `classes.required_form_id`; `spaces.host_requires_card`. New enum `comment_entity_type`.
|
||||
|
||||
Helper functions: `user_effective_roles(uid,sid)`, `user_has_permission(uid,sid,perm)` (both SECURITY DEFINER, search_path=public), plus governance quorum/tally/SLA functions.
|
||||
Helper functions: `user_effective_roles(uid,sid)`, `user_has_permission(uid,sid,perm)`, `members_with_permission(sid,perm)` (all SECURITY DEFINER, search_path=public), plus governance quorum/tally/SLA functions.
|
||||
|
||||
Reference in New Issue
Block a user