Managed Members — Code Map
All paths from the repo root. Mobile paths are in the taikan-mobile repo.
Schema and migration (libs/db)
| File | Role |
|---|---|
libs/db/drizzle/0168_managed_members.sql | The single migration. Order and safety notes in data-model.md §5. |
libs/db/src/lib/schema/guardianships.ts | guardianships: subject, guardian, optional org scope, status (pending → active / revoked / expired), source, the 13 can* capabilities, attestation fields, objectionLodged, suppression (accessSuppressedFrom, reason, evidence ref). Three partial unique indexes (global, org-scoped, one primary per child). |
libs/db/src/lib/schema/users.ts | email nullable (:36) with the partial unique index users_email_unique_idx (:97); kind 'account' | 'managed' (:67); national_id_hash; CHECK that a managed user has a birth date (:108). |
libs/db/src/lib/schema/memberships.ts | participation 'trains' | 'guardian_only' (:64). |
libs/db/src/lib/schema/scheduling.ts | bookings.bookedByUserId / cancelledByUserId (:264-265). |
libs/db/src/lib/schema/forms.ts | form_signatures.signedByUserId / signedInCapacity (:355-356), signerFullName, attestationText; form_instances.signerRequirement and health-artefact expiry. |
libs/db/src/lib/schema/enums.ts | user_kind, participation_kind, guardianship_status, guardianship_source (incl. staff_enrolled), guardian_relationship, signing_capacity, actor_capacity, suppression_reason, import_reconciliation_reason. |
Shared (libs/shared)
| File | Role |
|---|---|
libs/shared/src/lib/schemas/guardianship.schema.ts | Zod schemas and types for grants, household, capabilities, staff enrolment; MANAGED_MIN_AGE_YEARS (:30). |
libs/shared/src/lib/acting-for.ts | Who the member app acts for and for whom an action may be done: defaultActingFor, actingOptions, resolveActingFor. Shared by web and mobile so both start and offer the same people. |
libs/shared/src/lib/constants/guardian-attestation.ts | The verbatim attestation text, rendered server-side and stored on the grant. |
libs/shared/src/lib/constants/feature-flags.ts | FeatureFlags.MANAGED_MEMBERS = 'managed-members'. |
libs/shared/src/lib/i18n/dictionaries/{en,he,ru}.json | managedMembers namespace (staff enrolment email, family hub, switcher, accept page, household section). |
API — the feature (apps/api/src/guardianships)
| File | Role |
|---|---|
guardianships.controller.ts | All routes: staff enrolment (POST managed-members, resend), household, pending detail, member guardianships and dependants, child profile edit, invite, request, accept, decline, approve, reject, capabilities, revoke, make-primary, objection, suppress, unsuppress. |
guardianships.service.ts | Grant lifecycle. Every public method asserts the flag first. accept creates the adult’s guardian_only membership; suppress stamps accessSuppressedFrom with the database clock; sendInvitation sends the staff-enrolment or attestation email, with a Clerk sign-up invitation as the button when the adult has no login. |
managed-members.service.ts | Staff Add child (createByStaff), child profile edits (contact-only for a guardian: 403 staff_only_field on name or email), resend, and the import entry used by the CSV importer. |
guardian-access.service.ts | The one authority resolver. actingMembership (flag, then capability, then the subject’s membership), can / check, activeGrantsFor, listAccessibleMembers (who appears in the switcher), consentQuorum, assertGuardianAge (21+). |
guardian-capability.guard.ts, require-capability.decorator.ts | Route guard: a request naming another subject needs the flag and the declared capability. |
managed-members-flag.service.ts | enabled(orgId) / assertEnabled(orgId): tier managed_members AND PostHog managed-members; fails closed. |
notification-recipients.service.ts | Who receives a notification about a person: the person, or a managed member’s confirmed adults with canReceiveNotifications. Ungated. |
guardian-access.module.ts, guardianships.module.ts | DI wiring. |
dto/*.ts | Request DTOs (staff-enrol-child, accept-guardianship, invite-guardian, request-guardianship, update-capabilities, revoke-guardianship, suppress-guardianship, objection, update-managed-member, pending-guardianship-query). |
API — touchpoints in other modules
| File | Role |
|---|---|
apps/api/src/memberships/participation.ts | promoteToTrainsOnOwnPlan: a guardian_only adult whose own plan goes live (active or scheduled, never pending) becomes trains. Called where a row is inserted live (SubscriptionsService.createSubscription for non-pending rows, plan change, and import for an active row only — an import of a cancelled membership promotes nothing) and wherever a row goes live later: WebhookProcessingService.handlePaymentCompleted (every provider, Cardcom return verification included, and a revived abandoned checkout), PresaleCheckoutService.handle, ManualPaymentService (cash prepayment for plans and packs, and advanceSubscription) and ExternalPaymentApplyService.advanceSubscription. The two advanceSubscription writers promote on every activation, whatever the prior status, so a checkout paid after the sweep released it still promotes. |
apps/api/src/memberships/memberships.service.ts | responsibleAdults=true filter (:578); the guardian’s view of a child’s member detail; actingMembership for member reads. |
apps/api/src/memberships/responsible-adults.controller.ts | Staff search for an adult to name in Add child. |
apps/api/src/class-sessions/class-sessions.service.ts, apps/api/src/bookings/bookings.service.ts | Schedule and booking for a child via actingMembership; bookedByUserId / cancelledByUserId. |
apps/api/src/bookings/booking-form-requirement.ts, apps/api/src/forms/forms.service.ts | Guardian signing (resolveSigner), youth consent (parental_consent_youth, issue + booking gate when the flag is on), signing links routed to adults. |
apps/api/src/payments/services/payer-resolver.service.ts, payment-method.service.ts | Payer and card-owner resolution for a child’s subscription. |
apps/api/src/subscriptions/subscriptions.service.ts, plan-change.service.ts, apps/api/src/plans/plans.service.ts | Buying and changing a child’s plan as their adult. |
apps/api/src/users/users.service.ts | Teen sign-up block: SignupEmailHeldByManagedError (:57, thrown at :139, :251). |
apps/api/src/webhooks/clerk-webhook.controller.ts | Acknowledges the refused sign-up with 2xx and audits it with ids only. |
apps/api/src/import/import.service.ts, import.controller.ts | Managed CSV rows (:793), reconciliation queue (:1367), GET/POST jobs/:jobId/reconciliation (:185, :201). |
apps/api/src/common/message-purpose.ts, apps/api/src/automations/channels/message-purpose.ts | Promotional sends to a minor or managed subject are hard-blocked. |
apps/api/src/progress-photos/progress-photos.service.ts | Hard block for managed members (:178). |
apps/api/src/organizations/minisites.service.ts | A managed member is never a public profile (:1123). |
apps/api/src/analytics/analytics.service.ts, apps/api/src/insights/insights.service.ts | Counts only participation = 'trains'. |
apps/api/src/organization-leads/organization-leads.service.ts | Lead matching skips managed identities. |
Web (apps/web/src)
| File | Role |
|---|---|
components/members/add-child-dialog.tsx | Staff Add child (from Members, or pre-filled from an adult’s record). |
app/[lang]/(protected)/dashboard/members/members-content.tsx | Add child entry and the People filter (training members / responsible adults); gated on tier and flag (:234). |
components/overview/members/member-detail-page.tsx | Add child on an adult’s record (:102), Message {guardian} about {child} (:444). |
components/overview/members/member-household-section.tsx | Household section: a child’s adults or an adult’s children (:47). |
components/members/pending-guardian-notice.tsx | ”Waiting to confirm” with resend on a child’s record. |
app/[lang]/(protected)/(member)/family/accept/[grantId]/page.tsx, components/member/family/accept/accept-guardianship.tsx | The adult’s confirmation: typed name (prefilled), attestation, and the birth date when the profile has none. Signed out: inline ticket sign-up, or a redirect to sign-in and back. |
app/[lang]/(protected)/(member)/family/add/page.tsx, components/member/family/add-child/* | The setup steps after accepting: health, waiver, plan, first booking. Does not create a child. |
app/[lang]/(protected)/(member)/profile/family/page.tsx, components/member/family/family-hub.tsx, household-tile.tsx | Family hub under Profile (/family redirects there). |
app/[lang]/(protected)/(member)/profile/family/[childId]/page.tsx | A child’s profile: contact-only edits. |
providers/acting-context-provider.tsx, components/member/family/member-switcher.tsx, member-rail.tsx, lib/acting-paths.ts, lib/acting-scoped-query.ts | View as child: the selected subject (starting at defaultActingFor), the switcher, and child-keyed queries. |
components/member/acting-for-picker.tsx, app/[lang]/(protected)/(member)/shop/page.tsx, shop/payment-return/page.tsx, components/member/schedule/session-detail-drawer.tsx | ”Who is this for?” on the Shop and “Booking for” on a session; buying for a child (onBehalfOfUserId) and confirming it on return (?for=). |
components/member/family/view-only-notice.tsx, action-notice.tsx, child-plan-summary.tsx | View-only states and the child’s plan summary. |
Mobile (taikan-mobile)
| File | Role |
|---|---|
src/providers/acting-provider.tsx | View-as-child context. |
src/components/family/member-switcher.tsx, household-tile.tsx, view-only-gate.tsx, section-not-permitted.tsx | Switcher and permission states. |
app/family/accept/[grantId].tsx, src/components/family/guardian-attestation.tsx | Confirmation. |
app/(tabs)/profile/family/index.tsx, [childId]/profile.tsx, [childId]/setup.tsx, src/components/family/setup-steps.ts, child-forms-step.tsx | Family hub, child profile, setup steps. |
Tests
| Area | Specs |
|---|---|
| Grants and access | apps/api/src/guardianships/guardianships.int.spec.ts, guardian-access.service.int.spec.ts, guardian-capability.guard.unit.spec.ts, managed-members-flag.service.unit.spec.ts, __tests__/route-capability-architecture.unit.spec.ts |
| Enrolment and children | staff-enrolment.int.spec.ts, managed-members.int.spec.ts, apps/api/src/memberships/managed-member-guards.int.spec.ts, member-detail-authz.int.spec.ts, member-erasure-guardianship.int.spec.ts |
| Booking, training, forms | apps/api/src/bookings/guardian-booking.int.spec.ts, apps/api/src/workout-results/view-as-child-training.int.spec.ts, apps/api/src/forms/guardian-signing.int.spec.ts |
| Billing | apps/api/src/payments/services/payer-resolver.service.int.spec.ts, payer-routing.int.spec.ts, apps/api/src/subscriptions/guardian-subscription-authority.int.spec.ts |
| Notifications | notification-recipients.service.int.spec.ts, apps/api/src/notifications/managed-member-routing.int.spec.ts, apps/api/src/announcements/announcement-guardian-routing.int.spec.ts |
| Guards | apps/api/src/progress-photos/managed-member-block.int.spec.ts, apps/api/src/messages/managed-member-direct-message.int.spec.ts, apps/api/src/organization-leads/lead-managed-identity.int.spec.ts, apps/api/src/analytics/participation-filter.int.spec.ts, apps/api/src/automations/channels/message-purpose.unit.spec.ts |
| Sign-up and import | apps/api/src/users/managed-email-signup.int.spec.ts, apps/api/src/import/managed-import.int.spec.ts |
| Web | components/members/add-child-dialog.int.spec.tsx, dashboard/members/members-add-child.int.spec.tsx, overview/members/member-household-section.int.spec.tsx, member/family/**/*.int.spec.tsx, providers/acting-context-provider.int.spec.tsx, profile/family/**/*.int.spec.tsx |