New: PHASE8_ENROLLMENT_OPERATIONS.md (phase summary), WINTER_BREAK_CAMP_OPERATIONS.md (the real operational walkthrough), REGISTRATION_AND_GUARDIAN_COMMUNICATIONS.md, OFFERING_ADMIN_GUIDE.md. Updated: ROOTNODE_ACADEMY_BUSINESS_AND_PRODUCT_ARCHITECTURE.md (BUILT NOW/PHASE 8 BUILT table), OFFERING_AND_REGISTRATION_MODEL.md (both ordering bugs, launch readiness, registration enforcement), STUDENT_GUARDIAN_DATA_MODEL.md (guardian communications now wired), WEBSITE_ENROLLMENT_INTEGRATION.md (the real, live registration contract with worked examples, replacing the old speculative future-flow section), platform/README.md (test list). Co-Authored-By: Claude Sonnet 5 <[email protected]>
3.9 KiB
Registration & Guardian Communications
Phase 8 §8-§11 — how registration-stage notifications extend the existing Phase 5C notification
system. No second email subsystem was built: same notification_events table, same durable
worker (notification-worker.js), same Google Workspace-backed provider adapter
(email/provider.js), same masked-recipient admin API.
What's new vs. Phase 5C
notification_events.student_id is now nullable, and a registration_id column was added (a
CHECK constraint guarantees every row still has a real subject) — because a registration-stage
notification (Registration Received, Agreement Required) may need to go out before any student
account exists at all, for a brand-new guardian-submitted registration. notification_type's
CHECK constraint was widened to include five new types. See 033_phase8_...sql and
036_phase8_notification_types.sql.
A real bug found and fixed during this phase's own testing: the new notification types were
added to notifications.js/notification-worker.js before the database CHECK constraint was
widened to accept them — every registration-stage enqueue call was silently failing (caught by
the deliberate "a notification failure never blocks the real action" try/catch) until this was
caught and fixed. See docs/PHASE8_ENROLLMENT_OPERATIONS.md.
The five new templates
- Registration Received — queued the moment a registration is created (website or admin).
- Registration Confirmed — queued when a registration moves to
confirmed. - Registration Needs Action — available for an admin/future-flow to queue with a reason when a registration needs something before it can proceed (not automatically triggered by any single lifecycle transition this phase — a deliberate choice, since "needs action" covers many different real reasons an admin should state explicitly).
- Agreement Required — queued once per missing required agreement when a registration
enters
agreements_pending. - Camp/Offering Operational Update — a deliberately generic operational notice (e.g. "camp starts Monday, here's what to bring"), NOT a marketing template — no promotional content, no discount codes, no unrelated announcements. Available for an admin to trigger manually; nothing queues it automatically.
All five are HTML + plain-text, RootNode-branded, no tracking pixels, no external images, no
passwords or sensitive data — same templates.js conventions Phase 5C established.
Recipient resolution — extended, never overwritten
resolveRecipient()'s existing order (student's own email → the enrollment's
metadata.contact_email) now has a third, final fallback: a real, communications-enabled
primary guardian's email (student_guardians/guardians). This is purely additive — a student
who already resolves correctly today is completely unaffected, since the new fallback is only
ever reached when the first two return nothing. enrollmentContactEmail (Phase 5C, unchanged)
and this new guardian fallback deliberately coexist: contact_email remains a per-enrollment
override for the live website integration's existing contract, while the guardian relationship
is the durable, cross-enrollment identity — prefer the guardian model going forward, but the
transitional field is never broken.
For registration-stage notifications (no student yet, possibly), a separate
resolveRegistrationRecipient() tries: the registration's own student (if already converted) →
its linked guardian → the registrant's own supplied email.
What was deliberately NOT built
No bulk/marketing email composer, no free-form admin-authored message sent to an arbitrary recipient — every notification is one of the fixed templates above, triggered by a real lifecycle event or an explicit, scoped admin action (never a raw "compose email" form). No SMS. No third notification channel beyond email.