plans
2026-05-11
2026 05 11 Specs Update

Specs Folder Update Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Update docs/superpowers/specs/ to accurately document the current implementation state of House of Legends app - all features, flows, user stories, and data models.

Architecture: Restructure specs into authoritative reference documents that reflect current codebase state. Each spec is a living document, not a plan for future work.

Tech Stack: N/A (documentation task)


File Structure

After this update, docs/superpowers/specs/ will contain:

docs/superpowers/specs/
├── README.md                     # Entry point - links to all specs
├── tech-stack.md                 # Current tech stack reference
├── data-model.md                 # Complete Convex schema documentation
├── booking-flow.md               # 4-step booking flow (current)
├── public-pages.md               # Landing pages, shows, experiences
├── admin-dashboard.md            # Admin panel features
├── staff-pos.md                 # POS system, kitchen, reception
├── inquiry-forms.md              # Contact, venue rental, workshops, etc.
├── gamification.md               # Photo wall, challenges, guest profiles
├── payments.md                  # OnePay integration, payment flow
├── notifications.md             # Email, WhatsApp, CRM sync
└── user-stories.md              # All user stories organized by actor

Interlinking pattern: Every spec starts with a "Related specs" section linking to directly related documents. The README links to all.

Deprecate: All old numbered specs (01-foundation, 02-guest-journey, etc.) and legacy plan files that describe now-implemented features.


Task 1: Create Specs README (README.md)

Files:

  • Create: docs/superpowers/specs/README.md — Entry point linking to all specs

  • Step 1: Create the overview document

# House of Legends — Specification Index
 
> **Status:** Canonical — this index is the entry point for all specs
> **Last Updated:** 2026-05-11
> **Codebase:** Reflects current implementation state
 
---
 
## How to Use These Specs
 
This folder contains authoritative documentation of House of Legends platform. Each spec covers:
 
| Spec                                    | Content                           | Audience          |
| --------------------------------------- | --------------------------------- | ----------------- |
| [tech-stack](./tech-stack.md)           | Current technology choices        | All developers    |
| [data-model](./data-model.md)           | Convex schema, all tables         | Backend, frontend |
| [booking-flow](./booking-flow.md)       | 4-step booking SPA                | Frontend, product |
| [public-pages](./public-pages.md)       | Landing pages, shows, experiences | Frontend          |
| [admin-dashboard](./admin-dashboard.md) | Admin panel features              | Admin users       |
| [staff-pos](./staff-pos.md)             | POS, kitchen, reception           | Staff             |
| [inquiry-forms](./inquiry-forms.md)     | Contact, venue rental, workshops  | Marketing         |
| [gamification](./gamification.md)       | Photo wall, challenges, profiles  | Product           |
| [payments](./payments.md)               | OnePay, payment flow              | Backend, finance  |
| [notifications](./notifications.md)     | Email, WhatsApp, CRM              | Backend           |
| [user-stories](./user-stories.md)       | All user actors and journeys      | Product, QA       |
 
---
 
## Quick Links
 
### Getting Started
 
- [Tech Stack](./tech-stack.md) — Start here to understand the technology choices
- [Data Model](./data-model.md) — Understand the database schema
 
### Core Features
 
- [Booking Flow](./booking-flow.md) — How guests book tickets
- [Payments](./payments.md) — OnePay integration
- [Public Pages](./public-pages.md) — Landing and show pages
 
### Operations
 
- [Admin Dashboard](./admin-dashboard.md) — Admin panel
- [Staff POS](./staff-pos.md) — Point of sale system
- [Notifications](./notifications.md) — Email, WhatsApp, CRM
 
### Guest Experience
 
- [Inquiry Forms](./inquiry-forms.md) — Contact and quote forms
- [Gamification](./gamification.md) — Photo wall, challenges, reactions
 
### Planning
 
- [User Stories](./user-stories.md) — All actors and use cases
 
---
 
## Related Specs Map

tech-stack ├── data-model (schema.ts is the source) ├── booking-flow ├── public-pages └── admin-dashboard

data-model ├── booking-flow (uses experiences, events, reservations) ├── payments (uses reservations, payments) ├── notifications (uses reservations, notifications) ├── staff-pos (uses tables, orders, menuItems) ├── gamification (uses guestProfiles, challenges) └── inquiry-forms (uses formSessions)

booking-flow ├── payments (payment integration) ├── notifications (confirmation emails) ├── public-pages (shows are entry points) └── user-stories (US-B* stories)

public-pages ├── booking-flow (shows link to booking) ├── inquiry-forms (inquiry pages) └── gamification (wall page)

admin-dashboard ├── staff-pos ├── data-model ├── booking-flow ├── payments (view payment status) └── notifications

staff-pos ├── data-model (tables, orders, menuItems) ├── gamification (challenges at table) └── notifications (order alerts)

inquiry-forms ├── notifications (admin alerts) └── admin-dashboard (kanban view)

gamification ├── data-model (guestProfiles, challenges) ├── staff-pos (challenges at table) └── public-pages (wall page)

payments ├── data-model (reservations, payments) ├── booking-flow └── notifications (confirmation)

notifications ├── payments (triggers) ├── booking-flow (confirmation) └── admin-dashboard (notification center)


---

## Deprecation Notice

The following files are deprecated and should not be referenced:

- `01-foundation.md` → [data-model.md](./data-model.md)
- `02-guest-journey.md` → [public-pages.md](./public-pages.md) + [booking-flow.md](./booking-flow.md)
- `03-admin-backoffice.md` → [admin-dashboard.md](./admin-dashboard.md)
- `04-staff-operations.md` → [staff-pos.md](./staff-pos.md)
- `05-guest-profiles.md` → [gamification.md](./gamification.md)
- And all other legacy numbered specs (06-photo-wall.md through 18-booking-flow.md)

**Reason:** These files describe planned features that have since been implemented with different designs.

Task 2: Document Current Tech Stack (tech-stack.md)

Files:

  • Create: docs/superpowers/specs/tech-stack.md

  • Step 1: Write tech stack spec

Document the ACTUAL current tech stack based on package.json, convex.config.ts, and code inspection:

# Tech Stack — Current Implementation
 
> **Status:** Canonical
> **Last Updated:** 2026-05-11
> **Verification:** Run `grep -r "from " apps/frontend/package.json` to verify versions
 
---
 
## Related specs
 
- [Data Model](./data-model.md) — The schema defined here underpins all tech decisions
- [Booking Flow](./booking-flow.md) — Uses Convex queries and mutations
- [Admin Dashboard](./admin-dashboard.md) — Staff auth and role-based access
- [Public Pages](./public-pages.md) — Frontend routing and components
 
---
 
## Core Stack
 
| Layer     | Technology                        | Version | Notes                              |
| --------- | --------------------------------- | ------- | ---------------------------------- |
| Frontend  | Next.js 16                        | ^16.x   | App Router, Turbopack              |
| Styling   | Tailwind CSS                      | v4      | CSS variables, tailwindcss-animate |
| Backend   | Convex                            | ^1.37.x | PostgreSQL, real-time              |
| Auth      | Clerk                             | ^5.x    | Staff auth, guest OAuth            |
| i18n      | paraglide-js                      | ^2.x    | en + vi locales                    |
| Forms     | React Hook Form + Zod             | latest  | Per-component validation           |
| State     | React localState + BookingContext | —       | Booking uses convexQuery bindings  |
| Icons     | Lucide React                      | ^0.4.x  | Never emoji                        |
| Animation | tailwindcss-animate               | ^1.x    | Fades, slides, zoom                |
 
## Package Locations
 
- Frontend: `apps/frontend/package.json`
- Backend (Convex): `packages/backend/package.json`
 
## Key Paths

apps/frontend/ ├── app/ │ ├── [locale]/ # en, vi locales │ │ ├── (landing)/ # Public pages │ │ │ ├── page.tsx # Homepage │ │ │ ├── about/ │ │ │ ├── artists/ │ │ │ ├── schedule/ │ │ │ ├── reviews/ │ │ │ ├── wall/ │ │ │ ├── experiences/ # french-mentalist, dinner-theater, our-evening │ │ │ └── inquiry/ # contact, venue-rental, workshops, private-events, artist-proposal, host-an-event │ │ └── dashboard/ # Admin/staff routes │ │ ├── admin/ # Admin panel │ │ ├── pos/ # POS views │ │ ├── checkin/ │ │ ├── events/ │ │ ├── experiences/ │ │ ├── reservations/ │ │ ├── inquiries/ │ │ └── event-payments/ │ └── layout.tsx ├── components/ │ ├── booking/ # Booking flow components │ ├── home/ # Homepage sections │ ├── marketing/ # Landing page sections │ ├── layout/ # Header, Footer │ └── ui/ # shadcn/ui primitives └── lib/ ├── hooks/ # Custom hooks ├── utils/ # Utilities ├── data/ # Static data └── schemas/ # Zod schemas

packages/backend/convex/ ├── schema.ts # All tables ├── domains/ # Queries + mutations by domain │ ├── experiences.ts │ ├── events.ts │ ├── reservations.ts │ ├── addons.ts │ ├── profiles.ts │ ├── checkins.ts │ ├── notifications.ts │ ├── crm.ts │ ├── forms.ts │ ├── analytics.ts │ ├── payments.ts │ ├── minigames.ts │ └── storage.ts ├── functions/ │ ├── events.ts │ ├── eventReservations.ts │ └── scheduled.ts ├── http/ │ ├── onepay.ts │ ├── onepayReturn.ts │ ├── tickets.ts │ └── gift_card.ts ├── lib/ │ ├── auth.ts │ ├── experiencesData.ts │ ├── onepay/ │ └── env.ts └── crons.ts


## Convex API Pattern

All frontend calls use `api.domains.<domain>.<operation>`:

```typescript
import { useQuery, useMutation } from "convex/react";
import { api } from "~/convex/_generated/api";

// Queries
const experiences = useQuery(api.domains.experiences.listActive);
const upcomingEvents = useQuery(api.domains.events.upcomingForExperience, { experienceId, limit });

// Mutations
const createReservation = useMutation(api.domains.reservations.createPending);
const updateStatus = useMutation(api.domains.events.updateStatus);

Design System

See apps/frontend/DESIGN.md for complete design tokens and component library.

Key tokens:

  • --color-gold: #c5a059 — Primary brand
  • --color-background: #0a0a0f — Dark background
  • --color-foreground: #ededed — Body text
  • --color-surface: #16161a — Card backgrounds

---

## Task 3: Document Complete Data Model (data-model.md)

**Files:**
- Create: `docs/superpowers/specs/data-model.md`

- [ ] **Step 1: Document current schema from packages/backend/convex/schema.ts

```markdown
# Data Model — Convex Schema Reference

> **Status:** Canonical
> **Last Updated:** 2026-05-11
> **Source:** `packages/backend/convex/schema.ts`

---

## Related specs

- [Tech Stack](./tech-stack.md) — Key paths and import conventions
- [Booking Flow](./booking-flow.md) — Uses experiences, events, reservations
- [Payments](./payments.md) — Uses reservations, payments tables
- [Staff POS](./staff-pos.md) — Uses tables, orders, menuItems
- [Gamification](./gamification.md) — Uses guestProfiles, challenges tables
- [Inquiry Forms](./inquiry-forms.md) — Uses formSessions table
- [Notifications](./notifications.md) — Uses notifications, notificationLogs tables

---

## Entity Relationship Diagram

experiences (show templates) │ └── experienceEvents (scheduled instances) │ └── reservations (bookings) │ ├── checkIns (QR scans) └── bookingDrafts (in-progress bookings)

addOns (global add-on library) │ └── linked to reservations.addOns[]

users (staff/admin accounts) │ ├── tables (venue layout) │ │ │ └── orders → orderItems → menuItems │ ├── guestProfiles (created on QR scan) │ │ │ ├── guestReactions │ ├── photoSubmissions → photoLikes │ └── spinResults │ ├── challengeConfig │ │ │ └── challengeSubmissions │ └── notifications

formSessions (inquiry form submissions) │ └── inquirySessions (admin overlay) │ └── inquiryFollowUps

payments (OnePay transaction tracking) │ └── linked to reservations


## Tables

### experiences (Level 1 — Show Templates)

| Field | Type | Description |
|-------|------|-------------|
| code | `string` | Unique code e.g. "CINE-GASTRO" |
| title | `string` | Show title |
| tagline | `string` | Short description |
| description | `string` | Full rich text |
| embeddedVideo | `string?` | YouTube/Vimeo URL |
| gallery | `string[]` | Image URLs |
| thumbnailUrl | `string?` | Admin-configurable |
| supportedTicketTypes | `("DINNER_THEATRE" \| "SHOW_ONLY")[]` | Ticket options |
| defaultDinnerPrice | `number` | VND |
| defaultShowOnlyPrice | `number` | VND |
| defaultCapacity | `number` | Max 32 |
| status | `"ACTIVE" \| "DRAFT" \| "ARCHIVED"` | Lifecycle |
| slug | `string` | URL-friendly ID |
| createdAt, updatedAt | `number` | Unix timestamps |

**Indexes:** by_status, by_slug, by_code

### experienceEvents (Level 2 — Scheduled Instances)

| Field | Type | Description |
|-------|------|-------------|
| experienceId | `Id<"experiences">` | FK to template |
| code | `string` | Unique e.g. "TMTL260521N" |
| date | `string` | ISO date "2026-05-21" |
| time | `string` | "19:30" |
| dinnerPrice | `number` | Denormalized |
| experienceOnlyPrice | `number` | Denormalized |
| experienceOnlyEnabled | `boolean` | Admin toggle |
| actualCapacity | `number` | Override possible |
| bookedCount | `number` | Calculated from PAID |
| thumbnailUrl | `string?` | Per-event override |
| status | `"SCHEDULED" \| "CANCELLED" \| "SOLD_OUT"` | Event status |
| assignedTables | `Id<"tables">[]` | Linked tables |
| createdAt, updatedAt | `number` | Unix timestamps |

**Indexes:** by_experience, by_date, by_experience_date, by_date_status, by_code

### reservations (Level 3 — Bookings)

| Field | Type | Description |
|-------|------|-------------|
| eventId | `Id<"experienceEvents">` | FK to event |
| customerFirstName | `string` | |
| customerLastName | `string` | |
| customerEmail | `string` | |
| customerPhone | `string?` | |
| customerNote | `string?` | |
| ticketType | `"DINNER_THEATRE" \| "SHOW_ONLY"` | |
| quantity | `number` | Guest count |
| bundleId | `string?` | Bundle pricing |
| guests | `number` | Same as quantity |
| tableId | `Id<"tables">?` | Assigned table |
| addOns | `{addOnId, quantity}[]` | Selected add-ons |
| subtotal | `number` | Before discounts |
| totalAmount | `number` | Final price |
| paymentStatus | see below | |
| status | see below | |
| paymentMethod | `string?` | |
| onePayOrderId | `string?` | OnePay reference |
| qrCode | `string?` | Generated QR |
| qrCodeUrl | `string?` | QR image URL |
| token | `string?` | Unique for QR scan |
| bookingExpiresAt | `number?` | Seat hold expiry |
| checkedInAt | `number?` | When scanned |
| discountAmount | `number` | Bundle discount |
| discountPercent | `number` | |
| vipSurcharge | `number` | |
| dayOfWeekSurcharge | `number` | Friday/Saturday |
| smallPartySurcharge | `number` | 1-2 guests |
| bookingStep | see below | Flow tracking |
| createdAt, updatedAt | `number` | |

**paymentStatus values:** PENDING, PAID, REFUNDED, FAILED, CANCELLED, REFUND_PENDING

**status values:** PENDING, PAID_CONFIRMED, CHECKED_IN, CANCELLED, REFUNDED

**bookingStep values:** EXPERIENCE, SHOW, TICKETS, ZONE, BUNDLE, ADDONS, CUSTOMER_INFO, PAYMENT, CONFIRMATION

**Indexes:** by_event, by_email, by_payment_status, by_expires, by_table, by_booking_step, by_token, by_vpcMerchTxnRef

### addOns

| Field | Type | Description |
|-------|------|-------------|
| name | `string` | |
| description | `string` | |
| price | `number` | VND |
| imageUrl | `string?` | |
| type | `"COCKTAIL" \| "FOOD" \| "UPGRADE" \| "OTHER"` | |
| enabled | `boolean` | Global toggle |
| createdAt, updatedAt | `number` | |

**Indexes:** by_enabled

### users (Staff/Admin)

| Field | Type | Description |
|-------|------|-------------|
| email | `string` | Unique |
| passwordHash | `string?` | |
| role | `"ADMIN" \| "STAFF"` | |
| name | `string` | |
| createdAt, updatedAt | `number` | |

**Indexes:** by_email, by_role

### tables

| Field | Type | Description |
|-------|------|-------------|
| name | `string` | "T01", etc. |
| capacity | `number` | |
| status | `"AVAILABLE" \| "OCCUPIED" \| "RESERVED" \| "MAINTENANCE"` | |
| position | `{x, y}?` | Floor plan |
| createdAt, updatedAt | `number` | |

**Indexes:** by_status

### menuItems

| Field | Type | Description |
|-------|------|-------------|
| name | `string` | |
| description | `string` | |
| price | `number` | VND |
| category | see below | |
| station | `"KITCHEN" \| "BAR"` | |
| imageUrl | `string?` | |
| isAvailable | `boolean` | |
| isFeatured | `boolean?` | |
| createdAt, updatedAt | `number` | |

**category values:** FOOD, BEVERAGE, DESSERT, COCKTAIL, WINE, BEER

**Indexes:** by_category, by_available, by_station

### orders

| Field | Type | Description |
|-------|------|-------------|
| tableId | `Id<"tables">` | |
| reservationId | `Id<"reservations">?` | |
| eventId | `Id<"experienceEvents">?` | |
| status | `"OPEN" \| "SUBMITTED" \| "PREPARING" \| "SERVED" \| "PAID" \| "CANCELLED"` | |
| subtotal | `number` | |
| totalAmount | `number` | |
| notes | `string?` | |
| createdAt, updatedAt | `number` | |

**Indexes:** by_table, by_status, by_event

### orderItems

| Field | Type | Description |
|-------|------|-------------|
| orderId | `Id<"orders">` | |
| menuItemId | `Id<"menuItems">` | |
| quantity | `number` | |
| unitPrice | `number` | |
| totalPrice | `number` | |
| notes | `string?` | |
| status | `"PENDING" \| "PREPARING" \| "READY" \| "SERVED"` | |
| station | `"KITCHEN" \| "BAR"` | |
| isComp | `boolean` | Complimentary |
| compSource | `"SPIN" \| "PHOTO_WIN" \| "GOOGLE_REVIEW"?` | |
| createdAt | `number` | |

**Indexes:** by_order, by_order_status, by_station_status

### guestProfiles

| Field | Type | Description |
|-------|------|-------------|
| reservationId | `Id<"reservations">?` | |
| tableId | `Id<"tables">?` | |
| token | `string` | QR identifier |
| avatarUrl | `string?` | |
| avatarStorageId | `string?` | |
| nickname | `string` | |
| country | `string` | |
| origin | `string` | |
| moodTags | `string[]` | |
| bio | `string?` | |
| experienceDate | `string` | ISO date |
| checkedIn | `boolean` | |
| createdAt, updatedAt | `number` | |

**Indexes:** by_reservation, by_experience_date, by_token

### guestReactions

| Field | Type | Description |
|-------|------|-------------|
| fromProfileId | `Id<"guestProfiles">` | |
| toProfileId | `Id<"guestProfiles">` | |
| reactionType | `"WAVE" \| "CHEERS" \| "HEART"` | |
| experienceDate | `string` | |
| createdAt | `number` | |

**Indexes:** by_to_profile, by_from_profile, by_experience_date

### bookingDrafts

| Field | Type | Description |
|-------|------|-------------|
| sessionId | `string` | User auth subject |
| eventId | `Id<"experienceEvents">?` | |
| experience | `string?` | |
| ticketType | `"DINNER_THEATRE" \| "SHOW_ONLY"?` | |
| quantity | `number?` | |
| reservationId | `Id<"reservations">?` | |
| bookingExpiresAt | `number?` | |
| addOns | `{addOnId, quantity}[]?` | |
| bundle | `string?` | |
| guests | `number?` | |
| customerInfo | `{firstName, lastName, email, phone}?` | |
| currentStep | see below? | |
| expiresAt | `number` | Auto-cleanup |
| createdAt, updatedAt | `number` | |

**currentStep values:** EXPERIENCE, SHOW, TICKETS, BUNDLE, ADDONS, CUSTOMER_INFO, PAYMENT, CONFIRMATION

**Indexes:** by_session, by_expires

### formSessions

| Field | Type | Description |
|-------|------|-------------|
| sessionId | `string` | localStorage UUID |
| formType | see below | |
| data | `string` | JSON |
| submitted | `boolean` | |
| expiresAt | `number` | 7 days |
| createdAt, updatedAt | `number` | |

**formType values:** CONTACT, VENUE_RENTAL, PRIVATE_EVENTS, WORKSHOPS, ARTIST_PROPOSAL, HOST_AN_EVENT, FRENCH_MENTALIST, DINNER_THEATER, CHECKOUT, RESERVATION, PROFILE, EXPERIENCE, ADDON

**Indexes:** by_session_type, by_expires, by_data_search

### inquirySessions

| Field | Type | Description |
|-------|------|-------------|
| formSessionId | `Id<"formSessions">` | |
| formType | same as formSessions | |
| status | `"NEW" \| "READ" \| "REPLIED" \| "ARCHIVED"` | |
| adminNotes | `string?` | |
| reviewedBy | `string?` | Clerk user ID |
| reviewedAt | `number?` | |
| createdAt, updatedAt | `number` | |

**Indexes:** by_formSession, by_formType, by_status, by_formType_status

### inquiryFollowUps

| Field | Type | Description |
|-------|------|-------------|
| inquiryId | `Id<"inquirySessions">` | |
| authorId | `string` | Clerk user ID |
| authorName | `string` | |
| content | `string` | |
| createdAt | `number` | |

**Indexes:** by_inquiry

### challengeConfig

| Field | Type | Description |
|-------|------|-------------|
| challengeType | `"PHOTO_WALL" \| "LUCKY_SPIN" \| "GOOGLE_REVIEW"` | |
| enabled | `boolean` | |
| maxValue | `number?` | |
| prizeDescription | `string?` | |
| steps | `{order, text, imageUrl?}[]` | |
| activeForDates | `string[]` | |
| createdAt, updatedAt | `number` | |

**Indexes:** by_type

### photoSubmissions

| Field | Type | Description |
|-------|------|-------------|
| profileId | `Id<"guestProfiles">` | |
| orderId | `Id<"orders">?` | |
| tableId | `Id<"tables">` | |
| imageUrl | `string` | |
| caption | `string?` | |
| likeCount | `number` | |
| status | `"ACTIVE" \| "HIDDEN"` | |
| winner | `boolean` | |
| experienceDate | `string` | |
| createdAt, updatedAt | `number` | |

**Indexes:** by_experience_date, by_profile, by_status, by_table_experience, by_likes

### photoLikes

| Field | Type | Description |
|-------|------|-------------|
| submissionId | `Id<"photoSubmissions">` | |
| profileId | `Id<"guestProfiles">` | |
| createdAt | `number` | |

**Indexes:** by_submission, by_profile_submission, by_profile

### spinPrizes

| Field | Type | Description |
|-------|------|-------------|
| label | `string` | |
| prizeType | `"MENU_ITEM" \| "DISCOUNT" \| "FREE_ITEM"` | |
| menuItemId | `Id<"menuItems">?` | |
| discountPercent | `number?` | |
| weight | `number` | |
| enabled | `boolean` | |
| createdAt, updatedAt | `number` | |

**Indexes:** by_enabled

### spinResults

| Field | Type | Description |
|-------|------|-------------|
| profileId | `Id<"guestProfiles">` | |
| orderId | `Id<"orders">` | |
| tableId | `Id<"tables">` | |
| prizeId | `Id<"spinPrizes">` | |
| displayText | `string` | |
| experienceDate | `string` | |
| createdAt, updatedAt | `number` | |

**Indexes:** by_experience_date, by_table_experience, by_profile

### challengeSubmissions

| Field | Type | Description |
|-------|------|-------------|
| profileId | `Id<"guestProfiles">` | |
| orderId | `Id<"orders">` | |
| tableId | `Id<"tables">` | |
| challengeType | `"GOOGLE_REVIEW"` | |
| screenshotUrl | `string` | |
| status | `"PENDING" \| "APPROVED" \| "REJECTED"` | |
| rewardMenuItemId | `Id<"menuItems">?` | |
| reviewedBy | `Id<"users">?` | |
| reviewedAt | `number?` | |
| notes | `string?` | |
| experienceDate | `string` | |
| createdAt, updatedAt | `number` | |

**Indexes:** by_status, by_experience_date, by_table_experience

### notifications

| Field | Type | Description |
|-------|------|-------------|
| type | `"ORDER_READY" \| "NEW_RESERVATION" \| "EXPERIENCE_REMINDER" \| "ALERT" \| "SYSTEM"` | |
| title | `string` | |
| message | `string` | |
| isRead | `boolean` | |
| priority | `"LOW" \| "MEDIUM" \| "HIGH"` | |
| metadata | `string?` | JSON |
| createdAt | `number` | |

**Indexes:** by_read, by_type, by_created

### notificationLogs

| Field | Type | Description |
|-------|------|-------------|
| notificationType | see below | |
| channel | `"EMAIL" \| "WHATSAPP"` | |
| recipient | `string` | |
| subject | `string?` | |
| status | `"SUCCESS" \| "FAILED"` | |
| errorMessage | `string?` | |
| reservationId | `Id<"reservations">?` | |
| createdAt | `number` | |

**notificationType values:** EMAIL_CONFIRMATION, EMAIL_CANCELLATION, WHATSAPP_CONFIRMATION, EMAIL_ADMIN_NEW_BOOKING

**Indexes:** by_reservation, by_status, by_created

### zohoSyncLogs

| Field | Type | Description |
|-------|------|-------------|
| operationType | see below | |
| entityType | see below | |
| entityId | `string?` | Zoho ID |
| status | `"SUCCESS" \| "FAILED"` | |
| errorMessage | `string?` | |
| reservationId | `Id<"reservations">?` | |
| createdAt | `number` | |

**operationType values:** CONTACT_UPSERT, DEAL_CREATE, INVOICE_CREATE, INVOICE_MARK_PAID

**entityType values:** CONTACT, DEAL, INVOICE

**Indexes:** by_reservation, by_status, by_created

### payments

| Field | Type | Description |
|-------|------|-------------|
| reservationId | `Id<"reservations">` | |
| vpcMerchTxnRef | `string` | OnePay reference |
| vpcTransactionNo | `string?` | |
| amount | `number` | |
| currency | `string` | |
| status | `"PENDING" \| "SUCCESS" \| "FAILED"` | |
| responseCode | `string?` | |
| message | `string?` | |
| card | `string?` | |
| cardNum | `string?` | |
| createdAt, updatedAt | `number` | |

**Indexes:** by_vpcMerchTxnRef

### checkIns

| Field | Type | Description |
|-------|------|-------------|
| ticketId | `string` | Reservation token |
| eventId | `Id<"experienceEvents">` | |
| checkedInAt | `number` | Unix timestamp |
| checkedInBy | `string?` | Staff user ID |

**Indexes:** by_ticket, by_event

Task 4: Document Booking Flow (booking-flow.md)

Files:

  • Create: docs/superpowers/specs/booking-flow.md

  • **Step 1: Document current booking flow

# Booking Flow Specification
 
> **Status:** Canonical
> **Last Updated:** 2026-05-11
> **Source:** `apps/frontend/app/[locale]/booking/` and booking components
 
---
 
## Related specs
 
- [Tech Stack](./tech-stack.md) — Convex API pattern used here
- [Data Model](./data-model.md) — reservations, bookingDrafts tables
- [Public Pages](./public-pages.md) — Shows are entry points to booking
- [Payments](./payments.md) — OnePay integration during checkout
- [Notifications](./notifications.md) — Confirmation emails after payment
- [User Stories](./user-stories.md) — US-B01 through US-B03 cover booking
 
---
 
## Overview
 
The booking flow is a 4-step SPA with no page reloads between steps. Entry is always from a show page where date/time is locked.
 
**Entry:** `/booking/[occurrenceId]/tickets` — occurrenceId is the experienceEvent ID
 
## Flow Steps

┌─────────────────────────────────────────────────────────────┐ │ STEP 1: TICKETS │ │ - Select ticket type (Dinner Theatre / Show Only) │ │ - Select quantity (1-32, capped at availability) │ │ - See sticky cart with real-time total │ │ - 10-minute countdown timer starts │ │ → Continue → │ ├─────────────────────────────────────────────────────────────┤ │ STEP 2: ADD-ONS (Skippable) │ │ - "Make your evening even more memorable" │ │ - Display add-on cards with price, description │ │ - Toggle add-ons on/off │ │ - Skip & Continue always available │ │ → Continue → │ ├─────────────────────────────────────────────────────────────┤ │ STEP 3: CHECKOUT (Single Page) │ │ - Left: Booking recap with edit links │ │ - Right: Customer form (name, email, phone) │ │ - Terms acceptance checkbox │ │ - Payment logos (VNPay, Visa, Mastercard) │ │ → Pay Now → (redirect to OnePay) │ ├─────────────────────────────────────────────────────────────┤ │ STEP 4: CONFIRMATION (Post-Payment) │ │ - Animated checkmark │ │ - Booking recap │ │ - QR code for check-in │ │ - Add to Calendar buttons │ │ - Download ticket PDF │ │ - "A confirmation email has been sent" │ └─────────────────────────────────────────────────────────────┘


## URL Structure

/booking/[eventId]/tickets → Step 1 (tickets) /booking/[eventId]/addons → Step 2 (add-ons) /booking/[eventId]/checkout → Step 3 (checkout) /booking/[eventId]/confirmation → Step 4 (confirmation)


## Sticky Cart

- **Desktop:** Fixed right sidebar
- **Mobile:** Fixed bottom bar

Always visible during steps 1-3 with:
- Selected ticket type × quantity
- Selected add-ons
- Real-time total in VND

## Countdown Timer

- Starts on Step 1 entry
- 10-minute hold on seats
- Display: "Your seats are reserved for 09:54"
- On expiry: Modal alert "Your reservation expired" with "Restart booking" button
- Seats auto-released on expiry

## Pricing Rules

### Base Pricing
- Dinner Theatre: From experienceEvents.dinnerPrice
- Show Only: From experienceEvents.experienceOnlyPrice (only if enabled)

### Surcharges (added to totalAmount in schema)
- **Day of week:** Friday + Saturday = +50K VND/guest
- **Small party:** 1-2 guests = +100K VND

### Discounts (subtracted)
- **Bundle discounts:** Applied via bundleId
- **VIP surcharge:** +500K VND if VIP bundle

## Scarcity Signals

- Show "Only X seats left" when <10 remaining
- Show "Few left" badge when 1-10 seats
- Show "Sold out" and disable button when 0

## Trust Signals (Step 3)

- VNPay, Visa, Mastercard logos
- "Secure encrypted payment" badge
- No language selector during booking (locked from entry)

## Customer Form Fields (Step 3)

| Field | Required | Validation |
|-------|----------|------------|
| First name | Yes | Non-empty |
| Last name | Yes | Non-empty |
| Email | Yes | Valid email format |
| Phone | No | Optional |
| Terms acceptance | Yes | Must check |

## OnePay Integration

On "Pay Now" click:
1. Create pending reservation in Convex
2. Call OnePay API with return URL
3. Redirect to OnePay payment page
4. On return, verify signature and update reservation status

## Payment Status Flow

PENDING → PAID (OnePay success) → FAILED (OnePay fail/cancel) → CANCELLED (user cancels) → REFUND_PENDING → REFUNDED (admin/process)


## Key Components

| Component | Location | Purpose |
|-----------|-----------|---------|
| BookingProvider | `components/booking/booking-provider.tsx` | Context for booking state |
| StickyCart | `components/booking/sticky-cart.tsx` | Persistent cart display |
| CountdownTimer | `components/booking/countdown-timer.tsx` | 10-min seat hold |
| TicketSelector | `components/booking/ticket-selector.tsx` | Step 1 |
| AddonPicker | `components/booking/addon-picker.tsx` | Step 2 |
| CheckoutForm | `components/booking/checkout-form.tsx` | Step 3 |
| ConfirmationView | `components/booking/confirmation-view.tsx` | Step 4 |
| QRCode | `components/booking/qr-code-image.tsx` | QR generation |

Task 5: Document Public Pages (public-pages.md)

Files:

  • Create: docs/superpowers/specs/public-pages.md

  • **Step 1: Document public pages structure

# Public Pages Specification
 
> **Status:** Canonical
> **Last Updated:** 2026-05-11
> **Source:** `apps/frontend/app/[locale]/(landing)/`
 
---
 
## Related specs
 
- [Tech Stack](./tech-stack.md) — Frontend routing structure
- [Booking Flow](./booking-flow.md) — Shows link to booking flow
- [Inquiry Forms](./inquiry-forms.md) — Inquiry pages within public pages
- [Gamification](./gamification.md) — Wall page for photo submissions
- [User Stories](./user-stories.md) — US-G01 through US-G04 cover guest browsing
 
---
 
## Route Structure

[locale]/(landing)/ ├── page.tsx # Homepage ├── about/ │ └── page.tsx ├── artists/ │ └── page.tsx ├── schedule/ │ └── page.tsx ├── reviews/ │ └── page.tsx ├── wall/ │ └── page.tsx ├── experiences/ │ ├── french-mentalist/ │ │ ├── page.tsx │ │ └── metadata.ts │ ├── dinner-theater/ │ │ ├── page.tsx │ │ └── metadata.ts │ └── our-evening/ │ ├── page.tsx │ └── metadata.ts └── inquiry/ ├── contact/ ├── venue-rental/ ├── workshops/ ├── private-events/ ├── artist-proposal/ └── host-an-event/


## Homepage (`/`)

### Sections (top to bottom)
1. **Hero** — Full-width video/image with headline, CTA
2. **Upcoming Experiences Carousel** — Next 5-8 events across all shows
3. **Experience Schedule** — Calendar/list of upcoming shows
4. **Why House of Legends** — Bento grid features
5. **Services** — What we offer
6. **Community/Wall** — Photo wall preview
7. **Reviews** — Google reviews section
8. **Contact Form** — Quick contact
9. **Partner Logos** — Social proof
10. **Footer** — Links, social, contact

### Upcoming Experiences Carousel
- Auto-plays every 6 seconds, pauses on hover
- Touch swipe on mobile
- Each card shows: hero image, show title, date/time, availability badge, price "From X VND"
- Click → navigate to show page (NOT booking)

### Experience Schedule Section
- Calendar picker or date list
- Filter by show
- Click date → show page

## Show/Experience Pages (`/experiences/[slug]`)

Each experience has:
- **Hero** — Embedded video (autoplay muted) or image
- **Title + Tagline**
- **"See dates" button** — smooth scroll to occurrences
- **Description** — Rich text storytelling
- **Photo gallery** — Carousel or masonry
- **What to expect** — Duration, language, atmosphere
- **Artists** — If relevant
- **UPCOMING DATES** — The key conversion zone

### Upcoming Dates Section

Vertical list, each row:

Friday May 2 7:30 PM ● 12 seats left [Book Now] Saturday May 3 7:30 PM ● Available [Book Now] Friday May 9 7:30 PM ● Few left (3) [Book Now] Saturday May 10 7:30 PM ● Sold out [—]


**Badge colors:**
- Green: Available (>10 seats)
- Orange: Few left (1-10 seats)
- Grey: Sold out (0 seats, button disabled)

**Critical:** Clicking Book → `/booking/[eventId]/tickets` with date/time LOCKED

## Inquiry Pages

All inquiry pages use the same pattern:
- Hero section with form
- Form submitted via Convex mutation
- Success state shown inline
- Admin can view in dashboard

### Contact (`/inquiry/contact`)
- Fields: name, email, subject, message

### Venue Rental (`/inquiry/venue-rental`)
- Fields: name, email, phone, event type, date, guest count, message

### Workshops (`/inquiry/workshops`)
- Fields: name, email, phone, workshop type, message

### Private Events (`/inquiry/private-events`)
- Fields: name, email, phone, event type, date, guest count, message

### Artist Proposal (`/inquiry/artist-proposal`)
- Fields: name, email, phone, performance type, description, links

### Host an Event (`/inquiry/host-an-event`)
- Fields: name, email, phone, event type, date, guest count, message

## Admin Form Management

All inquiry submissions:
1. Stored in `formSessions` table
2. Admin notification created in `notifications` table
3. Viewable in `/dashboard/inquiries`

Admin can:
- Mark as READ, REPLIED, ARCHIVED
- Add follow-up notes
- See submission data and timestamps

Task 6: Document Admin Dashboard (admin-dashboard.md)

Files:

  • Create: docs/superpowers/specs/admin-dashboard.md

  • **Step 1: Document admin dashboard

# Admin Dashboard Specification
 
> **Status:** Canonical
> **Last Updated:** 2026-05-11
> **Source:** `apps/frontend/app/[locale]/dashboard/`
 
---
 
## Related specs
 
- [Tech Stack](./tech-stack.md) — Staff auth and role-based access
- [Data Model](./data-model.md) — References all tables
- [Booking Flow](./booking-flow.md) — Admin can view reservations
- [Staff POS](./staff-pos.md) — POS views within admin
- [Payments](./payments.md) — View payment status per event
- [Notifications](./notifications.md) — Notification center in dashboard
- [User Stories](./user-stories.md) — US-A01 through US-A08 cover admin
 
---
 
## Route Structure

dashboard/ ├── layout.tsx # Admin layout with sidebar ├── page.tsx # Overview/analytics ├── admin/ │ ├── page.tsx # Admin home │ ├── pos/ │ │ └── challenges/ │ │ └── page.tsx # Challenge management ├── events/ │ └── page.tsx # Experience events list ├── experiences/ │ └── page.tsx # Experience templates ├── reservations/ │ └── page.tsx # All reservations ├── inquiries/ │ └── page.tsx # Inquiry management (kanban) ├── checkin/ │ └── page.tsx # QR scanner ├── event-payments/ │ └── page.tsx # Payment tracking


## Dashboard Home (`/dashboard`)

Shows:
- Today's events overview
- Recent reservations
- Quick actions
- Notification bell

## Reservations (`/dashboard/reservations`)

### List View
- Paginated table
- Filters: show, date, payment status, ticket type
- Search by name/email

### Reservation Detail
- Customer info
- Tickets (type, quantity)
- Add-ons
- Total paid
- Payment status
- QR code
- Actions: cancel, resend confirmation email

### Status Badges
- **PENDING** — Yellow, awaiting payment
- **PAID_CONFIRMED** — Green, confirmed
- **CHECKED_IN** — Blue, guest arrived
- **CANCELLED** — Red strikethrough
- **REFUNDED** — Grey

## Events (`/dashboard/events`)

### List View
- All experienceEvents
- Filter by experience, date range
- Show: date, time, show name, capacity, booked, status

### Event Detail
- Edit capacity
- Toggle Show Only tickets
- Override prices
- Cancel event (with customer notification)

## Experiences (`/dashboard/experiences`)

### List View
- All experience templates
- Status filter (active, draft, archived)

### Experience Editor
- Title, tagline, description
- Embedded video URL
- Photo gallery (multi-upload)
- Ticket type configuration
- Default prices
- Default capacity
- Slug (URL identifier)

### Batch Create Events
- Select days of week
- Select time
- Date range (start/end)
- Capacity (inherited or override)
- Generate all occurrences in one click

## Inquiries (`/dashboard/inquiries`)

### Kanban Board View
Columns: NEW | READ | REPLIED | ARCHIVED

### Card Display
- Form type icon
- Submitter name/email
- Submission date
- Preview of message

### Card Actions
- Click → see full details
- Drag to change status
- Add follow-up notes
- Reply button (future: email integration)

## Check-In (`/dashboard/checkin`)

### QR Scanner
- Camera-based scanner
- Scan reservation QR code
- Shows guest details
- Mark as checked in

### Manual Lookup
- Enter reservation code
- View details
- Manual check-in button

## Event Payments (`/dashboard/event-payments`)

### Per-Event Payment Summary
- Event details
- Total revenue
- Payment breakdown by type
- Pending payments
- Failed payments

## POS Challenges (`/dashboard/admin/pos/challenges`)

### Challenge Configuration
- Photo Wall: enable/disable, max submissions
- Lucky Spin: enable/disable, prize configuration
- Google Review: enable/disable, reward item

### Per-Challenge Stats
- Participation rate
- Submission count
- Winner selection

Task 7: Document Staff POS (staff-pos.md)

Files:

  • Create: docs/superpowers/specs/staff-pos.md

  • **Step 1: Document staff POS system

# Staff POS Specification
 
> **Status:** Canonical
> **Last Updated:** 2026-05-11
> **Source:** POS components in `apps/frontend/components/pos/`
 
---
 
## Related specs
 
- [Tech Stack](./tech-stack.md) — Real-time via Convex subscriptions
- [Data Model](./data-model.md) — tables, orders, orderItems, menuItems
- [Admin Dashboard](./admin-dashboard.md) — Admin configures POS challenges
- [Gamification](./gamification.md) — Challenges (spin, photo wall) at table
- [Notifications](./notifications.md) — ORDER_READY notifications
- [User Stories](./user-stories.md) — US-S01 through US-S05 cover staff
 
---
 
## POS Views
 
> **Last Updated:** 2026-05-11
> **Source:** POS components in `apps/frontend/components/pos/`
 
## POS Views
 
The POS system has three main views for different staff roles:
 
### 1. Reception View
 
**Purpose:** Check in guests, manage tables
 
Located: `/dashboard/admin/pos/reception` (implied from components)
 
Features:
 
- Table layout visualization
- Reservation list for shift
- QR code scanning for check-in
- Table status updates
- Walk-in management
 
### 2. Kitchen Display (KDS)
 
**Purpose:** View and update order preparation
 
Components: `components/pos/kitchen-display.tsx`
 
Features:
 
- Orders list with status
- Status filters: Received, Preparing, Ready, Served
- Order cards showing:
  - Table number
  - Items ordered
  - Special notes
  - Time since order
- One-tap status updates
- Audio alerts on new orders
 
### 3. Staff Mobile View
 
**Purpose:** Floor staff take orders at tables
 
Components: `components/pos/staff-order.tsx`
 
Features:
 
- Table list with status
- Take order at table
- Add items from menu
- Submit order to kitchen
- View order status
 
## Table Management
 
### Table States
 
- **AVAILABLE** — Empty, ready for seating
- **RESERVED** — Expected reservation
- **OCCUPIED** — Guests seated, order in progress
- **MAINTENANCE** — Unavailable
 
### Floor Plan
 
- Visual grid of tables
- Click table → see details/actions
- Status color coding
- Drag to rearrange (admin only)
 
## Order Flow

OPEN → SUBMITTED → PREPARING → READY → SERVED │ │ │ │ │ │ │ │ │ └─ Guest receives food │ │ │ └─ Staff picks up │ │ └─ Kitchen prepares │ └─ Sent to kitchen └─ Created at table


## Order Details

### Order Card Shows
- Table number
- Reservation ID (if linked)
- Items with quantities
- Special instructions
- Order time
- Status badge

### Order Actions
- Update item status
- Mark order complete
- Add comp items
- Print ticket (future)

## Menu Items

### Categories
- FOOD: Appetizers, Mains, Desserts
- BEVERAGE: Soft drinks, Beer
- COCKTAIL: Bar drinks
- WINE: Wine list

### Item Display
- Name
- Description
- Price (VND)
- Availability toggle
- Featured badge

## Comp System

Staff can mark items as complimentary from:
- **Spin result** — Lucky spin prize
- **Photo win** — Photo wall winner
- **Google review** — Review challenge reward

Comp items tracked in `orderItems.isComp` with `compSource` field.

## Real-Time Updates

All POS views use Convex subscriptions for real-time updates:
- New orders appear immediately
- Status changes reflect instantly
- No page refresh needed

Task 8: Document Inquiry Forms (inquiry-forms.md)

Files:

  • Create: docs/superpowers/specs/inquiry-forms.md

  • **Step 1: Document inquiry form system

# Inquiry Forms Specification
 
> **Status:** Canonical
> **Last Updated:** 2026-05-11
> **Source:** `apps/frontend/app/[locale]/(landing)/inquiry/`
 
---
 
## Related specs
 
- [Tech Stack](./tech-stack.md) — Forms use React Hook Form + Zod
- [Data Model](./data-model.md) — formSessions, inquirySessions tables
- [Public Pages](./public-pages.md) — Inquiry pages are part of public pages
- [Admin Dashboard](./admin-dashboard.md) — Kanban view in admin for managing inquiries
- [Notifications](./notifications.md) — Admin alerts when new inquiry submitted
- [User Stories](./user-stories.md) — US-G04 covers inquiry submission
 
---
 
## Form Types
 
| Form            | Route                      | Purpose                 | Storage      |
| --------------- | -------------------------- | ----------------------- | ------------ |
| Contact         | `/inquiry/contact`         | General inquiries       | formSessions |
| Venue Rental    | `/inquiry/venue-rental`    | Private venue booking   | formSessions |
| Workshops       | `/inquiry/workshops`       | Workshop inquiries      | formSessions |
| Private Events  | `/inquiry/private-events`  | Private event bookings  | formSessions |
| Artist Proposal | `/inquiry/artist-proposal` | Performer applications  | formSessions |
| Host an Event   | `/inquiry/host-an-event`   | Corporate/event hosting | formSessions |
 
## Form Architecture
 
### Frontend
 
Each inquiry page is a self-contained form:
 
- Hero section with page title
- Form fields (React Hook Form + Zod validation)
- Submit button with loading state
- Success/error messages
 
### Backend Storage
 
All form submissions stored in two tables:
 
**formSessions** — Raw submission
 
- sessionId: UUID
- formType: enum
- data: JSON stringified fields
- submitted: boolean
- expiresAt: 7 days
 
**inquirySessions** — Admin overlay
 
- formSessionId: FK
- formType: enum
- status: NEW | READ | REPLIED | ARCHIVED
- adminNotes: optional
- reviewedBy: Clerk user ID
- reviewedAt: timestamp
 
## Form Fields by Type
 
### Contact
 
- name (required)
- email (required, validated)
- subject (required)
- message (required)
 
### Venue Rental
 
- name (required)
- email (required)
- phone (required)
- eventType (required)
- date (required)
- guestCount (required)
- message (optional)
 
### Workshops
 
- name (required)
- email (required)
- phone (required)
- workshopType (required)
- message (optional)
 
### Private Events
 
- name (required)
- email (required)
- phone (required)
- eventType (required)
- date (required)
- guestCount (required)
- message (optional)
 
### Artist Proposal
 
- name (required)
- email (required)
- phone (required)
- performanceType (required)
- description (required)
- links (optional)
 
### Host an Event
 
- name (required)
- email (required)
- phone (required)
- eventType (required)
- date (required)
- guestCount (required)
- message (optional)
 
## Submission Flow
  1. User fills form → React Hook Form validates
  2. Submit → useMutation(api.domains.forms.submitInquiry)
  3. Convex stores in formSessions
  4. Convex creates inquirySession with status=NEW
  5. Convex creates notification for admin
  6. Frontend shows success message

## Admin Management

### Kanban Board (`/dashboard/inquiries`)
- Columns: NEW | READ | REPLIED | ARCHIVED
- Drag cards between columns to update status
- Click card to expand details

### Card Display
- Form type badge
- Submitter name
- Submitter email
- Date submitted
- Message preview (first 100 chars)

### Detail View
- All form fields
- Submission timestamp
- Current status
- Admin notes (add/edit)
- Follow-up history

### Follow-ups
Admin can add follow-up notes visible in inquiry detail.

Task 9: Document Gamification (gamification.md)

Files:

  • Create: docs/superpowers/specs/gamification.md

  • **Step 1: Document gamification features

# Gamification Specification
 
> **Status:** Canonical
> **Last Updated:** 2026-05-11
> **Source:** Schema tables and `packages/backend/convex/domains/minigames.ts`
 
---
 
## Related specs
 
- [Tech Stack](./tech-stack.md) — Real-time via Convex subscriptions
- [Data Model](./data-model.md) — guestProfiles, challenges, spinResults tables
- [Public Pages](./public-pages.md) — Wall page at `/wall`
- [Admin Dashboard](./admin-dashboard.md) — Challenge configuration in admin
- [Staff POS](./staff-pos.md) — Challenges triggered at table level
- [User Stories](./user-stories.md) — US-CG01 through US-CG04 cover guest gamification
 
---
 
## Features Overview
 
| Feature         | Description             | Tables                                |
| --------------- | ----------------------- | ------------------------------------- |
| Guest Profiles  | QR scan creates profile | guestProfiles                         |
| Photo Wall      | Guests submit photos    | photoSubmissions, photoLikes          |
| Guest Reactions | Wave, Cheers, Heart     | guestReactions                        |
| Lucky Spin      | Wheel for prizes        | spinPrizes, spinResults               |
| Google Review   | Review challenge        | challengeConfig, challengeSubmissions |
 
## Guest Profile System
 
### Creation
 
Profiles are created when a guest scans their reservation QR code at check-in.
 
### Profile Data
 
- Nickname (guest entered)
- Country
- Origin (how they heard about us)
- Mood tags (selectable)
- Bio (optional)
- Avatar (optional)
 
### Wall Page (`/wall`)
 
Public gallery of guest photos with like functionality.
 
- Grid of photo submissions
- Like button per photo
- Winner badges for featured photos
 
### Table View (`/dashboard/table`)
 
Staff can view profiles at their table.
 
- Guest list for table
- Profile cards
- Mood tags display
 
## Photo Wall
 
### Submission Flow
 
1. Guest visits photo station
2. Takes photo or selects from gallery
3. Adds caption (optional)
4. Submits
5. Photo appears on Wall after approval
 
### Photo Card
 
- Image
- Caption
- Like count
- Submitter nickname
- Winner badge (if applicable)
 
### Likes
 
- Any guest can like any photo
- One like per profile per photo
- Like count updates in real-time
 
### Winner System
 
Admin can mark photos as winners.
 
- Special badge displayed
- Featured in winner section
 
## Guest Reactions
 
### Types
 
- **Wave** — 👋
- **Cheers** — 🍷
- **Heart** — ❤️
 
### How It Works
 
- Guests see other profiles at their table/event
- Can send reactions to other guests
- Reactions accumulate on profile
- Displayed as reaction badges
 
## Lucky Spin
 
### Configuration
 
Admin configures via `/dashboard/admin/pos/challenges`:
 
- Enable/disable
- Prize list with weights
- Max value per spin
 
### Prizes
 
Types:
 
- **MENU_ITEM** — Specific menu item
- **DISCOUNT** — Percentage off
- **FREE_ITEM** — Free item
 
### Spin Flow
 
1. Guest at table initiates spin
2. Random prize selected by weight
3. Prize applied to order as comp
4. Result recorded in spinResults
 
## Google Review Challenge
 
### Configuration
 
Admin enables and sets:
 
- Reward menu item
- Challenge period
 
### Submission Flow
 
1. Guest writes Google review
2. Takes screenshot
3. Submits via app
4. Admin reviews screenshot
5. Approves/rejects
6. If approved, menu item added to bill as comp
 
## Challenge Management
 
### Admin Dashboard (`/dashboard/admin/pos/challenges`)
 
- Toggle challenges on/off
- Configure per-challenge settings
- View submission stats
 
### Per-Challenge Stats
 
- Total submissions
- Approval rate
- Participation trend

Task 10: Document Payments (payments.md)

Files:

  • Create: docs/superpowers/specs/payments.md

  • **Step 1: Document payment system

# Payments Specification
 
> **Status:** Canonical
> **Last Updated:** 2026-05-11
> **Source:** `packages/backend/convex/domains/payments.ts`, `packages/backend/convex/http/onepay.ts`
 
---
 
## Related specs
 
- [Tech Stack](./tech-stack.md) — External integration patterns
- [Data Model](./data-model.md) — reservations, payments, notificationLogs tables
- [Booking Flow](./booking-flow.md) — Checkout step integrates with payments
- [Notifications](./notifications.md) — EMAIL_CONFIRMATION, WHATSAPP_CONFIRMATION after payment
- [Admin Dashboard](./admin-dashboard.md) — Event payments view in admin
- [User Stories](./user-stories.md) — US-B01, US-B02 cover payment flow
 
---
 
## Payment Flow

┌─────────────────────────────────────────────────────────────┐ │ 1. User on checkout page │ │ - Fills customer info │ │ - Clicks "Pay Now" │ ├─────────────────────────────────────────────────────────────┤ │ 2. Create pending reservation │ │ - status: PENDING │ │ - paymentStatus: PENDING │ │ - bookingExpiresAt: now + 10 min │ ├─────────────────────────────────────────────────────────────┤ │ 3. Call OnePay API │ │ - Create payment URL with amount, order info │ │ - Redirect user to OnePay │ ├─────────────────────────────────────────────────────────────┤ │ 4. User completes payment on OnePay │ │ - Success → redirect to /booking/[id]/confirmation │ │ - Fail → redirect to /booking/[id]/checkout?error=... │ ├─────────────────────────────────────────────────────────────┤ │ 5. Handle return │ │ - Verify OnePay signature │ │ - Update reservation status │ │ - Create payment record │ │ - Send confirmation email │ └─────────────────────────────────────────────────────────────┘


## OnePay Integration

### Configuration
```typescript
// Environment variables (via npx convex env set)
ONEPAY_MERCHANT_ID=your_merchant_id
ONEPAY_ACCESS_CODE=your_access_code
ONEPAY_SECRET_KEY=your_secret_key
ONEPAY_URL=https://mtf.onepay.vn

Payment URL Creation

// packages/backend/convex/lib/onepay/api.ts
createPaymentUrl({
  amount: number,
  orderId: string,
  returnUrl: string,
  transactionType: "PAY",
});

Return URL Handling

// packages/backend/convex/http/onepayReturn.ts
- Extract VPC response params
- Verify secure hash
- Update reservation paymentStatus
- Redirect to confirmation or error

Payment Status

StatusDescriptionAction
PENDINGAwaiting paymentUser redirected to OnePay
PAIDPayment successfulConfirmation sent
FAILEDPayment failedShow error, allow retry
CANCELLEDUser cancelledRelease seats
REFUND_PENDINGRefund requestedAdmin processes
REFUNDEDRefund completedNotify customer

Virtual Account (Bank Transfer)

Flow

  1. User selects bank transfer
  2. System generates VA number
  3. User transfers to VA
  4. OnePay notifies on receipt
  5. Payment marked PAID

VA Number Display

Shown on checkout for bank transfer option.

Payment Tracking

payments Table

Stores all OnePay transactions:

  • vpcMerchTxnRef: Unique reference
  • vpcTransactionNo: OnePay transaction ID
  • amount: VND amount
  • status: PENDING | SUCCESS | FAILED
  • card: Card type (Visa, Mastercard)
  • cardNum: Last 4 digits

notificationLogs Table

Tracks delivery of confirmations:

  • EMAIL_CONFIRMATION
  • WHATSAPP_CONFIRMATION
  • EMAIL_ADMIN_NEW_BOOKING

Refund Flow

  1. Admin opens reservation detail
  2. Clicks "Cancel & Refund"
  3. System calls OnePay refund API
  4. Updates reservation status to REFUNDED
  5. Sends cancellation email

Pricing Display

All prices in VND. Format with:

// apps/frontend/lib/utils/format.ts
formatCurrency(amount: number): string
// Output: "500.000 đ"

---

## Task 11: Document Notifications (notifications.md)

**Files:**
- Create: `docs/superpowers/specs/notifications.md`

- [ ] **Step 1: Document notification system

```markdown
# Notifications & CRM Specification

> **Status:** Canonical
> **Last Updated:** 2026-05-11
> **Source:** Schema tables, `packages/backend/convex/domains/notifications.ts`, `packages/backend/convex/domains/crm.ts`

---

## Related specs

- [Tech Stack](./tech-stack.md) — External integrations (email, WhatsApp, Zoho)
- [Data Model](./data-model.md) — notifications, notificationLogs, zohoSyncLogs tables
- [Booking Flow](./booking-flow.md) — Confirmation triggers notification
- [Payments](./payments.md) — Payment success triggers notifications
- [Admin Dashboard](./admin-dashboard.md) — Notification bell in admin dashboard
- [Staff POS](./staff-pos.md) — ORDER_READY notifications for kitchen
- [User Stories](./user-stories.md) — US-S05 covers staff notifications

---

## Notification Types

> **Status:** Canonical
> **Last Updated:** 2026-05-11
> **Source:** Schema tables, `packages/backend/convex/domains/notifications.ts`, `packages/backend/convex/domains/crm.ts`

## Notification Types

| Type | Channel | Trigger |
|------|---------|---------|
| EMAIL_CONFIRMATION | Email | Payment success |
| EMAIL_CANCELLATION | Email | Reservation cancelled |
| WHATSAPP_CONFIRMATION | WhatsApp | Payment success |
| EMAIL_ADMIN_NEW_BOOKING | Email | New reservation created |

## Notification Flow
  1. Event occurs (payment, booking, etc.)
  2. Create notification record in notifications table
  3. notificationLogs tracks delivery
  4. Email/WhatsApp sent via integrations
  5. Status updated: SUCCESS or FAILED

## Email Integration

### Configuration
```bash
npx convex env set SMTP_HOST your-smtp-host
npx convex env set SMTP_PORT 587
npx convex env set SMTP_USER your-user
npx convex env set SMTP_PASSWORD your-password

Email Templates

  • Confirmation: Booking details, QR code, add to calendar
  • Cancellation: Refund info, cancellation confirmation
  • Admin alert: New booking notification

Template Variables

  • {{customerName}}
  • {{showTitle}}
  • {{eventDate}}
  • {{eventTime}}
  • {{ticketType}}
  • {{quantity}}
  • {{totalAmount}}
  • {{qrCodeUrl}}

WhatsApp Integration

Configuration

npx convex env set WHATSAPP_API_KEY your-api-key
npx convex env set WHATSAPP_PHONE_NUMBER your-phone

Message Templates

  • Booking confirmation with date/time
  • Reminder (24h before event)
  • Cancellation confirmation

Zoho CRM Integration

Purpose

  • Create contact on booking
  • Create deal linked to contact
  • Create invoice on payment

Configuration

npx convex env set ZOHO_CLIENT_ID your-client-id
npx convex env set ZOHO_CLIENT_SECRET your-secret
npx convex env set ZOHO_REFRESH_TOKEN your-refresh-token
npx convex env set ZOHO_ORGANIZATION_ID your-org-id

Sync Log

All Zoho operations logged in zohoSyncLogs table:

  • CONTACT_UPSERT
  • DEAL_CREATE
  • INVOICE_CREATE
  • INVOICE_MARK_PAID

Staff Notifications

In-App

Displayed in dashboard notification bell:

  • ORDER_READY: Kitchen order complete
  • NEW_RESERVATION: New booking
  • EXPERIENCE_REMINDER: Tomorrow's event
  • ALERT: Attention needed

Notification Card

  • Type icon
  • Title
  • Message
  • Timestamp
  • Read/unread state

Admin Dashboard Notifications

Bell Icon

  • Shows unread count
  • Dropdown list of recent
  • Click → mark as read

Types Displayed

  • New reservations
  • Order ready alerts
  • System alerts
  • Challenge submissions

---

## Task 12: Document User Stories (user-stories.md)

**Files:**
- Create: `docs/superpowers/specs/user-stories.md`

- [ ] **Step 1: Document all user stories

```markdown
# User Stories — House of Legends

> **Status:** Canonical
> **Last Updated:** 2026-05-11

---

## Related specs

This is a summary spec that references all other specs. See individual specs for detailed documentation:

- [Tech Stack](./tech-stack.md) — Technology background
- [Data Model](./data-model.md) — Database schema
- [Booking Flow](./booking-flow.md) — US-B01 through US-B03
- [Public Pages](./public-pages.md) — US-G01 through US-G04
- [Admin Dashboard](./admin-dashboard.md) — US-A01 through US-A08
- [Staff POS](./staff-pos.md) — US-S01 through US-S05
- [Inquiry Forms](./inquiry-forms.md) — US-G04
- [Gamification](./gamification.md) — US-CG01 through US-CG04
- [Payments](./payments.md) — Referenced by US-B01
- [Notifications](./notifications.md) — Referenced by US-S05

---

## Actors

| Actor | Description | Route Access |
|-------|-------------|--------------|
| Guest (Public) | Anonymous visitor | All public pages |
| Booking Guest | User going through booking | /booking/* |
| Checked-in Guest | Verified reservation holder | /wall, /dashboard/table |
| Staff | Venue operations | /dashboard/* (limited) |
| Admin | Full system access | /dashboard/* (full) |

---

## Guest (Public) User Stories

### US-G01: Browse Upcoming Shows
**As a** public guest
**I want to** see upcoming show dates
**So that** I can plan my visit

**Acceptance:**
- [ ] Homepage shows carousel of next 5-8 events
- [ ] Each card shows show name, date/time, price, availability
- [ ] Click card → show detail page

### US-G02: View Show Details
**As a** public guest
**I want to** learn about a show
**So that** I can decide to book

**Acceptance:**
- [ ] Show page has video, description, gallery
- [ ] Shows list of upcoming dates
- [ ] Each date shows availability badge
- [ ] "Book Now" button → booking flow with date locked

### US-G03: Submit Inquiry Form
**As a** public guest
**I want to** contact about venue rental/private event
**So that** I can inquire about hosting

**Acceptance:**
- [ ] Form validates required fields
- [ ] Success message shown on submit
- [ ] Submission stored and admin notified

### US-G04: View Photo Wall
**As a** public guest
**I want to** see guest photos
**So that** I can feel the atmosphere

**Acceptance:**
- [ ] Grid of approved photos
- [ ] Like count visible
- [ ] Winner badges shown

---

## Booking Guest User Stories

### US-B01: Book Tickets
**As a** booking guest
**I want to** select tickets and pay
**So that** I can attend a show

**Acceptance:**
- [ ] Step 1: Select ticket type and quantity
- [ ] Step 2: Add optional add-ons (skippable)
- [ ] Step 3: Fill customer info and pay
- [ ] Step 4: See confirmation with QR code
- [ ] 10-minute hold timer active

### US-B02: Receive Confirmation
**As a** booking guest
**I want to** get confirmation and QR code
**So that** I can check in at the venue

**Acceptance:**
- [ ] Confirmation page shows booking details
- [ ] QR code displayed
- [ ] Add to Calendar buttons work
- [ ] Email confirmation sent

### US-B03: View Booking on Mobile
**As a** booking guest
**I want to** complete booking on my phone
**So that** I can book while on the go

**Acceptance:**
- [ ] Mobile-friendly booking flow
- [ ] Sticky cart at bottom on mobile
- [ ] Touch-friendly buttons (44px min)

---

## Checked-in Guest User Stories

### US-CG01: Check In
**As a** checked-in guest
**I want to** scan my QR code
**So that** I can enter the venue

**Acceptance:**
- [ ] Staff scans QR at reception
- [ ] Guest profile created
- [ ] Welcome message displayed

### US-CG02: Submit Photo
**As a** checked-in guest
**I want to** submit a photo to the wall
**So that** I can share my experience

**Acceptance:**
- [ ] Photo submission form accessible
- [ ] Can add caption
- [ ] Photo appears on wall after approval

### US-CG03: React to Other Guests
**As a** checked-in guest
**I want to** send reactions to other guests
**So that** I can interact socially

**Acceptance:**
- [ ] Can see other profiles at table/event
- [ ] Can send Wave, Cheers, Heart
- [ ] Reactions accumulate on profile

### US-CG04: Participate in Challenges
**As a** checked-in guest
**I want to** join lucky spin or review challenge
**So that** I can win prizes

**Acceptance:**
- [ ] Can spin wheel if enabled
- [ ] Prize applied to order if won
- [ ] Can submit Google review if enabled

---

## Staff User Stories

### US-S01: View Shift Schedule
**As a** staff member
**I want to** see my tables and reservations
**So that** I can prepare for the shift

**Acceptance:**
- [ ] List of tables with status
- [ ] Reservations for shift
- [ ] Start/end times

### US-S02: Check In Guests
**As a** reception staff
**I want to** scan reservation QR codes
**So that** I can verify bookings

**Acceptance:**
- [ ] Camera scanner works
- [ ] Reservation details shown on scan
- [ ] Can mark as checked in

### US-S03: Take Table Orders
**As a** floor staff
**I want to** enter orders at the table
**So that** kitchen can prepare them

**Acceptance:**
- [ ] Menu displayed
- [ ] Can add items to order
- [ ] Submit sends to kitchen
- [ ] Order appears in KDS

### US-S04: Update Order Status
**As a** kitchen staff
**I want to** see and update order status
**So that** food gets served on time

**Acceptance:**
- [ ] Orders appear in real-time
- [ ] Can mark as Preparing, Ready, Served
- [ ] Status updates reflect for floor staff

### US-S05: View Notifications
**As a** staff member
**I want to** see alerts and notifications
**So that** I can respond to important events

**Acceptance:**
- [ ] Notification bell shows unread count
- [ ] Can view notification list
- [ ] Can mark as read

---

## Admin User Stories

### US-A01: Manage Shows
**As an** admin
**I want to** create and edit show templates
**So that** I can manage content

**Acceptance:**
- [ ] Can create new experience
- [ ] Can edit all fields
- [ ] Can archive old shows
- [ ] Can upload photos/videos

### US-A02: Schedule Events
**As an** admin
**I want to** create scheduled events
**So that** guests can book

**Acceptance:**
- [ ] Can create individual events
- [ ] Can batch generate recurring events
- [ ] Can edit event details
- [ ] Can cancel events

### US-A03: Manage Reservations
**As an** admin
**I want to** view and modify reservations
**So that** I can handle customer requests

**Acceptance:**
- [ ] Can search reservations
- [ ] Can view full details
- [ ] Can cancel/refund
- [ ] Can resend confirmation

### US-A04: View Analytics
**As an** admin
**I want to** see business metrics
**So that** I can make decisions

**Acceptance:**
- [ ] Dashboard shows key metrics
- [ ] Can see occupancy rates
- [ ] Can see revenue trends

### US-A05: Manage Inquiries
**As an** admin
**I want to** view and respond to inquiries
**So that** I can convert leads

**Acceptance:**
- [ ] Kanban board shows all inquiries
- [ ] Can update status
- [ ] Can add follow-up notes
- [ ] Can see inquiry history

### US-A06: Manage Challenges
**As an** admin
**I want to** configure gamification
**So that** I can engage guests

**Acceptance:**
- [ ] Can enable/disable Photo Wall
- [ ] Can configure Lucky Spin prizes
- [ ] Can review Google Review submissions

### US-A07: Manage Tables
**As an** admin
**I want to** configure venue layout
**So that** operations run smoothly

**Acceptance:**
- [ ] Can add/edit tables
- [ ] Can set table capacity
- [ ] Can view floor plan

### US-A08: Manage Menu
**As an** admin
**I want to** update food and beverage menu
**So that** guests have options

**Acceptance:**
- [ ] Can add/edit menu items
- [ ] Can set prices
- [ ] Can toggle availability
- [ ] Can set categories

Task 13: Deprecate Old Spec Files

Files:

  • Modify: Add deprecation notice to all old spec files

  • Step 1: Add deprecation notice to each old spec

For each old spec file (01-foundation.md through 18-booking-flow.md), add:

> ⚠️ **DEPRECATED** — This file describes planned features from 2026-05-03.
> The actual implementation differs significantly.
> See [README.md](./README.md) for current documentation.

Task 14: Update Project Index

Files:

  • Modify: docs/superpowers/IMPLEMENTATION-SUMMARY.md

  • **Step 1: Update implementation summary to point to new specs

# House of Legends — Implementation Roadmap
 
> ⚠️ **NOTE:** This document is deprecated. For current documentation, see [specs/README.md](../specs/README.md)
 
[Rest of existing content...]

Execution Options

Plan complete and saved to docs/superpowers/plans/2026-05-11-specs-update.md. Two execution options:

1. Subagent-Driven (recommended) - I dispatch a fresh subagent per task, review between tasks, fast iteration

2. Inline Execution - Execute tasks in this session using executing-plans, batch execution with checkpoints

Which approach?