Skip to content

Accounts & Authentication

Spec Source: Document 1 — Core Platform & Accounts | Document 10 — Data Security & Privacy | Last Updated: Feb 2026

Overview

Every person on DoCurious has a single account. That account is theirs forever — it belongs to the individual, not to any school, organization, or parent. A student who graduates keeps everything: their challenges, Track Records, achievements, and XP. A teacher who switches schools keeps their personal history. This is a core design principle.

Roles are contextual and additive. A teacher can also be a personal challenge doer on weekends. A parent can have their own Bucket List while also overseeing their child's account. The platform uses a context-switching model (similar to Slack workspaces) to keep these separate while living under one login.

The account system is built around three key concerns: (1) getting people signed up quickly so they can start doing things in the real world, (2) keeping minors safe through COPPA-compliant two-tier accounts, and (3) giving users full control over their data. DoCurious profiles are intentionally minimal — the platform is about doing, not self-presentation. Users express themselves through their Track Records, Bucket Lists, and community participation, not through profile pages.

How It Works

Registration & Sign-In

STATUS: BUILT

Auth store, login page, register page, forgot/reset password, Google and Apple OAuth stubs, mock and real API layers all implemented.

DoCurious supports three ways to create an account:

  1. Email + password — Standard registration with email verification
  2. Google Sign-In — OAuth 2.0 integration
  3. Apple Sign-In — Sign in with Apple

All three methods produce the same account type. A user who signs up with Google or Apple can later add a password for email-based login, and vice versa. The codebase has both a mock API (src/api/auth.api.ts) for development and a real API client (src/api/auth.real.api.ts) ready for backend integration.

What happens during registration:

  1. User provides email, password (or OAuth token), display name, and date of birth
  2. System checks date of birth for COPPA gating (see Two-Tier Under-13 Accounts)
  3. If under 13: user must register through a school code or provide a parent email — otherwise registration is rejected
  4. Display name is set — this is a permanent unique identifier for the account
  5. User arrives at the platform — interest-based challenge preferences are NOT presented during sign-up (they are collected on first visit to Explore Challenges instead)
  6. Interests are saved to user settings and can be updated anytime
  7. The platform learns from behavior over time: challenges viewed, started, completed, and categories interacted with inform future recommendations

Password requirements:

  • Minimum 8 characters
  • At least one uppercase letter, one lowercase letter, and one number
  • Checked against common password lists (Have I Been Pwned top 100k)
  • No maximum length cap (up to 128 characters)

Session Management

STATUS: BUILT

JWT tokens with persistence to localStorage, refresh token rotation, session initialization on app load all implemented in useAuthStore.

Sessions use JWT tokens with the following configuration:

  • Access token: 24-hour expiry (mock API) / 15-minute expiry (spec for production)
  • Refresh token: 7-day expiry (mock) / 30-day expiry (spec for production)
  • Refresh token rotation: a new refresh token is issued with each access token refresh
  • Tokens are HttpOnly, Secure, SameSite=Strict cookies in production
  • Maximum 5 concurrent sessions per user (configurable)
  • Idle timeout: 7 days of inactivity

Admin sessions have stricter rules:

  • 8-hour timeout
  • 1-hour idle timeout
  • Re-authentication required for sensitive actions

The auth store persists only tokens and active workspace to localStorage. User data is rehydrated from the API on each app load via the initialize() action.

Rate Limiting & Brute Force Protection

STATUS: BUILT

Login rate limiting is implemented on auth routes with 5 attempts/15min for login and 15 attempts/15min for general auth.

EndpointLimitLockout
Login5 attempts per 15 min per account15-minute lockout after 5 failures
Login (IP-level)20 attempts per 15 min per IPIP-level throttle
Password reset3 per hour per emailSilently ignore excess (no error shown — prevents enumeration)
Registration5 per hour per IPIP-level throttle
API (authenticated)100 requests per minute429 response
API (unauthenticated)20 requests per minute429 response
File upload10 per minute429 response

Lockouts are progressive: 15 minutes after 5 failures, 30 minutes after 10, 1 hour after 15. The login endpoint never reveals whether an email exists in the system — this prevents email enumeration attacks.

Password Reset

STATUS: BUILT

ForgotPassword and ResetPassword pages implemented with mock API flow.

  1. User requests a password reset from the login page
  2. System sends a reset link to the email on file (always returns success, even if email not found — prevents enumeration)
  3. Reset link contains a single-use token that expires in 1 hour
  4. User sets a new password
  5. All existing sessions are invalidated on password change

Maximum 3 password reset requests per hour per email address.

Multi-Factor Authentication (MFA)

STATUS: BUILT

TOTP-based 2FA is implemented with QR code setup, backup codes, login verification, and admin 2FA management in Account settings.

The spec requires:

  • Admin users: MFA is mandatory. Supports TOTP (Google Authenticator, Authy, etc.) with hashed backup codes. Recovery requires Super Admin approval.
  • General users: MFA is optional but available. TOTP support with email-based verification as fallback.

Context Switching

STATUS: BUILT

Context switcher with personal/school workspace toggling, context-aware selectors, and dashboard content switching all implemented.

Users with multiple roles see a context switcher in the global header (right side, adjacent to profile menu). This works like Slack's workspace model.

How it looks:

  • Dropdown showing the current context name and icon
  • Each context shows: icon (school logo or personal avatar), context name ("Personal," "Lincoln Elementary"), role label ("Student," "Teacher"), and active indicator (checkmark)

What happens when you switch context:

  • Dashboard content updates to reflect the selected context
  • Navigation items update (e.g., "Assignments" tab appears in school context)
  • Communities list filters to context-relevant communities
  • Notification badge counts update per context
  • URL updates (e.g., /school/lincoln-elementary/dashboard)
  • No page reload — content updates in place

What persists across all contexts:

  • User profile and account settings
  • Personal Bucket List and Interesting List (always accessible)
  • Notification center (shows all contexts, labeled by source)
  • Global search (searches across all contexts, results labeled)

What changes per context:

  • Dashboard layout and content widgets
  • Available navigation items
  • Community list
  • Challenge feeds and recommendations
  • Assignment visibility (school contexts only)
  • Analytics views (teacher/SA contexts only)

Users with only one role do not see the context switcher at all — the header space is used for other elements.

Account Linkages

A "linkage" is a formal relationship where one account has oversight or control over another. This is completely different from community membership. The linkage system governs permissions, data access, and legal compliance for minors.

Linkage Types

STATUS: BUILT

AccountLinkage type with all fields, LinkedAccounts management page, and parent-child relationship tracking in the User type all implemented.

Linkage TypeWhen RequiredPermissions GrantedConstraints
Parent-to-ChildMandatory for under-13 Tier 2 access. Optional for 13+.Full visibility into child's account: profile, bucket list, Track Records, communities, activity. Can gift, approve/decline gifts, remove from friend communities.Maximum 2 parent/guardian links per child.
Guardian-to-WardSame as parent-to-child. For legal guardians.Functionally identical to parent-to-child.Counts toward the 2-link maximum.
School-to-StudentEnables Tier 1 access for under-13. Full access for 13+.School has supervisory authority over school-related activities. Can assign challenges, view school progress, manage community membership.One active school link at a time. Schools billed per active user.

Multi-Parent Linking

A child can have up to 2 linked parent/guardian accounts. This covers the vast majority of custody situations without creating an unbounded permissions problem. Both linked parents have identical permissions and visibility.

First parent linking flow:

  1. Parent creates account (or logs in if they already have one)
  2. Verifies identity and creates an account for the child, OR approves connection if the child's account already exists
  3. During this flow, parent is prompted: "Would you like to create DoCurious accounts for additional children?" or "Would you like to link to another child who has a DoCurious account?"
  4. Parent can create accounts for multiple children in one session or link to multiple pre-existing accounts (batch approval)

Second parent for the same child:

  1. First parent OR the school can invite the second parent via email
  2. Second parent creates account (or logs in)
  3. Sees: "You've been invited to link to [Child Name] and [Child Name 2]."
  4. One-click "Approve All" or approve individually

Adding another child later:

  1. Parent dashboard has an "Add Child" button
  2. If child already has a DoCurious account (school-created), parent enters child's school email or a linking code
  3. Connection request sent — either the school confirms (for under-13) or the child confirms (if 13+)

Parent Account UX

STATUS: BUILT

LinkedAccounts page and parent child ID tracking built; parent oversight dashboard (viewing child's account in a new window) and parent-specific actions like approve/decline gifts are not yet implemented.

Parents see their own profile with a dropdown selector: "Viewing: [Child Name]." If multiple children are linked, the dropdown lists all of them. Selecting a child opens their account view in a new window for oversight.

Parent access is purely oversight. A parent CAN:

  • View child's profile, bucket list, Track Records
  • View child's communities
  • See activity and completions
  • Purchase/gift challenges to child
  • Approve or decline gifts to child
  • Remove child from friend communities
  • Communicate with school via contact forms
  • Initiate account deletion
  • Request data export

A parent CANNOT:

  • Post as their child
  • Edit their child's content
  • Complete challenges on their child's behalf

NOTE

A parent with the child's login credentials could technically log in directly and act as the child. From the parent account interface, access is oversight only.

Transition at Age 13

When a student turns 13:

  • Linkage status is unchanged by default — nothing changes automatically
  • Student gains a "Manage Parent Link" setting in their account
  • DoCurious does NOT push the student to sever or maintain the link
  • Student can modify or sever parent linkage at their discretion
  • Both tiers gain full account control at 13

Edge case: If a student tries to sever a parent link while still under 13, they must transfer oversight to another parent/guardian. Under-13 users cannot be independent — this is a hard constraint for COPPA compliance.

Two-Tier Under-13 Accounts

STATUS: BUILT

AccountTier type with tier_1_school_only / tier_2_full / standard, TierGuard route guard, ConsentGuard for pending consent, and tier-aware selectors (selectIsTier1, selectCanCreateCommunity, selectCanReceiveGifts, etc.) all implemented.

This system ensures no child is excluded from school activities because a parent is unresponsive, while maintaining COPPA compliance through appropriate authorization.

Tier 1: School-Linked Only

Authorization basis: School acts as agent under the COPPA school exception. No individual parental consent required.

Tier 1 students CAN:

  • Participate in school-assigned challenges
  • Create Track Records for school challenges
  • View and contribute to school communities (class, grade, school)
  • Receive gift challenges from school

Tier 1 students CANNOT:

  • Create friend communities
  • Build personal bucket lists
  • Share publicly outside school context
  • Receive personal gifts from individuals
  • Access Explore page beyond read-only browsing
  • Use Dealer's Choice random challenge feature

Tier 2: School + Parent Linked

Authorization basis: Explicit parental consent via account linking flow (see COPPA Compliance).

Everything in Tier 1, plus:

  • Create and join friend communities (Family, Trusted Friends, Casual Friends)
  • Build personal bucket lists and Interesting lists
  • Share publicly or with any community
  • Receive personal gifts from individuals (subject to community gifting permissions)
  • Full Explore page access
  • All social features
  • Dealer's Choice

Account States for Under-13 School Students

When a school creates an under-13 student account, it progresses through these states:

StateWhat Triggers ItStudent Experience
Pending Parent ApprovalAccount created by school (CSV import or manual entry). Parent invitation email sent.Student can log in. Welcome screen. Can browse public challenges (read-only). Can view school community but cannot participate.
Tier 1 ActiveSchool link established. School can begin assigning challenges.Can participate in school challenges, create Track Records for school work, contribute to school communities.
Tier 2 ActiveParent completes linking flow and grants consent.Full feature access including personal bucket lists, friend communities, public sharing.
Dormant30-day parent approval window expires without parent action.Student cannot log in. Account preserved (not deleted). Parent can activate at any time by completing approval.

Parent Approval Timeline

DayWhat Happens
Day 0School creates account. Parent invitation email sent.
Day 14First reminder email to parent.
Day 28Final reminder email to parent.
Day 30If no response, account becomes dormant.
After Day 30Parent can still complete approval at any time. Account reactivates immediately.

The AccountLinkage type tracks this with reminderSentDay14, reminderSentDay28, and approvalDeadline fields.

COPPA Compliance

STATUS: PARTIAL

Age gating, tier logic, and consent status tracking are built. Credit card verification for parental consent, consent revocation UI, and annual re-consent are not yet implemented.

For users under 13, DoCurious requires appropriate authorization before collecting personal information (photos, videos, text entries, location data).

Tier 1 Authorization: School Exception

Under the COPPA school exception, schools can consent to the collection of student information for educational purposes:

  • School acts as the authorized agent for data collection
  • Limited to school-related activities only
  • No personal/social features that would require individual parental consent
  • School maintains supervisory responsibility

For full platform access, explicit parental consent is required:

  • Parent creates their own account and links to child
  • The linking flow constitutes verifiable parental consent
  • Verification method: Credit card verification — the parent is charged a one-time fee of $1.00 per child link verified
  • This charge serves as the FTC-accepted mechanism for verifiable parental consent under COPPA
  • The charge is non-refundable and applies once per parent-child link (not per session or per action)

COMPLIANCE GAP

The $1.00 credit card verification for COPPA consent is specified but has no frontend implementation. This must be built before launch.

A parent can revoke consent at any time from their account settings ("Revoke consent for [Child Name]"):

  1. Child's account immediately reverts to Tier 1 (school-only) if school-linked, or enters a view-only state if no school link
  2. No new content creation or social features until consent is re-granted
  3. Existing content is preserved but sharing is disabled
  4. Parent can re-grant consent at any time, restoring Tier 2 access

Consent revocation is distinct from account deletion. Revoking consent limits features; deleting an account removes data.

COMPLIANCE GAP

No UI currently exists for parents to withdraw previously granted consent. This must be built before launch.

Under-13 Data Restrictions

The following restrictions apply to all under-13 data:

  • No persistent identifiers for tracking
  • No geolocation collection
  • No behavioral profiling
  • Collect only: display name, age, parent's email, school affiliation
  • Media uploads not scanned by third-party AI services without parental consent
  • Under-13 data not shared with any third party except school (for Tier 1, under school agreement) and essential service providers (hosting, email — with a Data Processing Agreement)
  • No advertising networks, no analytics services that create user profiles

Roles & Permissions

STATUS: BUILT

UserRole type with 9 roles, RoleDisplayNames mapping, role-based selectors, AdminRoleGuard, ContextGuard, and ParentGuard all implemented.

RoleContextWhat They Can Do
General UserPersonalBrowse/join challenges, create Track Records, create/join communities, share, earn XP/badges, save to Bucket List, recommend challenges.
VendorMarketplaceCreate challenge listings, manage vendor profile, view engagement analytics. Vendors sell through their own channels; DoCurious does not process payments.
School Admin (SA)School OrgRegister school, manage teachers/students/classes, import rosters via CSV, gift challenges to students, send surveys, manage grade promotions, configure school settings, suspend/remove students school-wide.
Head School AdminSchool OrgEverything an SA can do, plus create other admin accounts within the school.
TeacherSchool OrgCreate classes (with SA approval), manage class rosters, assign challenges, view student progress dashboards, request surveys, provide private feedback on Track Records, suspend/remove students from own classes.
StudentSchool OrgDepends on tier. Tier 1 (school-only): school challenges, school communities, Track Records for school challenges. Tier 2 (parent-approved): all Tier 1 plus personal features. Students 13+ have full access regardless of tier.
Parent/GuardianLinkedView linked child's complete account, approve/manage sharing for under-13, purchase/gift challenges to child, approve/decline gifts, remove child from friend communities, communicate with school via forms. Up to 2 per child.
StaffInternalReview submitted Track Records, moderate content, handle flags/reports.
Platform AdminInternalFull platform access: manage vendors, platform challenges, system settings, admin-configurable rejection reasons, user management.

Route Guards

The codebase enforces role-based access through a layered guard system:

GuardWhat It DoesLocation
AuthGuardRedirects to /login if not authenticated. Shows loading spinner during initialization.src/routes/guards/AuthGuard.tsx
AgeGuardBlocks under-13 users from age-restricted content (default: 13+). Shows "Age Restricted Content" fallback.src/routes/guards/AgeGuard.tsx
ConsentGuardBlocks under-13 users with pending parental consent from Tier 2 features. Shows "Parent Permission Required" fallback.src/routes/guards/ConsentGuard.tsx
TierGuardBlocks Tier 1 (school-only) accounts from personal features. Shows "Feature Not Available" fallback.src/routes/guards/TierGuard.tsx
AdminRoleGuardRestricts access to admin-only routes based on role.src/routes/guards/AdminRoleGuard.tsx
ContextGuardEnsures user has the correct active context (personal/school) for the route.src/routes/guards/ContextGuard.tsx
ParentGuardRestricts access to parent-only features.src/routes/guards/ParentGuard.tsx

Guards are composable — they can be nested. For example, a route might use AuthGuard > TierGuard > ConsentGuard to ensure the user is logged in, has Tier 2+ access, and has active parental consent.

Account Deletion & Data Management

Right to Deletion

STATUS: BUILT

AccountDeletion page with confirmation flow exists and enforces parent-only deletion for under-13 users (under-13 visitors see "Parent Permission Required" screen with redirect). Parent Dashboard includes "Delete Child's Account" button with 48-hour COPPA timeline. The user.api.ts has requestChildDeletion endpoint. 30-day deactivation window display and anonymization logic are not yet implemented.

Who can request deletion:

  • Any user 13+ can delete their own account from settings
  • For under-13 users, ONLY a linked parent/guardian can initiate deletion — the child cannot self-delete

COPPA-specific rule: Parent requests for under-13 deletion must be processed within 48 hours (not 30 days). No grace period applies.

Deletion Process

  1. User requests deletion from account settings
  2. 30-day deactivation window begins — account is immediately hidden from all communities, feeds, and search
  3. User sees a banner: "Your account is scheduled for deletion on [date]. You can cancel this at any time."
  4. During the 30-day window, user can log in and cancel deletion with one click. Full account is restored.
  5. After 30 days, permanent deletion executes

What gets permanently deleted:

  • Profile data (display name, date of birth, email, auth credentials)
  • Bucket list and Interesting list
  • Community memberships
  • Notification history
  • All personally identifiable information
  • Gifting permissions and community-specific settings
  • Uploaded media files (images, documents) from object storage

What gets anonymized (not deleted):

  • Track Records: author becomes "Deleted User." Content preserved so challenge galleries and community feeds do not break. All media attached to Track Records is retained under the anonymized record.
  • Discussion posts and comments: author becomes "Deleted User." Thread integrity preserved.
  • Challenge completion records: anonymized for aggregate analytics.

What is retained as-is:

  • Challenge data created by vendors (vendor owns this)
  • Community metadata (member count adjustments)
  • Financial transaction records (retained 7 years for legal compliance)
  • Audit log entries (anonymized, retained 2 years for compliance)
  • Parental consent records (retained 3 years after deletion)

Data Export

STATUS: BUILT

DataExportRequest and DataAccessRequest pages implemented. DataExportRequest type with format, includeMedia, and downloadUrl fields all defined.

Users (or parents of under-13 users) can request a complete data export from settings:

  1. System generates a downloadable archive within 48 hours
  2. Download link sent via email (link expires in 7 days)

Archive contents:

  • Profile data (JSON)
  • All Track Records with associated media files
  • Bucket list and Interesting list
  • Complete challenge history (started, completed, abandoned)
  • Community memberships list
  • XP and badge history
  • Notification history

Archive format: ZIP file containing JSON data files plus a /media folder with all uploaded images and documents. Available in JSON or CSV format.

School Removal of Under-13 Students

STATUS: BUILT

Business rules defined in spec; no frontend enforcement yet.

When a school removes a student, what happens depends on their linkage status:

Tier 2 student (parent linked):

  • School link is severed; school loses all access
  • Account continues as a normal parent-linked account with no interruption
  • Student retains all personal content, Track Records, and community memberships

Tier 1 student (school-only, no parent link): The school's authorization was the sole legal basis for data collection, so the platform cannot retain the minor's personal data without authorization:

  1. School link is severed immediately; school loses all access
  2. 90-day reclaim window begins
  3. Student/family is notified: "Your school account has been disconnected. Link a parent account within 90 days to keep your data."
  4. If a parent links during the 90 days: account converts to standard parent-linked (Tier 2 without school). All data preserved.
  5. If no parent links within 90 days AND the student does not turn 13 within that time: account is automatically deleted using the standard deletion process, including anonymization of Track Records.

Automated Cleanup

STATUS: BUILT

Requires background job infrastructure that does not exist yet.

Accounts that were never activated (created by school, parent never linked, student never logged in) are purged after 12 months:

  • 30-day advance notice email sent to parent email on file (if any)
  • Account and all associated data permanently deleted
  • No anonymization needed since no user-generated content exists

Required background jobs:

  • Daily: Check for parent approval deadlines (30-day). Move expired accounts to dormant.
  • Daily: Check for reclaim window deadlines (90-day). Execute automatic deletion.
  • Daily: Check for pending deletion accounts past 30-day deactivation window. Execute permanent deletion.
  • Monthly: Check for never-activated accounts older than 12 months. Send 30-day warning emails. Purge after warning period.
  • On-demand: Data export generation (within 48 hours of request).

Onboarding Flows

General User Onboarding

STATUS: BUILT

Register page, Onboarding page, RoleOnboarding page, and DemoLanding page all implemented.

  1. Sign up via email/password, Google, or Apple
  2. Basic profile setup: display name, date of birth (required for COPPA gating)
  3. User arrives at the platform
  4. On first visit to Explore Challenges, user sees interest selection (outdoor, building, music, cooking, art, science, fitness, etc.)
  5. Interests saved and used for recommendations going forward

School Onboarding

STATUS: BUILT

The school onboarding flow is fully implemented as a 6-step wizard in SchoolOnboarding.tsx: School Info, Calendar, COPPA Settings, First Class, Teachers, and Review. CSV roster import supports bulk student enrollment.

Two paths:

Path A: School Self-Registers

  1. School completes application on DoCurious
  2. DoCurious admin reviews and approves

Path B: DoCurious Admin Initiates

  1. DoCurious admin begins registration for school
  2. School receives email to review and complete
  3. School submits completed application
  4. DoCurious admin approves

Registration fields collected: School name, address, type (public/private/charter/parochial/homeschool co-op), primary admin contact, grade levels served, approximate enrollment, Tax ID/EIN, billing contact, organizational affiliation.

After approval, the SA receives a flexible dashboard with an implementation checklist. Tasks can be tackled in any order.

Student Roster Import (CSV)

STATUS: BUILT

CSV import types referenced in spec. No upload UI or parsing logic built yet.

SAs can import student rosters via CSV upload.

FieldRequired?Notes
Student First NameYes
Student Last NameYes
Student EmailNo (under-13)Required for 13+. Optional for under-13.
Date of BirthYesUsed for COPPA gating and age-tier determination.
GradeYesAuto-assigns to grade community if grade structure exists.
Parent/Guardian First NameNo
Parent/Guardian Last NameNo
Parent/Guardian EmailNoIf missing, account flagged "Incomplete -- Parent Email Needed."

The system accepts incomplete records but flags accounts accordingly. SA can add parent email later manually. The 30-day parental approval countdown starts when parent email is finally added. An error report is shown after import highlighting all issues.

Alternative: Manual entry form for small schools or individual student additions.

Parent Linking Flow

STATUS: BUILT

ParentalConsent page and parent email field in registration exist. Full multi-child batch approval and second-parent invitation flow are not yet built.

School-Initiated (first parent):

  1. School creates student account (CSV or manual). Parent invitation email sent.
  2. Parent clicks link in email and arrives at DoCurious.
  3. Parent creates account (or logs in if they already have one).
  4. Parent sees: "You've been invited to link to [Child Name]." If multiple children, all are listed with individual approve buttons or "Approve All."
  5. Parent approves. Child account upgrades from Tier 1 to Tier 2.
  6. Parent is prompted: "Would you like to invite another parent or guardian for [Child Name]?"

Second parent invitation:

  1. First parent or SA sends invitation email to second parent
  2. Second parent creates account or logs in
  3. Sees pending invitations for all children shared with this parent
  4. Can approve individually or all at once
  5. Second parent now has identical visibility and permissions as first parent

Vendor Onboarding

STATUS: BUILT

Vendor role, VendorProfile type, and full vendor onboarding wizard are implemented. RoleOnboarding.tsx includes a vendor-specific 3-step flow (Company Profile, Challenge Creation, Analytics). The vendor dashboard (VendorDashboard.tsx), settings (VendorSettings.tsx 31KB), analytics (VendorAnalytics.tsx), and challenge creation (VendorChallengeCreate.tsx 60KB) pages are all fully built.

  1. Vendor signs up for a DoCurious vendor account
  2. Vendor profile setup: company name, description, website, logo, revenue sharing proposal
  3. DoCurious admin reviews and approves vendor account
  4. Vendor creates challenge listings

See Gifting & Invitations for vendor marketplace details.

Notifications (Account-Level)

STATUS: BUILT

Notification types, preferences types, and notification store exist. The notification preference UI provides per-category/per-channel toggles, quiet hours, and email digest frequency settings. The component is wired to useNotificationStore with fetchPreferences on mount and updatePreferences on save.

Channels

  • In-App: Badge/bell icon with a notification center. Checked on page load (polling, not real-time websockets).
  • Email: Individual high-priority notifications + bundled digests for engagement notifications.
  • Push (Future): Mobile push notifications with the same restraint principles.

User Notification Preferences

Three tiers of user control:

  1. Master toggle per channel: in-app, email, push — on/off entirely
  2. Category-level toggles: "challenge updates," "social activity," "community activity," "reminders," "digests" — each toggleable per channel
  3. Quiet hours: time window + timezone. No notifications delivered during quiet hours.

Notification Principles

Notifications are deliberately restrained. The platform prioritizes NOT pulling users back to screens unnecessarily.

  • Email digests over push notifications
  • Weekly summaries over daily pings
  • Community feeds use a pull model — no notifications for new feed items
  • Consent requests (for parents) are the highest priority notification

Constraints & Limits

ConstraintValueRationale
Max parent/guardian links per child2Covers most custody situations without unbounded permissions complexity
Max active school links per student1Students can only be enrolled at one school at a time; billing is per active user
Under-13 self-deletionNot allowedCOPPA requires parental authority for data decisions
Under-13 sever parent linkMust transfer to another parentUnder-13 users cannot be independent accounts
Dormant account loginBlockedData preserved but access restricted until parent activates
Deactivated account contentHidden immediatelyAll content hidden from public view as soon as deletion is requested
Password reset token1 hour expiry, single-useSecurity best practice
Login lockout5 failures = 15 min lockoutProgressive: 10 failures = 30 min, 15 failures = 1 hour
Session timeout30 days (with refresh)7 days idle timeout
Admin session timeout8 hours1 hour idle timeout
Max concurrent sessions5 (configurable)Prevents credential sharing
Data export deliveryWithin 48 hoursCCPA requires within 30 days; 48 hours is our target
Data export download linkExpires in 7 daysSecurity: limits exposure window for exported data
Never-activated account purge12 months + 30-day warningPrevents orphaned data buildup
Reclaim window after school removal90 daysGives families time to link a parent account
Parent approval countdown30 days from email sentReminders at day 14 and day 28
COPPA deletion for under-1348 hours (no grace period)Stricter than standard 30-day window per FTC guidance
Display namePermanent unique identifierCannot be changed after account creation
Parental consent fee$1.00 per child linkFTC-accepted COPPA verification mechanism

Sensitive Actions Requiring Re-Authentication

The following actions require the user to verify their identity again (re-enter password or confirm MFA), even if they are already logged in:

  • Account deletion
  • Email change
  • Password change
  • Adding or removing a parent link
  • Exporting personal data
  • Admin impersonation
  • Changing school COPPA settings
  • Changing admin permissions

Design Decisions

Why accounts belong to individuals, not organizations

When a student leaves a school, the school's membership link is deactivated (school loses all access), but nothing is deleted from the student's account. This means a student's Track Records, achievements, and XP persist across school transfers and graduation. Graduating students become "Alumni" in the school community with restricted permissions.

This was a deliberate choice to make the platform valuable beyond any single institution. The alternative (school-owned accounts) would mean students lose their history when they move, reducing the platform's long-term value proposition.

Why profiles are intentionally minimal

User profiles collect only: display name, date of birth, avatar, bio, location. Most of this is only shared with others as a premium "partner finder" service or in friend/relative communities. The platform is about doing, not self-presentation. Users express themselves through their Track Records, Bucket Lists, and community participation.

This also reduces data collection surface area, which is important for COPPA compliance and user trust.

Why there is no direct messaging

DoCurious does not have in-platform messaging. Communication happens through comments on challenges/Track Records, structured contact forms, and external coordination. This avoids becoming a social media platform and supports the off-screen mission. It also dramatically reduces moderation burden and abuse vectors, especially important for a platform with minors.

Why there is no "following" model

Connections happen through shared contexts: communities, classes, and challenge feeds. If someone wants to see a friend's activity, they create or join a community together. No follower counts. Profiles show only what users have deliberately shared with viewers. This is a structural privacy choice, not just a settings toggle.

Why two tiers instead of one under-13 approach

The two-tier system exists because parents are sometimes unresponsive. Without Tier 1, a school could not use DoCurious with any student whose parent had not responded to an email — potentially excluding a large portion of the class. The school exception under COPPA provides the legal basis for Tier 1 to work with restricted features.

Recommendation: Revisit display name permanence

The spec states that display names are permanent unique identifiers. This is unusual for a consumer platform and may cause friction (users who make a typo or want to change their name later). Consider allowing display name changes with an audit trail and cooldown period, rather than making them truly permanent.

The spec recommends annual re-consent for COPPA but does not require it. Given the sensitivity of the under-13 audience, implementing an annual re-consent prompt (even if just a confirmation click, not a new $1.00 charge) would strengthen the compliance posture.

Technical Implementation

Key Files

CategoryFileSizeWhat It Does
State Managementsrc/store/useAuthStore.ts18.8 KBZustand store with persistence. Login, register, logout, context switching, role switching (dev), 20+ selectors for role/tier/consent checks.
User Typessrc/types/user.types.ts14.6 KBUser, UserRole, AccountTier, ConsentStatus, AccountStatus, AccountLinkage, DeletionRequest, DataExportRequest, SharingPermissions.
Auth Typessrc/types/auth.types.ts3.6 KBAuthTokens, LoginData, RegisterData, OAuthProvider, PasswordResetRequest/Confirm, ParentConsentRequest/Confirm, LoginAttempt, AuthErrorCode.
Mock APIsrc/api/auth.api.ts12.7 KBFull mock auth API with localStorage persistence. Registration with COPPA age check, login with account status check, password reset, Google/Apple OAuth stubs.
Real APIsrc/api/auth.real.api.ts5.5 KBHTTP client for real backend. Endpoints: /auth/register, /auth/login, /auth/google, /auth/apple, /auth/logout, /auth/me, /auth/refresh, /auth/forgot-password, /auth/reset-password, /auth/change-password, /auth/verify-otp, /auth/resend-otp, /auth/verify-email.
Context Helperssrc/lib/contextHelpers.tsUtility functions for context building, role checking, and workspace derivation.

Auth Pages

PageRouteWhat It Does
Login/loginEmail/password login with Google and Apple OAuth buttons
Register/registerRegistration with COPPA age gate, school code, and parent email fields
ForgotPassword/forgot-passwordEmail input for password reset link
ResetPassword/reset-passwordNew password form with token validation
VerifyEmail/verify-emailEmail verification landing page
AgeVerification/age-verificationDate of birth verification step
ParentalConsent/parental-consentParent consent request and approval flow
RoleOnboarding/onboarding/roleRole-specific setup after registration
SchoolInvite/school-inviteSchool invitation acceptance flow
DemoLanding/demoDemo mode entry point for exploring the platform without registering
Onboarding/onboardingGeneral onboarding flow after first login

Account Management Pages

PageRouteWhat It Does
AccountDeletion/account/deletePermanent deletion with "type DELETE to confirm" safety step
LinkedAccounts/account/linked-accountsOAuth provider connections and family account links
DataExportRequest/account/data-exportRequest downloadable data archive
DataAccessRequest/account/data-accessView and manage what data the platform holds
AppealForm/account/appealAppeal account actions (suspensions, content removals)

Route Guards

GuardFilePurpose
AuthGuardsrc/routes/guards/AuthGuard.tsxBlocks unauthenticated users; redirects to /login
AgeGuardsrc/routes/guards/AgeGuard.tsxBlocks under-13 from 13+ content
ConsentGuardsrc/routes/guards/ConsentGuard.tsxBlocks under-13 with pending consent
TierGuardsrc/routes/guards/TierGuard.tsxBlocks Tier 1 from personal features
AdminRoleGuardsrc/routes/guards/AdminRoleGuard.tsxRestricts admin-only routes
ContextGuardsrc/routes/guards/ContextGuard.tsxEnsures correct active context
ParentGuardsrc/routes/guards/ParentGuard.tsxRestricts parent-only features

Data Model

The backend database (PostgreSQL) uses these core tables for the accounts system:

  • users — Core user record with email, password_hash, display_name, date_of_birth, account_tier, parental_consent_status, account_status, interests, deletion_scheduled_at
  • account_linkages — Parent-child/guardian-ward/school-student relationships with consent tracking, approval deadlines, and reminder flags
  • organizations — Schools with type, address, grade levels, enrollment, billing contact, onboarding checklist
  • organization_memberships — User-to-org relationships with role, status, and grade
  • notifications / notification_preferences — Per-user notification configuration
  • data_export_requests — Export request tracking with download URL and expiration
  • audit_log — All account lifecycle actions logged for compliance
  • parental_consent_records — Detailed consent tracking with method, IP, policy version, scope
  • security_events — Authentication events, authorization failures, suspicious activity

Known Gaps & Compliance Risks

MUST FIX BEFORE LAUNCH

These items represent legal compliance gaps that must be addressed:

  1. COPPA payment verification — $1.00 credit card charge for parental consent is specified but not implemented
  2. Consent revocation UI — No way for parents to withdraw previously granted consent
  3. Under-13 parent-only deletion — AccountDeletion page does not enforce parent-only deletion for minors
  4. Under-13 data minimization — No frontend enforcement of collection minimization for under-13 users
  5. 48-hour COPPA deletion — Standard 30-day deletion process applies to all users; COPPA requires 48-hour processing for under-13
  • Challenges — What users actually do on the platform
  • Track Records — How users document their challenge completions
  • Communities — Social contexts that depend on account tier and linkages
  • Gifting — Gift flows that depend on Tier 2 access and parent approval
  • School Administration — School onboarding, roster management, and SA dashboard
  • Gamification — XP, badges, and levels tied to the user account
  • Notifications — Account-level notification preferences and channels
  • Privacy & Compliance — Encryption, access control, and compliance infrastructure

DoCurious Platform Documentation