Guest Profiles — House of Legends

Documented: 2026-05-11 Doc Status: Excellent | ✓ All 6 checks passed

Overview

After reservation is made, guest receives a QR code via email or WhatsApp. Upon arrival, scanning the QR at the venue creates or links their profile. Guests can then send reactions, submit photos, spin the lucky wheel, and complete challenges.

Guest Journey

After reservation is made, guest receives a QR code via email or WhatsApp. Upon arrival, scanning the QR at the venue creates or links their profile. From there, guests can:
  • Send reactions (Wave, Cheers, Heart) to other guests
  • Submit photos to the wall and like others’ photos
  • Spin the lucky wheel to win comp items
  • Complete the Google Review challenge to earn rewards

QR Code & Onboarding

QR Code Content

Each reservation gets a unique QR code containing:
{
  "reservationId": "abc123",
  "token": "guest-token-xyz",
  "showDate": "2026-05-15"
}

Profile Creation Flow

  1. Guest scans QR with phone camera
  2. App opens /profile?token=xxx
  3. If not logged in → Clerk OAuth (Google/Facebook)
  4. Profile created/linked via token
  5. Guest sees: nickname input, mood tags, origin

Tables

guestProfiles: defineTable({
  reservationId: v.optional(v.id("reservations")),
  tableId: v.optional(v.id("tables")),
  token: v.string(),
  googleId: v.optional(v.string()),
  facebookId: v.optional(v.string()),
  email: v.optional(v.string()),
  avatarUrl: v.optional(v.string()),
  nickname: v.string(),
  origin: v.string(),
  moodTags: v.array(v.string()),
  bio: v.optional(v.string()),
  showDate: v.string(),
  checkedIn: v.boolean(),
  createdAt: v.number(),
  updatedAt: v.number(),
})
  .index("by_reservation", ["reservationId"])
  .index("by_show_date", ["showDate"])
  .index("by_token", ["token"]);

Reactions (WAVE/CHEERS/HEART)

Guests can react to other guests (not themselves):
  • WAVE — Hello/greeting
  • CHEERS — Toast/celebration
  • HEART — Love/appreciation

Reaction Flow

  1. Guest views other profiles on wall/table
  2. Taps reaction button
  3. Reaction saved to guestReactions
  4. Target guest sees reaction notification

Table

guestReactions: defineTable({
  fromProfileId: v.id("guestProfiles"),
  toProfileId: v.id("guestProfiles"),
  reactionType: v.union(
    v.literal("WAVE"),
    v.literal("CHEERS"),
    v.literal("HEART"),
  ),
  showDate: v.string(),
  createdAt: v.number(),
})
  .index("by_to_profile", ["toProfileId"])
  .index("by_from_profile", ["fromProfileId"])
  .index("by_show_date", ["showDate"]);

Mood Tags

Guests select mood tags during onboarding:
TagDescription
LOOKING_FOR_DATELooking for a date
GET_DRUNKHere to enjoy drinks
FIRST_TIMEFirst time visitor
REGULARReturning guest
CELEBRATINGSpecial occasion
GOOD_FRIENDSOut with friends
SOLOFlying solo
WITH_FAMILYFamily outing

Components

Profile Card

Displays:
  • Avatar (or generated initial)
  • Nickname
  • Origin
  • Mood tags
  • Reaction count (received)

Reaction Button

Three-state button: WAVE / CHEERS / HEART
  • Tapping cycles through reactions
  • Shows count for each type

Onboarding Flow

  1. Scan QR → Token validated
  2. Login with Google/Facebook (or skip)
  3. Enter nickname
  4. Select mood tags (multi-select)
  5. Select origin (dropdown)
  6. Profile created → Redirect to experience

Backend Functions

FunctionPurpose
profiles.createFromReservationCreate profile on check-in
profiles.linkOAuthLink Google/Facebook to profile
profiles.addReactionAdd reaction to another guest
profiles.getReactionsGet reactions for a profile
profiles.updateMoodTagsUpdate mood tags