Skip to main content

Onboarding — Technical Reference

← Back to Onboarding

Where this lives

Backend

Frontend

Technical implementation checklist

  • completeOnboarding(interests: [String!]): User! — requires getFollowingCount(userId) >= 5 server-side, sets isOnboardingCompleted + onboardingCompletedAt, stores interests
  • interestSuggestions(limit, interests): [User!]! — uses passed interests (live during onboarding) or the viewer's stored interests; tops up with getSuggestedUsers so the list is never short
  • Persistent gate — ProtectedRoute redirects when user.isOnboardingCompleted === false (flag comes from the login/register payload; re-login re-triggers it)
  • isOnboardingCompleted added to the login / 2FA-verify / OAuth (Firebase, Apple, phone, passkey) user selections in Login.tsx; the Register mutation doesn't request the field, so Login.tsx defaults it to false there (new accounts always need onboarding)

GraphQL

type Query {
interestSuggestions(limit: Int, interests: [String!]): [User!]!
}

type Mutation {
completeOnboarding(interests: [String!]): User!
}

type User {
isOnboardingCompleted: Boolean! # self-only
# ...
}

Notes

  • Interests are stored on user.interests (text[]) — the Sequelize model attribute is interestTags (field interests) to avoid colliding with the existing Interest many-to-many association named interests.
  • Reuses the existing is_onboarding_completed column, so there is no migration for the gate itself; the user.interests column ships in 20260721120000-add-interests-to-user.