Workflow: Family Onboarding

Technical reference for the shared family onboarding aggregate. This module is currently projection-first: it centralizes readiness and next-step decisions used by parent and coordinator surfaces, even though it does not yet own many write commands.

Current scope

Family onboarding is active as a shared aggregate + projection layer. It currently answers questions such as whether the family has an address, whether any child exists, and which child IDs are ready for posting. It is not yet a heavy mutation workflow like the session or posting modules.

Module Contract

ConcernImplementationWhat it does
Workflow moduleworkers_nivaa/src/lib/workflows/family-onboarding/Owns the parent + child readiness aggregate and normalized family projection.
Aggregatetypes.ts + repository.tsLoads the parent account plus each child and linked student-profile intake readiness.
Projectionguards.ts + projections.tsCalculates has_family_address, has_any_child, ready_child_ids, and next_step.
Command surfacecommands.tsCurrently exposes observation only; mutation routes still live elsewhere.
Effectseffects.tsPackages the aggregate into the shared workflow result contract for API consumers.

Consumers

SurfaceHow it uses the workflowWhat changes because of it
GET /profile/parent/meReturns family_onboarding projection alongside parent particulars.Parent workspace can show the next family onboarding step without duplicating readiness logic.
GET /children/overviewAnnotates each child with ready_for_posting based on the aggregate.Parent and admin child lists can distinguish intake-complete vs not-ready children consistently.
POST /postingsUses requireFamilyOnboardingAggregate(), assertChildOwnedByParent(), and assertChildReadyForPosting().Parents cannot create a posting for a child that is missing intake readiness.
Admin parent detailReads the same family projection.Coordinator sees family readiness using the same rules as the parent-facing UI.

Detailed Lifecycle

StepTriggerWorkflow evaluationResultImpacted next action
1. Parent account existsParent signs up or is importedAggregate checks users.address_data and basic parent identity fields.Projection can still report has_family_address = false.Parent is steered toward family profile completion.
2. Child profile existsParent or coordinator creates a child rowAggregate now has at least one child but still checks student-profile intake linkage.Projection may show has_any_child = true but no ready_child_ids yet.Parent can continue child intake.
3. Student profile intake capturedChild intake/readiness flow creates or updates student_profiles requirements.Aggregate marks that child hasIntake = true and readyForPosting = true when the required fields are present.Child appears in ready_child_ids.Parent can create a posting for that child.
4. Posting request attemptedParent submits /postingsPosting workflow calls family-onboarding guards before any posting write occurs.If the child is not ready, the route fails before inserting a posting row.Parent must finish intake before retrying.
5. Parent and coordinator dashboards renderAny read of profile/overview/admin parent detailConsumers receive the same normalized next-step model from one place.No state drift across parent/admin views.Subsequent onboarding guidance stays consistent across the product.

Tables And Fields Touched

  • users: parent display_name, phone, address_data, created_at.
  • child_profiles: id, display_name, level/school/curriculum, deactivated_at.
  • student_profiles: intake requirement fields used as the readiness signal for posting eligibility.