docs(phase8): document enrollment operations
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]>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
# 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
|
||||
|
||||
1. **Registration Received** — queued the moment a registration is created (website or admin).
|
||||
2. **Registration Confirmed** — queued when a registration moves to `confirmed`.
|
||||
3. **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).
|
||||
4. **Agreement Required** — queued once per missing required agreement when a registration
|
||||
enters `agreements_pending`.
|
||||
5. **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.
|
||||
Reference in New Issue
Block a user