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 actorInterlinking 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 Maptech-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 Pathsapps/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_eventTask 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 timestampsTask 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 Structuredashboard/ ├── 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 selectionTask 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 FlowOPEN → 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 neededTask 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- User fills form → React Hook Form validates
- Submit → useMutation(api.domains.forms.submitInquiry)
- Convex stores in formSessions
- Convex creates inquirySession with status=NEW
- Convex creates notification for admin
- 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 trendTask 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.vnPayment 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 errorPayment Status
| Status | Description | Action |
|---|---|---|
| PENDING | Awaiting payment | User redirected to OnePay |
| PAID | Payment successful | Confirmation sent |
| FAILED | Payment failed | Show error, allow retry |
| CANCELLED | User cancelled | Release seats |
| REFUND_PENDING | Refund requested | Admin processes |
| REFUNDED | Refund completed | Notify customer |
Virtual Account (Bank Transfer)
Flow
- User selects bank transfer
- System generates VA number
- User transfers to VA
- OnePay notifies on receipt
- 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
- Admin opens reservation detail
- Clicks "Cancel & Refund"
- System calls OnePay refund API
- Updates reservation status to REFUNDED
- 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
- Event occurs (payment, booking, etc.)
- Create notification record in notifications table
- notificationLogs tracks delivery
- Email/WhatsApp sent via integrations
- 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-passwordEmail 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-phoneMessage 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-idSync 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 categoriesTask 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?