Class Booking Software

ClassTap

Fill Every Seat Effortlessly

ClassTap is a lightweight white‑label class-booking platform that handles scheduling, secure payments, waitlists, and automated SMS/email reminders for independent instructors, community centers, and small studios running in-person or hybrid classes, preventing double-bookings, halving admin time, cutting no-shows, and generating branded booking pages in under two minutes.

Subscribe to get amazing product ideas like this one delivered daily to your inbox!

ClassTap

Product Details

Explore this AI-generated product idea in detail. Each aspect has been thoughtfully created to inspire your next venture.

Vision & Mission

Vision
Empower independent instructors and small studios to fill every seat reliably, boost earnings, and run bookings without friction.
Long Term Goal
Within 3 years, power bookings for 50,000 independent instructors across North America, reduce aggregate no‑shows by 25%, and eliminate manual scheduling workflows.
Impact
Helps independent instructors and small studios cut administrative time by 50%, reduce no-shows by 30% through automated calendar-sync reminders, and boost booking conversions 15% with instant branded class pages, enabling new classes to be onboarded in under five minutes.

Problem & Solution

Problem Statement
Independent instructors and small-studio owners struggle with double-bookings, manual payments, and frequent no-shows, while marketplaces and enterprise schedulers are costly, complex, and erase local branding, leaving booking and payment workflows fragmented and fragile.
Solution Overview
We provide a lightweight white‑label booking platform that prevents double‑bookings and reduces no‑shows by syncing instructors' calendars in real time and sending automated, timed SMS and email reminders to students.

Details & Audience

Description
ClassTap is a lightweight SaaS that handles class scheduling, secure payments, waitlists, and automated reminders. It serves independent instructors, community centers, and small studios running in-person or hybrid classes. It prevents double-bookings, halves admin time, and cuts no-shows with calendar sync and scheduled reminders. Its instant class-page generator creates a branded booking page with native payment links in under two minutes.
Target Audience
Independent instructors and small-studio owners aged 25-55 needing effortless bookings, fewer no-shows, and on-the-go management.
Inspiration
As a weekend pottery teacher I juggled frantic texts, a tangled spreadsheet, and Venmo requests until a venue cancellation sent a flood of reschedules. I slapped together a one-page booking link and timed reminders; cancellations stopped, deposits landed, and familiar faces came back. That instant of calm—replacing chaos with a tiny booking page and automated nudges—sparked ClassTap: the tool I wished I’d had.

User Personas

Detailed profiles of the target users who would benefit most from this product.

C

Corporate Wellness Casey

- Age 29–42; HR/Benefits or Workplace Experience title - Mid-size to enterprise (200–5,000 employees); multi-office footprint - Bachelor’s in HR/business; SHRM or wellness certs - Budget authority up to $50K; KPI: participation rate

Background

Started as office coordinator managing room calendars and vendor invoices. After costly no-shows, built a wellness program from scattered spreadsheets. Now coordinates multi-site sessions and quarterly wellness challenges.

Needs & Pain Points

Needs

1. Companywide scheduling with room/resource conflict prevention 2. Bulk reminders driving attendance across departments 3. Consolidated invoices and attendance exports

Pain Points

1. No-shows from calendar clutter and forgotten invites 2. Double-booked rooms across offices and timezones 3. Vendor payments scattered across systems

Psychographics

- Measures success relentlessly, hates fuzzy metrics - Pragmatic problem-solver, favors dependable, low-drama tools - Employee wellbeing champion, budget-guarded realist - Prefers automation over manual follow-ups

Channels

1. LinkedIn groups 2. SHRM forum 3. Google Search 4. Hacking HR Slack 5. HR Brew newsletter

C

Creator Coach Cam

- Age 22–35; fitness, art, or wellness creator - 50K–500K followers across Instagram/TikTok - Income from classes, merch, digital programs - Solo or tiny team; rents studios ad hoc

Background

Built audience with short-form content and pop-up workouts. Tried DMs and forms for signups; lost revenue to no-shows and link friction. Now runs drops with tight caps and waitlists.

Needs & Pain Points

Needs

1. One-tap booking from stories and bio 2. Auto reminders reducing impulse no-shows 3. Quick waitlists for sold-out drops

Pain Points

1. DMs causing double-bookings and lost payments 2. Link-in-bio clutter hurting conversion 3. Last-minute location changes confusing attendees

Psychographics

- Obsessed with momentum and viral conversion - Values aesthetics; brand control non-negotiable - Moves fast; demands zero-setup tools - Community-first, prioritizes nurturing repeat superfans

Channels

1. Instagram stories 2. TikTok lives 3. Linktree bio 4. YouTube community 5. Substack newsletter

F

Franchise Ops Farah

- Age 30–48; multi-location fitness or arts franchise - Oversees 5–50 sites; regional managers and owners - Bachelor’s; background in operations or consulting - KPIs: utilization, revenue per class, cancellations

Background

Scaled from single studio manager to regional ops. After inconsistent spreadsheets caused double-bookings and missed revenue, mandated standardized systems. Now implements tools chainwide under budget constraints.

Needs & Pain Points

Needs

1. Multi-location calendar with role permissions 2. Chainwide branding and templates 3. Centralized reporting across sites

Pain Points

1. Inconsistent processes causing costly errors 2. Manual consolidation across locations weekly 3. Franchisees resisting tool adoption

Psychographics

- Standardization zealot; hates process variance - Data-driven; dashboards decide, not gut - Empowers local teams within clear guardrails - Risk-averse regarding security and compliance

Channels

1. LinkedIn feed 2. IHRSA newsletter 3. Google Search 4. Ops Leaders Slack 5. Zoom webinars

P

Parent Booker Priya

- Age 28–45; parent or guardian of 1–3 children - Suburban or urban; coordinates carpool and calendars - Heavy iPhone/Android use; Apple/Google Calendar synced - Budget-conscious; prefers class packs and credits

Background

Started with sporadic drop-ins; chaos led to missed sessions and fees. Adopted shared family calendar after double-booking soccer and piano. Prefers providers with easy reschedules and waitlists.

Needs & Pain Points

Needs

1. Book multiple children in one flow 2. Automatic calendar sync per child 3. Clear policies, easy reschedules, credits

Pain Points

1. Separate bookings per child are tedious 2. Missed waitlist promotions without alerts 3. Confusing refund and makeup policies

Psychographics

- Reliability fanatic; hates surprises and vague policies - Convenience-first; values speed over customization - Seeks trusted providers with kid-friendly communication

Channels

1. Facebook Groups 2. Google Maps 3. Instagram DMs 4. WhatsApp chats 5. Nextdoor posts

P

Pop-up Planner Parker

- Age 26–40; side-hustle or small event business - Mix of art, craft, wellness, or food workshops - Books community halls, cafes, parks monthly - Revenue from tickets and sponsorships

Background

Started with Eventbrite but wanted full branding and lower fees. Learned hard lessons from double-booked rooms and walk-up chaos. Now prioritizes waitlists and onsite check-in.

Needs & Pain Points

Needs

1. Two-minute branded page per venue 2. Capacity rules per location and equipment 3. QR check-in and day-of roster

Pain Points

1. Venue conflicts and permits missed 2. Walk-up bottlenecks delaying start times 3. Confusing directions reduce attendance

Psychographics

- Logistics-minded, thrives on tidy run-of-show - Frugal; hates unnecessary platform fees - Audience-builder; values email list growth

Channels

1. Instagram posts 2. Google Search 3. Facebook events 4. Mailchimp newsletter 5. Meetup groups

C

Compliance Registrar Riley

- Age 32–55; training director or registrar - Fields: healthcare, safety, finance, or trades - Runs cohorts quarterly; blends classroom and skills labs - Accountable for compliance audits and records retention

Background

Migrated from legacy registration software after failed audits flagged missing rosters. Consolidated waivers and certificates into one workflow. Now prioritizes clean exports and prerequisite enforcement.

Needs & Pain Points

Needs

1. Prerequisite gating and certification tracking 2. Digital waivers and attendance signatures 3. Audit-ready exports, retention controls

Pain Points

1. Missing signatures jeopardize accreditation 2. Manual roster cleanup before audits 3. Disconnected systems create data silos

Psychographics

- Compliance-first; zero tolerance for data gaps - Systematic thinker; values predictable workflows - Detail-obsessed; demands traceable records

Channels

1. LinkedIn groups 2. IACET newsletter 3. Google Search 4. L&D Collective Slack 5. Zoom webinars

Product Features

Key capabilities that make this product valuable to its target users.

Turbo Rebook

Surface a prominent one-tap Rebook button on class pages, past bookings, receipts, and reminders. Pre-selects the same class time, instructor, attendees, and preferred payment method so users confirm in under 10 seconds—boosting repeat conversions and reducing front-desk churn.

Requirements

Global Rebook CTA Placement
"As a returning student, I want a clearly visible Rebook button wherever I interact with a class or my past bookings so that I can rebook quickly without searching."
Description

Display a prominent, consistent Rebook button across key user touchpoints—class detail pages, past bookings, digital receipts, and SMS/email reminders. The CTA must be visually distinct, accessible (WCAG AA), and responsive across mobile and desktop. Button visibility should be conditional on eligibility (e.g., user has a prior booking for the class type, studio allows rebooking), and hidden or disabled when inapplicable. The component should support white‑label theming (colors, typography, copy) at the studio level and localization for supported languages. Implement a lightweight client module that can be embedded in branded booking pages and a server-side policy check for eligibility. Ensure consistent placement above the fold on supported layouts and provide a fallback link when space is constrained. Include basic loading states and error handling so the CTA never blocks the page render.

Acceptance Criteria
Rebook CTA visible and enabled on class detail page for eligible user
Given a signed-in user with at least one past booking for the same class type at the current studio and the studio has rebooking enabled When the user opens a class detail page for an upcoming session Then a primary Rebook button is rendered within the first viewport (element top < window.innerHeight) on mobile (≤414x896) and desktop (≥1280x800), is enabled, and is not overlapped by other UI And the button is placed in the designated primary-action slot consistent with the studio template And activating the button via click or Enter/Space navigates to the studio-configured rebook flow URL with classId, classTypeId, and instructorId included as parameters
Eligibility gating: hide or disable CTA when rebooking is inapplicable
Given the eligibility API responds ineligible with code POLICY_DISABLED for the studio Then the Rebook CTA is not rendered in the DOM on all touchpoints Given the eligibility API responds ineligible with code NO_PRIOR_BOOKING for the user and class type Then the Rebook CTA is not rendered in the DOM on all touchpoints Given the user is not authenticated and the studio requires sign-in to rebook When the page renders Then a disabled Rebook CTA is shown with aria-disabled=true and helper text Sign in to rebook, and clicking it routes to the sign-in flow; upon successful sign-in and eligibility recheck passing, the CTA becomes enabled without page reload
CTA meets WCAG AA accessibility requirements
Rule: Text-to-background contrast ratio is ≥ 4.5:1 for the button label across all studio themes; focus indicator has ≥ 3:1 contrast and ≥ 2 px width Rule: The control is reachable via keyboard Tab order; Enter and Space activate it; no keyboard trap Rule: The accessible name contains the localized phrase Rebook this class; when disabled, it announces as unavailable via aria-disabled=true Rule: Minimum hit area is 44 x 44 CSS px with at least 8 px spacing from adjacent interactive elements Rule: No color-only or motion-only cues; any icon has accompanying text; disabled state cannot be activated and is announced correctly by screen readers
Responsive, above-the-fold placement with fallback on constrained layouts
Given supported touchpoints (class detail page, past bookings, digital receipts, SMS/email reminders) When the page or template initially loads on mobile 360x640 and desktop 1366x768 reference viewports Then the Rebook CTA renders in the primary-action region and its top is above the first viewport bottom (element top < window.innerHeight) Given the available width for the primary action region is < 160 px Then render a text fallback link labeled Rebook in the header/meta area and do not render the button variant And the fallback link is focusable, has contrast ≥ 4.5:1, and navigates to the same rebook URL as the button And switching between button and fallback introduces CLS ≤ 0.05
Studio-level white-label theming is applied without breaking contrast
Given a studio theme config defining primary color, typography scale, and custom CTA copy When the page loads Then the Rebook CTA adopts those values via CSS variables within 200 ms of client module initialization And if computed contrast would drop below 4.5:1, the component auto-applies an accessible fallback text color to meet AA And changing the active studio theme at runtime updates CTA styles and copy within 200 ms without a flash of unstyled content > 100 ms And the CTA label supports studio override up to 24 characters and truncates with an accessible title attribute when longer
CTA localization and RTL layout support
Given the site locale is en, es, fr, or de Then the CTA label, aria-label, tooltip, and helper text render in that locale using platform i18n; otherwise they default to en Given an RTL locale (e.g., ar, he) Then the CTA mirrors layout, flips icon alignment, and sets direction=rtl without clipping or overflow at up to 30% text expansion When the locale is switched at runtime Then CTA strings update within 200 ms without page reload
Non-blocking client module with server-side eligibility check and graceful errors
Rule: The CTA client module loads asynchronously after critical content; gzipped payload size ≤ 12 KB; adds ≤ 20 ms Total Blocking Time on a mid-tier mobile device Rule: While eligibility is checked, show a skeleton/placeholder of ≤ 48 px height; the module never blocks page render and does not regress page FCP/LCP beyond the agreed budget Rule: The server eligibility endpoint returns a decision in ≤ 300 ms p95; if it times out after 400 ms or errors (HTTP 5xx/network), render a non-blocking Rebook text link that defers eligibility to the rebook flow Rule: Eligibility decisions are cached per user, studio, and class type for 5 minutes and invalidated immediately after a booking is created or canceled
Pre‑Filled Booking Context & Next Occurrence Logic
"As a repeat attendee, I want my previous booking details and the next equivalent class time auto‑selected so that I can confirm without re‑entering information."
Description

When a user taps Rebook, automatically preselect the most relevant next class instance and prior booking details: class type, instructor (when still assigned), location/modality (in‑person vs hybrid), attendee(s), and the user’s preferred payment method or credit pack. Implement smart selection to find the next valid occurrence matching the previous weekday/time window, instructor preference, and location; if the exact slot is unavailable, propose the closest alternatives in order of fit. Validate capacity, age/waiver requirements, and membership eligibility before presenting confirmation. Handle edge cases such as schedule changes, instructor substitutions, holidays, and price updates by transparently indicating differences and recalculating totals, taxes, and credits. Timezone-aware logic ensures travelers see correct local times. Place a short seat hold (e.g., 90 seconds) during confirmation to prevent double-bookings. Persist the prefill payload so deep links and resumes are consistent across devices.

Acceptance Criteria
One-Tap Rebook Prefills Previous Booking Context
Given a user has at least one past completed booking for a class, When they tap Rebook from a supported surface (class page, past booking, receipt, or reminder), Then within 2 seconds the booking form preselects class type, location/modality, instructor (if still assigned), attendee(s), and the preferred payment method or credit pack from the referenced booking. Given the prefilled form is displayed, When the user reviews it, Then all preselected fields are editable and no payment is processed until the user taps Confirm. Given the prior instructor is no longer assigned to that class type, When prefilling, Then the instructor field defaults to Any Instructor and Next Occurrence logic determines the session. Given the prior booking included multiple attendees, When prefilling, Then only eligible attendees are preselected and any ineligible attendee is excluded with an inline reason and a link to resolve (e.g., missing waiver).
Smart Next Occurrence Selection with Ranked Fallbacks
Given a referenced past booking with class type, location/modality, and instructor, When determining the next session, Then the system selects the next occurrence within 14 days on the same weekday with a start time within ±60 minutes and with the same instructor if available. Given no session matches all preferred attributes, When selecting alternatives, Then up to 3 options are proposed ordered by: (1) same instructor + same location + closest start time; (2) same location + closest start time; (3) same instructor + closest start time in the same modality. Given a holiday or temporary closure, When computing candidates, Then canceled or blocked sessions are excluded from both the preselection and alternatives. Given no matching sessions exist within 30 days, When the user opens Rebook, Then no session is preselected, Confirm is disabled, and a Notify Me/Waitlist option is presented.
Eligibility and Capacity Validation Before Confirmation
Given a preselected session is identified, When the form renders, Then seat availability is checked in real time and the Confirm button is disabled if capacity is 0 with an option to join waitlist. Given any attendee fails age, waiver, or signed-policy requirements, When validations run, Then Confirm remains disabled and inline actions allow the user to complete missing steps; upon completion, validation rechecks automatically. Given the selected payment method is a credit pack, When validations run, Then remaining credits are verified; if insufficient, the user is prompted to purchase/top up or switch payment before Confirm is enabled. Given the class requires an active membership, When validations run, Then membership status is verified and ineligible users are shown eligible products or a clear reason preventing booking. Given the user taps Confirm, When a final consistency check runs, Then capacity and eligibility are revalidated atomically; if any check fails, the booking is not created and a specific error with alternatives is shown.
Transparent Pricing Changes and Recalculation
Given a session is preselected, When pricing is calculated, Then current class price, taxes, fees, discounts, and credit application are recomputed and shown as a line-item breakdown before Confirm. Given the current price differs from the prior booking, When the breakdown is rendered, Then a Price Changed indicator shows the delta (absolute and percentage) versus the previous booking. Given a previously used promo or credit has expired or is ineligible, When pricing is recomputed, Then it is not applied and a short note explains why. Given credits fully cover the booking, When pricing is shown, Then total due equals $0.00 and card entry is not required. Given location determines tax jurisdiction, When tax is computed, Then the venue’s tax rules are applied and the grand total reflects the correct tax for the venue location.
Timezone-Aware Selection and Communication
Given the venue has a defined IANA timezone and the user device timezone may differ, When displaying the session time, Then the time is shown in the venue’s local time with a secondary annotation for the user’s local time when different. Given a session occurs across a DST transition, When the time is rendered, Then the UTC offset used matches the venue’s rules for that date and the displayed local time is correct. Given SMS/email reminders are generated, When composing times, Then the venue-local start time is included and, if the recipient’s timezone differs, the recipient-local time is appended. Given a traveler opens Rebook from a different timezone, When selecting the next occurrence, Then the scheduling logic uses the venue’s timezone for matching weekday and time window.
Seat Hold and Double-Booking Prevention
Given capacity is available and the user enters the confirmation step, When the confirmation screen is shown, Then a 90-second seat hold is created for the selected session and attendee count and a visible countdown begins. Given a seat hold exists, When the timer expires without confirmation, Then the hold is released, inventory is restored, Confirm is disabled, and the user is prompted to reselect or retry. Given high concurrency, When two users attempt to hold the last seat simultaneously, Then exactly one hold succeeds and the other user sees an out-of-capacity message with alternatives. Given the user taps Confirm within the hold window, When the booking is created, Then the hold is consumed and cannot result in duplicate bookings even if the user taps Confirm repeatedly (idempotent).
Persisted Prefill Payload and Cross-Device Resume
Given a user initiates Rebook, When the prefill payload is created, Then it is stored as a signed, expiring token containing only non-sensitive references (booking ID, selection parameters, attendee IDs, payment method token reference) and no raw payment data. Given the user opens a Rebook deep link on another device within 30 minutes, When the link is loaded, Then the booking form reproduces the same prefilled selections; if the exact session is no longer available, the Next Occurrence fallback is applied and a short notice explains the change. Given the user’s progress is interrupted (app closed or network loss), When they resume within the token validity window, Then the form restores to the last known state within 2 seconds. Given a booking is successfully completed or the token expires, When the token is reused, Then it is rejected and the user is directed to start a new Rebook flow.
One‑Tap Payment Confirmation
"As a student, I want to confirm my rebooking with one tap using my saved payment method so that the process is fast and secure."
Description

Provide a single-screen confirmation that completes the rebooking in one tap using a stored, tokenized payment method or available credits. Display a concise summary (date/time, instructor, location, attendees, price/credit usage) and a clear Confirm button. Integrate PSP tokenization, support network‑tokenized cards, and invoke step‑up authentication (3DS/SCA) only when required by risk or regulation; fall back to full checkout if step‑up fails. Support biometric confirmation on capable devices and quick-pay options (e.g., Apple Pay/Google Pay) when previously saved. Ensure PCI compliance, idempotent booking creation, and robust error handling with automatic retries where safe. On success, issue receipt, update attendance rosters, decrement capacity, and trigger reminders as usual. Average confirmation time from tap to success should be under 10 seconds on a 3G connection.

Acceptance Criteria
One-Tap Rebook with Stored Tokenized Card (No Step-Up)
Given the user has a previously stored PSP-tokenized payment method and no step-up authentication is required for this transaction And the selected class has available capacity When the user taps Rebook and is presented with the one-tap confirmation screen Then the screen displays date, time, instructor, location, attendees, price (and any credit usage), and the selected payment method And only a single primary action "Confirm" is visible and enabled And no PAN or CSC is displayed or logged; only masked details and token identifiers are used When the user taps Confirm over a simulated 3G connection Then one booking is created and confirmed within 10 seconds And class capacity is decremented and the attendance roster is updated atomically And the receipt is issued and SMS/email reminders are scheduled per standard rules And the UI shows a success state with booking details
Step-Up Authentication Path with Fallback to Full Checkout
Given the stored payment method requires 3DS/SCA for this transaction When the user taps Confirm Then a step-up authentication challenge is invoked via the PSP And upon successful completion the booking is created and confirmed, with receipt issued and roster/capacity updated If the step-up authentication fails or is abandoned Then no booking is created and no successful charge is captured And the user is routed to full checkout with all rebook details pre-populated
One-Tap Rebook Using Account Credits
Given the user has sufficient account credits to cover 100% of the class price When the confirmation screen loads Then the payment summary shows credits applied and zero additional charge When the user taps Confirm Then the credits balance is decremented accordingly, the booking is created, and no card charge is attempted And the receipt reflects credit usage and remaining balance
Biometric Confirmation with Saved Apple Pay/Google Pay
Given the device supports a previously saved Apple Pay or Google Pay method with biometric authentication enabled When the user taps Confirm Then the native wallet confirmation is presented and accepts biometric confirmation When biometric confirmation succeeds Then the booking is created and confirmed using the saved wallet token (network tokenized if available) If wallet authorization fails Then the user is routed to full checkout with pre-populated details and no booking created
Idempotent Booking Creation and Double-Tap Protection
Given the user taps Confirm multiple times within 2 seconds or the network causes duplicate submissions When the backend processes the confirmation requests using an idempotency key Then exactly one booking record is created And exactly one payment capture or credit deduction occurs And subsequent duplicate requests return the original booking reference without side effects
Transient Payment Error Retry and User Messaging
Given the PSP returns a transient error (e.g., timeout or HTTP 5xx) on confirmation Then the system automatically retries the payment request up to 2 times with exponential backoff within 8 seconds If all retries fail Then the user sees a clear error message with a retry option and a path to full checkout; no booking is created Given the PSP returns a definitive decline (e.g., insufficient funds, do not honor) Then no automatic retries are attempted and the user is routed to full checkout; no booking is created
Confirmation Performance on 3G Network
Given a simulated 3G network profile (approx. 1.6 Mbps down, 750 Kbps up, 300 ms RTT) When executing 30 one-tap confirmations without step-up authentication across representative classes Then the average time from Confirm tap to success is 10 seconds or less And instrumentation logs the tap and success timestamps for each transaction for auditability
Waitlist Auto‑Enroll Fallback
"As a student, I want to be auto‑enrolled to the waitlist with my saved preferences if a class is full so that I’m first in line without extra steps."
Description

If the target class is at capacity, offer one‑tap waitlist enrollment that preserves all rebook preferences and payment method. Support optional pre‑authorization or credit reservation per studio policy, and automatically confirm the booking when a seat opens, notifying the user via SMS/email with final details. Respect studio rules for waitlist order, cutoff times, and cancellation windows. Provide clear UI messaging about status and charges, and allow users to opt out or change preferences. Ensure atomic transitions from waitlist to confirmed to prevent double charges or overbooking, and update rosters and notifications accordingly.

Acceptance Criteria
Display Waitlist CTA for Full Class During Rebook
Given a user taps Rebook on a class that is at capacity When the rebook flow initializes Then a primary "Join Waitlist" CTA is displayed and the "Confirm Booking" CTA is suppressed for that class And the UI displays a clear message that the class is full and the user can join the waitlist, including an estimate of position if available And the same class time, instructor, attendees, and preferred payment method are preselected And the user can complete waitlist enrollment in ≤ 2 taps with a total p95 latency ≤ 3 seconds
Preserve Rebook Preferences and Payment on Waitlist Enrollment
Given a user has prior booking metadata (class time, instructor, attendees) and a saved payment method When the user joins the waitlist via Rebook Then those preferences are prefilled and persisted to the waitlist record And the user can optionally edit any preference before confirming enrollment And any edited preferences replace the defaults on the waitlist record And no charge is captured at this step unless the studio policy requires pre-authorization or credit reservation
Pre-Authorization/Credit Hold per Studio Policy
Given the studio policy requires pre-authorization or credit reservation to join a waitlist When the user confirms waitlist enrollment Then the system places a payment pre-authorization or reserves credits for the stated amount and duration And the UI and confirmation message state the hold amount, expiration, and capture conditions And if the pre-authorization fails, waitlist enrollment is blocked and the user receives a clear error with retry and payment update options And if the policy does not require a hold, no hold is placed and the UI states that no immediate charge will occur
Atomic Auto-Enrollment When Seat Opens
Given a seat becomes available before the studio’s auto-enroll cutoff and the user is next in waitlist order and meets policy constraints When the auto-enroll job runs Then the transition from waitlist to confirmed booking is executed atomically and idempotently with a single seat decrement And the payment is captured (from pre-auth) or charged exactly once with no duplicate authorizations And the roster, capacity counts, and user booking history update within 5 seconds And the user and studio receive SMS/email notifications with final booking details and receipt And if payment capture/charge fails, the user is notified to update payment within a configurable grace period and the next eligible waitlisted user is processed per policy
Honor Waitlist Order, Cutoffs, and Cancellation Windows
Given studio-defined waitlist order, auto-enroll cutoff times, and cancellation windows When allocating an opened seat Then the system honors the configured order (e.g., FIFO by join timestamp unless priority rules override) And no auto-enroll occurs after the cutoff; instead the next eligible user receives a claim-notification per studio policy And enrollments and cancellations are blocked if initiated outside the allowed windows, with clear messaging to the user
User Opt-Out and Preference Management for Waitlist
Given a user is on a waitlist via Rebook When the user opts out or edits preferences (attendees, payment method) before a seat is allocated Then the system immediately updates or cancels the waitlist record and releases any payment hold within 1 minute And the UI and SMS/email confirm the change or cancellation and reflect updated position or removal And if the user changes to preferences that no longer match the target class (e.g., different time/instructor), they are prompted to start a new rebook flow rather than silently modifying the existing waitlist request
Deep‑Link Rebook from Communications
"As a student, I want to rebook directly from an email or SMS with a single tap so that I can act immediately when I’m reminded."
Description

Embed secure, expiring deep links in email receipts and SMS reminders that open the prefilled Rebook confirmation screen directly. Links must include a signed, tamper‑proof token (HMAC/JWT) that encodes the booking context and user identity; support magic‑link authentication for frictionless access on new devices and respect device trust settings. On mobile, route to the hosted booking page or native app (if present) via universal/app links; on desktop, open the web confirmation view. Preserve attribution parameters for analytics. Tokens should be single‑use or time‑boxed, and gracefully degrade to a login prompt if validation fails or the context is stale, rehydrating the prefill upon successful authentication.

Acceptance Criteria
Secure Token Validation and Prefilled Rebook
Given a user taps a deep link from an email receipt or SMS reminder within the token validity window And the token is a signed HMAC/JWT with whitelisted alg, iss, aud, iat, and exp claims When the link is opened Then the backend verifies the signature and claims and rejects any altered payload And decodes booking context (class ID/time, instructor, attendees, price tier) and user ID And renders the Rebook confirmation view prefilled with class time, instructor, attendees, and preferred payment method And no login prompt is shown if the device is trusted and the current session user matches the token user And the confirmation view becomes interactive within 2s p50 and 4s p95 on baseline mobile and desktop networks
Token Expiry and Single‑Use Enforcement
Given a deep link is issued with a configurable TTL (default 72h) and single‑use enabled When the token is used to complete a rebook Then the token is marked consumed and cannot be reused And any subsequent open of the same link results in an invalid/expired state And the user is routed to a login prompt with a clear message and the rebook context preserved for rehydration after authentication And tokens past their exp are rejected with the same flow
Magic‑Link Auth and Device Trust Respect
Given a user opens a deep link on a device where they are not authenticated When magic‑link authentication is allowed for the tenant and risk checks pass Then the user is seamlessly authenticated without password entry And device trust is applied per policy (trusted if enabled; otherwise session remains temporary) And the Rebook confirmation view appears with the original prefill intact And if an existing session belongs to a different user, the system prompts to switch accounts before proceeding and preserves the prefill after switch And if step‑up verification is required, the user completes it and then sees the prefilled confirmation
Mobile Routing via Universal/App Links
Given a user taps a deep link on iOS or Android When the native app is installed and universal/app links are correctly configured Then the OS routes into the app’s Rebook confirmation screen with full prefill and attribution parameters intact And if the app is not installed or link association fails, the link falls back to the hosted mobile web confirmation view within 1s, preserving prefill and attribution And no intermediate chooser or error dialog is shown
Desktop Web Confirmation Routing
Given a user clicks a deep link on a desktop browser When the token is valid Then the user is taken directly to the web Rebook confirmation view with all fields prefilled and ready to confirm And the canonical URL reflects the confirmation route without exposing PII And browser back/forward navigation preserves the prefilled state
Attribution Preservation and Analytics
Given a deep link contains attribution parameters (e.g., utm_source, utm_medium, utm_campaign, message_id, channel) When the link is opened and the user confirms the rebook Then the parameters are propagated to analytics events (deep_link_open, rebook_confirmed) and stored on the new booking record And parameters survive app routing and web redirects without duplication or loss And personally identifiable data is not logged in client‑side analytics payloads And attribution is correctly associated with the tenant and instructor
Graceful Degradation and Prefill Rehydration
Given a deep link is invalid, expired, already used, or the booking context is stale (class cancelled/full, time changed, price updated, payment method invalid) When the user opens the link Then the user is shown a clear message and, if needed, a login prompt to continue And upon successful authentication or resolution, the system rehydrates the prefill with the most current equivalent options (next available time, waitlist option, updated price) and preserved attendees and payment details And if no equivalent class is available, the user is offered alternatives (waitlist or browse schedule) without blocking And no sensitive token data is exposed in client/UI error messages And a structured error/diagnostic event is emitted for observability
Admin Controls & Eligibility Rules
"As a studio owner, I want to control where Rebook appears and who can use it so that it aligns with my business rules and branding."
Description

Provide studio-level configuration for Turbo Rebook: enable/disable feature globally or per class/category, choose surfaces (class page, past bookings, receipts, reminders), customize button label and copy, and set eligibility criteria (e.g., membership types, minimum time since last attendance, blackout windows before class start, cooldown between rebooks). Define behavior for price changes, discount/credit application precedence, seat-hold duration, and whether to allow instructor substitutions. Expose policy previews and validation messages in the dashboard. Include audit logs of configuration changes and a sandbox mode for testing before enabling in production.

Acceptance Criteria
Global, Category, and Class-Level Enablement with Surface Selection and Precedence
1) Given Turbo Rebook is globally enabled, when I disable it for Category A, then the Rebook button is hidden on all selected surfaces for classes in Category A and remains visible for other categories. 2) Given Turbo Rebook is globally disabled, when I explicitly enable it for Class X, then the Rebook button is visible for Class X and remains hidden for all other classes. 3) Given precedence (class overrides category; category overrides global), when conflicting toggles exist, then the most specific level applies and is reflected across all selected surfaces within 1 minute. 4) Given I select surfaces [Past Bookings, Receipts], when I save, then the Rebook button renders only on those surfaces and is absent on [Class Page, Reminders]. 5) Given I save any configuration change, when I open audit logs, then an entry records admin user, timestamp (UTC), changed fields, old→new values, and originating IP.
Eligibility Rules: Membership Types, Cooldowns, Blackout Windows
1) Given allowed membership types are [Gold, Silver], when a Bronze member views a Rebook surface, then the button is disabled and a message states “Not eligible: membership type.” 2) Given minimum time since last attendance is 7 days, when a user attempts to rebook after 3 days, then the action is blocked and the message shows remaining time (e.g., “Eligible in 4 days”). 3) Given a blackout window of 2 hours before class start, when within that window, then Rebook is disabled and displays “Rebooking closes 2h before start.” 4) Given a cooldown between rebooks of 24 hours, when a user rebooks at 10:00, then they cannot rebook the same class again until after 10:00 the next day. 5) Given the dashboard policy preview with a chosen test profile, when I run eligibility preview, then it shows pass/fail with the exact rule(s) causing failure and the next eligible time if applicable. 6) Given invalid or conflicting rule entries (e.g., negative cooldown), when I attempt to save, then inline validation messages identify the fields and prevent saving.
Custom Button Label and Copy Propagation
1) Given I set the button label to “Quick Rebook” and helper copy to custom text, when I save, then all selected surfaces display the new label and copy on next page load. 2) Given locales en-US and es-ES have distinct label/copy entries, when I switch profile language, then the correct localized text appears; if missing, it falls back to the default locale. 3) Given I click “Reset to default,” when I save, then system default texts are restored across all surfaces.
Price Changes, Discounts, and Credit Precedence
1) Given pricing policy = “Use current price,” when current price ≠ prior booking price, then checkout shows current price and notes the policy in the price details. 2) Given pricing policy = “Honor last paid price,” when the prior price is lower, then checkout reflects the prior price and labels it “Grandfathered price.” 3) Given discount precedence = [Promo Code > Credit Balance > Membership Discount], when all are applicable, then the system applies them in that order with a line-item breakdown. 4) Given I change the precedence order in settings, when I run a preview with a sample booking, then the preview reflects the new order and resulting total. 5) Given a promo code is expired or ineligible, when rebooking, then it is not applied and a message explains the reason.
Seat-Hold Duration and Expiration
1) Given seat-hold duration is set to 2 minutes, when a user taps Rebook, then one seat is held for that class/time for 2 minutes and a countdown is shown. 2) Given the hold expires before payment, when time elapses, then the seat is released, the rebook flow exits to the class page, and the user is informed the hold expired. 3) Given there are no available seats, when a user taps Rebook, then no hold is created and the user is offered to join the waitlist if enabled. 4) Given payment completes within the hold window, when booking confirms, then the hold converts to a confirmed reservation and no extra seats remain held.
Instructor Substitution Policy
1) Given “Allow instructor substitutions” is enabled, when the original instructor is unavailable but the same timeslot has Instructor B, then Rebook offers that slot with a notice “Instructor may vary.” 2) Given “Allow instructor substitutions” is disabled, when the original instructor is not assigned to the timeslot, then Rebook is blocked for that slot with a message “Instructor mismatch.” 3) Given substitution is allowed, when a substitution occurs post-confirmation, then the attendee receives an updated notification per the studio’s notification settings.
Sandbox Mode Activation and Isolation
1) Given Sandbox Mode is enabled, when viewing consumer surfaces, then Turbo Rebook buttons are visible only to admin/test accounts and hidden from the public. 2) Given Sandbox Mode is enabled, when completing a rebook flow, then no real charges are captured, no production inventory is decremented, no live reminders are sent, and an in-flow banner reads “Sandbox—no live bookings.” 3) Given Sandbox Mode is enabled, when I view audit logs, then entries are tagged “Sandbox” and are segregated from production logs. 4) Given Sandbox Mode is disabled and changes are published, when I confirm, then sandbox test data is retained for reference but not migrated, and production behavior resumes.
Rebook Analytics & Experimentation
"As a product/studio owner, I want visibility into Rebook performance and A/B testing so that I can optimize placement and maximize repeat bookings."
Description

Instrument end-to-end Rebook funnels with events for impressions, clicks, prefill success, confirmation success/failure, waitlist enrollments, time-to-confirm, and revenue/credit consumption. Segment metrics by surface (class page, past bookings, receipt, SMS/email), device, class type, and studio. Provide a dashboard with trends and conversion rates, plus exports to existing analytics sinks (e.g., Segment, GA4) and webhooks for BI tools. Enable A/B testing of CTA placement, copy, and default behaviors (e.g., instructor substitution allowed) with statistically sound sampling and guardrails. Use privacy-safe aggregation and respect user consent preferences.

Acceptance Criteria
Event Instrumentation: End‑to‑End Rebook Funnel
Given a user views any Turbo Rebook surface When the page or message is rendered Then an impression event is fired with surface, device_type, class_id, studio_id, instructor_id (if applicable), pseudonymous user_id, session_id, impression_id, and occurred_at timestamp Given the Rebook CTA is visible When the user taps or clicks it Then a click event is fired with event_id, impression_id correlation, and the same context fields Given a previous booking exists When the Rebook flow loads Then a prefill_success event is fired if class time, instructor, attendees, and payment method are pre-populated; Else a prefill_failure event is fired with failure_reason codes (e.g., CLASS_TIME_UNAVAILABLE, PAYMENT_METHOD_MISSING) Given the user attempts to confirm When payment authorization completes Then a confirm_success event is fired with booking_id, amount, currency, payment_method_type or credits_used, time_to_confirm_ms, experiment_variant, and surface Given the class is full When the user opts for waitlist Then a waitlist_enroll event is fired with waitlist_position and notification_channel Given a confirmation attempt fails When an error occurs Then a confirm_failure event is fired with failure_reason code and retriable flag Given events are emitted When they reach the ingestion pipeline Then they are deduplicated by event_id and ordered by occurred_at within session
Segmentation and Dimensions Coverage
Given any Rebook analytics event is recorded Then it includes required dimensions: surface, device_type, os, browser, locale, class_type, class_id, studio_id, experiment_id, experiment_variant, and session_id Given the analytics dashboard is open When a user applies filters for any combination of surface, device_type, class_type, and studio over a date range Then all charts and tables reflect only matching events and update within 5 seconds p95 Given an incoming event payload is missing a required dimension or has a type mismatch Then the payload is rejected with a schema validation error, logged with contextual metadata, and an alert is raised if rejection rate exceeds 0.5% of hourly volume
Rebook Analytics Dashboard: Trends and Conversion Metrics
Given a date range is selected When viewing the dashboard Then it displays for each surface: impressions, clicks, click-through rate, prefill_success rate, confirmation rate, waitlist enrollments, time_to_confirm p50/p90, revenue, and credits consumed Given segment filters are applied Then metrics recalculate correctly and totals equal the sum of segments without double counting Given a daily granularity is selected Then trend charts render one point per day in the studio’s timezone and tooltips show precise counts and definitions Given a validation query is run against the event store for a random sample of 100 sessions Then dashboard counts match within ±1% absolute for event counts and ±2% for revenue for that sample
Analytics Exports: Segment and GA4
Given exports are enabled for a tenant When events are generated Then they are forwarded to Segment as track calls with schema v1 and to GA4 with event names: rebook_impression, rebook_click, rebook_prefill_success, rebook_confirm_success, rebook_confirm_failure, rebook_waitlist_enroll, carrying mapped parameters for dimensions and revenue/credits Given normal operation Then ≥99% of exported events are delivered to each destination within 5 minutes p95, with retry and exponential backoff up to 24 hours on failure Given a destination outage occurs Then events are queued durably and delivered upon recovery without duplication, using event_id for idempotency; export lag is visible on an ops dashboard Given exports are toggled OFF for a tenant Then no events are sent to that destination while internal storage and dashboard remain unaffected
Webhooks for BI Tools
Given a studio registers a webhook endpoint and secret When analytics events are available Then the system POSTs batched JSON payloads (max 500 events or 1 MB per batch) to the endpoint with an HMAC-SHA256 signature header over the raw body Given delivery failures (HTTP 5xx, timeouts, or network errors) Then the system retries with exponential backoff for up to 72 hours; batches that still fail are moved to a dead-letter queue with observable metrics and alerts Given a replay request is made via admin API with batch_id or date range Then the system re-sends the requested batches preserving original occurred_at and event_id, and marks them as replays in headers Given privacy constraints Then webhook payloads exclude raw PII (no email, phone, or full name); user_id and device identifiers are pseudonymous
A/B Testing and Guardrails for Rebook CTA
Given eligible traffic for a defined experiment (CTA placement, copy, or default behaviors) When users enter the experiment Then assignment uses stratified randomization by studio and surface with sticky bucketing by user_id; default allocation is configurable (e.g., 50/50) Given the experiment is running Then exposure, click-through, confirmation conversion, time_to_confirm, payment failure rate, and revenue per session are tracked per variant; SRM checks run continuously and alert on p<0.01 Given guardrail conditions are breached Then the platform auto-pauses the experiment if confirm_success rate drops by ≥5% absolute or payment failures increase by ≥3% absolute vs control at p<=0.05 for two consecutive checkpoints Given the experiment concludes Then results include effect sizes with 95% CIs, achieved power (>=0.8), and decision status; winning variant can be promoted and results exported to Segment/GA4 and webhooks
Privacy, Consent, and Aggregation Controls
Given a user has not consented to analytics Then no analytics events are emitted for that user beyond strictly necessary operational events that exclude user_id and PII Given a user updates consent When they opt in or out Then the change takes effect across all surfaces, exports, and webhooks within 5 minutes and is auditable Given analytics data are displayed on the dashboard Then only aggregated metrics are shown and k-anonymity is enforced (k>=10) for any segmented breakdown to prevent re-identification Given a verified data deletion request Then all associated pseudonymous analytics for that user are deleted from internal stores and redacted from downstream exports within 30 days, with deletion status logged

Wallet Hand-Off

Deep links from SMS/email or web jump straight into the native Apple Pay/Google Pay sheet on trusted devices—no login or card entry required. The familiar wallet flow increases trust, slashes typing on mobile, and lifts completion rates for on-the-go bookings.

Requirements

Signed Deep Link Payloads
"As a mobile customer, I want a secure booking link that carries my class and price details so that I can pay instantly without re-entering information."
Description

Generate short, white-label deep links in SMS/email that encapsulate booking intent (class/session identifiers, start time, seat count, price, currency, tax, discount, tenant brand, locale, and return/cancel URLs) as a compact URL-safe signed token (e.g., JWS). Include issued-at, not-before, and expiration claims; per-tenant key management and rotation (JWKs); and tamper detection server-side before invoking wallet. Links must be unique, traceable, and compatible with iOS/Android default browsers, and support UTM parameters for attribution without leaking PII.

Acceptance Criteria
JWS Token Structure and Claims Validity
Given a deep link containing a URL-safe signed token When the token header and payload are decoded Then header.alg is one of the tenant-approved algorithms (RS256 or ES256) And header.kid references an active tenant key And payload includes jti, tenant_id, class_id or session_id, start_time (RFC 3339), seat_count (>=1), amount, currency (ISO 4217 uppercase), tax_amount, discount_amount, locale (BCP 47), return_url, cancel_url And payload includes iat, nbf, exp where exp - iat <= 30 minutes and nbf <= iat + 2 minutes And return_url and cancel_url use https and match tenant-allowed domains And payload and URL contain no PII (e.g., name, email, phone)
Per-Tenant JWK Key Management and Rotation
Given each tenant exposes a JWKS with unique kids for signing keys When verifying a token signed with the active key Then signature verification succeeds and the used kid is logged When verifying a token signed with a rotated-out key within a defined grace window Then verification succeeds; after the grace window elapses, verification fails with an explicit error When a kid is not found in cache Then JWKS is refreshed once before failing verification Then key rotation events and verification results are audit-logged with tenant_id and kid
Server-Side Tamper Detection and Replay Prevention
Given a token with any modified header, payload, or signature When verification is attempted Then the request is rejected with 401 invalid_token and wallet invocation is not started Given a previously redeemed token (jti) When the same token is presented again Then it is rejected as a replay and no new booking or payment is initiated Given repeated invalid verifications from the same IP/device beyond threshold N within T minutes Then rate limiting is applied and events are logged with correlation_id and reason
Unique, Traceable Links with UTM Attribution (No PII)
Given a deep link is generated for a booking intent Then it includes a unique jti and a click_id to support attribution and deduplication When the link is opened Then a click event is recorded with timestamp, tenant_id, jti, click_id, user_agent, and any UTM parameters present Then UTM parameters are not part of the signed payload and are preserved end-to-end And neither the token nor URL query contains PII
Cross-Platform Wallet Invocation and Fallback
Given a supported device with Apple Pay or Google Pay configured When the deep link is opened in the default browser (iOS Safari/Chrome, Android Chrome) Then the native wallet sheet appears within 1.5 seconds without login or card entry When the device lacks wallet capability or trust Then the user is redirected to a secure web checkout fallback within 2 seconds Then on payment success the user is redirected to return_url and on cancel to cancel_url And a booking hold is established during the wallet session to prevent double-booking
Compact URL-Safe Encoding and White-Label Compatibility
Given a generated deep link Then the URL uses the tenant’s white-label HTTPS domain and base64url encoding without padding for the token And the total URL length is <= 700 characters to ensure SMS/email compatibility And the link renders and opens correctly from default SMS and major email clients on iOS and Android without line-breaking issues And the link remains valid through permitted link-shortening without breaking signature verification
Price, Tax, Discount, and Currency Integrity
Given payload includes amount, tax_amount, discount_amount, currency, and seat_count When the server validates the payload Then all monetary fields are non-negative and conform to currency minor units (e.g., 2 decimals) And currency is ISO 4217 uppercase and allowed by the tenant And computed_total = amount*seat_count + tax_amount - discount_amount; if |payload_total - computed_total| > 1 minor unit, reject with 422 And any referenced discount is active, tenant-owned, and applicable to the class/session before wallet invocation
Wallet Eligibility & Device Trust Check
"As a customer on my phone, I want the system to detect if my device can pay with Apple Pay or Google Pay so that I only see checkout options that work for me right now."
Description

On link open, perform a fast, privacy-preserving preflight to detect Apple Pay/Google Pay availability and merchant eligibility for the current browser, OS, region, and network. Validate that the tenant’s brand/domain is wallet-verified, the amount/currency is supported, and required contact fields are available or requested minimally. Provide immediate branching to wallet sheet where eligible, otherwise route to graceful fallback without exposing technical errors to the user.

Acceptance Criteria
iOS Safari Apple Pay Eligible Handoff
Given a user opens a Wallet Hand-Off link on iOS 16+ Safari with Apple Pay set up and device biometrics enabled And the tenant domain is wallet-verified and merchant is eligible for Apple Pay in the user’s region And the amount and currency are supported by the merchant and Apple Pay When the link loads over HTTPS and the preflight runs Then the preflight completes within 300 ms at p95 without transmitting PII And the native Apple Pay sheet is presented within 1 second at p95 And the user is not prompted to log in or enter card details And the merchant display name matches the tenant brand and the exact amount and currency are shown
Android Chrome Google Pay Eligible Handoff
Given a user opens a Wallet Hand-Off link on Android 11+ in Chrome with Google Pay set up and device lock enabled And the tenant merchant is eligible for Google Pay in the user’s region And the amount and currency are supported by the merchant and Google Pay When the link loads over HTTPS and the preflight runs Then the preflight completes within 300 ms at p95 without transmitting PII And the native Google Pay sheet is presented within 1 second at p95 And the user is not prompted to log in or enter card details And the merchant display name matches the tenant brand and the exact amount and currency are shown
Unsupported Environment Graceful Fallback
Given a user opens a Wallet Hand-Off link on a browser/OS without Apple Pay or Google Pay support, or without a configured wallet, or in a non-secure context When the preflight detects ineligibility for wallet handoff Then the user is routed to the branded fallback checkout within 1 second at p95 And no technical error codes or stack traces are displayed to the user And a generic, friendly message offers alternative payment methods And any previously supplied contact fields are prefilled when available And wallet invocation is not retried more than once per session unless the environment changes
Merchant Domain and Brand Verification Gate
Given the tenant brand and booking domain are included with the payment intent When the preflight validates the domain-brand-to-merchant mapping against the payment provider’s wallet verification Then Apple Pay/Google Pay is offered only if the mapping is verified and active And on verification failure, the user is routed to the fallback without exposing verification details And an internal, non-PII error code is recorded for observability
Amount and Currency Support Validation
Given the payment intent includes amount and currency When the preflight checks currency support and min/max limits for the wallet network and merchant Then eligibility is true only if currency is supported and amount is within allowed bounds and correctly rounded to currency minor units And on unsupported currency or amount, route to fallback with generic copy and do not attempt wallet invocation
Contact Fields Availability and Minimal Prompting
Given the class requires specific contact fields (e.g., email; phone optional) And contact data may be available from a signed link token or an existing session/profile When the preflight runs Then if all required contact fields are available, the wallet sheet is invoked without additional prompts And if any required field is missing, display a single lightweight prompt that collects only the missing required fields (0–2 inputs max) And no optional fields are requested before wallet And time-to-wallet, including the prompt, remains under 2 seconds at p95
Privacy-Preserving Preflight and Data Minimization
Given a preflight is executed to determine wallet eligibility When collecting signals for browser/OS, wallet capability, region, network security, and merchant status Then no PII (email, phone, card details) or persistent device identifiers are transmitted or stored And logs contain only anonymized eligibility outcomes and internal error codes And all network requests occur over HTTPS and transfer less than 100 KB total at p95
One-Tap Wallet Sheet Invocation
"As a busy attendee, I want the wallet sheet to open immediately with the class and total prefilled so that I can complete payment in a single tap."
Description

Invoke the native Apple Pay or Google Pay sheet directly from the deep link with prefilled merchant name (tenant brand), line item (class name and time), total, currency, and minimal contact fields. Use ApplePay JS or Payment Request API with wallet-specific configs to present the familiar native sheet without login or card entry. Ensure fast-first-paint, accessibility, and clear cancel/timeout handling, and emit client telemetry for sheet shown, authorized, canceled, and error events.

Acceptance Criteria
One-Tap Wallet Sheet on Trusted Device
Given a user taps a valid Wallet Hand-Off deep link from SMS/email on a device with an enrolled wallet (Apple Pay on Safari iOS/macOS or Google Pay on Chrome/Android) and a trusted browser profile And the deep link payload includes tenant brand, class id, class name, class start datetime (UTC), total amount, currency (ISO 4217), and a short-lived booking token When the page loads and verifies the token with the server Then the native wallet sheet is invoked using ApplePay JS or the Payment Request API without requiring login or manual card entry And the merchant display name equals the tenant brand exactly And the line item shows "<Class Name> — <localized start date/time>" And the total equals the provided amount in the provided currency And no more than 2 contact fields are requested (email and/or phone), and no postal address is requested
Unsupported/Untrusted Device Fallback
Given a device lacks a supported/enrolled wallet or the device/browser is not trusted, or token verification fails When the deep link is opened Then the native wallet sheet is not invoked And a secure fallback checkout is rendered within 1500 ms of First Contentful Paint And a clear message explains the fallback without exposing sensitive details And telemetry event "wallet_error" is emitted with error_code in {unsupported_device, no_enrolled_wallet, untrusted_context, token_invalid}
Cancel and Timeout Behavior
Given the wallet sheet is shown When the user cancels explicitly or there is no interaction for 60 seconds Then the sheet dismisses and the user returns to the booking screen with all prefilled details intact And any seat hold is released within 5 seconds and no payment is captured And a non-intrusive banner states "Payment canceled" or "Payment timed out" And telemetry event "wallet_canceled" or "wallet_timeout" is emitted with reason and latency_ms
Successful Authorization and Booking Creation
Given the user authorizes payment in the native wallet sheet When the payment token is received client-side Then the token is sent to the server over TLS with an idempotency key unique to the deep link And exactly one booking is created and confirmed, seat inventory is decremented, and double-booking is prevented And a confirmation screen is shown within 2 seconds of server approval with class details and receipt summary And confirmation SMS/email are queued within 5 seconds And telemetry event "wallet_authorized" is emitted with transaction_id, amount, currency, and latency_ms
Performance: Fast First Paint and Sheet Invocation
Given a standard mobile network profile (RTT 150–300 ms, 1–2 Mbps) and a mid-tier device When the deep link is opened Then First Contentful Paint occurs within 1200 ms And the wallet sheet is presented within 700 ms after FCP on supported devices And total JS downloaded before sheet invocation is ≤ 150 KB (gzip), with no render-blocking third-party scripts And requests for wallet config are parallelized and cached with max-age ≥ 5 minutes
Accessibility and Localization
Given users relying on assistive technologies or diverse locales When the wallet sheet is invoked and any supporting UI is displayed Then focus is managed so assistive tech announces the sheet and context change And all interactive elements meet contrast ratio ≥ 4.5:1 and have accessible names And class date/time and currency are formatted in the user's locale and timezone, with RTL layouts supported And keyboard activation and screen-reader actions can trigger the same flow as tap
Telemetry Events and Reliability
Given any wallet flow outcome (shown, authorized, canceled, error) When the event occurs Then a telemetry event in {wallet_sheet_shown, wallet_authorized, wallet_canceled, wallet_error} is emitted with fields: correlation_id, tenant_id, class_id, wallet_type, device_type, amount, currency, latency_ms, error_code (if any) And events are sent using sendBeacon or equivalent to survive tab close, with ≥ 99% delivery within the session under normal network conditions And no PII (full card data, email content, phone number) is included; consent and regional privacy flags are respected And event payloads conform to a versioned schema; rejected events are counted locally for diagnostics
PSP Tokenization & Merchant Routing
"As a studio owner, I want wallet payments to process through my configured gateway and merchant accounts so that funds settle to my business without extra steps."
Description

Integrate Apple Pay/Google Pay payment tokens with the configured payment service provider per tenant (e.g., Stripe, Adyen, Braintree), including gateway merchant IDs, domain verification for Apple Pay on white-label subdomains, and Google Pay gateway configuration. Validate cryptograms, handle network tokenization, and apply SCA/3DS logic according to region and gateway rules while maintaining PCI boundaries. Map processor responses to unified success/failure codes and capture/authorize per business rules.

Acceptance Criteria
Apple Pay Domain Verification on White‑Label Subdomains
Given a tenant’s white‑label subdomain is configured with an Apple Pay merchant ID, When https://{subdomain}/.well-known/apple-developer-merchantid-domain-association is requested, Then the exact association file is served with HTTP 200 and content-type text/plain Given Apple domain verification is initiated for the subdomain, When Apple’s verification API runs, Then verification succeeds and the status is stored as Verified with timestamp in tenant settings Given the association file is missing or incorrect, When verification runs, Then the status is stored as Failed, Apple Pay presentation is suppressed on that domain, and an audit log + alert is emitted
Google Pay Gateway Tokenization Configuration per Tenant
Given a tenant has Google Pay enabled and a PSP (Stripe|Adyen|Braintree) selected, When generating the Google Pay paymentDataRequest, Then tokenizationSpecification.type is PAYMENT_GATEWAY, parameters.gateway matches the PSP adapter id, and gatewayMerchantId/merchantId equals the tenant’s configured MID Given the environment is set to test, When the paymentDataRequest is produced, Then environment=TEST and allowedCardNetworks/authMethods match tenant policy Given tokenization parameters are incomplete or invalid, When the payment sheet is requested, Then the API returns a configuration error and the UI disables Google Pay for that request while emitting an audit log
Merchant Routing and MID Selection by Region/Currency
Given a tenant has routing rules by region and currency, When a wallet payment is initiated for currency=C and region=R, Then the request is sent to the configured PSP and merchant account id matching C and R Given no matching merchant route exists, When the payment is initiated, Then the transaction is blocked pre‑gateway with unified code CONFIGURATION_ERROR and a clear operator message Given concurrent requests for the same tenant, When routing occurs, Then the selected PSP and MID are deterministic and recorded in payment metadata and audit logs
Tokenization and Cryptogram Validation via PSP (Apple Pay and Google Pay)
Given an Apple Pay token is received from a trusted device, When the payment is processed, Then the token payload is forwarded unmodified to the PSP’s Apple Pay endpoint and the cryptogram is validated by the PSP; if invalid, the unified code is DECLINED_SCA_INVALID_CRYPTOGRAM Given a Google Pay tokenized card is received, When the payment is processed via the configured PSP gateway, Then network tokenization is honored and processing uses the token without requesting PAN Given payment processing and logging are executed, When token payloads pass through the system, Then no PAN, full token payload, or cryptogram is persisted or logged; sensitive fields are redacted, and only masked card data, network, and last4 are stored
SCA/3DS Application Rules for Wallet Tokens
Given an EEA transaction using Apple Pay or Google Pay network tokens, When the PSP returns ECI/cryptogram indicating SCA performed, Then the payment is marked SCA_SATISFIED and no additional 3DS challenge is triggered Given the PSP returns a soft decline requiring authentication (e.g., authentication_required), When mapping the response, Then unified outcome is REQUIRES_ACTION and the client is directed to complete the PSP‑native challenge flow (if applicable) Given a non‑EEA transaction or an allowed exemption per tenant policy, When rules are evaluated, Then exemption indicators are set on the authorization request and frictionless outcomes are accepted with reason recorded
Unified Processor Response Mapping
Given a PSP response is received, When mapping to platform outcomes, Then the result is one of {APPROVED, DECLINED, REQUIRES_ACTION, FRAUD_REJECTED, NETWORK_ERROR, GATEWAY_ERROR, TIMEOUT, CONFIGURATION_ERROR} with normalized reason codes Given an APPROVED authorization, When storing the result, Then authorizationId, pspTransactionId, networkReference, and PSP name are persisted; for failures, the raw PSP code/message are captured in support metadata Given an unmapped/unknown PSP code is encountered, When mapping occurs, Then outcome is GATEWAY_ERROR with the raw code preserved for diagnostics and a runbook link included in metadata
Authorization vs Capture per Business Rules with Idempotency
Given tenant settings capture_mode=deferred and capture_offset_minutes=N, When a booking is created for a class starting in more than N minutes, Then an authorization is created and a capture job is scheduled for start_time−N minutes Given capture_mode=immediate or the class starts in ≤N minutes, When the authorization is approved, Then capture is executed immediately in the same flow Given a cancellation occurs before capture and before authorization expiry, When the system processes the cancel, Then the authorization is voided and no capture is attempted; if already captured, a refund is initiated per policy Given transient errors or retries, When the same booking payment is re‑submitted, Then an idempotency key (tenantId+bookingId) ensures exactly one authorization/capture at the PSP
Idempotent Booking & Capacity Lock
"As an attendee, I want my seat confirmed exactly once when I pay so that I’m not double-charged or left unsure about my reservation."
Description

Create or reserve the booking atomically with payment using idempotency keys derived from link and wallet token data to prevent double charges and double-bookings. Place a short-lived capacity hold when the wallet sheet is presented; convert to a confirmed seat on success or release on cancel/timeout. If capacity is exhausted mid-flow, offer automatic waitlist enrollment with clear messaging, and ensure refunds or voids are issued immediately for declined or late-conflict scenarios.

Acceptance Criteria
Idempotent Booking on Repeated Wallet Submissions
Given a booking deep link contains nonce NLK for class_id C and the user is on a trusted device with wallet token W And an idempotency window of 5 minutes is active for (NLK, W, C) When the user submits the wallet sheet multiple times or the client retries due to network errors within the window Then the API returns HTTP 200 with the same booking_id and payment_id on each retry And exactly one booking record exists for class C for the customer And exactly one successful charge is captured And available capacity is decremented only once And subsequent retries after a successful booking do not create additional holds
Capacity Hold on Wallet Sheet Presentation
Given class C has N remaining seats When the wallet sheet is presented for a deep link for class C Then a capacity hold of 1 seat is recorded within 1 second And public capacity displays N-1 across all channels within 2 seconds And the hold TTL is 2 minutes And no more holds are accepted once remaining capacity is 0, returning a "class temporarily full" response within 500 ms
Hold Release on Cancel or Timeout
Given a capacity hold exists for class C for session S When the user cancels the wallet sheet or no payment authorization occurs within 2 minutes Then the hold is released within 5 seconds And public capacity reflects the release within 2 seconds And no authorization or charge remains on the payment method And an audit event "hold_released" is recorded with reason "cancel" or "timeout"
Conversion to Confirmed Booking on Payment Success
Given a capacity hold exists for class C for user U When the wallet payment is authorized and captured successfully Then the hold converts atomically to a confirmed booking in a single transaction And capacity remains decremented by 1 And the booking status is "confirmed" and payment status is "captured" And the confirmation page renders within 2 seconds and SMS/email dispatch within 60 seconds And the idempotency key returns the same booking if re-invoked within 5 minutes
Capacity Exhausted Mid-Flow -> Waitlist Enrollment
Given class C reaches 0 seats available while user U is in wallet flow without a confirmed booking When U attempts to authorize payment or a conflict is detected prior to capture Then U is shown "Class full — join waitlist?" with a single-tap option And if U accepts, U is added to the waitlist within 2 seconds and no charge is captured And any pending authorization is voided within 60 seconds and the API responds with status "voided_conflict" And if U declines, the flow ends with no hold and no charge
Immediate Void/Refund on Decline or Late Conflict
Given a payment authorization exists for booking attempt B for class C When the processor declines the payment or a capacity conflict is detected after capture Then any authorization is voided or captured charge is refunded immediately And the void/refund is initiated within 5 seconds and recorded with reason "decline" or "late_conflict" And the customer sees "Payment reversed — no seat assigned" and is offered waitlist And no booking remains in a confirmed state for B
Cross-Device/Multiple-Channel Idempotency
Given the same deep link nonce NLK for class_id C is opened on two devices using the same wallet account within 5 minutes When both devices submit payment via the wallet sheet Then only one confirmed booking and one captured charge result And the losing attempt returns HTTP 200 with the winning booking_id if the winner succeeds first while capacity remains And if capacity is 0 at the time of the losing attempt, it returns a "conflict_waitlist_offer" without any charge And no duplicate notifications are sent to the customer
Single-Use Link Expiry & Replay Protection
"As a customer, I want my payment link to be safe and single-use so that no one else can use it or charge me by mistake."
Description

Enforce single-use, time-bound deep links with server-side nonce tracking to prevent replay and phishing. After successful payment or explicit cancel, mark the token as consumed and require regeneration for reuse. Provide clear user messaging for expired/consumed links and a safe path to reissue a fresh link, preserving attribution and pricing rules without re-entering data.

Acceptance Criteria
Token Issuance with TTL and Server-Side Nonce
Given a booking invitation requires a wallet deep link When the system generates the link Then the server creates a token with status ACTIVE, a cryptographically secure nonce, a signed payload, and an expires_at of now + configurable TTL (default 15 minutes) And the token record persists booking_id, recipient_id, channel, attribution, and price_snapshot_id And the deep link contains only the token and signature (no PII) And links cannot be generated without a valid booking context and pricing snapshot
First Use: Valid Link Opens Wallet and Atomically Consumes Token
Given a token is ACTIVE and not expired When the recipient taps the deep link on a device with Apple Pay/Google Pay available Then the backend validates signature, TTL, and recipient/channel binding and transitions the token to IN_PROGRESS with an idempotency key And a single payment intent is created and the native wallet sheet opens with correct merchant, amount, and descriptor And upon payment success, the token transitions IN_PROGRESS -> CONSUMED atomically And any subsequent attempt with the same token is blocked per consumed-link rules
Expired Link: Clear Messaging and One-Tap Safe Reissue
Given a token is EXPIRED (now > expires_at) When the deep link is opened Then the wallet sheet is not launched and the user sees an "Link expired" message with error code LINK_EXPIRED and HTTP 410 (or platform equivalent) And a prominent "Get a new link" action is provided And no sensitive PII is displayed; only minimal class details (title, date/time) are shown And the attempt is logged with reason EXPIRED
Consumed Link Replay: Blocked with Regeneration Path
Given a token status is CONSUMED When the link is opened from any device or channel Then the wallet sheet is not launched and the user sees "This link has already been used" with error code LINK_CONSUMED and HTTP 409/410 (or equivalent) And a one-tap "Request new link" action is provided And the event is logged as REPLAY_BLOCKED And rate limiting is applied to repeated attempts from the same IP/device
User Cancel from Wallet: Token Consumed and Reissue Offered
Given a token is IN_PROGRESS and the wallet sheet is shown When the user cancels from the native wallet UI Then the backend marks the token CONSUMED and voids or cancels any pending payment intent And the original link no longer opens the wallet and displays LINK_CONSUMED messaging And the user is offered a "Get a new link" action to reattempt with a fresh token
Reissued Link Preserves Pricing and Attribution Without Re-entry
Given a token is EXPIRED or CONSUMED and the user selects "Get a new link" When the reissue endpoint is called Then a new ACTIVE token is created with a fresh nonce, signature, and TTL And booking_id, recipient_id, attribution (campaign/source/referrer), and price_snapshot_id or pricing rule reference are preserved And any valid promo codes are carried forward; the quoted amount matches the preserved snapshot or recomputed rules as configured And the user is not required to re-enter personal details; the new link deep-launches the wallet sheet And all prior tokens are invalidated
Concurrent Use: Race-Proof Token Consumption
Given the same ACTIVE token is invoked concurrently by multiple taps/devices within TTL When validation and state transition occur Then exactly one request succeeds to transition the token to IN_PROGRESS and create a single payment intent (idempotent by key) And other concurrent requests receive LINK_IN_PROGRESS with HTTP 423/409 (or equivalent) and do not open the wallet And after a terminal outcome (success or cancel), all further attempts receive LINK_CONSUMED messaging And no duplicate charges or duplicate wallet sheets are produced
Fallback Web Checkout & Error Recovery
"As a customer on an unsupported device, I want a quick fallback checkout with my details prefilled so that I can still book without starting over."
Description

When wallet is unavailable or fails preflight, route to the branded web checkout with all details prefilled from the deep link, preserving tracking and preventing data loss. Provide resilient error states for network issues, gateway declines, and domain verification problems, with contextual retry, alternative methods, and support escalation. Log structured errors and correlate with link and tenant IDs for rapid troubleshooting.

Acceptance Criteria
Fallback to Prefilled Web Checkout When Wallet Unavailable
Given a user opens a ClassTap deep link on a device without a supported wallet or with wallet disabled When the wallet availability preflight reports unavailable Then the user is routed within 1.5 seconds to the tenant-branded web checkout And class, timeslot, price, taxes/fees, promo, and attendee name/email/phone from the deep link are prefilled And the user is not required to log in to proceed And an analytics event checkout_fallback_initiated is recorded with link_id and tenant_id And no data is lost across the transition
Wallet Preflight Failure Auto-Recovery
Given the wallet sheet launch is requested from a deep link and preflight returns an error (e.g., domain_not_verified, merchant_capability_missing, unsupported_device) When the preflight error is received Then the native wallet sheet is not presented And the user is routed to the branded web checkout with a non-blocking banner explaining wallet unavailability and suggesting alternative methods And the banner includes a Try Wallet Again action when the condition may be transient And the fallback action is idempotent and preserves the same checkout_session_id And the error is logged with structured fields tenant_id, link_id, checkout_session_id, error_code, error_source=wallet_preflight, severity=warn
Network Error Recovery During Web Checkout
Given the user is on the fallback web checkout with prefilled details When a network timeout or offline condition occurs during payment initiation Then the UI shows a recoverable error state with Retry and Choose Another Method actions And tapping Retry reattempts the same checkout_session_id up to 3 times with exponential backoff starting at 1s And the form state and selection remain intact after each attempt And after 3 failed attempts, a Contact Support link opens the tenant's configured support channel And all attempts and outcomes are logged with error_code, attempt_number, and network_status
Gateway Decline Handling Without Double-Booking
Given the payment gateway returns a decline for the checkout_session_id (e.g., card_declined, insufficient_funds, do_not_honor) When the decline is received Then no booking is created and no seat is reserved And the UI displays a clear decline message mapped from the gateway without exposing sensitive codes And the user can switch to an alternative enabled payment method (e.g., manual card entry) without re-entering attendee details And a subsequent successful payment results in exactly one booking and one charge, enforced via idempotency keys And the decline event is logged with tenant_id, link_id, checkout_session_id, gateway_code, mapped_reason
Domain Verification Failure Degrades Gracefully
Given Apple Pay or Google Pay domain verification fails for the tenant domain during preflight When a user opens a deep link that would normally invoke the wallet flow Then the system immediately routes to the branded web checkout and suppresses any wallet UI And a notice informs the user that wallet is temporarily unavailable and recommends continuing via web checkout And an internal alert is emitted with tenant_id, domain, verification_status, first_seen_timestamp, severity=error And alerts for the same tenant/domain are deduplicated for 1 hour
Deep-Link Metadata and Tracking Preservation
Given a booking is initiated from a deep link containing tracking parameters (utm_source, utm_medium, utm_campaign, gclid, fbclid) and correlation IDs (link_id, tenant_id) When the user is routed to the fallback web checkout and completes payment Then all tracking and correlation parameters persist into the checkout session, booking record, and receipt metadata And the parameters are included in analytics events checkout_fallback_initiated and checkout_completed And the success page URL includes the original tracking parameters for attribution And no additional PII is added to query parameters beyond what was present in the deep link
Structured Error Logging and Cross-Service Correlation
Given any error occurs during wallet preflight, fallback routing, web checkout initialization, or payment processing When the error is handled Then a structured log entry is emitted with fields: timestamp (ISO-8601), tenant_id, link_id, checkout_session_id, user_agent, platform, error_code, error_message, error_source, http_status (if applicable), correlation_id And error logs are queryable within 1 minute in the monitoring system And PII is excluded or masked per policy And traces across wallet and web checkout are linked via correlation_id for end-to-end troubleshooting

FastAuth 3DS

Intelligent authentication that skips CVV/3DS where allowed and triggers step-up only when risk signals require it. Pre-warms network calls to keep taps instant while preserving high approval rates and preventing false declines—speed without sacrificing security.

Requirements

Adaptive Risk Scoring & Exemption Engine
"As a studio owner, I want legitimate payments to be approved without extra friction so that students can book quickly while keeping fraud risk low."
Description

Implement a real-time decision engine that evaluates each payment attempt using device fingerprinting, IP reputation, geolocation, BIN country, historical buyer behavior, booking value, class type, velocity checks, and issuer preferences to determine whether to skip CVV/3DS, request step-up, or block. Support PSD2 SCA exemptions (TRA, low-value, MIT, corporate/commercial) and regional scheme rules, outputting standardized decision codes consumed by checkout and the payment gateway. Enforce a strict latency budget (<50 ms at p95 for the decision), include rules versioning and canary rollout, and ensure privacy by minimizing PII and adhering to PCI scope boundaries. Integrates with ClassTap’s checkout to deliver frictionless approvals while reducing false declines.

Acceptance Criteria
Latency Budget: p95 Decision Under 50 ms
Given the risk engine is deployed in a production-like performance environment with warmed caches and pre-warmed network calls When a 15-minute load test runs at a sustained 200 RPS with a 60/30/10 mix of SKIP/STEP_UP/BLOCK decisions and p50 payload size of 2 KB Then the internal decision_time_ms at p95 is <= 50 ms and at p99 is <= 75 ms and timeouts are <= 0.05% And error_rate (non-2xx) is <= 0.10% during the test window And cold-start after a rolling deploy produces p95 decision_time_ms <= 90 ms for the first 100 requests per instance
PSD2 SCA Exemptions: Selection, Signaling, and Fallback
Given a card issued in the EEA and a merchant/acquirer operating in the EEA When the transaction qualifies for a Low-Value exemption (amount <= 30 EUR) and no issuer preference forbids exemptions Then the engine returns decision_code=SKIP_AUTH and exemption_type=LOW_VALUE and sets the appropriate SCA exemption indicators for the payment gateway Given a transaction eligible under TRA per configured acquirer policy and risk outcome supports TRA When the engine evaluates the payment Then the engine returns decision_code=SKIP_AUTH and exemption_type=TRA and includes reason_codes including TRA_ELIGIBLE Given a transaction classified as MIT or a corporate/commercial card BIN range When the engine evaluates the payment Then the engine returns decision_code=SKIP_AUTH and exemption_type in {MIT, CORP_COMM} as applicable Given an issuer rejects an exemption with a soft decline on the authorization When the checkout retries per gateway guidance Then the engine returns decision_code=STEP_UP_3DS and adds reason_codes including EXEMPTION_REJECTED and SCA_REQUIRED Given a non-EEA region or ineligible scheme context When the engine evaluates the payment Then no PSD2 exemption is set (exemption_type=NONE) and the decision is based on risk and issuer preferences only
Risk Signals-to-Decision Mapping (Skip, Step-Up, Block)
Given a trusted device fingerprint, good IP reputation, geolocation matches BIN country, low booking value, low velocity, and no issuer 3DS requirement When the engine evaluates the payment attempt Then it returns decision_code=SKIP_AUTH with reason_codes including LOW_RISK and signals_used including DEVICE_OK, IP_OK, GEO_MATCH, VELOCITY_OK Given a TOR/VPN or malicious IP reputation, BIN country/geolocation mismatch > 2, high booking value, velocity above configured threshold, or known chargeback device When the engine evaluates the payment attempt Then it returns decision_code=BLOCK with reason_codes including at least one of {IP_REPUTATION_BAD, GEO_BIN_MISMATCH, VELOCITY_HIGH, DEVICE_HIGH_RISK} Given a new device, moderate booking value, medium IP risk, or issuer preference recommending step-up When the engine evaluates the payment attempt Then it returns decision_code=STEP_UP_3DS with reason_codes including MEDIUM_RISK or ISSUER_PREF_STEP_UP Given the same normalized input signals are evaluated multiple times within 5 minutes When the engine processes duplicate requests Then the decision_code and reason_codes are deterministic and identical across evaluations
Standardized Decision Code Contract with Checkout/Gateway
Given the engine returns a response to checkout When the decision is SKIP_AUTH Then the response JSON contains decision_code in {SKIP_AUTH, STEP_UP_3DS, BLOCK}, exemption_type in {NONE, LOW_VALUE, TRA, MIT, CORP_COMM}, reason_codes[], rules_version (semver), correlation_id (UUIDv4), and optional risk_score (0-100) And the checkout suppresses CVV/3DS prompts and proceeds to auth without SCA indicators Given the engine returns STEP_UP_3DS When checkout receives the response Then checkout initiates a 3DS challenge within 1 second and includes SCA indicators to the gateway per scheme format Given the engine returns BLOCK When checkout receives the response Then checkout halts payment submission and surfaces a generic decline message while logging correlation_id and reason_codes Given the gateway receives fields mapped from the engine’s response When the gateway submits authorization Then the exemption/3DS indicators match the decision (as verified in gateway request logs)
Rules Versioning, Canary Release, and Rollback
Given a new rules configuration is published as a higher semantic version When it is promoted to canary at 5% traffic for 10 minutes Then approval_rate delta vs control is within ±2.0 percentage points and decision_time_ms p95 increases by < 10 ms and error_rate does not exceed 0.2% Given canary success criteria are met When traffic is increased to 50% for 10 minutes and then to 100% Then the same thresholds hold and the rollout is marked complete with rules_version updated Given any threshold breach during canary or full rollout When the monitoring alert triggers Then automated rollback to the prior rules_version occurs within 2 minutes and traffic is reverted, with an audit log entry capturing who, what, when, and why Given a merchant or studio requires a pinned rules version When the rules_version override is set for that tenant Then subsequent decisions for that tenant use the pinned version and include it in the response
Privacy, PII Minimization, and PCI Scope Boundaries
Given the risk engine processes a payment evaluation request When inputs are validated Then PAN and CVV are not accepted or stored by the engine; only network tokens, last4, BIN, and non-sensitive metadata are permitted And email, phone, and device identifiers are hashed or tokenized before storage; IP addresses are stored only in truncated or hashed form And logs and traces redact sensitive fields and never include PAN/CVV; debug logs can be enabled without exposing PII Given data retention policies are applied When risk decision artifacts are stored Then PII-minimized artifacts and reason codes are retained for <= 30 days and older records are purged Given a PCI scope review When the engine and data flows are inspected Then the engine is classified out of PCI DSS scope for PAN/CVV storage and adheres to organizational privacy policies
Regional Scheme Rules and Issuer Preference Compliance
Given issuer or BIN-level preferences indicate Requires3DS When the engine evaluates any transaction for that issuer/BIN Then decision_code is STEP_UP_3DS regardless of other low-risk signals Given scheme or regional rules allow CVV/3DS skip for network tokens with strong cryptograms and device binding When the engine evaluates such transactions and no issuer preference forbids skipping Then decision_code is SKIP_AUTH and reason_codes include TOKEN_CRYPTO_OK Given transactions outside EEA (e.g., US, CA) When the engine evaluates PSD2 exemptions Then exemption_type remains NONE and decisioning follows risk signals and regional scheme rules only Given BIN country differs from geolocation by more than the configured threshold and class type is high-risk per configuration When the engine evaluates the payment Then decision_code is STEP_UP_3DS or BLOCK based on configured policy and reason_codes include GEO_BIN_MISMATCH and CLASS_RISK_HIGH
3DS2 Step‑Up Orchestration & Fallback
"As a student paying online, I want a seamless secure challenge only when my bank requires it so that I can complete my booking without confusion or delays."
Description

Provide full EMV 3DS 2.x orchestration for browser and mobile web, including 3DS Method execution, device data collection, frictionless flows, and challenge presentation via secure modal/redirect with graceful timeout handling. Capture and pass ECI/CAVV/DS transaction IDs to the PSP, and automatically fall back to 3DS 1 or decoupled authentication when required by the issuer or region. Ensure PSD2 compliance (EEA/UK) by triggering step-up when exemptions are not applicable, and localize challenge UX and messaging. Maintain accessibility, cross-browser support, and robust error recovery with idempotent submission to avoid double bookings.

Acceptance Criteria
Frictionless 3DS2 with 3DS Method and device data
Given a supported card and issuer that support EMV 3DS 2.x When the shopper submits the payment form and the transaction is assessed as low risk/exempt Then the 3DS Method and device data collection execute and complete, and an ARes is received with transStatus in [Y, A], and the flow remains frictionless without a challenge And the correct scheme-specific ECI is set based on transStatus, and CAVV and DS Transaction ID are captured when transStatus=Y, and all values are forwarded to the PSP in the authorization request And the 3DS Method is attempted within 1000 ms of page render and no visible UI flicker or navigation occurs
3DS2 Challenge via Accessible Localized Modal with Fallback Redirect
Given the issuer requests a challenge (transStatus=C) for a browser/mobile web transaction When step-up is initiated Then a secure modal challenge is presented within 1500 ms with focus trap, keyboard navigation, labeled controls, and screen-reader announcements (WCAG 2.1 AA) And the challenge UI text and ACS frames are localized to the shopper's locale, and numbers/date formats reflect the locale If the modal cannot render or is blocked Then the flow falls back to full-page ACS redirect without data loss On challenge completion Then the authentication result is received (Y/N/U/R), the UI closes, and the payment resumes accordingly; if no completion within 5 minutes, show a timeout message, cancel the challenge, and offer retry or alternative payment
PSD2 SCA Enforcement and Exemptions Handling (EEA/UK)
Given a card issued in EEA/UK and an in-scope e-commerce transaction When no valid exemption applies Then the system requests SCA (3DS2 step-up) and records the SCA reason When an exemption (TRA/LVP/Whitelisting) is requested Then include the correct indicators to the DS/ACS; if the issuer accepts, proceed frictionless; if the issuer rejects (R), trigger a challenge For out-of-scope or exempt flows (e.g., MIT subsequent/3RI, MOTO) Then do not trigger SCA but include the appropriate indicators, and send the correct ECI to the PSP And all SCA decisions and outcomes are logged with timestamps, BIN country, and exemption codes
Automatic Fallback to 3DS1 or Decoupled Authentication
Given 3DS2 is unavailable, unsupported for the BIN, or an error occurs before ARes When authentication is required Then automatically attempt 3DS1 with a compliant redirect/iframe and preserve session context If the ACS indicates decoupled authentication (transStatus=D) Then inform the shopper, poll/await callback for up to 5 minutes, and handle the final result accordingly Post-fallback Then set ECI per scheme rules for the achieved authentication level (authenticated/attempted), include authentication values (e.g., CAVV/XID/DS/3DS1 IDs as applicable), and forward them to the PSP And all fallback decisions and errors are captured with reason codes and retriable vs non-retriable classification
Idempotent Submission and Double-Booking Prevention
Given a shopper refreshes the page, clicks Pay multiple times, or the network triggers retries When the payment is submitted with a stable idempotency key Then only one authorization and one class booking are created And duplicate submissions within a 10-minute window return the same final status and authentication outcome, and the UI displays a single booking confirmation And challenge sessions can be safely resumed after navigation or refresh without restarting the transaction, and partial states are cleaned up after completion And all retries correlate via the idempotency key in logs and audit trail
Cross-Browser and Mobile Web Support for 3DS2 Flows
Given the latest two major versions of Chrome, Safari, Firefox, and Edge on desktop, and Safari (iOS) and Chrome (Android) on mobile When executing 3DS Method, device data collection, frictionless, and challenge modal/redirect Then all flows complete successfully without layout breakage or blocked popups And browsers with ITP/third-party cookie restrictions are handled without requiring third-party cookies; no mixed-content warnings; all communication occurs over HTTPS/TLS 1.2+ And the solution detects unsupported environments and provides a graceful fallback path or clear messaging
CVV/3DS Skip for Tokenized Card‑on‑File
"As a returning student, I want to pay in one tap using my saved card so that checkout is fast and hassle‑free."
Description

Enable CVV and 3DS skipping for returning customers using network tokens or vaulted cards when risk scores and scheme/regional rules allow. Enforce first-transaction SCA/CVV collection, then apply issuer- and scheme-validated exemptions on subsequent transactions based on token trust level, device consistency, and velocity thresholds. Dynamically hide CVV input when skipped, log the exemption rationale for audit, and ensure PCI DSS compliance with secure vaulting and token lifecycle management (provisioning, rotation, de-tokenization).

Acceptance Criteria
First Transaction Requires SCA and CVV
Given a customer without an existing network token or vaulted card on file When they attempt their first payment Then the CVV field is visible and required and a 3DS/SCA flow is initiated per scheme/regional rules And When CVV is missing or the 3DS challenge is not completed Then the authorization is not attempted and the UI displays an actionable error And When the payment is successful Then a network token is provisioned (if supported) and vaulted with token metadata stored and linked to the customer profile
Skip on Trusted Tokenized Return Purchase (Allowed Region)
Given a returning customer with a provisioned network token or vaulted card mapped to the same customer and device and with a risk score below the configured threshold and no velocity rule violations and exemption allowed by issuer/scheme/regional policy When the customer confirms payment Then the CVV input is hidden and not required and no 3DS challenge is initiated And Then the authorization request includes the correct exemption indicator/DS flags per scheme and the CVV value is not transmitted And Then the approval response is received without a step-up requirement and the transaction is marked as "exemption_applied"
Dynamic Fallback to Step‑Up When Issuer Requires Challenge
Given a returning tokenized customer who passed local exemption pre-checks When the issuer responds with a soft decline or step-up required Then the UI reveals the CVV field within 200 ms and initiates a 3DS challenge in-line without page reload and re-submits once with CVV And Then the final authorization either succeeds or fails with a clear user-facing message and no duplicate charges are created And Then the exemption decision log records reason=issuer_required_step_up and links both attempts under one checkout session ID
Risk, Device, and Velocity Gates Prevent Skip
Given a returning tokenized customer When any of the following is true: risk_score >= threshold OR device_fingerprint not consistent beyond tolerance OR more than N successful/failed attempts within 24 hours OR region/scheme disallows exemption for this BIN/MCC Then CVV is required and a 3DS/SCA flow is performed And Then the attempt is tagged as "exemption_blocked" with the failing gate(s) recorded
Exemption Rationale Audit Log and Export
Given any transaction where skip was applied or considered When the payment attempt completes Then an immutable audit record is written containing: transaction_id, customer_id hash, token_id, exemption_type, decision_rule_id, risk_score, model_version, device_id_hash, device_consistency_result, velocity_counters, scheme_indicator, regional_basis, issuer_response_code, timestamp, and actor_id (if manual) And Then audit records are retained for at least 395 days and are exportable in CSV and JSON by admins with permission "payments.audit.read" And Then PII fields exclude full PAN and CVV and all stored values are encrypted at rest
PCI DSS and Token Lifecycle Controls
Given the payments system in production When storing card credentials Then only network tokens or gateway vault references are stored; PAN and CVV are never persisted in ClassTap systems And When token provisioning occurs Then the token is bound to customer, device, and merchant account; rotation occurs on reissuance or per scheme recommendation; deprovision occurs on customer request or inactivity policy; all events are logged And When key management is inspected Then encryption at rest uses AES-256, keys are rotated at least annually, and access is restricted by role with MFA and least privilege And Then an annual PCI DSS assessment or SAQ attestation is available and linked in compliance documentation
Latency and Approval KPIs for Skip vs Step‑Up
Given production traffic with feature enabled at 100% When skip is applied Then click-to-authorization-request median <= 400 ms and p95 <= 800 ms And When step-up is required Then click-to-complete median <= 900 ms and p95 <= 1800 ms And Then approval rate for exempted transactions is within ±1.0 percentage point of the 30-day pre-rollout baseline; otherwise feature auto-rollbacks via a kill switch and alerts are sent to on-call
Pre‑warmed Payment & 3DS Network Calls
"As a student at checkout, I want the pay button to respond instantly so that I feel confident my booking is confirmed without delay."
Description

Reduce perceived latency by preconnecting and prefetching critical endpoints (DNS/TLS preconnect to PSP, DS, and common ACS domains), caching BIN/routing metadata, preloading 3DS Method URLs, and retrieving tokens ahead of button tap under user intent cues. Execute risk prechecks on page load without committing funds, respecting privacy and consent. Target end-to-end frictionless auth decision p95 <300 ms and p99 <500 ms. Implement circuit breakers, backoff, and graceful degradation if pre-warm fails, with parity across desktop and mobile web.

Acceptance Criteria
DNS/TLS Preconnect to PSP, DS, and ACS Domains on Page Load
Given a checkout page is rendered for a supported payment method When the DOM is interactive (DOMContentLoaded) and consent banner has been accepted (where applicable) Then DNS resolution and TLS preconnects are initiated within 100 ms to the configured PSP API, Directory Server (DS), and top ACS/3DS Method hostnames without sending application payloads And p95 time to established TLS session for each target is ≤150 ms on broadband and ≤300 ms on 4G in synthetic tests And ≥99% of eligible sessions attempt preconnects without causing console errors or CORS violations And if a preconnect is blocked by the browser or policy, the system records a non-fatal metric and proceeds without retrying immediately
BIN Metadata Cache Seed and Hit Ratio
Given a user inputs a primary account number and at least the first 8 digits are available When BIN lookup is requested for routing and 3DS decisioning Then the cache returns metadata (scheme, issuer country, product, 3DS exemption eligibility, DS routing) with a p95 response time ≤20 ms in-memory And the BIN cache hit ratio is ≥95% for the top 90% of traffic over a rolling 24h window And cache TTL and SWR are enforced (TTL ≥24h, SWR ≤6h) with automatic background refresh not blocking the UI thread And on cache miss, network fetch completes ≤150 ms p95 without blocking user input; failures fall back to a safe default (no exemptions) and are logged
3DS Method URL Preload and Timeout Handling
Given a 3DS server response includes a threeDSMethodURL for the card range When the payment section becomes visible Then a hidden iframe loads the 3DS Method within 100 ms, with a hard timeout of 10 s and an early-return at 5 s if method completion callback fires And failures or timeouts do not block Pay button interactivity and are flagged to proceed with challenge flow as needed And no personally identifiable information is sent in the method iframe beyond required device data per spec And p95 method completion (or timeout decision) occurs before user tap, with a budget ≤300 ms impact on overall E2E
Risk Precheck on Page Load Without Funds Commitment
Given the checkout page loads and the user has not tapped Pay When risk prechecks execute Then only non-funds-committing calls are made (no authorization, no capture, no hold) and are idempotent And data collection is limited to consented device/risk signals with DPIA controls; if consent is not granted, calls are suppressed And precheck completes p95 ≤200 ms and runs off the main thread without jank (Long Task <50 ms) And risk decisions are cached for the session and invalidated on material changes (amount, BIN, SCA exemption flags)
Token Retrieval Ahead of Tap Under Intent Cues
Given a user demonstrates intent (e.g., focuses card fields, completes CVV, scrolls into Pay button viewport, or hovers/clicks Pay) When prefetch is eligible per risk policy Then a payment token (or client_secret) is requested in advance with p95 latency ≤200 ms and stored securely in memory And tokens are single-use, bound to cart/amount, and have expiry; expired tokens auto-refresh once without UI delay And no funds movement occurs; authorization only initiates after explicit Pay action And concurrent prefetches are coalesced; duplicate requests are deduped via request keying and idempotency keys
Circuit Breakers, Backoff, and Graceful Degradation
Given pre-warm operations experience elevated errors or latency When error rate ≥5% over 1 minute or p95 latency ≥800 ms for a target endpoint Then a circuit breaker trips for that endpoint for 2 minutes, halting pre-warm and switching to on-demand calls And retries use exponential backoff with jitter (base 250 ms, max 4 s, max 3 attempts) without blocking user actions And the UI remains fully functional; only pre-warm benefits are disabled, with clear metrics and logs emitted for observability And recovery automatically closes the breaker when health falls below thresholds for 5 consecutive checks
Mobile/Desktop Parity and Latency Targets
Given a frictionless authentication-eligible transaction When the user taps Pay Then end-to-end decision time (tap to auth decision) meets p95 <300 ms and p99 <500 ms on both desktop and mobile web in real-user monitoring And platform parity gap is ≤10% for p95 between mobile web and desktop across equivalent networks (3G/4G/Wi‑Fi) And if pre-warm is unavailable, the flow still completes with p95 <600 ms using on-demand calls And metrics are segmented by device, network type, and browser, with automated alerts on SLO breach
Soft‑Decline Auto‑Retry & Smart Routing
"As an instructor, I want the system to rescue avoidable declines so that fewer legitimate bookings are lost and my classes stay full."
Description

Automatically recover from soft declines and SCA_required responses by triggering immediate step-up 3DS or retrying the transaction via alternative acquirers/routes when configured. Use idempotency keys to prevent duplicate charges and coordinate with inventory to temporarily hold a class spot during retry. Present a single-tap retry UX with clear status messaging, capture issuer reason codes, enforce retry limits, and log outcomes for analysis. Ensure compliance with scheme retry guidance and avoid cycling doomed transactions.

Acceptance Criteria
Immediate Step-Up on SCA Required or Soft Decline
- Given a payment attempt returns an issuer response indicating SCA required or a soft decline eligible for step-up, When the response is received, Then the UI displays a single-tap "Verify & Pay" within 300 ms and initiates a 3DS2 challenge. - Given the user successfully completes 3DS, When the challenge result is received, Then the system re-attempts authorization within 200 ms using the original idempotency key and no duplicate charge is created. - Given 3DS fails, is abandoned, or times out, When the result is processed, Then the system stops automatic retries and shows a clear failure message with next steps. - Given the step-up flow runs, When events occur, Then audit logs include original decline category/code, 3DS result (frictionless/challenged/outcome), timestamps, and final authorization outcome.
Smart Routing on Soft Decline
- Given a soft decline occurs and issuer indicates retry is allowed without additional authentication, When an alternate acquirer/route is configured and healthy, Then the system retries via the next-ranked route within 1 second while reusing the same idempotency key. - Given multiple routes are available, When selecting a route, Then the router chooses based on configured rank plus recent health signals (last 5-minute success rate and latency) and records the selection rationale. - Given scheme retry guidance requires cooldowns and attempt limits, When applying retries, Then the system enforces configured cooldowns and will not exceed 2 retries within 24 hours for the same transaction. - Given all eligible routes are exhausted or a hard/non-retryable decline code is received, When processing, Then no further retries are attempted and the final failure is surfaced to the user and logs.
Idempotent Retries Prevent Duplicate Charges
- Given the initial authorization is created with an idempotency key, When any retry (3DS step-up or alternate route) is performed, Then the same idempotency key is used across all attempts. - Given concurrent retry triggers (e.g., double-tap or reconnect), When processing, Then only one active retry is allowed; subsequent attempts are deduplicated and receive the same final outcome. - Given the transaction ultimately authorizes, When inspecting payment records, Then exactly one successful authorization/capture exists in the ledger and gateway; no duplicates are created or settled. - Given a prior attempt is in-flight, When a new retry would start, Then the system waits for the in-flight result (up to 30 seconds) and suppresses overlapping retries.
Temporary Seat Hold During Payment Retry
- Given a payment enters the retry flow, When the retry begins, Then the system places a hold on one class seat for that schedule and customer for up to 5 minutes (configurable) and removes it from public availability. - Given the retry succeeds, When authorization is confirmed, Then the seat hold converts to a booking and the waitlist is updated accordingly. - Given the retry fails or times out, When the flow ends, Then the seat hold is released immediately and any waitlisted candidate is notified per notification settings. - Given the user has multiple tabs or devices, When retries are triggered, Then only one seat hold exists per customer per class instance and all sessions reflect the hold status within 2 seconds via real-time updates.
Single-Tap Retry UX with Clear Status Messaging
- Given a soft decline occurs, When presenting the recovery UI, Then the user sees a single primary action labeled "Retry Payment" or "Verify & Pay" (for SCA) without re-entering card details unless the issuer requires re-authentication or data refresh. - Given a retry is in progress, When status changes, Then the UI displays step-wise statuses: "Retrying via bank...", "Verification required" (if 3DS), "Processing...", followed by "Success" or a specific failure message with issuer reason. - Given accessibility requirements, When interacting with the retry UI, Then controls are keyboard accessible, labeled, provide visible focus, announce status changes via ARIA live regions, and meet WCAG 2.1 AA contrast. - Given network variability, When retry starts, Then initial visual feedback appears within 500 ms and the overall operation times out at 60 seconds with a clear fallback message and no duplicate attempts.
Comprehensive Retry Logging and Metrics
- Given any retry attempt occurs, When logging, Then the system records transaction ID, idempotency key, route/acquirer ID, attempt number, issuer response category and reason code, 3DS method/result, end-to-end latency, and outcome. - Given logs are stored, When queried by authorized admins, Then entries are available within 15 minutes and exportable as CSV and JSON. - Given privacy constraints, When persisting logs, Then no PAN, CVV, or full PII is stored; only tokenized identifiers and truncated metadata per policy. - Given analytics dashboards, When viewing FastAuth metrics, Then soft-decline recovery rate, average retry count, approval uplift vs. baseline, per-route success, and 3DS challenge conversion are displayed with filters by date, merchant, class, and BIN.
Retry Limits and Anti-Cycling Enforcement
- Given a decline is received, When evaluating retry eligibility, Then the system consults a configurable allowlist/blocklist of issuer response codes and will not retry on hard declines, suspected fraud, or do-not-retry codes. - Given a transaction is eligible for retry, When performing retries, Then the system enforces a maximum of 2 retries per transaction and a per-card per-merchant cooldown of 30 minutes after two consecutive declines. - Given retries are exhausted or a non-retryable code is received, When finalizing, Then the user is shown a final failure state with guidance to use a different card or contact their bank; no background retries occur. - Given scheme rules or policies change, When configuration is updated, Then new limits take effect immediately without code changes and the update is audit-logged with actor, timestamp, and before/after values.
Merchant Policy Controls & Safeguards
"As a studio owner, I want to adjust authentication aggressiveness and exemptions so that I can balance conversion and risk for my business context."
Description

Provide an admin console for configuring FastAuth policies per merchant/location/region: risk thresholds, allowed exemptions, CVV-skip eligibility, issuer/region allowlists, velocity limits, and blocklists. Include safe defaults, role-based access control, change history, preview/simulation mode, and guardrails that prevent non-compliant configurations (e.g., disabling SCA where mandated). Expose feature flags for gradual rollout and per-segment tuning.

Acceptance Criteria
Scoped Policy Configuration (Merchant/Location/Region)
Given a merchant with locations in multiple regions When an Admin sets merchant-level defaults for risk thresholds, exemptions, CVV-skip eligibility, issuer and region allowlists, velocity limits, and blocklists Then the defaults are persisted as a draft version and are retrievable via UI and API Given a region-level override is created for a specific region When the override is saved Then the effective policy for that region uses the override for specified fields and inherits unspecified fields from the merchant level Given a location-level override exists within that region When conflicting values exist across levels Then effective policy precedence is Location > Region > Merchant and is reflected in the computed policy Given a transaction context (merchant, location, region, issuer) When requesting the effective policy via API Then the API responds within 200 ms with the computed policy and a field-origin map indicating the source level of each field
Safe Defaults and Initialization
Given a newly onboarded merchant with no custom policies When the admin console is opened for FastAuth configuration Then safe defaults are auto-populated: SCA mandated regions enforce step-up, CVV-skip eligibility is disabled unless permitted, velocity limits use system defaults, and allow/block lists are empty Given the merchant operates in an SCA-mandated region When defaults are generated Then exemptions are disabled by default unless low-value/TRA is supported and documented, and 3DS step-up is enabled Given the defaults are displayed When the Admin saves without changes Then the policy is saved as Version 1 (Default) with timestamp and owner and is available for simulation and publication
Role-Based Access Control for FastAuth Policies
Given a Viewer role user When accessing FastAuth policy pages or APIs Then the user can view effective policies, simulations, and audit logs but cannot create, edit, publish, or toggle feature flags (actions result in 403 and audit entries) Given a Manager role user When editing policies Then the user can create and edit drafts and run simulations but cannot publish or modify guardrail settings or feature flags Given an Admin role user When managing policies Then the user can create/edit drafts, publish, configure guardrails, and manage feature flags Given API tokens scoped by role When using the policy management API Then permissions mirror UI capabilities and unauthorized attempts are blocked with 403 and audited
Compliance Guardrails and Validation
Given the merchant includes EEA countries When an Admin attempts to disable SCA or enable CVV-skip where regulations prohibit it Then the system blocks the change, displays a compliance error with citation, and prevents save and publish Given velocity limits outside permissible ranges are entered When saving the policy Then validation fails with specific messages indicating the allowed range and the field is not persisted Given issuer/region allowlists conflict with blocklists When saving Then the system highlights conflicts and requires resolution before publish can proceed Given client-side validation is bypassed via API When submitting a non-compliant policy Then the server rejects with HTTP 400, structured error codes, and an audit log entry is created
Policy Change History and Audit Trail
Given a policy is created, edited, published, or rolled back When the action completes Then an immutable audit entry records actor, role, timestamp, IP, scope (merchant/region/location), action type, optional reason, and before/after field diffs Given audit entries exist When filtering by date range, actor, scope, or action type Then results return within 1 second for up to 10,000 entries and can be exported as CSV Given a specific policy version is selected When requesting a diff against current Then the UI shows field-level differences and the responsible user for each change
Preview/Simulation of Policy Impact
Given at least 30 days of historical data or a connected sandbox When running a simulation for a draft policy over a selected scope and time range Then the system returns projected approval rate, 3DS challenge rate, SCA compliance rate, false decline estimate, and p95 latency impact with confidence intervals Given simulation results are available When viewing breakdowns Then the UI ranks top issuers and regions by impact delta and supports CSV export of results Given simulation mode When executing simulations Then no production traffic, flags, or live policies are altered and the run is logged in the audit trail Given simulation detects non-compliance When attempting to publish the draft Then publishing is blocked with specific reasons linked to the offending settings
Feature Flags and Gradual Rollout Controls
Given a draft policy version When creating a rollout feature flag Then targeting can be configured by merchant, location, region, issuer BIN range, device type, payment method, and risk score band Given a percentage-based rollout plan When setting exposure to 5%, 25%, 50%, or 100% Then traffic is allocated within ±2% of the target and exposure counts are reported in near real time Given monitoring thresholds for approval-rate drop and 3DS-challenge spike are defined When thresholds are breached during rollout Then the system auto-pauses the flag, reverts to last stable policy, sends alerts, and records an audit entry Given an emergency stop is required When the Admin activates the kill switch Then the feature flag disables globally and reverts to baseline within 60 seconds and the action is audited Given rollout status is requested When viewing the flag Then the UI shows current percentage, active segments, start time, last change, and linked policy version
Authentication Observability & A/B Experimentation
"As a product manager, I want deep visibility and safe experimentation with authentication settings so that we can continuously improve conversion without increasing risk."
Description

Deliver real-time dashboards and alerts covering approval rate, challenge rate, completion rate, soft-decline recovery, false-decline indicators, and p95/p99 latency by issuer, BIN, country, device, and class category. Provide experiment tooling to A/B test risk thresholds, pre-warm strategies, and CVV-skip policies with statistically sound analysis and automatic rollback on regression. Support export to BI tools, privacy redaction, and retention policies suitable for compliance audits.

Acceptance Criteria
Real-Time Auth Dashboard Segmented Metrics Accuracy
Given live auth events across issuers, BINs, countries, devices, and class categories with a verified ground-truth aggregate for the selected time window When a user loads the dashboard and applies any combination of filters and time ranges (last 15m/1h/24h/7d/custom) and timezone Then approval rate, challenge rate, completion rate, soft-decline recovery, false-decline indicator rate, and p95/p99 authentication latency match ground truth within ±0.1 percentage points for rates and ±10 ms for latency per visible segment And metrics refresh within 5 seconds of ingestion; late-arriving events are backfilled within 2 minutes and labeled as backfill And zero-data segments render "No data" without affecting totals; missing data is distinguished from zeros And exporting the current view as CSV includes applied filters, time range, and segment columns
Approval/Latency Threshold Alerts with Dedup and Auto-Resolve
Given alert rules configured per metric and dimension (issuer, BIN, country, device, class category) with thresholds and evaluation windows When a rule’s metric breaches its threshold for the full evaluation window (e.g., approval rate drop >2 pp over 15 m; p99 latency > 800 ms over 10 m) Then one alert notification is sent per rule per unique dimension set with deduplication for 30 m, containing metric, dimension values, current value, baseline, threshold, link to dashboard, and incident ID And alerts deliver to configured channels (email, Slack, PagerDuty) within 60 s; PagerDuty uses the active on-call schedule And the alert auto-resolves after the metric remains within threshold for one full evaluation window And scheduled maintenance windows suppress alerts; historical backfills do not trigger alerts
A/B Testing Risk/CVV-Skip/Pre-Warm with Auto-Rollback
Given an experiment configured to A/B test risk thresholds, pre-warm strategy, or CVV-skip policy with randomization at payment-attempt level, 50/50 split, and sticky assignment by device+BIN+issuer When the experiment runs and traffic passes sample-ratio-mismatch checks (chi-square p ≥ 0.01) and meets the pre-specified MDE and power requirements Then the platform computes approval, challenge, completion, soft-decline recovery, false-decline indicator, and p95/p99 latency per arm and per segment with sequential analysis and 95% confidence intervals And if any guardrail is breached (e.g., approval rate −1.0 pp or worse vs control, p95 latency +100 ms or more) for 10 consecutive minutes with significance (p ≤ 0.05), auto-rollback disables the variant within 2 minutes and routes all traffic to control And an immutable experiment report is generated with configuration, timeframe, per-metric outcomes, per-segment deltas, statistical method, and CSV export; configuration is locked post-start And experiment APIs and UI expose assignment logs and support pause/resume; stopping preserves data integrity and sets end time
Secure BI Export (Snowflake/BigQuery/Redshift/S3) with Redaction
Given an authorized user with Export permission and a configured destination (Snowflake share, BigQuery dataset, Redshift schema, or S3 bucket) When the user schedules daily full exports and 15-minute incrementals, or triggers an on-demand export Then datasets deliver within SLA (full ≤ 24 h, incremental ≤ 15 m), are idempotent, and include high-watermarks and schema version And PII is redacted per policy (no CVV; PAN tokenized; BIN+last4 only; email/phone hashed; IP truncated /24 IPv4 or /48 IPv6) before export; data is encrypted in transit (TLS 1.2+) and at rest (AES-256/SSE-KMS) And column definitions and data dictionary are accessible; breaking schema changes are versioned with a 30-day deprecation window And all export actions are logged (who, when, what, destination) and visible in audit trails
Privacy Redaction and Data Retention Controls
Rule: No CVV is stored or exported; full PAN is never stored; only token, BIN, and last4 may be retained Rule: Device identifiers are pseudonymized with rotating salt; IPs are truncated; free-text fields are scanned and redacted for PII before persistence and export Rule: Access to raw authentication events is RBAC-controlled; all reads/writes are audited immutably for 7 years Rule: Default retention is 13 months for auth events and aggregates; per-tenant overrides allowed (3–24 months); deletions propagate to BI exports and backups Rule: Data residency is enforced per tenant (e.g., EU-only storage when selected); backups respect residency and retention Rule: Data subject deletion requests are fulfilled within 30 days; subject access requests are fulfilled within 7 days; completion is logged and independently verifiable
Soft-Decline Recovery and False-Decline Indicators Visibility
Given a dashboard module focused on soft-declines and false-decline indicators When a user selects any issuer, BIN, country, device, class category filter and time range Then soft-decline recovery rate = recovered approvals / soft-declines is displayed per segment with 95% Wilson confidence intervals; target thresholds are configurable for alerts And false-decline indicator rate = declines followed by success within 24 h for the same PAN token and merchant is displayed per segment with 95% confidence intervals And users can drill down to a sample of 20 redacted events per segment; event detail shows reason codes, step-up outcome, timestamps, and excludes PAN/CVV And the metrics API returns identical values to the UI with p95 ≤ 300 ms and p99 ≤ 500 ms response time; metric definitions are linked from the UI

One-Tap Upsells

Offer lightweight add-ons (mat rental, guest pass, class pack) inside the wallet confirmation step. Users toggle extras with a single tap before paying, increasing average order value without adding friction or redirecting away from the flow.

Requirements

Upsell Toggle Panel in Checkout
"As a student booking a class, I want to quickly add optional extras with one tap before I pay so that I can complete checkout faster without leaving the flow."
Description

Present a compact, brandable upsell panel on the final review step immediately before invoking the native wallet sheet (Apple Pay/Google Pay), enabling users to add or remove lightweight extras (e.g., mat rental, guest pass, class pack) with a single tap. The panel updates order totals in real time, shows incremental price deltas, and preserves checkout continuity with no redirects or additional forms. It supports accessibility (WCAG AA), fast load (<150 ms), responsive layouts, and localization. The component must also render in non-wallet checkout flows with identical behavior to maintain a single UX pattern.

Acceptance Criteria
Wallet Checkout: One-Tap Upsell Panel Visibility and Toggle Behavior
Given the user is on the final review step with Apple Pay or Google Pay available When the step is displayed Then a branded upsell panel renders directly above the Pay button before the native wallet sheet is invoked and within 150 ms of step display And each available upsell is shown with a toggle control defaulting to off unless merchant configuration sets a default And upsells that are out of stock or inapplicable are hidden or shown disabled with an explanatory note When the user toggles an upsell on or off Then the selection is applied immediately without opening any new dialogs or forms And the toggle state persists if the user opens and cancels the wallet sheet and returns to the review step And selection states are saved in the session so a refresh restores them
Real-Time Price Update and Incremental Delta Display
Given the upsell panel is visible When the user toggles any upsell Then the order subtotal, taxes/fees (if applicable), and grand total recalculate and visually update within 150 ms And a per-upsell incremental price delta (e.g., +$5.00) is displayed adjacent to each upsell and reflects its on/off state And the aggregated total change equals the sum of selected deltas with no more than ±$0.01 rounding variance When multiple upsells are toggled rapidly Then totals remain accurate and do not display intermediate stale values If an upsell is free due to promotion Then the delta shows +$0.00 and totals remain unchanged If an upsell becomes unavailable at confirmation Then it is removed from the order and the total adjusts with a non-blocking inline notice
Checkout Continuity: No Redirects or Extra Forms
Given the user interacts with the upsell panel on the final review step When toggling upsells Then no navigation, page reload, route change, or modal dialog occurs And no additional input fields are required to add the upsell And the primary Pay button remains visible and enabled (subject to standard validation) When the user taps Pay Then the native wallet sheet opens exactly once with the updated total including selected upsells And browser history is unchanged by upsell interactions (no new entries) And network activity from toggling is limited to background pricing updates without full page refresh
Accessibility: WCAG AA for Upsell Panel
Given a keyboard-only user When tabbing through the review step Then all upsell toggles and the Pay button are reachable in a logical order and operable via Enter/Space And each toggle exposes role "switch" (or native equivalent) with accessible name, on/off state, and price delta announced by screen readers And focus indicators are visible with at least 3:1 contrast; text meets 4.5:1 contrast And total changes are announced via an aria-live polite region within 1 second of a toggle change And there are no keyboard traps; content remains usable at 200% zoom and with prefers-reduced-motion enabled
Responsive Layout and Tap Targets
Given viewport widths from 320 px to 1440+ px and both portrait and landscape orientations When rendering the upsell panel Then content fits without horizontal scrolling; one-column layout is used on narrow viewports and multi-column where space allows And interactive controls meet a minimum 44x44 dp tap target with at least 8 px spacing And the panel respects safe areas/notches and does not overlap the Pay button or fixed elements And toggling items does not cause cumulative layout shift greater than 0.1
Localization and Currency Formatting
Given the checkout locale and currency are set When rendering the upsell panel Then all copy, deltas, and totals display in the selected language and currency format (symbols, separators, precision) And right-to-left locales render mirrored layouts and correct reading order And long translations (P95 length) do not overflow; text wraps or truncates with tooltip without losing critical information When the locale is changed prior to payment Then the panel updates copy and number formats without a page reload
Non-Wallet Checkout Parity
Given the user is in a non-wallet checkout flow (e.g., card form) When the final review step is displayed Then the upsell panel renders with the same layout, copy, toggle behavior, and price update logic as in wallet checkout When toggling upsells Then totals update in real time and the Pay/Submit button amount reflects the new total And no additional steps, redirects, or forms are introduced compared to the wallet flow
Add-on Catalog and Eligibility Rules
"As a studio owner, I want to define which add-ons appear for each class and who can buy them so that offers stay relevant and increase revenue without confusing customers."
Description

Provide an admin-configurable catalog of add-ons scoped by studio, instructor, class, or category, including name, description, icon, price, tax category, currency, inventory linkage, and display order. Support rules for visibility and purchase constraints (e.g., first-time customers only, members only, class-type specific, date/time windows), default toggle state (off/on), single vs multi-quantity, min/max per booking, and mutually exclusive groups. Ensure white‑label text/imagery overrides and allow per-brand copy. Expose configuration via dashboard and API with versioning and audit logs.

Acceptance Criteria
Scoped Add-on Creation and Catalog Fields
Given an admin with permissions is on the brand dashboard add-on creator When they create an add-on with name, description, icon, price, currency, tax category, scope (studio/instructor/class/category), inventory linkage (SKU/stock source), display order, quantity mode (single or multi with min/max), and default toggle state (on/off) Then the system validates required fields and types, showing inline errors for any missing/invalid values without saving And on save the add-on is persisted with a unique ID and current version number And the add-on appears in the catalog list with correct scopes and display order And the public API GET /addons reflects the same fields and values for the chosen scope within 2 seconds
Visibility and Purchase Constraints Enforcement
Given an add-on configured with visibility/purchase rules (first-time customers only, members only, class-type specific, and a date/time window) When a first-time, non-member books a qualifying class within the window Then the add-on is visible and selectable in the one-tap upsell step And when a returning, non-member or a booking outside the window views the same flow Then the add-on is hidden and not selectable And any attempt to attach the add-on via API when rules are not satisfied returns 422 with a rule-violation code and no add-on is attached
Default Toggle State and Quantity Constraints in One-Tap Flow
Given an add-on with default toggle state = on and quantity mode = multi (min=1, max=3) When the wallet confirmation sheet renders Then the add-on appears pre-selected with quantity = 1 and quantity controls limited to 1–3 And increasing/decreasing quantity updates the order total and tax within 200 ms without navigating away And setting quantity outside bounds is prevented in UI and via API (422)
Mutually Exclusive Groups Behavior
Given two add-ons assigned to the same mutually exclusive group When the user selects Add-on A in the one-tap upsell Then Add-on B is automatically deselected/disabled with an explanation message And attempting to select both via API results in 422 with a mutually-exclusive constraint code And removing Add-on A re-enables Add-on B
Inventory Linkage, Reservation, and Stockout Handling
Given an add-on linked to inventory with available quantity = N When M users concurrently attempt to add the add-on where M > N Then no more than N successful confirmations include the add-on, with atomic reservation at payment confirmation And out-of-stock state hides or disables the add-on with a Sold Out label And canceling a booking or removing the add-on restores inventory within 60 seconds
White-Label Per-Brand Copy and Imagery Overrides
Given a tenant with two brands A and B using the same base add-on When the admin overrides name, description, and icon for brand B only Then brand A continues to display base copy/imagery and brand B displays the overrides across dashboard previews and public checkout And prices/tax category remain sourced from the base add-on unless explicitly edited for that brand is supported And API responses include brand-specific fields where overrides exist and base fields otherwise
Dashboard/API Configuration, Versioning, and Audit Logs
Given add-on configurations are edited via dashboard and API When an admin updates fields and saves Then a new version is created with incremented version number and ETag And the audit log records actor, timestamp, changed fields (old→new), and scope And the API requires If-Match with the latest ETag for updates; stale ETags return 412 without applying changes And audit entries are filterable and exportable (CSV) by actor, date range, and scope
Real-time Pricing, Tax, and Discount Calculation
"As a buyer, I want the total to update immediately when I add or remove extras so that I know exactly what I will be charged before I confirm payment."
Description

When an add-on is toggled, recalculate totals instantly, including itemized subtotals, taxes by jurisdiction, fees, and discounts, and display the incremental change. Respect coupon rules (e.g., applies to class only, excludes add-ons), handle tax-inclusive/exclusive pricing, multi-currency rounding, and class pack proration where applicable. Expose a consistent price breakdown to the wallet payment sheet and receipts, ensuring parity between displayed and charged amounts to avoid declines.

Acceptance Criteria
Real-Time Add-On Toggle Recalculation and Incremental Delta
Given a visible class price, taxes, fees, and available add-ons, When the user toggles an add-on on or off, Then subtotal, taxes, fees, discounts, and total recalculate and visually update within 500ms without page reload. Given an add-on is toggled, When totals update, Then an incremental change indicator (e.g., +$X.XX or -$X.XX) appears and equals the net difference attributable to that add-on including applicable taxes and fees. Given multiple add-ons are toggled in succession, When totals update after each toggle, Then each intermediate total is correct and the final total equals the sum of the itemized breakdown displayed.
Coupon Application Rules: Class-Only vs Excluding Add-Ons
Given a coupon configured to discount the class price only and exclude add-ons and fees, When the coupon is applied and an add-on is toggled, Then the discount applies only to the class line, add-ons and fees remain undiscounted, and the total reflects these rules. Given an invalid or expired coupon is entered, When applied, Then no discount is applied, an inline error is shown, and the totals remain unchanged. Given a fixed-amount coupon larger than the class price, When applied, Then the discount caps at the class amount, the total never goes below zero, and no discount is applied to add-ons or fees.
Jurisdictional Taxes: Tax-Inclusive and Tax-Exclusive
Given tax configuration is tax-exclusive at the shopper's jurisdiction, When an add-on is toggled, Then tax is computed on the taxable base after discounts and proration, displayed as a separate tax line, and total equals subtotal + tax + fees. Given tax configuration is tax-inclusive at the shopper's jurisdiction, When an add-on is toggled, Then the included tax component is updated and displayed, unit prices remain constant, and total equals displayed price plus fees without double-taxing. Given mixed taxability (e.g., class taxable, add-on non-taxable), When both are in the cart, Then only taxable items contribute to the tax line and the tax calculation reflects item taxability flags.
Multi-Currency Precision and Rounding
Given currency USD (2 decimal places), When totals are computed with add-ons, taxes, fees, and discounts, Then all amounts are rounded to the currency's minor unit per ISO 4217 and the sum of rounded lines equals the rounded total. Given currency JPY (0 decimal places), When totals are computed, Then amounts are rounded to whole yen, no fractional values are displayed or charged, and the wallet sheet shows an integer amount. Given a currency with 3-decimal minor units (e.g., BHD), When totals are computed, Then rounding follows the currency's minor units and the wallet sheet amount equals the backend authorized amount exactly with zero discrepancy.
Class Pack Proration and Tax Interaction
Given the user adds a class pack upsell and has an existing eligible pack, When proration is applied, Then a proration credit line appears and is applied before tax in tax-exclusive jurisdictions and as a reduction of the included tax base in tax-inclusive jurisdictions. Given a coupon is applied alongside a proration credit, When totals are computed, Then the application order follows the defined business rule and totals remain non-negative with correct tax recomputation. Given an add-on that is not subject to proration, When toggled, Then proration affects only the class pack line and does not alter add-on amounts beyond tax recalculation where required.
Parity Across Display, Wallet Sheet, Backend Charge, and Receipt
Given the canonical server-calculated price breakdown is available, When the wallet payment sheet is presented, Then the amount and itemization shown match the breakdown displayed in the UI. Given payment is authorized and captured, When the receipt is generated, Then the charged amount and itemized breakdown exactly match the wallet sheet and UI with zero discrepancy tolerance. Given a discrepancy is detected between client-displayed and server-calculated totals, When the user attempts to pay, Then the Pay action is blocked, a recalculation is triggered, and no authorization is attempted until parity is restored.
Inventory Reservation and Validation
"As an operations manager, I want inventory to be checked and held when customers add extras so that we avoid double-booking limited resources."
Description

Validate add-on availability on toggle and reserve inventory with a short time-to-live hold during checkout to prevent overselling (e.g., limited mat rentals). Re-verify availability on payment confirmation, gracefully handle race conditions with clear inline errors and auto-revert toggles, and release holds on timeout, cancellation, or payment failure. Log events for reconciliation and support capacity limits tied to class enrollment and multi-quantity purchases.

Acceptance Criteria
One-Tap Add-On Toggle Creates TTL Inventory Hold
Given a user is at the wallet confirmation step with an add-on available to upsell When the user toggles the add-on on Then the system performs an atomic availability check for the requested quantity And if available, creates a reservation hold with a short configurable TTL associated to the user’s checkout session And the order total and line items reflect the add-on immediately And the global available inventory decreases by the held quantity until the hold is released And when the user toggles the add-on off before payment, the hold is released immediately and totals/inventory update accordingly
Concurrent Toggle Race Condition Is Gracefully Handled
Given two or more users toggle the same limited add-on within the TTL window with fewer units remaining than requested When the server processes the toggle requests Then holds are granted only up to the true remaining inventory with no oversell And rejected requests receive an inline error message in the wallet step explaining the add-on is no longer available And the add-on toggle auto-reverts to off and totals are restored without leaving the flow And the ordering of accepts/rejects is deterministic and idempotent per request (no duplicate holds or double decrements)
Payment Confirmation Re-Verification Adjusts Order Safely
Given a user has one or more add-ons on hold and is confirming payment When the system re-verifies add-on availability immediately before authorizing payment Then if all held quantities are still available, the holds convert to final allocations and payment is authorized successfully And if any held quantity is no longer available, those line items are removed or reduced to available quantity, totals are recalculated, and an inline message explains the change And payment does not proceed for unavailable quantities, and the user can continue to pay the updated total without leaving the wallet step And no oversell or duplicate charges occur
Automatic Hold Release on Timeout, Cancellation, or Payment Failure
Given a reservation hold exists for an add-on When the hold TTL expires, the user cancels checkout, or payment authorization fails or times out Then the hold is released promptly, inventory is restored, and the add-on is removed from the order summary And the UI reflects the release (toggle off, totals updated) within the current session And releasing a hold is idempotent and safe to retry
Multi-Quantity Add-Ons Respect Inventory and Class-Linked Capacity
Given an add-on supports multi-quantity selection and may be capacity-linked to the class enrollment When the user increases quantity from the wallet step Then the system validates against the true remaining inventory (and any class-linked capacity constraints) and creates or expands holds per unit And the user cannot increase beyond the available quantity and receives inline feedback if a limit is reached And when the user decreases quantity or toggles the add-on off, the corresponding held units are released immediately and totals/inventory update accordingly And if the user changes the selected class or the class capacity changes server-side during checkout, the add-on quantities are revalidated and adjusted with inline messaging
Event Logging for Inventory Validation and Holds
Given an availability check, hold create/update/release, payment re-verification, or final allocation occurs When the event is processed Then an audit log entry is recorded with timestamp, event type, class ID, add-on ID, user/session ID, quantity, hold ID, outcome (success/fail), reason, and resulting available inventory And entries are correlated to the checkout session via a correlation ID for reconciliation And logs exclude sensitive payment data and are retrievable for support within retention policy
Payment Gateway Line-Itemization and Refunds
"As a finance admin, I want add-ons to appear as separate line items in payments and refunds so that reporting is accurate and customer service can process partial refunds easily."
Description

Include add-ons as distinct line items in payment intents for Apple Pay/Google Pay via the processor (e.g., Stripe) with correct tax breakdowns and metadata for reconciliation. Ensure a single authorization captures class plus add-ons, support partial and full refunds at the line-item level, and expose itemization to accounting exports and webhooks. Maintain idempotency and ensure charge amounts match the displayed total to minimize declines.

Acceptance Criteria
Wallet Payment Intent Line-Itemization
Given a user selects a class and one or more add-ons in the wallet confirmation step When a PaymentIntent is created for Apple Pay or Google Pay via Stripe Then the PaymentIntent contains distinct line items for the class and each add-on with correct name, quantity, currency, unit_amount, subtotal, tax_amount, and total per item And each line item includes a tax breakdown (rate id, jurisdiction, inclusive/exclusive flag) matching the configured tax profile And PaymentIntent metadata includes order_id, booking_id, user_id, class_id, addon_ids, tax_profile_id, and source=wallet And the PaymentIntent amount equals the sum of item totals (subtotals + taxes − discounts) and matches the UI-displayed total exactly And all monetary values are stored and transmitted in minor currency units with consistent rounding rules
Single Authorization and Capture for Class + Add‑ons
Given a wallet checkout containing a class and selected add-ons When the user confirms payment via Apple Pay or Google Pay Then a single authorization is created for the combined total and captured in one transaction And no additional authorizations or separate charges are created for add-ons And the captured amount equals the displayed total at confirmation time with zero variance And retrying the confirmation with the same idempotency key produces no duplicate authorizations or captures
Item‑Level Partial and Full Refunds
Given a settled charge that includes a class line item and one or more add-on line items When an admin requests a refund for specific line items Then a Stripe Refund is created for the exact refundable amount of the selected items and metadata includes order_id and refunded_line_item_ids And refunding an add-on does not cancel the class booking; refunding the class cancels the booking per policy And multiple partial refunds are supported up to the total captured amount; attempts to over-refund return a validation error and no refund is created And webhooks for the refund include item-level attribution and updated refundable balances
Accounting Export with Itemization
Given completed orders within a selected date range When the accounting export is generated Then the export contains one row per line item with columns: order_id, booking_id, user_id, item_type (class|addon), item_name, quantity, currency, unit_amount, subtotal, tax_rate_id, tax_amount, discount_amount, line_total, processor_charge_id, refund_amount, refunded_at, metadata And the sum of line_total per order equals the captured amount reported by the processor And numeric amounts are in minor units; timestamps are ISO 8601 in the account’s timezone; column headers are stable and documented
Webhook Itemization and Idempotency
Given payment_intent.succeeded, charge.captured, and refund.succeeded events occur When webhooks are delivered (including retries) Then each payload includes an itemization array with item_id, item_type, quantity, unit_amount, tax_amount, discounts, and for refunds the refunded_line_item_ids and amounts And each event includes order_id and an idempotency_key enabling consumers to deduplicate And the platform treats duplicate deliveries as idempotent: processing the same event twice does not duplicate records or alter balances
Displayed Total vs Processor Charge Consistency
Given a wallet checkout review displaying subtotal, taxes, discounts, and total When the user pays via Apple Pay or Google Pay Then the processor capture amount must equal the displayed total exactly And if a mismatch is detected pre-confirmation, the payment is aborted, the user is shown an error with a prompt to retry, and a telemetry event is logged with variance data And end-to-end tests validate zero variance across supported currencies and tax configurations
Post-Purchase Communication and Redemption
"As a customer, I want my confirmation to show the extras I bought and how to use them so that I know what to expect when I arrive."
Description

Include purchased add-ons in confirmation emails/SMS and receipts with clear labels, quantities, and redemption instructions. Surface add-ons in staff check-in views and attendee manifests, optionally generating scannable tokens (QR/barcode) for items like guest passes. Sync to calendar invites where relevant and support reminders that reference add-ons (e.g., “Mat reserved”). Ensure localization and white-label branding across channels.

Acceptance Criteria
Add-Ons Included in Confirmation Email and SMS
Given a completed purchase with one or more add-ons When the transaction is confirmed Then a confirmation email and SMS are sent within 2 minutes And both messages contain an "Add-ons" section listing each add-on by name and quantity And each listed add-on includes concise redemption instructions (SMS ≤ 200 chars; essential info not truncated) And if no add-ons were purchased, no "Add-ons" section appears
Receipts Display Add-Ons with Labels and Quantities
Given a purchase includes add-ons When the receipt (web and email) is generated Then each add-on appears as a separate line item with label, quantity, unit price, and line total And the order subtotal, taxes/fees/discounts, and grand total accurately include add-ons And the receipt includes a "How to redeem" note per add-on
Staff Check-In and Manifest Surfacing
Given staff opens the class check-in view for a session When an attendee has purchased add-ons Then add-ons are displayed adjacent to the attendee with clear labels and quantities And staff can mark each add-on as redeemed/not redeemed with a single tap And redemption status syncs to all staff sessions and attendee manifests within 5 seconds And the exported attendee manifest CSV includes columns for add-ons and redemption status
Scannable Tokens for Tokenizable Add-Ons
Given an add-on is configured as tokenizable (e.g., guest pass) When it is purchased Then the system generates unique QR and barcode tokens per unit quantity And each token is single-use; scanning marks it redeemed and prevents reuse And tokens can be scanned from the staff app or web check-in using a device camera And staff can manually mark as redeemed without scanning, with a timestamped audit entry And tokens expire at the class end time and cannot be redeemed afterward
Calendar Invite Sync References Add-Ons
Given a booking with calendar-relevant add-ons (e.g., mat rental) When the user adds the event to their calendar (ICS or native) Then the event description includes an "Add-ons" section with item names and quantities And changes to add-ons before the start time trigger an updated ICS and notification to refresh the calendar entry And the calendar entry uses the purchaser’s locale for date/time formatting
Automated Reminders Reference Add-Ons
Given reminders are enabled for the class When a reminder is sent for a booking with add-ons Then the message includes a concise add-on summary (e.g., "Mat reserved x1") And for tokenizable items, the reminder includes a "Show your pass" note and a link to view tokens And reminder content is channel-optimized (SMS ≤ 160 GSM chars) while preserving add-on info
Localization and White-Label Branding Across Channels
Given a studio’s branding configuration and the purchaser’s locale When generating confirmations, receipts, reminders, calendar invites, and staff views Then all user-facing text is localized to the purchaser’s locale (min supported: en, es, fr) with correct currency and date/number formats And all communications and pages display the studio’s name/logo/colors and omit ClassTap branding And all links use the studio’s custom domain if configured; otherwise use the default white-label domain
Analytics, Experimentation, and Personalization
"As a product manager, I want to test and measure which upsells perform best for different segments so that we can increase revenue without hurting conversion."
Description

Instrument events to measure attach rate, AOV lift, per-add-on conversion, and drop-off. Provide a dashboard and exports, and support A/B testing of default toggle states, placement, and copy. Enable simple personalization rules (e.g., suggest class pack to repeat attendees) with guardrails to avoid dark patterns. Ensure privacy compliance (GDPR/CCPA), honor consent, and anonymize data where required.

Acceptance Criteria
Upsell Funnel Event Instrumentation
Given a buyer views the wallet confirmation step with upsell options visible, when the step renders, then an event upsell_impression is logged with session_id, user_id (if authenticated), upsell_group_id, locale, device_type, experiment_variant, and timestamp. Given a buyer toggles an add-on on or off, when the toggle state changes, then an event upsell_toggle is logged with add_on_id, previous_state, new_state, price, currency, and timestamp and is emitted exactly once per change. Given a buyer completes payment, when the payment is authorized, then events order_completed and upsell_purchase (if any add-ons were purchased) are logged with order_id, add_on_ids, subtotal, add_on_total, total, currency, and experiment_variant. Given a buyer exits before payment, when the session ends or payment is abandoned, then an event checkout_dropoff is logged with last_step and last_interaction within 60 seconds of inactivity. Then attach_rate, per_add_on_conversion, AOV, and step_dropoff can be computed from events; event duplication rate is <0.5% and event loss rate is <0.5% within 15 minutes of event time.
Analytics Dashboard Metrics and Segmentation
Given a date range is selected, when an admin opens the Upsells Analytics dashboard, then metrics show attach_rate, AOV, AOV_lift vs baseline, per_add_on_conversion, revenue_from_add_ons, and funnel drop-off by step. Then filters exist for location, instructor, class_type, device_type, experiment_variant, and user_segment (new vs returning) and apply with P50 latency ≤2s and P95 ≤5s. Then a data freshness indicator shows last update time and metrics are within 15 minutes of event time. Then dashboard totals for a given period match the CSV export within 0.5% for the same filters and time zone. Then time zone can be selected (account default, viewer local) and persists per user preference.
Experimentation on Toggle State, Placement, and Copy
Given an experiment targeting the wallet confirmation step is created, when variants define default toggle state, upsell placement, and copy, then traffic is randomly assigned at user_id level (fallback session_id) and assignment persists for 30 days. Then a control holdout of 10% can be configured; sample ratio mismatch is auto-detected and alerted if observed proportions significantly deviate (p<0.01). Then experiments can be started, paused, and stopped without code deploys, and only one active experiment per surface is allowed at a time. Then primary metrics attach_rate and AOV_lift and secondary per_add_on_conversion are computed with 95% confidence intervals and minimum sample size guardrails before declaring a winner; results are segmentable by device_type and location.
Personalization Rules and Guardrails
Given a repeat attendee (≥2 prior bookings) with personalization consent, when viewing the wallet confirmation step, then a class pack upsell is displayed with a "Recommended" label and rationale "You’ve booked 2+ classes." Then default toggle for personalized upsells is Off unless an explicit experiment variant sets it otherwise; any pre-selected add-on is clearly indicated and reversible with a single tap. Then users can dismiss a personalized upsell and it remains suppressed for 30 days or until eligibility changes. Then personalization never hides mandatory fees or misrepresents pricing; total price updates immediately and clearly when an add-on is toggled; no countdown timers or coercive copy are used for personalized upsells.
Privacy, Consent, and Data Minimization
Given a user declines analytics or selects CCPA Do Not Sell/Share, when they proceed through checkout, then no analytics, experimentation, or personalization events are recorded and a default, non-tracked experience is shown. Then IP addresses are not stored; analytics identifiers are pseudonymous; EU-sourced events are geo-routed, anonymized per GDPR, and stored in an EU region. Then consent states are honored and auditable; withdrawing consent stops tracking immediately and historical identifier linkages are erased within 30 days. Then DSAR access/delete requests export and delete all analytics identifiers and linked events within 30 days of verified request. Then raw analytics event retention is capped at ≤13 months and PII fields are blocked by schema validation from event payloads.
Exports and Data Access
Given an admin selects a date range and metrics, when requesting an export, then a CSV is generated within 2 minutes containing line-level upsell events and a data dictionary. Then scheduled daily exports can be configured to S3 or SFTP with PGP encryption; failures trigger email alerts and retry up to 3 times. Then export row counts and key aggregates match dashboard metrics within 0.5% for the same filters and date range. Then only users with Analytics Viewer or higher can access exports; all exports are audit-logged with requester, filters, and timestamp.
Reliability and Data Quality Monitoring
Given normal traffic, when events are ingested, then 99.5% are processed and available for analytics within 15 minutes; retries occur up to 3 times with idempotent keys to prevent duplicates. Then schema versioning enforces required fields; malformed events are rejected with error codes and logged to an ops dashboard. Then weekly data quality reports compute duplicate_rate, loss_rate, and field_null_rate with thresholds and alerting to Slack/email when exceeded. Then staging and production analytics pipelines are isolated and staging data never appears in production dashboards or exports.

Smart Seat Hold

Automatically holds a seat for 60 seconds the moment the wallet sheet opens, preventing double-bookings during peak demand. Releases on timeout or failure and confirms instantly on success—ensuring fairness and clean rosters for staff.

Requirements

Real-time Seat Lock on Checkout Initiation
"As a student booking a popular class, I want my seat held the instant I start checkout so that no one else can take it while I complete payment."
Description

When a user opens the wallet/payment sheet, the system immediately creates a server-side provisional seat hold for the selected class occurrence with a 60-second TTL. The hold is keyed by class occurrence, account, and user/session plus payment intent to ensure one active hold per user per class and to prevent over-capacity bookings. The lock must be atomic, globally consistent across regions, and visible to capacity checks in all booking endpoints. It must be idempotent (reopening checkout or network retries must not create duplicate holds) and resilient to client disconnects (server TTL governs release). Works across web and mobile SDKs with a single API (CreateHold) returning hold_id, expiry timestamp (server time), and remaining capacity including held seats. Emits metrics and logs for hold_created and hold_collision events.

Acceptance Criteria
60-Second Countdown and Auto-Release
"As a student, I want a clear countdown showing how long my spot is reserved so that I can decide quickly and understand when the seat will be released."
Description

Expose a synchronized 60-second countdown to the client using the hold’s server expiry to avoid clock drift. The server automatically releases the hold at expiry and publishes a hold_released event that updates capacity and UI subscribers. The client displays a prominent timer and disables confirm actions upon expiry. If the user navigates back or dismisses the wallet sheet, the client calls ReleaseHold; the server must handle double-release safely. Holds must never outlive the TTL, even if the client is offline. Provide localized messaging and accessibility support for screen readers for the countdown and expiry states.

Acceptance Criteria
Server-Synchronized Countdown Display
Given a user opens the wallet sheet and a hold H is created with server expiry timestamp T When the wallet sheet loads Then the client initializes the countdown from T (server time), not the device clock And the countdown updates every 1 second and never displays negative time And the displayed remaining time deviates from server time by no more than ±1 second when checked at 0s, 30s, and 59s And the timer is visible above the confirm action and shows mm:ss format
Automatic Hold Expiry and Event Publication
Given an active hold H with expiry T When T is reached on the server Then the server releases H within 1 second of T And the class capacity is incremented by 1 on the server And exactly one hold_released event is published containing hold_id, class_id, and released_at ≥ T And all subscribed clients receive the event and update available seats within 2 seconds And no duplicate hold_released event is emitted for H
Client Behavior on Expiry: Disable Confirm and Show Expired State
Given the active hold H reaches expiry locally or a hold_released event for H is received When the client state updates Then the Confirm action becomes disabled within 500 ms and cannot be activated And any attempt to confirm via API after expiry returns HTTP 409 with code HOLD_EXPIRED And the UI displays an "Hold expired" message and presents a retry or waitlist option when available And if a hold_released event arrives before the local countdown reaches 00:00, the UI immediately reflects expiry and stops the timer
Release on Back Navigation or Wallet Dismissal
Given the wallet sheet is open with an active hold H When the user navigates back or dismisses the wallet sheet Then the client calls ReleaseHold(H) once within 300 ms And the server responds 200 OK whether H is active or already released And a hold_released event is published only if H was active at the time of processing And subscribed clients update displayed capacity within 2 seconds of the event
Idempotent Double-Release Handling
Given ReleaseHold(H) is invoked multiple times due to retries or rapid user actions When the server processes these requests Then the first valid call releases H and increments capacity once And subsequent calls return 200 OK with no side effects And at most one hold_released event is published for H And server logs or metrics indicate deduplication using hold_id or request_id
TTL Enforcement While Client Is Offline
Given a hold H with a 60-second TTL and the client goes offline or the app is terminated before expiry When the server time reaches the expiry T Then the server releases H and publishes hold_released regardless of client connectivity And the seat is available for other users immediately after release And upon client reconnection, H is reported as expired and no countdown is displayed And the client reconciles state by processing missed events or fetching current capacity
Localization and Screen Reader Accessibility for Countdown and Expiry
- Countdown and expiry messages are localized to the user’s locale; verified for en-US, es-ES, and fr-FR with correct numerals and pluralization - If a locale is unavailable, fallback to en-US with no missing message keys - The countdown exposes an accessible name "Seat hold: {mm:ss} remaining" to screen readers - A polite live region announces at start and at 30s and 10s remaining; on expiry, an assertive announcement "Hold expired" is made - Focus moves to the primary next action on expiry without trapping focus; interaction remains keyboard-accessible - Visual timer meets WCAG 2.1 AA (contrast ratio ≥ 4.5:1) and does not flash more than 3 times per second
Instant Confirmation and Roster Sync on Success
"As an instructor, I want successful payments to instantly confirm the booking and update my roster so that I have an accurate headcount without manual reconciliation."
Description

Upon payment success callback/webhook, atomically promote the hold to a confirmed booking, decrement capacity, remove the hold, and add the attendee to the roster in a single transactional operation. Ensure idempotency for duplicate callbacks using payment intent IDs. Return immediate confirmation to the client and send branded confirmation email/SMS. Update instructor dashboards and staff rosters in real time, showing the attendee as Confirmed and removing any visible hold annotation. Publish booking_confirmed events for downstream integrations (analytics, CRM) and record audit entries linking hold_id to booking_id.

Acceptance Criteria
Atomic Promotion of Hold to Confirmed Booking on Payment Success
Given an active seat hold with hold_id and associated payment_intent_id and available capacity When a payment success webhook/callback is received with that payment_intent_id Then the system performs a single atomic transaction that: - creates or updates a booking to status=Confirmed linked to hold_id and attendee_id - decrements class capacity by one - removes the seat hold - inserts the attendee into the class roster And no partial changes are committed if any step fails (all-or-nothing rollback) And the final persisted state shows no hold for that attendee and capacity decreased by 1 And the booking record includes references: hold_id, payment_intent_id, and class_id
Idempotent Handling of Duplicate Payment Success Callbacks
Given a prior successful processing of payment_intent_id X resulting in booking_id B When a duplicate success callback for payment_intent_id X is received any time within 24 hours Then the system must not create a new booking or decrement capacity again And it returns HTTP 200 with the existing booking_id B and status=Confirmed And no additional confirmation email/SMS is sent And no additional booking_confirmed event is published And an audit entry records the duplicate callback with a reference to booking_id B
Immediate Client Confirmation Response
Given the server has successfully applied the atomic transaction for the payment intent When the client awaits confirmation after checkout or polls/fetches booking status Then the API responds with 2xx within 2 seconds of processing completion And the response body includes booking_id, class_id, attendee_id, status=Confirmed, start_time, venue (or join_link), and capacity_remaining And the client-visible hold annotation is absent in the response payload
Branded Confirmation Notifications Sent Once
Given a booking transitions to Confirmed from a seat hold When processing completes successfully Then a branded email and SMS are queued within 5 seconds and delivered to the attendee's verified contacts And the content includes brand name/logo, class title, date/time, location or virtual link, cancellation policy, and booking_id And notifications are sent exactly once per payment_intent_id even if duplicate callbacks arrive And notification delivery failures are retried per policy and logged without blocking booking confirmation
Real-Time Instructor Dashboard and Roster Sync
Given an instructor dashboard session subscribed to the class When a booking is confirmed from a hold Then within 3 seconds the dashboard updates to show the attendee in the roster as Confirmed And any visible hold annotation for that attendee is removed And the displayed capacity/available seats count reflects the decremented capacity And no ghost holds or duplicate roster entries appear after refresh
Booking Confirmed Event and Audit Trail
Given a booking is confirmed from a hold via payment_intent_id X When the transaction commits Then a booking_confirmed event is published to the event bus within 2 seconds with payload including booking_id, class_id, attendee_id, hold_id, payment_intent_id, timestamp, and source=smart_seat_hold And the event includes an idempotency key equal to payment_intent_id to prevent downstream duplication And an immutable audit record is written linking hold_id to booking_id with actor=system, action=promote_hold, and correlation_id=payment_intent_id And both event and audit records are queryable by booking_id and payment_intent_id
Concurrency Safety Under Peak Load
Given multiple workers/processes receive the same payment success notification concurrently for payment_intent_id X When they attempt to promote the same hold Then at most one transaction succeeds in confirming the booking and decrementing capacity And all other attempts return a successful idempotent response referencing the existing booking without side effects And no deadlocks occur and per-attempt lock wait or timeout does not exceed 5 seconds And system metrics record zero over-decrements of capacity
Failure and Abandonment Handling
"As a student, I want the seat to be released right away if my payment fails so that I can retry or let someone else book without confusion."
Description

If payment fails, is canceled, or the wallet sheet is dismissed, immediately release the hold and restore capacity with a hold_released reason code. Surface a clear error to the user with retry options. Reconciliation must handle races between timeout and failure to avoid double release. Integrate with payment processor failure webhooks to catch late failures and clean up any lingering holds. Log structured failure reasons, user agent, and latency to support supportability and funnel analysis. Ensure holds from crashed clients are safely released by TTL without human intervention.

Acceptance Criteria
Immediate Release on Payment Failure/Cancellation/Dismissal
Given a user has an active 60-second seat hold initiated by opening the wallet sheet When the payment processor returns a failure OR the user cancels payment OR dismisses the wallet sheet Then the system releases the hold within 200 ms of receiving the event And the class capacity is incremented by 1 atomically And the hold record is updated to state=Released with reason_code=hold_released and cause in [payment_failed, user_canceled, wallet_dismissed] And no booking confirmation is created And the seat appears available to other users within 1 second
User Error Messaging and Retry Path
Given a payment attempt ends in failure, cancellation, or wallet dismissal When the user returns to the booking screen Then an inline error banner is displayed within 300 ms with a human-readable message mapped to the failure cause And a primary "Retry payment" action is available that reopens the wallet and acquires a new 60-second hold only if capacity >= 1 And a "Choose another method" secondary action is available if multiple payment methods are supported And analytics events payment_error_shown and payment_retry_clicked are emitted with hold_id and failure_type
Idempotent Release on Timeout vs Failure Race
Given a seat hold with TTL=60s and a distinct hold_id and idempotency_key And a failure event arrives within ±500 ms of the TTL expiration When release is processed Then exactly one release occurs (no double increment of capacity) And the final hold state is Released with a single audit log entry containing release_path in [timeout, client_failure, webhook_failure] and the earlier of the two timestamps And no duplicate notifications are sent
Processor Failure Webhook Cleanup
Given the client did not send a failure signal due to termination or network loss And a payment.processor.failure webhook is received for a payment intent linked to an active or stale hold When the webhook is processed Then the hold is released if not already, with reason_code=hold_released and cause=webhook_failure And any pending provisional booking records are canceled And capacity is accurate post-processing (no negative or over-capacity states) And the webhook handler is idempotent using payment_intent_id and can be safely retried And processing latency p95 <= 1 second from webhook receipt
Crash/Offline Client TTL Auto-Release
Given a user opens the wallet sheet creating a hold and then closes the app or loses connectivity without completing payment When 60 seconds elapse without a success signal Then the server automatically releases the hold with reason_code=hold_released and cause=timeout And capacity is restored and visible in the availability API within 1 second And no manual intervention is required
Structured Failure Logging and Metrics
Given any failure, cancellation, dismissal, or timeout that triggers a release When the release operation completes Then a structured event is produced with fields: hold_id, payment_intent_id, user_id (if available), class_id, timestamp, failure_type, cause, release_path, user_agent, client_version, latency_ms_wallet_open_to_release, idempotency_key, and trace_id And the event is delivered to the analytics pipeline with at-least-once semantics and appears in dashboards within 5 minutes (p99) And missing mandatory fields cause the operation to retry logging without blocking the release
Capacity Restoration and Waitlist Promotion on Release
Given a class at full capacity with an active waitlist and a seat hold is released due to failure, cancellation, dismissal, or timeout When the release is committed Then displayed capacity increases by 1 within 1 second And if waitlist is enabled, the next eligible waitlisted user is promoted and notified within 2 seconds according to fairness rules And the promotion consumes the newly freed seat atomically, ensuring no double-booking
Waitlist Auto-Promotion on Hold Expiry
"As a waitlisted student, I want to be offered a seat the moment one becomes available after someone’s hold expires so that I have a fair chance to join the class."
Description

When a class is full and a hold is released due to timeout or explicit failure, publish a seat_available event to the waitlist service. The waitlist service promotes the next eligible person according to configured rules (e.g., FIFO, membership tier), sends an offer notification, and optionally places a short offer hold separate from checkout holds. Ensure that waitlist promotions do not trigger while any seat holds are active that keep capacity effectively zero. Provide guardrails to prevent oscillation when multiple holds expire concurrently and expose admin reporting on promotions triggered by hold expiries.

Acceptance Criteria
Seat available event on checkout hold timeout
Given a class is at full capacity and a checkout hold H is active for that class When hold H expires due to timeout and the seat release is persisted Then exactly one seat_available event is published within 2 seconds with fields {class_id, seat_delta:1, hold_id:H, reason:"hold_timeout", event_id (unique), occurred_at} And duplicate deliveries of the same event_id are ignored by the waitlist service And the event is retried until acknowledged by the waitlist service
Seat available event on explicit checkout failure
Given a class is at full capacity and a checkout hold H is active When checkout is explicitly failed (e.g., payment authorization fails or user cancels) and hold H is released Then exactly one seat_available event is published within 2 seconds with fields {class_id, seat_delta:1, hold_id:H, reason:"checkout_failure", event_id (unique), occurred_at} And no additional seat_available event is emitted for the same hold release
Waitlist promotion and offer hold creation on seat availability
Given the waitlist service receives a seat_available event for class X with seat_delta:1 and there is at least one eligible waitlisted user When the service applies the configured prioritization rule (e.g., FIFO, membership tier) Then the next eligible user is promoted with promotion_reason:"hold_expiry" and the decision is recorded with rule_applied And an offer notification is sent via all configured channels containing a claim link And a distinct offer hold is created for the configured offer_hold_duration (in minutes), separate from checkout holds And class effective capacity decreases by 1 while the offer hold is active And if the user claims within the offer_hold_duration, checkout is initiated and the offer hold transitions appropriately And if the offer hold expires, it is released and a new seat_available event is published within 2 seconds
Gating promotions when effective capacity is zero
Given a class has active holds (checkout and/or offer) and effective_capacity = capacity - confirmed_bookings - active_checkout_holds - active_offer_holds equals 0 When any single hold expires but effective_capacity remains 0 due to other active holds Then no seat_available event is published and no waitlist promotion is attempted And when effective_capacity transitions from 0 to >=1 with no conflicting holds Then exactly one seat_available event is published per newly available seat and promotions proceed accordingly
Concurrency guardrails and idempotent promotions
Given K (K>=2) holds for the same class expire within a 1-second window When the system processes the hold releases Then at most K seats of availability are exposed and no more than K promotions are initiated And promotions are computed against an atomic availability snapshot to prevent over-promotion or oscillation And each promotion carries a unique promotion_key (e.g., class_id + event_id) enabling idempotent handling across retries And no user receives more than one simultaneous offer for the same class instance
Admin reporting for hold-expiry-triggered promotions
Given promotions have been triggered by hold expiries When an admin queries the Hold-Expiry Promotions report/API for a time range and class Then each promotion record includes {class_id, class_start_at, seat_release_reason, hold_id, event_id, promoted_user_id, rule_applied, notification_channels, offer_hold_duration, outcome, timestamps} And aggregate counts (promotions, accepted, expired, declined) reconcile with underlying events for the selected range And results are filterable by class, rule_applied, and seat_release_reason and exportable to CSV
No duplicate promotion on duplicate seat_available events
Given the waitlist service receives duplicate deliveries of the same seat_available event_id due to at-least-once messaging When processing the duplicates Then at most one promotion is created for that event_id And no duplicate notifications are sent And metrics and reporting reflect a single promotion for that event_id
Offer decline or expiration re-publishes availability
Given a user was promoted via hold-expiry and an offer hold is active When the user declines the offer or the offer hold expires Then the offer hold is released within 1 second And exactly one seat_available event is published within 2 seconds with reason:"offer_released" and event_id (unique) And the next eligible waitlisted user is considered according to the configured rule
Admin Controls and Audit Analytics
"As a studio owner, I want to configure hold behavior and see analytics on holds and conversions so that I can balance fairness with revenue and reduce no-shows."
Description

Provide per-organization and per-class settings to enable/disable Smart Seat Hold, set hold duration (default 60 seconds, with enforceable min/max), and toggle waitlist integration. In staff views, display held seats with remaining time and reason. Offer analytics on hold creation rate, conversion rate, time-to-pay distribution, expiries, and failures, segmented by class and channel. Include an audit log linking user, hold_id, booking_id, timestamps, and state transitions for support and compliance. All settings must be available via dashboard UI and Admin API with role-based access control.

Acceptance Criteria
Org/Class Dashboard Controls for Smart Seat Hold
Given I am an Organization Admin on the dashboard, When I open Organization > Smart Seat Hold settings, Then I can enable/disable Smart Seat Hold, set hold_duration_seconds with default prefilled to 60, and toggle waitlist integration Given the hold duration input is displayed, When I focus the field, Then the UI shows the allowed range (MIN_HOLD_SECONDS–MAX_HOLD_SECONDS) and enforces it with inline validation Given I enter a value outside the allowed range, When I click Save, Then the Save action is blocked and I see an error message indicating the allowed range Given I open a specific Class > Smart Seat Hold settings, When I toggle "Override organization defaults", Then I can independently enable/disable holds, set hold_duration_seconds, and toggle waitlist integration for that class Given I save changes at the class level, When the save succeeds, Then the class shows it is overriding org defaults and the new settings are applied to new holds started after the save time Given I click "Use organization defaults" at the class level, When I confirm, Then class-level overrides are cleared and the class inherits org settings Given I am a Staff role (non-admin), When I view these settings, Then fields are read-only and any attempt to edit returns 403 Forbidden
Admin API for Seat Hold Settings with RBAC
Given I have an Admin API token, When I GET /admin/orgs/{orgId}/seat-hold-settings, Then I receive 200 OK with JSON including enabled, hold_duration_seconds, waitlist_enabled, min_hold_seconds, max_hold_seconds Given I have an Admin API token, When I PUT /admin/orgs/{orgId}/seat-hold-settings with values within [min_hold_seconds, max_hold_seconds], Then I receive 200 OK and subsequent new holds use the updated values Given I send a PUT with hold_duration_seconds outside the allowed range, When the request is processed, Then I receive 422 Unprocessable Entity with a field error describing the allowed range Given I have a Staff API token, When I PUT seat hold settings at org or class endpoints, Then I receive 403 Forbidden; When I GET, Then I receive 200 OK with readOnly=true in the payload Given I have an Admin API token, When I GET/PUT /admin/classes/{classId}/seat-hold-settings, Then the payload supports inherit=true/false and per-class overrides for enabled, hold_duration_seconds, and waitlist_enabled Given I include Idempotency-Key on PUT, When I resend the same payload with the same key, Then the response is identical and only one audit entry is written Given I update settings via API, When the operation succeeds, Then an audit log entry records actor_id, source="api", old_values, new_values, and timestamp
Staff Roster View Shows Active Holds and Countdown
Given a class has active seat holds, When a Staff user opens the roster view, Then each held seat is labeled "Held" with a mm:ss countdown and a reason (e.g., "Checkout in progress" or "Manual hold") Given the roster view is open, When time elapses, Then each countdown decrements every second without a full page refresh Given a held seat expires, When the timer reaches 00:00, Then the held indicator disappears or reverts to "Available" within 2 seconds of expiry Given a held seat converts to a booking, When payment succeeds, Then the entry transitions from "Held" to "Booked" without duplicate seat entries Given the class capacity is N, When viewing the roster, Then booked + held never exceeds N in the display Given Smart Seat Hold is disabled for the class, When viewing the roster, Then no "Held" labels or countdowns are shown
Waitlist Integration Controlled by Toggle
Given a class is at capacity and waitlist integration is enabled for that class, When a seat hold expires, Then the next eligible waitlisted user is automatically notified/promoted per policy and the seat is reserved or offered to them Given waitlist integration is disabled for the class (or inherited disabled from org), When a seat hold expires, Then no auto-promotion occurs and the seat returns to available inventory Given an admin changes the waitlist toggle, When the change is saved, Then the new behavior applies to expirations that occur after the save timestamp, and any already-sent promotions are unaffected Given a hold expiration occurs, When waitlist behavior is evaluated, Then an audit log event is written indicating whether promotion occurred and the reason (e.g., toggle_off, no_waitlist)
Seat Hold Analytics Dashboard and Export
Given an Organization Admin opens Analytics > Seat Holds, When a date range and filters (class, channel) are selected, Then the dashboard shows holds_created, conversion_rate, time_to_pay (median, p90, histogram), expiries, and failures Given class and channel segment controls are used, When segments are toggled, Then charts/tables update to reflect segmentation by class and channel (e.g., web, mobile, POS) Given new seat hold events occur, When viewing analytics, Then data freshness is ≤15 minutes between event time and appearance on the dashboard Given an Admin validates a sample window, When comparing dashboard counts to raw events, Then differences are ≤0.5% for counts and ≤0.5 percentage points for rates Given the dashboard is visible, When the user clicks a metric segment, Then a drill-down appears listing the underlying hold_ids/booking_ids matching that segment and filters Given the user clicks Export CSV, When the export completes, Then a CSV downloads within 10 seconds containing the same aggregates and filters as displayed
Comprehensive Audit Log for Seat Holds and Bookings
Given any seat hold lifecycle event occurs, When the system processes it, Then an audit record is written with hold_id, booking_id (nullable), user_id or session_id, class_id, channel, actor_id (nullable), event_name, and UTC ISO 8601 timestamp with millisecond precision Given common lifecycle events occur, When they are logged, Then the following event_names are supported at minimum: hold_created, hold_released_timeout, hold_released_failure, hold_converted_booking, payment_attempted, payment_succeeded, payment_failed, settings_changed Given audit records are stored, When queried, Then records are append-only (immutable); corrections appear as new events linked by correlation_id; hard deletes are disallowed Given an Admin or Compliance user searches the audit log, When filtering by hold_id, booking_id, user identifier, class_id, event_name, or time range, Then results return within 2 seconds for the 95th percentile of queries up to 10,000 records Given a Staff user attempts to access the audit log, When requesting via UI or API, Then access is denied with 403 Forbidden Given an Admin uses the API, When calling GET /admin/audit/holds with pagination parameters, Then results are paginated deterministically and include next/prev cursors

Reminder Paylinks

Automated SMS/email reminders include secure, expiring TapPass links that open directly to one-tap confirm. Supports quick rebooks, waitlist promotions, and last-minute fills—cutting no-shows and keeping classes at capacity with zero admin effort.

Requirements

Secure Expiring Paylink Tokens
"As a student, I want reminder links that safely expire and are single-use so that my payment and booking can be confirmed securely with one tap without risking misuse."
Description

Generate cryptographically signed, single-use TapPass URLs embedded in SMS/email reminders that expire after a configurable TTL and are scoped to a specific user, class instance, and price. Tokens must be tamper-evident (e.g., HMAC with rotating keys), support optional device/IP binding, and be invalidated after first successful use or upon manual revoke. Include short-linking with studio-branded domains and deep-linking into the mobile web/PWA checkout. Server validates claims (user, class, seat, price, expires_at, nonce) and returns friendly states for expired/invalid links with safe recovery paths (e.g., regenerate or navigate to class page). All events (issued, opened, redeemed, expired) are logged for audit and analytics. Outcome: secure, trustable links that mitigate fraud and misuse while enabling true one-tap flows.

Acceptance Criteria
Signed Token Issuance with Required Claims and Configurable TTL
Given a reminder is generated for a specific user, class instance, seat, and price When the server issues a TapPass token Then the token is HMAC-signed using the active key and includes claims: user_id, class_instance_id, seat_id, price_id or price_amount, expires_at, nonce And the token includes a key identifier to support rotation and validates with any unexpired active or grace-period key And the TTL is set from studio configuration within allowed min/max bounds And the nonce is globally unique and has at least 128 bits of entropy And any modification to any claim causes signature verification to fail and the server returns an "invalid link" friendly state with a safe recovery path
Single-Use Redemption, Idempotency, and Manual Revoke
Given a valid, unexpired, unrevoked TapPass token When the user opens the link and confirms Then validation and redemption complete atomically and the token is marked redeemed immediately And exactly one of any concurrent requests succeeds; all others return an "already used" friendly state with a link to the class page or to request a new link And subsequent attempts to use the token after redemption return "already used" with no additional charge or seat allocation And if the token is manually revoked before redemption, any attempt returns a "revoked" state with options to regenerate a new link or navigate to the class page
Expiration Handling with Friendly Recovery
Given a TapPass token with an expires_at claim When the current server time is greater than expires_at Then the server rejects redemption and displays an "expired" friendly state explaining the timeout window And, if the user is authenticated as the token's user and a seat is still available, an option to generate a fresh link is presented And, if not authenticated or no seats remain, the user is directed to the class page or waitlist without processing payment
Scope and Price Enforcement
Given a TapPass token scoped to a specific user, class instance, seat, and price When the link is accessed by a different authenticated user or the class instance/seat/price in the request does not match the token claims Then the server rejects the attempt with an "invalid scope" friendly state and provides navigation to the correct class page or sign-in as the intended user And the server uses only the price in the token for charging and rejects any client-supplied price overrides
Optional Device/IP Binding
Given device/IP binding is enabled for the studio When a TapPass link is first opened Then the server binds the token to the opening device fingerprint and/or IP per configuration And later redemption from a device/IP outside the configured tolerance is rejected with a "device mismatch" state and an option to request a new link And when binding is disabled, the token redeems regardless of device/IP
Branded Short Links and Deep Linking
Given a TapPass token is issued for reminder delivery When the system generates the link for SMS/email Then the link uses the studio-branded HTTPS short domain and resolves within 300 ms to a deep link And the deep link opens the PWA/mobile web checkout directly to one-tap confirm for the target class instance And if the PWA is unavailable, the user is routed to the responsive mobile web checkout with the same state And tracking parameters (e.g., channel) are preserved end-to-end without exposing PII in the URL
Event Logging and Analytics
Given TapPass tokens are issued and interacted with When events occur (issued, opened, redeemed, expired, revoked) Then an immutable event is written within 2 seconds with fields: token_id or nonce, user_id, class_instance_id, timestamp, channel, user_agent, IP (if available), event_type, outcome And duplicate deliveries are deduplicated by token_id+event_type within a 10-minute window And events are queryable via audit API and included in analytics aggregates within 15 minutes
One-Tap Confirm & Payment
"As a student, I want to confirm and pay for a class with a single tap from a reminder so that I don’t miss out due to a lengthy checkout process."
Description

Provide a frictionless flow where opening a TapPass instantly loads a confirmation screen with pre-filled class details and a single confirm action that triggers payment and booking. Use stored payment methods (Stripe Customer) or native wallets (Apple Pay/Google Pay) and seamlessly handle SCA/3DS challenges within the flow; fall back to standard checkout if no method is available. Ensure idempotent bookings via Payment Intents and idempotency keys, support taxes, promo codes, credits/passes, and send receipt plus calendar attachment upon success. Present clear error/retry states for declines or interrupted authentications without losing the reservation. Outcome: higher conversion and fewer abandoned checkouts from reminders.

Acceptance Criteria
Stored Card One-Tap Success with Taxes and Promo
Given the recipient opens a valid, unexpired TapPass to a class with at least one available seat and has a Stripe Customer with a default saved card and an applicable promo code When they tap Confirm Then a Stripe Payment Intent is created with the discounted subtotal, taxes computed per venue jurisdiction, correct currency, and a unique idempotency key tied to the TapPass And if SCA is required, an in-flow 3DS challenge is presented and, upon completion, the payment is confirmed without redirect And upon successful confirmation, exactly one booking is created and linked to the Payment Intent And the success screen renders within 3 seconds of payment confirmation with class details and a View Booking action And a receipt via email/SMS including itemized taxes and discount is sent within 60 seconds And a .ics calendar attachment with accurate start/end time, timezone, and location is included in the receipt And the TapPass is marked consumed and cannot be reused
Native Wallet with SCA Challenge
Given the device supports Apple Pay or Google Pay with at least one active card and the issuer requires SCA When the user taps Confirm and chooses the native wallet Then the wallet sheet displays the correct payee name, amount, currency, and line-item summary if supported And the 3DS/SCA challenge occurs within the wallet flow and can be completed without leaving the app or page And on success, the Payment Intent is confirmed and the booking is created within the same session And on cancel or timeout, an explicit error message with Retry and Change Payment Method options is shown And the seat hold persists for at least 5 minutes from initial open
No Saved Method Fallback to Standard Checkout
Given no saved payment methods exist for the user and native wallets are unavailable When the TapPass is opened and Confirm is tapped Then the user is routed to the standard checkout with class, price, promo, and taxes pre-filled and non-editable class details And after successful checkout, a booking is created and a receipt + .ics are sent within 60 seconds And if checkout is abandoned, no booking is created, no charge occurs, and the TapPass remains usable until its expiration
Idempotent Confirm and Network Retry
Given the same TapPass triggers multiple Confirm requests within a 60-second window due to double tap or network retry When the backend processes the requests Then the same idempotency key is used to ensure a single Payment Intent confirmation And at most one booking record exists; subsequent requests return the same booking ID and status And only one charge appears in the payment processor and on the customer's statement And telemetry logs include a single success event and deduplicated retries
Declines and Recovery Without Losing Reservation
Given the payment attempt fails due to decline, authentication failure, or processor error When the failure occurs Then the user sees a clear error message with an actionable reason category and a masked reference code And a Retry Payment option is available without reloading the page And a Change Payment Method option allows selecting another saved card or opening standard checkout And the seat remains reserved for at least 5 minutes from the first confirm attempt; upon expiry, a message indicates the hold has ended And no booking or receipt is created until a successful payment occurs
Credits/Passes Application in One-Tap
Given the user has available credits or an active pass applicable to the class When the TapPass is opened and Confirm is tapped Then credits/passes are applied before charging any card per business rules And if the total is $0.00 after application, the booking is created immediately with no payment confirmation required And if a partial balance remains, only the remainder is charged to the default method or wallet And taxes are computed on the correct taxable base after credits and discounts And the receipt itemizes credit/pass usage and remaining balances
TapPass Expiry, Single Use, and Security
Given a TapPass is expired, already used, or the token is invalid When the link is opened Then an Expired or Already Used state is shown with class details and a CTA to view availability or join the waitlist And the link cannot initiate payment or create a booking And all accesses are logged with timestamp and IP for audit And excessive invalid token attempts (>=10 within 5 minutes from one IP) are rate limited with HTTP 429
Reminder Orchestration & Delivery (SMS/Email)
"As an instructor, I want automated reminders with embedded paylinks sent at the right times and channels so that my classes stay full without extra admin work."
Description

Automate scheduling and delivery of reminders that include TapPass links for upcoming classes, last-minute fills, abandoned confirmations, and re-engagement. Support timezone-aware scheduling, quiet hours, per-studio send windows, rate limits, and per-contact channel preferences with compliant opt-in/opt-out (STOP/unsubscribe). Provide templating with personalization (name, class, location, time, spots left), per-brand assets, and safe link insertion. Integrate with Twilio (SMS) and SendGrid/SES (email), with delivery status tracking and graceful retries. Ensure deduplication across channels and enforce frequency caps to avoid spam. Outcome: timely, relevant reminders that reduce no-shows and drive confirmations.

Acceptance Criteria
Timezone-Aware Quiet Hours & Send Windows
Given Studio A has a send window of 08:00–20:00 local and quiet hours enabled, and a learner in America/Chicago timezone, When a reminder is scheduled at 07:30 local, Then it is deferred and sent at 08:00 local. Given the same settings, When a reminder is scheduled at 19:59 local, Then it is sent before 20:00 local and not deferred to the next day. Given the same settings and class start at 07:45 local, When the next allowable send time (08:00) is after class start, Then the reminder is suppressed and logged as "suppressed: missed window". Given per-studio override "allow last-minute outside window" is false, When a vacancy alert would be sent at 22:00 local, Then it is deferred to 08:00 local. Given a daylight saving time transition, When a reminder is scheduled across the DST shift, Then the scheduled local time is preserved relative to wall-clock time.
Channel Preferences, Opt-In/Opt-Out Compliance
Given a contact with SMS=opted-in, Email=opted-out and preferred channel=SMS, When a reminder is orchestrated, Then only an SMS is attempted. Given a contact sends "STOP" to any ClassTap number, When the STOP MO is received, Then the contact's SMS consent is set to opted-out within 1 second and a single compliance confirmation is sent, and no further SMS are sent until "START" is received. Given a contact clicks the email unsubscribe link, When the webhook confirms unsubscribe, Then Email consent is set to opted-out and future emails are suppressed. Given a contact re-subscribes via double opt-in email, When confirmed, Then Email consent is set to opted-in and orchestration may use Email again. Given a per-contact do-not-disturb window, When inside DND, Then no channel is used even if opted-in, and the attempt is rescheduled or suppressed per policy.
Secure TapPass Link Generation and Behavior
Given a reminder requires a TapPass link, When generating the message, Then a unique, signed, non-guessable HTTPS link on the brand domain is inserted without breaking template formatting. Given link TTL is class_start_time or a configured expiry (e.g., 120 minutes after send), When the link is opened before expiry, Then one-tap confirmation succeeds and attendee status updates to Confirmed within 2 seconds. Given the link is opened after expiry, Then the user sees a "Link expired" screen with options to view schedule or join waitlist and no confirmation is applied. Given the recipient has already confirmed or canceled, When the link is opened, Then an idempotent response is shown and no duplicate state change occurs. Given PII constraints, When generating the link, Then no email, phone, or name is embedded in the URL path or query string.
Cross-Channel Deduplication and Frequency Caps
Given both SMS and Email are eligible, When SMS is delivered (DLR=delivered) within 5 minutes of send, Then the corresponding email reminder for the same intent is canceled. Given SMS fails permanently (e.g., Twilio 30003) or no DLR after 5 minutes, When Email is allowed, Then an email is sent as fallback once. Given frequency caps configured (e.g., max 2 reminders per contact per 24h; max 1 reminder per class per contact), When a send would exceed a cap, Then the reminder is suppressed and the suppression reason is recorded. Given separate caps for promotional vs transactional, When the reminder is transactional (upcoming class), Then it does not count against the promotional cap, but still respects the per-class cap.
Provider Integration, Throttling, Retries, and Status Tracking
Given a Twilio SMS send rate limit of 1 msg/sec per sender, When a batch of 120 messages is queued, Then throughput is throttled to the configured rate with jitter and completes without provider 429 errors. Given a transient provider error (HTTP 5xx or Twilio 30001), When sending, Then retries occur with exponential backoff (e.g., 1s, 4s, 16s) up to 3 attempts before marking as Failed. Given SendGrid/SES webhooks, When events Delivered, Bounce, Deferred, SpamReport, and Unsubscribe are received, Then the message status timeline is updated and email consent is adjusted (Bounce/SpamReport -> suppress future sends). Given permanent SMS errors or carrier blocks, When detected, Then SMS consent is not changed automatically but the number is flagged for review and SMS is suppressed for 7 days. Given a message is sent, When viewing delivery logs, Then the system shows provider message ID, send time, attempts, final status, and error codes.
Template Personalization and Brand Assets
Given a template with placeholders {{first_name}}, {{class_title}}, {{location}}, {{start_time_local}}, and {{spots_left}}, and brand header/footer, When rendering, Then all placeholders resolve correctly using the recipient's locale and the brand assets are applied. Given a missing optional field (e.g., spots_left), When rendering, Then a safe default or omission is used without broken syntax. Given SMS content length and encoding, When the personalized SMS exceeds 160 GSM-7 chars or includes Unicode, Then it is segmented per standard and total parts do not exceed the configured max (e.g., 2 parts); otherwise the message is truncated with ellipsis and the TapPass link is preserved. Given HTML email templates, When rendering, Then HTML is sanitized, inline CSS applied, images have alt text, and a visible unsubscribe link is present. Given preview mode, When a studio admin previews a template for a selected recipient and class, Then the preview matches the final rendered output and flags any unresolved variables.
Event Triggers: Upcoming, Vacancy Fills, Abandoned Confirmation, Re-Engagement
Given an upcoming class reminder rule (e.g., 24h and 2h before start), When a class is scheduled, Then reminders are enqueued at the correct local times respecting quiet hours and caps. Given a booked seat is released within 3 hours of class start and a waitlist exists, When vacancy detection runs, Then a TapPass vacancy SMS/email is sent to the top waitlisted contact with a 15-minute hold; if unclaimed, it cascades to the next without double-booking. Given a booking is started but not confirmed within 10 minutes, When abandonment is detected, Then a single TapPass reminder is sent via the preferred channel. Given a contact has had no bookings for 30 days and is opted-in, When re-engagement rules run, Then a personalized TapPass offer is sent once, respecting promotional caps.
Waitlist Auto-Promotion Paylinks
"As a waitlisted student, I want an instant paylink when a spot opens so that I can claim it quickly before someone else does."
Description

When a seat becomes available, automatically notify the next eligible waitlisted users with prioritized, expiring TapPass links and a clear hold window. Enforce first-confirmed-first-served rules, fairness (e.g., FIFO with tie-breakers), and maximum active offers per user. Cascade notifications to subsequent waitlisters if the paylink expires or is declined, and update waitlist/roster states in real time. Provide instructor-facing controls for promotion pace and capacity thresholds. Outcome: rapid, hands-off conversion of waitlists into paid bookings.

Acceptance Criteria
FIFO Promotion With Tie-Breakers and Hold Window
Given a class session has ≥1 open seat and a waitlist with N users, When auto-promotion runs, Then candidates are selected strictly by waitlist_position ascending (FIFO); if created_at timestamps are identical, the lower waitlist_entry_id is prioritized. Given promotion pace batch_size = K, When notifications are sent, Then only the top K eligible users receive TapPass links in this wave. Given a TapPass is sent, When the user receives the SMS/email, Then the message includes the explicit expiration timestamp and the remaining minutes of the hold window in the class’s local timezone. Given a TapPass has hold_window_minutes = H, When current_time ≥ sent_at + H minutes, Then the TapPass becomes invalid and cannot be used to confirm.
Max Active Offers Per User
Given max_active_offers_per_user_for_session = 1, When a user already has an active TapPass for the session, Then the system does not send another offer to that user in subsequent waves and logs skip_reason = "active_offer_exists". Given an active TapPass is confirmed, expired, or declined, When eligibility is next evaluated, Then the user’s active offer count for that session is updated within 3 seconds accordingly. Given the instructor sets max_active_offers_per_user_for_session to X (1..3), When promotion runs, Then no user receives more than X simultaneous active TapPass links for that session.
First-Confirmed-First-Served Enforcement
Given multiple active TapPass offers exist for the same session, When any recipient taps confirm and payment authorization succeeds, Then that user is added to the roster immediately and all other active offers for that session are auto-invalidated with a "seat_taken" notice within 5 seconds. Given a user taps confirm but payment authorization fails, When the attempt completes, Then the seat is not allocated and all other active offers remain valid. Given the roster reaches capacity, When any outstanding TapPass link is opened, Then it displays "class full" and cannot be used to book.
Cascading Promotions After Expiry or Decline
Given an active TapPass expires or is explicitly declined, When the cascade job runs, Then the next eligible waitlisted user(s) are notified within 60 seconds, respecting the configured batch_size. Given there are fewer waitlisted users than batch_size, When the cascade triggers, Then offers are sent only to the remaining eligible users and the wave completes without error. Given all waitlisted users have been offered and all offers expire/decline with no confirmations, When the seat remains open, Then the instructor is notified according to notification preferences.
Real-Time Waitlist and Roster Synchronization
Given any of these events occur: offer_sent, offer_expired, offer_declined, confirm_success, confirm_failure, cancellation, When viewed on the instructor dashboard or student waitlist page, Then waitlist positions and roster counts reflect the event within 3 seconds end-to-end. Given two users open their TapPass pages concurrently, When one confirms, Then the other user’s page reflects a "seat taken" state within 5 seconds without requiring a full page reload. Given audit logging is enabled, When promotions and confirmations occur, Then immutable audit entries record user_id, session_id, event_type, timestamp, prior_state, and new_state.
Instructor Promotion Pace and Threshold Controls
Given the instructor sets promotion pace batch_size = K and wave_delay_minutes = D, When seats are available, Then offers are sent in waves of K every D minutes until seats fill or the waitlist is exhausted. Given the instructor sets a start condition of at_least_open_seats = S and a last_minute_cutoff_minutes = C, When conditions are evaluated, Then auto-promotion only runs while open_seats ≥ S and never sends offers less than C minutes before class start. Given the instructor updates any of these settings, When saved, Then subsequent promotion decisions reflect the change within 1 minute and settings persist across sessions and browser refresh.
Secure, Expiring TapPass One-Tap Confirm
Given a TapPass is generated, When inspected, Then it is single-use, cryptographically signed, scoped to {user_id, session_id}, and expires at sent_at + hold_window_minutes. Given a TapPass is opened by a non-matching user or after it is used/expired/invalidated, When accessed, Then the system returns an invalid state (API: HTTP 401/403/410; UI: "Link invalid or expired") and never creates or holds a booking. Given the user has a stored payment method, When they open the TapPass, Then they can confirm with one tap and receive booking confirmation and receipt within 10 seconds; if no stored method, Then a minimal, prefilled payment form is presented and confirmation succeeds end-to-end under 90 seconds at P95.
Inventory Hold & Double-Booking Prevention
"As a student, I want the seat held when I open a paylink so that I don’t lose it to someone else while I’m confirming payment."
Description

Reserve a seat for a short, configurable hold period when a TapPass is opened, displaying a countdown to the user. Use atomic reservations (e.g., Redis locks plus DB transactions) to prevent race conditions across multiple paylinks and channels, and release the hold on timeout or failed payment. Ensure the booking operation is idempotent and only the first successful confirmation finalizes the seat; others see a friendly ‘seat taken’ or waitlist option. Log state transitions for traceability and reconciliation. Outcome: no double-bookings and a trustworthy checkout experience during high demand.

Acceptance Criteria
Seat Hold on TapPass Open
Given a class with N available seats and hold duration configured to 5 minutes And a valid, unexpired TapPass link for that class When the user opens the TapPass page Then a seat is reserved exclusively for that user for 5 minutes And public availability decreases by 1 within 1 second And a visible countdown timer displays 5:00 and decrements every second And the countdown persists across page refresh within the hold window And no payment is captured until confirmation
Hold Release on Timeout and Payment Failure
Given a seat is on hold for a user via TapPass When the countdown reaches 0 without successful payment Then the hold is released within 2 seconds And public availability increases by 1 And the user sees "Hold expired" with options to retry or join the waitlist Given a seat is on hold and the user submits payment that is declined When the processor returns a non-success status Then the hold is released within 2 seconds And the user sees a clear error message with a retry option And no booking record is finalized And no charge is captured
Idempotent Booking and Duplicate Click/Webhook Protection
Given a seat is on hold for a user When the user clicks Confirm multiple times within the hold window Then exactly one booking record is created And subsequent duplicate requests return the same booking reference with a 200 idempotent response And the user is charged exactly once Given the payment provider sends duplicate webhook events for the same transaction When the system processes the events Then no duplicate booking is created And duplicate events are acknowledged without side effects
Atomic Reservation Under Concurrent Confirmation Attempts
Given exactly one seat remains in the class And two different users have active holds via separate TapPass links When both users attempt to confirm within 100 ms of each other Then exactly one confirmation succeeds and finalizes the booking And the other attempt fails gracefully with a "Seat taken" message And the final class roster contains no duplicate attendees And retries by the losing attempt remain prevented until availability increases
Friendly Seat Taken Messaging with Waitlist Option
Given a user's confirmation attempt fails because the last seat was taken by another user When the failure response is returned Then the user sees a "Seat taken" message within 1 second with a CTA to join the waitlist And selecting the waitlist CTA adds the user to the correct class waitlist And the user receives SMS/email confirmation of waitlist status And any existing hold for the user is immediately released
Reservation Lock TTL and Consistency Across Services
Given the hold duration is configured to 5 minutes When a reservation hold is created Then the reservation lock TTL equals 5 minutes And the lock is automatically released at TTL expiry even if services restart And additional holds for the last remaining seat are prevented until the lock expires And creating a second hold for the same user and class before expiry is rejected And system metrics expose counts of active holds, confirmations, and expirations
State Transition Logging and Audit Trail
Given a TapPass flow from link open through confirmation or expiry When any state change occurs (opened, hold_created, payment_submitted, payment_succeeded, payment_failed, hold_released, booking_confirmed) Then an audit log entry is written with timestamp, correlation_id, user (or anonymous token), class_id, previous_state, and new_state And log entries can be queried by correlation_id to reconstruct the ordered sequence And each transition is recorded once (no duplicates) with monotonic timestamps And a reconciliation report over a time range lists counts of holds created, expired, and confirmed that match database records within 0.1%
Quick Rebook Paylinks
"As a returning student, I want a one-tap link to rebook my next class so that I can maintain my routine without searching the schedule."
Description

Enable generation of TapPass links that pre-select the next logical session or a preferred schedule series for a student, using rules like same day/time next week, same instructor, or recommended progression. Include membership/credit eligibility checks, pricing application, and calendar-friendly timings. Trigger after attendance, successful completion, or instructor prompts, and send via preferred channel with clear one-tap confirm. Provide fallback browsing for alternate dates if the suggested slot is unavailable. Outcome: increased repeat bookings with near-zero friction.

Acceptance Criteria
Auto-send next-week same-slot quick rebook after attendance
Given a student is marked Attended for a class instance and the class has a recurring schedule When the attendance event is saved Then the system computes the next logical session using the rule “same day and start time next week” in the student’s timezone, skipping blackout dates and instructor time-off, and limiting search to the next 8 weeks And the suggested session preserves location and format (in-person/hybrid/online) and prefers the same instructor when available And the suggestion is only created if the target session has available capacity and is bookable per studio rules And a Quick Rebook suggestion record is created with metadata (classId, sessionId, rule, generatedAt) within 2 minutes of attendance save And a TapPass link is generated referencing the suggested session with a default expiry of 72 hours and marked single-use And an event QuickRebookSuggested is logged with studentId, classId, sessionId, rule, channel-intent
Instructor-prompted quick rebook for same-instructor series
Given an instructor opens today’s roster and selects Prompt Rebook for a student When the instructor confirms the rule “same instructor recommended progression” Then the system suggests the next session in the defined series or progression map taught by the same instructor within the next 6 weeks And if no same-instructor session exists, the system suggests the same class type with closest time slot only if cross-instructor rebook is enabled for that class And the TapPass link is generated in under 5 seconds and associated to the instructor-initiated campaign type And the suggestion includes an optional note from the instructor rendered in the message template And audit logs capture instructorId, studentId, rule, suggestedSessionId
Membership/credit eligibility and pricing application on quick rebook
Given a student has one or more active products (membership, class pack, credits) and may have a saved payment method When the student taps the TapPass link Then eligibility is validated against the target session date/time and product rules (credit balance, blackout classes, grace windows, membership validity) And if eligible credit exists, the one-tap confirm applies the credit and sets price to $0 at confirm time And if no eligible credit exists but a saved payment method is on file, the one-tap confirm charges the correct price (including taxes/fees/discounts) using the student’s default method and issues a receipt And if payment requires SCA/3DS, the flow seamlessly prompts for authentication and completes the booking upon success, or gracefully returns to a payable state upon failure without creating a booking And all pricing and deductions occur atomically with booking creation and are reversed automatically if booking creation fails
Secure expiring TapPass and one-tap confirm flow
Given a student receives a TapPass link for a suggested session When the link is opened before expiry Then the system validates a signed, tamper-evident token (HMAC or equivalent), student-session binding, and single-use status And on one-tap confirm, if capacity and eligibility checks pass, a booking is created, confirmation page is shown, and email/SMS confirmation is sent within 2 seconds p95 And repeat taps or duplicate opens return the existing booking confirmation without creating duplicates (idempotency key enforced) And if the token is expired, revoked, or invalid, the user is redirected to the fallback browsing experience with a non-technical message And no personally identifiable information is encoded in the link; tokens expire by default in 72 hours and can be overridden per studio policy
Fallback browsing when suggested slot is unavailable
Given a student opens a TapPass link and the suggested session is full, canceled, or no longer valid When the system detects unavailability or rule failure Then the student is redirected to a filtered class browser showing the same class type, location, and instructor (if applicable) with the next 10 upcoming dates/times And the student can select an alternative date in one click and confirm in one additional tap using the same eligibility and payment rules And if no alternatives exist within the next 8 weeks, the interface offers to join the waitlist or browse related classes And analytics track fallback_opened and fallback_converted events And the experience preserves timezone-correct times and any applicable pricing or credits
Conflict and double-booking prevention during quick rebook
Given a student opens a TapPass link When they confirm the rebook Then the system validates there is no time overlap with the student’s existing bookings (including buffer rules) and that the class capacity will not be exceeded And if a conflict exists, the student is shown a clear message with options to view alternatives; no booking is created and no charges or credit deductions occur And booking creation, capacity decrement, and payment/credit deduction occur in a single atomic transaction with row-level locking to prevent oversell And concurrent confirmations on the last remaining seat result in exactly one successful booking and a graceful Sold Out message for others
Preferred channel delivery and messaging clarity
Given a student has a recorded communication preference (SMS, Email, or Both) and valid contact info When a quick rebook suggestion is generated Then the message is sent via the preferred channel within 2 minutes (p95), with automatic fallback to the alternate channel if a bounce or hard failure occurs And the message includes class name, date, local time with timezone abbreviation, instructor, venue, price/credit usage summary, CTA label “Confirm in 1 tap”, and opt-out instructions (STOP for SMS / unsubscribe link for email) And messages respect DND/quiet hours policies and opt-outs; no message is sent outside allowed windows And open and conversion events are tracked and attributed to the delivery channel with campaign identifiers
Admin Controls & Performance Analytics
"As a studio owner, I want to configure paylink reminders and see conversion metrics so that I can optimize attendance and prove ROI."
Description

Offer a dashboard where studios configure reminder schedules, TapPass expiry/hold durations, templates, channels, quiet hours, and targeting rules. Provide preview/test-send tools, role-based access, and brand customization (logos, colors, sender IDs, link domains). Deliver analytics on sends, opens, clicks, paylink redemption, conversion, revenue uplift, fill rate, and no-show reduction with cohort and A/B comparisons. Include export APIs, data retention controls, GDPR/CCPA compliance, and audit logs for link lifecycle events. Outcome: studios can tune paylink strategy and prove impact on attendance and revenue.

Acceptance Criteria
Configure Reminder Schedules, Quiet Hours, Channels, and Targeting
Given a studio admin with permission "Reminders:Configure" When they create reminder rules (e.g., T-24h, T-3h, T-30m) and select channels per rule (SMS, Email) And they set quiet hours (e.g., 21:00–08:00) with defer policy "send at 08:00" And they add targeting rules (e.g., unpaid reservations only, first-time attendees, waitlist-promoted) Then the UI validates conflicts and consent (no rule causes >3 messages per reservation, channels require user opt-in) And the configuration is versioned with an effective-from timestamp and saved successfully And a preview shows the next 7 days’ projected send counts by class/location/channel And a test-send to a verified contact returns within 10 seconds and includes correct merge fields and a valid TapPass link And reminders queued during quiet hours are deferred and delivered at the configured resume time
TapPass Expiry and Hold Duration Settings with Audit Trail
Given expiry duration (e.g., 30 minutes) and seat hold duration (e.g., 10 minutes) are configured When a reminder containing a TapPass is sent Then the link expires exactly at send_time + expiry_duration and returns an "expired" page if opened after expiry And the first "Confirm" click applies a seat hold immediately and auto-releases precisely at hold_duration if payment is not completed And a redeemed link cannot be reused or replayed (subsequent attempts show "already redeemed") And all lifecycle events (generated, delivered, opened, clicked, confirmed, paid, expired, hold_set, hold_released) are recorded with ISO timestamps, channel, and user/session in an immutable audit log And multiple links for the same reservation are uniquely tokenized and independently auditable
Brand Customization and Sender Identity Verification
Given a studio uploads a logo and sets brand colors and typography defaults And configures sender IDs (registered SMS sender/number and verified email domain) and a branded link domain (CNAME) When previewing SMS and email templates Then the preview and test-send render brand assets correctly, apply configured colors, and pass WCAG AA contrast checks And links resolve under the branded domain via HTTPS with a valid certificate (no mixed content) and redirect to the one-tap confirm page And email passes SPF/DKIM/DMARC alignment; SMS uses the registered sender; if not verified, the system blocks sending and surfaces actionable errors And fallbacks (default domain/sender) are applied only when configured and recorded in the audit log
Role-Based Access and Permissions Enforcement
Given roles Admin, Manager, Instructor, and Analyst with defined permissions When a user without "Reminders:Configure" attempts to modify schedules, templates, or expiry settings Then the action is blocked with HTTP 403/UI error and an audit entry is recorded (actor, action, resource, timestamp) When an Analyst accesses Analytics Then KPIs are viewable but configuration pages and PII (phone/email bodies) are hidden or masked And permission changes take effect within 1 minute and are reflected in access tokens/sessions upon refresh And all settings edits show who/when/what changed with before/after diffs
Analytics KPI Accuracy and A/B Cohort Comparison
Given reminders have been running for at least 7 days When viewing Analytics by dimension (date, class, instructor, location, channel, template, cohort, A/B variant) Then KPIs display: sends, delivered, opens, clicks, unique paylink redemptions, conversions (paid), revenue uplift vs control, fill rate, no-show reduction, with visible metric definitions And data freshness is ≤15 minutes; dashboard totals reconcile with the export within ±1% for the same filters and time range And an A/B test with a configured holdout/control computes uplift and shows a significance flag when p < 0.05 and sample size ≥ configured minimum And filters and timezones apply consistently across all charts and tables; CSV download reflects active filters
Export API and Data Retention (GDPR/CCPA) Compliance
Given an API key with scope "Analytics:Export" When calling the exports endpoint with date range, dimensions, and metrics Then the API responds within 60 seconds for up to 100k rows or returns an async job handle for larger requests, with paginated results and a documented schema And opt-outs/consent states are respected (no messages sent to opted-out users; analytics flags opt-out events) When a data subject deletion request is executed Then personal data in reminders, analytics, and message bodies is deleted or irrevocably pseudonymized within 30 days, while audit logs retain non-PII event metadata And admin-configured retention periods purge message content and event data on schedule, with purge jobs logged and verifiable by record counts

Smart Expiry

Automatically adjusts each booking’s join-link validity window to open just before class and expire shortly after, with time zone awareness and class-type rules. Prevents early link leaks and late access issues so attendees join at the right moment without confusion.

Requirements

Dynamic Validity Window Engine
"As an attendee, I want my join link to become active shortly before class and expire soon after so that I can join at the right time without confusion or unauthorized reuse."
Description

Implement a backend service that computes and enforces open/expire times for each booking’s access link based on scheduled class start/end times and configurable offsets (e.g., open 10 minutes before, expire 15 minutes after). Store validity windows per booking (valid_from, valid_to) and reevaluate upon schedule changes. Enforce the window at the API layer and in link resolution so links cannot be used outside the active interval. Provide configuration at account and class levels, with sensible defaults, and ensure high reliability under peak traffic. Expected outcome: links activate just before class and close shortly after, reducing early access and post-class misuse.

Acceptance Criteria
Per-Booking Validity Window Computation on Creation
Given an account default of open_before=10m and expire_after=15m, and a class scheduled 10:00–11:00 in IANA time zone 'America/New_York' with no class-level override When a booking transitions to Confirmed Then valid_from = class_start - 10m (localized to the class time zone) and valid_to = class_end + 15m And valid_from/valid_to are persisted per booking, retrievable via GET /bookings/{id}, non-null, and immutable except via schedule/config changes And timestamps are stored in UTC with the class time zone id retained; precision ≥ 1 second; no rounding beyond 1s
Access Enforcement at API and Link Resolver
Given a booking link is requested before valid_from When resolving the link Then respond 403 LINK_NOT_ACTIVE and do not redirect Given a booking link is requested within [valid_from, valid_to] When resolving the link Then respond 302 to join_url and record an access event with timestamp and booking_id Given a booking link is requested after valid_to When resolving the link Then respond 410 LINK_EXPIRED and do not redirect And all API endpoints that gate access by booking_id enforce the same window semantics And a clock-skew tolerance of ±60s is applied consistently; attempts outside tolerance are denied And CDN/cache respects per-booking TTL ≤ 5s and never serves a redirect outside [valid_from, valid_to]
Automatic Recalculation on Schedule Changes
Given class start and/or end times are updated When the change is saved Then all non-canceled bookings recompute valid_from/valid_to within 30s And if a class is canceled Then all associated booking links expire immediately (valid_to set to now) and further access returns 410 LINK_EXPIRED And if a booking has lock_window=true override Then its window is not modified by schedule changes And an audit log entry is recorded per booking with old/new values and change cause (schedule_update|cancel|config_update) And re-computation is idempotent and resilient to retries, yielding exactly one final state per booking
Time Zone and DST Correctness
Given a class time zone is stored as an IANA identifier (e.g., America/New_York) When computing windows on DST start day where 02:00–03:00 is skipped and class start is set to 02:30 local Then the engine normalizes start to the next valid wall time (03:30 local) and computes valid_from/open_before and valid_to/expire_after from that normalized time When computing windows on DST end day with an ambiguous time (e.g., start 01:30) Then the engine resolves using the stored offset for the scheduled occurrence and computes windows accordingly And no computation yields invalid/NaT timestamps; unit tests cover spring-forward and fall-back cases with expected valid_from/valid_to assertions
Configuration Precedence and Validation
Given system default offsets (open_before=10m, expire_after=15m), account-level override (5m, 20m), class-level override (0m, 30m), and class-type rule 'Online' min_open_before=2m When computing a booking for an 'Online' class with a class-level override present Then precedence is class-level > class-type rule > account-level > system default, yielding (0m, 30m) but honoring min_open_before by clamping to 2m if override < 2m And offset values must be integers in minutes within [0, 120]; invalid configs are rejected with 400 and do not alter existing bookings And configuration changes affect only future computations and any re-evaluations triggered by explicit schedule/config change events
Peak Traffic Performance and Reliability
Given 500 RPS sustained link resolutions with 10k concurrent active windows and cache hit rate ≥ 85% When enforcing validity windows under load Then p95 latency ≤ 150ms and p99 ≤ 400ms for link resolution endpoints And ≥ 99.95% of requests are enforced correctly with no false accepts beyond the ±60s skew tolerance during a 60-minute soak test And zero data loss of valid_from/valid_to during node restarts or deploys; replication lag ≤ 1s does not produce incorrect allows And on cache outage the system degrades safely, enforcing from the source of truth with p95 ≤ 600ms
Waitlist Promotion and Reschedule Handling
Given a learner is promoted from waitlist to confirmed When promotion occurs Then compute and persist a new validity window based on the current schedule and configuration And any previous booking link for the same learner and class instance is invalidated immediately (returns 410) When a confirmed booking is rescheduled to a different class time Then the old link expires immediately and a new link resolves only within the new window And all changes propagate to link resolution within 30s; no window overlaps allow access to both old and new sessions
Global Time Zone & DST Safety
"As a global attendee, I want the link timing to respect my local time zone and DST so that I never miss class due to time conversion errors."
Description

Normalize all class schedules to UTC and use IANA time zones to compute per-booking validity windows with full daylight-saving awareness. Ensure windows display and function correctly across attendee locales, including edge cases like DST transitions, windows spanning midnight, and cross-border classes. Provide consistent local-time messaging in UI, email, and SMS. Include automated tests for major time zones and DST boundaries to prevent regressions.

Acceptance Criteria
UTC Normalization & IANA Zone Enforcement
Given a class is scheduled using an IANA time zone (e.g., Europe/Paris) with class-type rules (open N minutes before start, expire M minutes after start) When a booking is created and the validity window is computed Then the class start and both validity window bounds are stored in UTC with the original IANA zone id recorded And fixed-offset time zones (e.g., UTC+01:00) are rejected at scheduling time with a validation error And all API responses include both the UTC instants and the IANA zone id for start/open/expiry And the join-link activation/inactivation logic uses the stored UTC instants and is invariant to the viewer’s device or locale time settings
DST Spring Forward Window Correctness (Europe/Berlin)
Given a class scheduled at 03:05 on the local day of DST start in Europe/Berlin with rules open 10 minutes before and expire 15 minutes after start When the pre-class open time (03:05 − 10 minutes) falls into the DST spring gap (a non-existent local time) Then the join-link open time is set to the first valid local instant after the gap and its exact UTC instant is persisted And UI, email, and SMS all display the same local open and expiry times with the correct zone abbreviation (e.g., CEST) and without contradictory times And automated tests assert that the open time is not earlier than the first valid post-gap instant and that activation matches the persisted UTC instant
DST Fall Back Ambiguity Resolution (America/New_York)
Given two classes scheduled at 01:30 on the local day of DST end in America/New_York where one is explicitly resolved to the first occurrence (EDT) and the other to the second occurrence (EST) When bookings are created with rules open 10 minutes before and expire 15 minutes after start Then each class’s validity window open/expire are computed from their resolved UTC instants (fold-aware) with no cross-assignment And UI, email, and SMS display the correct local offset/abbreviation (EDT vs EST) for each class consistently And automated tests verify both folds produce distinct UTC instants and correct activation/inactivation in real time
Validity Window Spanning Midnight
Given a class scheduled at 00:05 local time with rules open 15 minutes before and expire 10 minutes after start When the computed open time is on the previous local calendar day and the expiry is on the class day Then the join-link activates at the previous local day’s time and deactivates at the correct local time on the class day And all surfaces (UI, email, SMS) display the correct local dates and times including day-of-week to avoid ambiguity And automated tests assert correct date roll-over and matching UTC instants for open/expiry across attendee locales
Cross-Zone Attendee Messaging Consistency
Given a class scheduled in the instructor’s IANA zone (e.g., Europe/London) and an attendee with profile/browser time zone America/Los_Angeles When the system renders the booking confirmation, reminder email, and SMS Then all surfaces display the attendee-local open and expiry times with explicit zone labels/abbreviations and a link to view in the class’s zone And the join-link activation/inactivation occurs according to the UTC instants derived from the class zone, independent of the attendee’s zone And no surface shows conflicting times; automated UI and content tests assert equality of the displayed instants across channels
Automated Regression Suite for Time Zones & DST Boundaries
Given the Smart Expiry service When the test suite runs in CI Then it includes parameterized tests for at least: America/New_York, Europe/London, Europe/Berlin, Asia/Tokyo, Australia/Sydney, Pacific/Auckland, and Africa/Johannesburg And for each zone it tests non-DST days, DST start day, and DST end day (where applicable) for various N/M rule values and classes near midnight And tests assert: correct UTC storage; correct open/expiry activation in a time-mocked clock; consistent formatting in UI/email/SMS renderers; and no off-by-one-hour errors And the pipeline blocks merges on any failure and records code coverage ≥ 80% for time computation modules
Class-Type Rules & Instance Overrides
"As an instructor or admin, I want to set default validity windows by class type and override them per class so that the policy matches each format’s operational needs."
Description

Enable default validity policies by class type (virtual, in-person, hybrid) and allow per-class-instance overrides. Support distinct windows for each modality (e.g., virtual: open 10 min prior; hybrid: virtual link opens 5 min prior, in-person QR opens at start). Provide admin UI to set account-level defaults, class-template rules, and one-off overrides with preview of resulting windows. Persist audit notes for overrides to aid support.

Acceptance Criteria
Account-Level Default Windows by Class Type
Given I am an account admin on Smart Expiry settings When I set default windows: Virtual open=-10m expire=+15m; In-person QR open=0m expire=+5m; Hybrid Virtual open=-5m expire=+10m; Hybrid In-person QR open=0m expire=+5m and click Save Then the values are validated to ensure each expire offset is greater than its corresponding open offset and all offsets are integers between -1440 and +1440 minutes And the settings are persisted and retrievable on reload And new class templates created thereafter pre-populate with these defaults
Class-Template Rules Override Account Defaults With Preview
Given a class template using account defaults When I toggle "Custom validity windows" and enter Virtual open=-15m expire=+20m and In-person QR open=0m expire=+10m Then the account defaults are not applied to this template And the template preview shows computed open and expire timestamps for a selected example session date/time and time zone And classes scheduled from this template inherit these template windows by default
Per-Class-Instance Override With Mandatory Audit Note
Given a scheduled class instance created from a template When I open Smart Expiry for this instance, enable "Override for this class only", change Virtual open from -15m to -5m, and enter an audit note "Coach requested tighter window" Then Save is enabled only if an audit note of at least 5 characters is present And upon saving, the instance stores the override offsets, the audit note, the actor, timestamp, previous values, and new values And future instances from the template remain unaffected
Hybrid Classes Have Distinct Virtual and In-Person Windows
Given a Hybrid class instance with template windows Virtual open=-5m expire=+10m and In-person QR open=0m expire=+5m When the clock is 7 minutes before start Then the virtual join link is not yet valid And the in-person QR code is not yet valid When the clock reaches 5 minutes before start Then the virtual join link becomes valid while the in-person QR remains invalid until start When the clock reaches class start Then the in-person QR becomes valid When the clock is 11 minutes after start Then the virtual link is expired And when the clock is 6 minutes after start Then the in-person QR is expired
Time Zone Awareness in Windows and Preview
Given the class template time zone is America/Los_Angeles and class start is 10:00 AM PT When the template sets Virtual open=-10m expire=+15m Then the preview shows open at 9:50 AM PT and expire at 10:15 AM PT And an attendee in America/New_York sees the window in their local time as 12:50 PM ET to 1:15 PM ET And access enforcement uses the class time zone to determine the absolute UTC window
Reschedule Recomputes Windows
Given a scheduled class instance with Virtual open=-10m expire=+15m and start at 10:00 AM local When I reschedule the instance to start at 11:30 AM local Then the computed absolute open moves to 11:20 AM local and expire to 11:45 AM local And the preview and any admin-visible window timestamps update immediately And access enforcement honors the new times
Access Enforcement Prevents Early and Late Access
Given a virtual class instance with open=-10m expire=+15m When a user attempts to access the join link 11 minutes before start Then access is denied with a message indicating when access opens When a user attempts to access at 5 minutes before start Then access is granted When a user attempts to access 16 minutes after start Then access is denied with a message indicating the link has expired
Secure Tokenized Access Links & Anti‑Sharing Controls
"As an instructor or admin, I want secure, unique, non-shareable access links so that only valid bookings can join and leaked links don’t allow unauthorized access."
Description

Issue per-booking, signed, time-scoped tokens (e.g., JWT/HMAC) embedded in access links, validating class ID, booking ID, and validity window. Enforce single-booking access with optional constraints such as one active session at a time, device/IP heuristics, and rate limiting to deter sharing. Invalidate tokens on cancellation/refund and rotate on reissue. Provide tamper-proof error responses and safe fallbacks that never disclose class details when invalid or expired.

Acceptance Criteria
Per‑Booking Signed Token Issuance
Given a confirmed booking for a scheduled class When the system generates an access link for that booking Then the link contains a signed token whose claims include booking_id, class_id, valid_from (UTC), valid_to (UTC), and a unique jti And the token is signed using the configured algorithm (HS256 or RS256) and validates against the current server-side secret/key And the token is rejected with 403 if any claim is missing, malformed, or the signature is invalid And the token's valid_from and valid_to exactly match the computed Smart Expiry window for that booking
Time‑Scoped Validity Aligned with Smart Expiry
Given Smart Expiry is configured with open_offset_minutes=10 and close_offset_minutes=15 for the class type And a class is scheduled in its class timezone When a token is presented before valid_from Then access is denied with HTTP 403 and a generic message that reveals no class details When a token is presented between valid_from and valid_to (inclusive) Then access is granted (HTTP 200) and the join endpoint is returned When a token is presented after valid_to Then access is denied with HTTP 410 and a generic message that reveals no class details And valid_from/valid_to are computed using the class's timezone rules (including DST) and enforced in UTC without off-by-one-minute errors
Single Active Session Enforcement
Given one-active-session policy is enabled for the class type And an attendee has an active session established using their booking token When a second session using the same booking token attempts to connect from a different device or browser Then the second session is blocked with HTTP 409 and a generic message, while the first session remains active And once the first session ends or has been idle for 2 minutes, a new session using the same token is allowed
Device/IP Heuristics and Rate Limiting
Given anti-sharing heuristics are set to Standard When the same token is presented from more than 3 distinct device fingerprints within 30 minutes Then subsequent attempts are blocked with HTTP 403 and a generic message When the same token is validated more than 10 times by the same IP within 60 seconds Then further validations from that IP for that token are rate-limited with HTTP 429 for 5 minutes And all blocks and rate limits are recorded in audit logs with timestamp, token jti, and reason
Cancellation/Refund Revokes Access Immediately
Given a booking with an issued token is canceled or refunded When the cancellation/refund event is processed Then all tokens for that booking are invalidated within 60 seconds And any active sessions established with those tokens are terminated within 30 seconds And subsequent access attempts with those tokens return HTTP 410 with a generic message revealing no class details
Token Rotation on Link Reissue
Given a user requests a new access link for an existing confirmed booking When the system issues a new link Then a new token with a new jti is generated and the previous tokens for that booking are revoked immediately And the new token inherits the remaining Smart Expiry window (or recomputed window if not yet open) per configuration And attempts to use any revoked token return HTTP 410 with a generic message
Tamper‑Proof Error Responses and Safe Fallbacks
Given a token is missing, expired, invalid, or does not belong to the specified class/booking When the token is validated Then the API responds with appropriate status codes: 401 (missing), 403 (invalid/signature/claim mismatch), or 410 (expired/revoked) And the response body and any rendered fallback page display a generic message that does not include class name, time, location, instructor, or booking identifiers And no stack traces, token contents, or server internals are exposed in the response And a support link and a "Request new link" action are provided when permitted by configuration
Edge Case Automation: Reschedules, Late Bookings, Waitlist Promotions
"As an operations manager, I want link windows to auto-adjust for reschedules, late bookings, and waitlist promotions so that attendees always have timely access without manual intervention."
Description

Automatically recalculate validity windows when classes are rescheduled, when attendees book after the window would normally open, or when waitlisted attendees are promoted shortly before start time. Ensure immediate issuance or extension of links as needed, with safeguards against stale links. Handle instructor substitutions and class overruns with rules-based adjustments and provide event hooks for downstream systems.

Acceptance Criteria
Reschedule: Recalculate and Refresh All Join-Link Windows
Given a class with active bookings and existing join-link windows When the class start time is rescheduled to a new time T' (any time zone) Then open and expire times for all attendee links are recalculated from T' per class-type rules within 60 seconds Given prior links exist When recalculation completes Then previously issued links that no longer align are invalidated within 60 seconds and return "link_replaced" if visited Given multiple reschedules occur within 5 minutes When the final edit is saved Then only the last-saved schedule determines link windows and duplicate notifications/hooks are suppressed via idempotency Given the reschedule crosses a DST boundary When recalculating windows Then open/expire use UTC times for T' and do not shift by the DST delta Given attendees have different local time zones When presenting times Then attendee-facing times reflect their local zone while enforcement uses UTC
Late Booking: Immediate Issuance and Correct Window
Given now is on or after the configured open-window time relative to class start When a new booking is confirmed Then a join link is issued within 5 seconds and is immediately usable Given a class-type expiration offset E When issuing a late-booking link Then the expiration is set to class end time plus E and never earlier than now Given transient issuance failures When they occur Then retries happen up to 3 times over 30 seconds; after that an error is surfaced and no duplicate links are created Given attendee communications are enabled When issuance succeeds Then confirmation is sent via configured channels with correct local start time and validity window Given a booking is attempted after class end time When processing Then issuance is blocked and a "class_ended" error is returned
Waitlist Promotion Near Start: Instant Access Without Stale Links
Given an attendee on the waitlist When promoted at or within the configured open-window threshold before start (or after the window has opened) Then a join link is generated within 5 seconds and is immediately open Given the attendee previously received any tentative access token When promotion occurs Then prior tokens are revoked within 30 seconds and visiting them returns "link_replaced" Given promotion occurs within the configured minimum remaining time before class end When processing Then promotion is denied with reason "too_late" and no link is issued Given capacity constraints When promotion triggers link issuance Then the roster count does not exceed capacity and no overbooking occurs
Instructor Substitution: Preserve or Replace Links per Meeting Details
Given a substitution changes only the instructor identity and not the meeting join details When the change is saved Then attendee link tokens are not regenerated and all existing links remain valid Given a substitution changes the meeting join location/provider (e.g., room ID or URL) When the change is saved Then all attendee links are regenerated within 60 seconds, previous tokens are invalidated, and old links return "link_replaced" Given start/end times are unchanged When regenerating links due to substitution Then open and expire windows are preserved per class-type rules Given downstream integrations are configured When substitution is saved Then events "class.updated.instructor" (identity change) and/or "class.updated.meeting" (join details change) are emitted within 30 seconds with correlation IDs
Class Overrun: Extend Expiry Without Allowing New Entrants
Given an active class approaches scheduled end time When the instructor flags an overrun or the system detects overrun up to the configured cap Then attendee link expirations extend accordingly within 30 seconds Given expirations are extended due to overrun When enforcing access Then only attendees on the roster at scheduled end retain access; new bookings and waitlist promotions remain blocked after the start cutoff Given the overrun exceeds the configured cap When enforcing Then links expire at the cap limit and no further extension occurs Given class-type overrun rules differ When applying extensions Then the configured per-class-type behaviors are respected
Event Hooks: Accurate, Timely, and Idempotent Emissions
Given any recalculation or regeneration due to reschedule, late booking, waitlist promotion, instructor substitution, or overrun When processed Then an event is emitted within 30 seconds containing type, reason, booking/class IDs, prior and new open/expire timestamps (UTC), and a correlation ID Given retries or duplicate processing When emitting events Then idempotency keys ensure at-most-once delivery per change or duplicates carry the same event_id and are marked "duplicate": true Given webhook receivers return non-2xx When delivering events Then retries occur with exponential backoff for up to 24 hours before marking failed with audit log entry Given security requirements When delivering events Then requests are HMAC-signed with tenant secret and include a timestamp, and signatures older than 5 minutes are rejected
Link State Messaging & Notifications Integration
"As an attendee, I want clear messages and reminders indicating when my link will activate or why it’s expired so that I know exactly what to do at any moment."
Description

Expose clear link-state messaging across booking pages and notifications: countdown and local activation time before open, friendly guardrail message when not yet active, and guidance on what to do post-expiry. Integrate with email/SMS so reminders include links that activate at the correct time and display the activation time if tapped early. Provide real-time status on the attendee portal and consistent error codes for support diagnostics.

Acceptance Criteria
Booking Page Pre-Activation Countdown and Guardrail
Given an attendee opens their booking page before the join-link activation window When the page loads Then it displays the message "Join link activates at {local_time}" using the attendee’s current time zone and a live second-level countdown And the Join action is disabled, labeled "Not yet active", and includes a friendly guardrail explanation with aria-disabled=true And the countdown remains accurate without page refresh by syncing to server time and tolerates up to ±2 minutes of device clock drift And the page shows the time zone abbreviation with a tooltip clarifying conversion from class time And analytics event link_state_viewed is emitted with state=pre_active and includes class_id and booking_id
Early Tap on Reminder Link Prior to Activation
Given a recipient taps the join link in an email or SMS reminder before the activation window When the landing page opens Then it shows the local activation time and a live countdown instead of allowing access And a user-friendly message explains that access will open automatically at activation, with a single primary CTA to "Refresh at activation" And the email/SMS content includes the text "Join link activates at {recipient_local_time}" generated at send time using the recipient’s time zone And server-side validation prevents access regardless of device clock changes and responds with error code LNK-001 (NotYetActive) in telemetry And UTM/tracking parameters are preserved without breaking link-state logic and are logged with link_state_viewed
Real-Time Activation State Change at Window Open
Given the activation window start time is reached When the server time crosses the threshold Then the join action becomes enabled on booking pages and attendee portal within 5 seconds And any open pages automatically transition from countdown to "Join now" without manual refresh And the state is consistent across devices and channels (booking page, portal, email deep link) with no stale cache responses And analytics event link_state_changed is emitted with from_state=pre_active and to_state=active And access attempts prior to activation are denied and after activation are permitted per class-type rules
Post-Expiry Messaging and Next-Step Guidance
Given the expiry window has elapsed for a booking When an attendee opens the link Then the page does not expose the join action and displays a clear "Link expired" message And it provides next-step guidance per class configuration (e.g., contact host, request recording if enabled, rebook, join waitlist) with working links And server returns standardized error code LNK-002 (Expired) in logs/telemetry while showing friendly copy to the user And the attendee portal marks the session as Expired and removes active join controls And analytics event link_state_viewed is emitted with state=expired
Attendee Portal Real-Time Link State Badges
Given an attendee views their portal with upcoming and current classes When link states are evaluated server-side Then each class tile shows one of: Not Yet Active (with local activation time), Active (with remaining time), or Expired (with expired timestamp) And badge states auto-refresh within 5 seconds via websocket or polling without full page reload And screen reader users receive state announcements when a status changes And time zones on all timestamps reflect the attendee’s selected local time zone with an option to view class time zone And filtering/sorting by state works and is accurate to within 1 second of server time
Consistent Error Codes and Support Diagnostics
Given any link access results in a non-active state or error When the system renders the user-facing message Then a stable, documented machine-readable code is attached in telemetry and page metadata (e.g., data-error-code), chosen from LNK-001 NotYetActive, LNK-002 Expired, LNK-003 InvalidBooking, LNK-004 PermissionDenied, LNK-005 TimeWindowNotConfigured And the user-facing copy is friendly and does not expose raw codes unless support mode is enabled And all errors log correlation_id, booking_id, class_id, and state with PII minimized and compliant with regional data policies And support can reproduce the state from logs using the correlation_id within 60 days retention And error code usage appears consistently across booking page, attendee portal, email deep link landings, and API responses
Class-Type Rules, Time Zone, and Reschedule Edge Cases
Given class-type rules define custom activation/expiry windows and delivery mode (online, hybrid, in-person) When a class is in-person or hybrid with no join link required Then booking pages and reminders omit the join action and instead show venue details while still showing schedule time And when a class is rescheduled after reminders were sent, the landing page reflects the new activation time immediately and shows a prominent Rescheduled badge And daylight saving transitions and non-hour offsets are handled correctly so local activation times remain accurate And if the attendee changes their profile time zone, all future views recalculate activation times accordingly And waitlisted or unpaid bookings never show an active join state and surface code LNK-004 PermissionDenied with friendly payment/waitlist guidance

Device Lock

Binds a join link to the attendee’s first verified device. If the link is opened elsewhere, ClassTap triggers a quick step-up check or blocks access based on your policy. Stops link forwarding while still allowing legitimate device changes with a tap-to-verify flow.

Requirements

First-Device Binding Fingerprint
"As an attendee, I want my join link to work seamlessly on my first device so that I can access class without extra steps and prevent others from using my link."
Description

Bind each attendee’s join link to the first verified device by generating a privacy-respecting device fingerprint at first successful access (post identity check) and associating it server-side with the attendee’s session/token. Support web, iOS, and Android with resilient matching that tolerates minor fingerprint drift (browser/version updates) while rejecting materially different devices. Store only hashed/rotated identifiers; avoid prohibited tracking techniques and third-party cookies. Enforce binding during the event’s access window, with configurable pre-class grace periods. Seamlessly integrates with ClassTap’s booking records and reminder links so the initial tap from SMS/email establishes the device without added steps. Handles incognito/private modes gracefully with a fallback prompt to persist a lightweight key where permitted.

Acceptance Criteria
Auto-Bind on First Verified Tap from Reminder Link
Given an attendee opens a valid reminder/join link and passes the configured identity check When it is their first successful access on a device Then the system generates a privacy-respecting device fingerprint and binds it server-side to the attendee's session/token within 500 ms And Then subsequent opens from the same device within the event access window succeed without additional prompts And Then the binding event is recorded with timestamp, event ID, booking ID, and a hashed device identifier; no raw device identifiers are stored
Cross-Platform Fingerprint Generation & Matching (Web/iOS/Android)
Given Web (Chrome, Safari, Firefox, Edge), iOS, and Android clients When first verified access occurs Then a device fingerprint/key is generated using first-party storage only (no third-party cookies) and persisted via: Web = first-party storage, iOS = Keychain, Android = Keystore And Then the same device on each platform is recognized on subsequent opens with ≥95% success across the supported matrix in QA tests And Then if persistence fails on a platform, a step-up verification flow is offered rather than silently allowing access
Tolerant Matching for Minor Fingerprint Drift
Given the same device has minor changes (e.g., browser minor version, OS patch, IP change, timezone change ≤1 hour) When the attendee reopens the join link Then a similarity score ≥0.85 results in an automatic match with no step-up required And Then similarity score <0.85 triggers policy action as configured (step-up or block) And Then drift factors contributing to the score are logged for analytics without storing PII
Block or Step-Up on Materially Different Device
Given a join link is opened on a device whose similarity score is <0.6 to the bound device When the policy is set to "step-up" Then a one-time verification is required via 6-digit code or tap-to-verify link sent to the booking contact, valid for 3 minutes and up to 3 attempts And Then on successful verification, access is granted and per policy either rebinds to the new device or grants one-time access only When the policy is set to "block" Then access is denied with a clear error and support link, the attempt is logged, and no event content is revealed And Then repeated failed attempts are rate-limited to a maximum of 5 per 10 minutes per booking
Incognito/Private Mode Fallback Key Persistence
Given the join link is opened in a private/incognito context that restricts persistence When first verified access occurs Then the user is shown a single-screen prompt to allow storing a lightweight first-party key (single tap to continue) If the user consents or storage is permitted Then the key is stored and subsequent opens in the same context recognize the device If the user declines or storage is not permitted Then a session-scoped key is issued, initial access proceeds, and subsequent opens require step-up verification And Then initial access is not blocked solely due to private/incognito mode
Configurable Access Window and Pre-Class Grace Enforcement
Given an event with an access window (start/end) and a pre-class grace period in minutes When a user binds before the start but within the grace period Then the device binding is created but content access is gated until the start time When access occurs after the end time plus the configured grace Then access is denied regardless of device match And Then changes to event times take effect immediately; reschedules retain the binding if the booking ID is unchanged, otherwise rebind is required
Privacy Compliance: Hashed/Rotated Identifiers and No Prohibited Tracking
Given device fingerprinting and persistence are required Then only hashed and salted identifiers are stored; salts rotate at least every 30 days without breaking bindings for active events And Then no prohibited tracking techniques (e.g., third-party cookies, cross-site tracking, canvas fingerprinting without consent) are used; privacy review and static analysis checks pass And Then logs contain no PII beyond booking ID, event ID, and hashed device ID; device-binding records are purged N days after event end (configurable, default 30)
Step-Up Challenge on Unrecognized Device
"As an organizer, I want suspicious link opens to require quick verification so that forwarded links don’t grant unauthorized access."
Description

When a join link is opened on an unbound or high-risk device (new fingerprint, geo/IP anomaly, rapid multi-attempts), trigger a lightweight verification flow based on organizer policy: SMS one-time code, email magic link, or in-app push. Provide configurable escalation (e.g., require two factors on high risk, block after N failures) with rate limiting, lockouts, and human-verification CAPTCHAs. Present clear, localized UX with retry timers and support contact. On success, optionally rebind to the new device per policy; on failure, block and log. Integrates with ClassTap’s messaging providers and honors per-class access windows and waitlist promotions.

Acceptance Criteria
Step-Up Trigger on Unrecognized/High-Risk Device
Given an attendee opens a valid join link within the class access window And the device has an unrecognized fingerprint OR a geo delta > 500 km within 30 minutes OR >= 3 join attempts in 5 minutes from different device fingerprints/IPs When the link is accessed Then the system blocks direct entry and presents the step-up verification per organizer policy And no class content is accessible until verification succeeds And the trigger event is logged with a correlation ID
Policy-Driven Verification Method and Escalation
Given organizer policy method = SMS OTP When step-up is invoked Then send a 6-digit OTP via the configured SMS provider, mask the phone number (e.g., +1 •••• ••34), accept codes for 10 minutes, and accept only SMS as a factor Given organizer policy method = Email Magic Link When step-up is invoked Then send a signed single-use magic link valid for 10 minutes to the attendee’s email, and accept only the magic link as a factor Given organizer policy method = In-App Push When step-up is invoked Then send a push approval request to the ClassTap app with a 60-second expiration, and accept only the push approval as a factor Given calculated risk score >= 80 (high risk) per policy When step-up is invoked Then require two distinct factors (e.g., SMS + Email) in the same session; else require a single factor And record method(s) used in the audit log
Rate Limiting, Lockout, and CAPTCHA Enforcement
Given an attendee enters 5 incorrect OTPs or fails 5 verification attempts within 15 minutes When the next attempt is initiated Then lock verification for 15 minutes, display a visible countdown timer, and present a support contact link Given the attendee requests more than 3 OTP/resend/magic-link sends within 5 minutes When an additional resend is requested Then throttle and show the next available time Given 3 failed attempts within 2 minutes When the attendee tries again Then require a human-verification CAPTCHA before proceeding Then all lockouts, throttles, and CAPTCHA challenges are logged with timestamps and device fingerprints
Localized UX With Retry Timers and Support Contact
Given the user’s locale resolves to a supported language When the step-up screen renders Then all labels, error messages, helper texts, and time formats are localized to that language; otherwise, fall back to English And sensitive fields (email/phone) are masked in the UI, and accessibility attributes (aria-labels) exist for all interactive elements When a lockout or resend cooldown is active Then the UI shows a live countdown timer in mm:ss and a localized explanation, and provides a visible link/button to contact support as configured by the organizer
Successful Verification Grants Access and Optional Rebind
Given verification completes successfully within the class access window When organizer policy RebindOnSuccess = true and the device is unbound Then bind the link to the new device fingerprint and revoke any prior binding Given verification completes successfully within the class access window When organizer policy RebindOnSuccess = false Then do not change the existing binding Then grant class access immediately, update the attendee session state, and log success including device fingerprint, method(s) used, and binding outcome
Access Window and Waitlist Promotion Enforcement
Given a class access window configured (e.g., open 15 minutes before start to 10 minutes after start) When a verification attempt occurs outside this window Then block access regardless of verification outcome and display the next eligible window Given an attendee on the waitlist who is not yet promoted When they open a join link Then present a localized message explaining access is not yet granted due to waitlist status and do not initiate step-up Given an attendee has been promoted from the waitlist When they open a join link within the access window Then proceed with step-up per policy
Messaging Delivery Handling and Fallback
Given method = SMS or Email When a code or magic link is sent Then use the configured primary messaging provider and record delivery status (queued, sent, delivered, bounced/failed) When the primary provider returns a send failure Then automatically retry once and, if a secondary provider is configured, fail over within 5 seconds; otherwise, show retry guidance to the user Given method = Push When a push is sent Then display in-app status (sent/pending/expired) and allow a single in-session resend after 30 seconds Then all send attempts, statuses, and failures are written to the audit log with provider identifiers
Tap-to-Verify Device Switch
"As an attendee, I want an easy way to move my access to a new device so that I can switch without being locked out."
Description

Allow legitimate device changes via an attendee-initiated flow. From the currently bound device, provide a “Move to new device” action that displays a QR code or short code to confirm on the new device; alternatively send a one-tap email/SMS approval. After confirmation, atomically transfer the binding so only one active device remains. Include a short grace period where both devices can access to prevent drops during live switches. Offer a recovery path if the original device is lost (email verification plus organizer override). Limit switch frequency and log all transitions. Ensure minimal friction and consistency across web and mobile deep links.

Acceptance Criteria
Initiate Device Switch From Bound Device
Given an attendee is signed in on the currently bound device and viewing a booking or join page When they tap "Move to new device" Then a modal displays a scannable QR code and a 6-digit numeric short code, each valid for 5 minutes, and an option to "Send one-tap link" Given the modal is open When 5 minutes elapse or the attendee cancels the flow Then all issued tokens (QR and short code) are invalidated server-side and the UI reflects an expired or cancelled state Given policy requires recent re-authentication When the attendee has not authenticated within the last 10 minutes Then the system prompts for re-auth (password/biometric) before showing any codes or links
Verify New Device Using QR or Short Code
Given the QR code is scanned on a new device When the link opens Then a verify screen shows class name, start time, and masked attendee identity with "Bind this device" and "Cancel" actions Given the short code is entered at classtap.com/switch on a new device When the code matches an active token Then the same verify screen is shown; otherwise an error "Code invalid or expired" is displayed Given the attendee confirms on the verify screen When the token is valid and unused Then the device binding transfers to the new device within 2 seconds and the token is consumed (single-use) Given the QR or code flow completes within the token validity window When the attendee uses the QR flow Then the switch completes in no more than 2 taps on the new device and does not require credential entry Given a token is replayed after consumption or expiry When the link is visited again Then access is denied and an audit event with outcome=replay is recorded
One-Tap Email/SMS Approval
Given the attendee selects "Send one-tap link" from the bound device When they confirm the masked destination (email/SMS) Then a one-tap approval link is sent within 10 seconds and is valid for 15 minutes Given the one-tap link is opened on a new device When the attendee taps "Approve" Then the device is bound, the link is immediately invalidated, and subsequent opens show "Link already used" Given the one-tap link is opened after expiry When the page loads Then the attendee is prompted to restart the switch flow and no binding occurs
Atomic Transfer With Grace Period
Given a device switch is confirmed by any method (QR/code/one-tap) When the binding operation executes Then both old and new devices retain access for a grace period of 120 seconds, after which only the new device remains authorized Given the grace period has ended When the old device accesses protected join routes Then access is denied with a "Device switched" message and guidance to initiate a new switch if needed Given multiple switch attempts are initiated concurrently When a binding is in progress Then no additional switch tokens are issued until the current attempt completes or expires, and the attendee sees a message indicating an active switch is in progress
Switch Frequency Limits and Audit Logging
Given an attendee account When device switches are completed Then enforce a limit of at most 3 successful switches per rolling 24 hours and at most 1 active pending switch token per attendee Given the attendee exceeds the switch limit When they attempt another switch Then the request is blocked and the UI shows the time remaining until the next allowed switch window Given any switch event (created, confirmed, expired, failed, blocked) When it occurs Then an immutable audit log entry is recorded with timestamp, user_id, class_id, from_device_id, to_device_fingerprint, method (QR/code/link/recovery/override), initiator IP, and outcome
Lost Device Recovery and Organizer Override
Given the original device is unavailable When the attendee selects "I lost my device" on the switch page Then they must verify their email via a 6-digit code and confirm recent booking details before proceeding Given recovery verification succeeds When the attendee confirms on the new device Then the binding transfers immediately and the old device is revoked without a grace period Given the attendee cannot complete recovery When the organizer uses the dashboard "Override bind" action Then they must provide a reason, the binding is reset to the selected device, notifications are sent to the attendee and organizer, and the action is fully logged with actor identity and reason
Cross-Platform Deep Link Consistency
Given the new device has the ClassTap mobile app installed When the QR/link is opened Then the verify screen opens in-app via deep link with identical copy and steps to the web flow; otherwise it opens the mobile web verify screen Given a desktop browser is used to start the switch When the QR is scanned with a phone Then the desktop shows a real-time status banner and updates to "Switched" within 2 seconds of completion on the phone Given transient network issues on the new device When the verify screen loads Then it retries for up to 30 seconds with clear status and provides a fallback to manual short code entry
Admin Policy Controls and Overrides
"As a studio owner, I want to configure how Device Lock behaves for my classes so that I can balance security with attendee convenience."
Description

Provide granular controls for studios/instructors to configure Device Lock per organization and per class: enforcement mode (strict block, step-up then rebind, allow up to N devices, time-window-limited), allowed verification methods, retry limits, risk thresholds, and exception rules (e.g., venue IP allowlist for hybrid/in-person check-in). Expose an instructor console to reset an attendee’s device binding, temporarily lift restrictions, and view current device status. Supply API endpoints and webhooks for automation. Defaults prioritize security with sensible UX. All changes are audited and can be applied to upcoming sessions via templates.

Acceptance Criteria
Organization Policy Configuration and Secure Defaults
Given I am an organization admin with the Device Lock:Manage permission When I open the Device Lock settings Then I can select an enforcement mode from [Strict Block, Step-Up Then Rebind, Allow up to N devices, Time-Window-Limited] Given I configure allowed verification methods to [SMS OTP, Email Link, TOTP, Push] subset When a step-up is triggered Then only the selected methods are offered Given I set retry limit to 3 and cooldown to 15 minutes When an attendee fails step-up 3 times within the cooldown window Then further attempts are blocked until cooldown expires and an audit entry is created Given a new organization is created When no custom policy is set Then Device Lock defaults are applied such that enforcement is not "Allow unlimited devices", the retry limit is <= 3, and at least one out-of-band verification method is enabled Given I save a valid policy change Then it persists, is reflected in the Admin UI, and is retrievable via GET /v1/device-lock/policies/{orgId} Given a non-admin user attempts to modify Device Lock policy When they submit changes Then the system returns 403 and no changes are persisted
Class-Level Overrides and Template Application to Upcoming Sessions
Given an org-level policy template exists When I apply the template to Class A Then upcoming sessions of Class A inherit the template and the effective policy is shown in the class details and GET /v1/device-lock/policies/{classId} Given Class A has a class-level override When I remove the override Then the class reverts to the organization default policy Given I publish changes to a template When sessions are already in progress Then those sessions are not affected; only not-yet-started sessions are updated Given I schedule new sessions of Class A after applying the template Then those sessions inherit the current template without additional steps Given I confirm changes in the UI Then an audit entry is created with actor, timestamp, affected class/session IDs, and before/after policy values
Enforcement Modes Execute as Configured
Given enforcement mode = Strict Block When a verified attendee opens the join link on a second device Then access is denied with a clear policy message, no rebind occurs, and an audit event device_lock.blocked is recorded Given enforcement mode = Step-Up Then Rebind When the attendee opens on a second device and passes an allowed verification method Then the binding updates to the new device, the prior device loses access immediately, and an audit event device_lock.rebound is recorded Given enforcement mode = Allow up to 2 devices When the attendee has verified on two devices Then both can join; when attempting a third device Then access is denied and the message indicates the device limit was reached Given enforcement mode = Time-Window-Limited with window = 15 minutes When the attendee opens on a different device within 15 minutes of first verification and passes step-up Then access is allowed and the new device is bound; when after 15 minutes Then access is denied per policy Given any enforcement mode When access is denied Then the response includes a reason code and correlation_id for support
Exception Rules: Venue IP Allowlist and Hybrid/In-Person Check-In
Given a venue IP allowlist contains CIDR 203.0.113.0/24 When an attendee opens a join link from 203.0.113.10 Then device lock enforcement is bypassed as configured (no step-up) and the session is marked with a Venue Exception badge Given a request originates from a non-allowlisted IP When the attendee opens the join link Then the standard enforcement policy applies with no exception Given both a strict policy and an IP allowlist exception apply When the request is from an allowlisted IP Then the exception takes precedence as configured and an audit entry records the rule applied and source IP Given a registered kiosk device is used for check-in When an attendee scans their QR at the venue Then they are checked in without consuming a personal device slot and an audit entry links the kiosk device ID
Instructor Console: Overrides and Device Reset
Given an instructor opens the attendee detail panel for a session Then they can view device status including current device fingerprint, last seen timestamp, last IP/CIDR, verification method used, and effective enforcement mode Given the instructor has Override permission When they click Reset Device Binding and confirm Then the attendee’s current binding is cleared, the next verified device becomes bound, prior device access is revoked, and a webhook device_lock.override.applied is emitted Given the instructor sets a Temporary Lift for 30 minutes When the attendee joins during the window Then they can access from any device; when the window ends Then the original policy is automatically reinstated Given an instructor without Override permission attempts any override action Then the action is blocked, a UI error is shown, and an audit entry records the denied attempt
Automation APIs and Webhooks
Given valid API credentials with scope device_lock:write When I PUT /v1/device-lock/policies/{scope} with a valid payload Then the policy updates and the 200 response returns the canonical policy document including etag Given I PUT /v1/device-lock/policies/{scope} with an invalid payload (e.g., device_limit > 5 or unknown verification method) Then the API responds 400 with field-level error codes and no change is persisted Given I POST /v1/device-lock/overrides/reset with attendee_id and session_id Then the attendee’s device binding is cleared and a webhook device_lock.override.applied is delivered with a signed signature and correlation_id Given a step-up challenge result occurs Then webhooks device_lock.challenge.passed or device_lock.challenge.failed are emitted within 5 seconds, are retriable with exponential backoff, include a monotonically increasing delivery id, and can be verified via HMAC signature Given I GET /v1/device-lock/status?attendee_id=...&session_id=... Then the API returns device_count, last_verification_method, effective_policy_scope (org|class|override), and last_updated
Audit Trail and Change Governance
Given any policy, template, override, or exception rule change occurs Then an immutable audit record is created with actor (user id or API client id), UTC timestamp, target scope (org/class/session/attendee), action, before/after values, and optional reason Given I view the audit log in the Admin Console When I apply filters for actor, time range, target, or action type Then matching entries are displayed and can be exported to CSV Given an attempt is made to modify or delete past audit records Then the system prevents the change and records the attempt as a separate audit entry with reason unauthorized_mutation Given I apply a template to multiple upcoming sessions Then a single parent audit entry is created with references to all affected session IDs and per-session child entries are accessible via the parent record
Secure Tokenization and Anti-Replay
"As a security-conscious admin, I want join links to be resistant to replay and tampering so that only the intended attendee can use them."
Description

Issue signed, time-scoped, single-attendee join tokens with unique jti nonces. Enforce one active token per attendee per session; bind token to device fingerprint on first use and rotate tokens on subsequent accesses. Implement server-side replay detection and immediate invalidation on bind reset or policy violations. Require TLS, HSTS, and strict SameSite cookie usage where applicable. Ensure deep link compatibility on mobile. Provide optional offline QR fallback for in-person check-in that still respects one-device rules when later synced. Minimize PII in tokens and centralize secrets management and key rotation.

Acceptance Criteria
First Use Device Binding
Given a signed, time-scoped join token containing only attendee_id, session_id, exp, jti, and kid And the token is delivered via an HTTPS link And jti has not been seen before for this session When the attendee opens the link on an unbound device Then the server verifies the signature using the key identified by kid from the active JWKS And validates exp is within the configured TTL And binds the attendee-session to the device fingerprint derived on first use And marks the token as bound to that fingerprint And returns a 200 OK join response And writes an audit log entry with timestamp, IP, device fingerprint hash, jti, and outcome
Token Rotation and Single Active Token Enforcement
Given an attendee-session is already bound to a device fingerprint And there is exactly one active token T1 with jti J1 When the attendee accesses the join link again from the same bound device over HTTPS Then the server issues a new signed token T2 with a new jti J2 and fresh exp within policy limits And immediately invalidates T1 so only T2 is active for that attendee-session And any request using T1 thereafter returns 401 with error code token_rotated And the system records rotation in the audit log with prior and new jti
Replay Detection and Immediate Invalidation
Given a valid token T with jti J bound to a device fingerprint F When the server receives a second request bearing the same token T (same jti J) Then the server classifies it as a replay and denies the second request with 401 and error code replay_detected And increments a replay counter on the attendee-session And does not change the existing device binding And, if policy requires, triggers a step-up verification challenge before allowing further access And logs the replay event with jti, fingerprint hash, IPs, and timestamps
Cross-Device Access Policy Enforcement (Step-Up or Block)
Given an attendee-session is bound to device fingerprint F1 When the join link is opened on a different device producing fingerprint F2 ≠ F1 Then if policy = step_up And the attendee completes the configured step-up challenge (e.g., OTP via SMS/email) within the allowed window Then the binding is transferred to F2, all prior tokens are invalidated, and a new token with a new jti is issued And the event is logged with prior and new fingerprint hashes Else if policy = block or the challenge fails Then access is denied with 403 and error code device_mismatch And the original binding to F1 remains unchanged And the event is logged
Transport, Cookie, and Key Management Security
Given any web join request When the request is received over HTTP Then it is redirected to HTTPS and Strict-Transport-Security is set with max-age ≥ 15552000 and includeSubDomains And all subsequent requests must use TLS 1.2+ with strong ciphers And any session cookies set by the join experience include Secure, HttpOnly, and SameSite=Strict And the join token is not persisted in localStorage or sessionStorage and is not sent in Referer due to Referrer-Policy: same-origin And JWTs include kid and are signed with keys managed in centralized KMS And key rotation supports at least one previous active signing key for validation during rollout, verified by tests that pass with both current and previous keys
Mobile Deep Link Compatibility
Given a join link is opened on a supported mobile device When the ClassTap app is installed and configured for universal/app links Then the link opens the native app without intermediate browsers, and the token is passed via the OS link handoff to the app And device binding and token rotation behavior mirror the web flow When the app is not installed Then the link opens the responsive web join page over HTTPS with the token preserved And the token is not exposed via clipboard or system share sheets during handoff And iOS (16+) and Android (11+) tests confirm successful join, rotation on re-open, and no token leakage in referrer logs
Offline QR Fallback with Sync and One-Device Enforcement
Given offline check-in is enabled for a session And an attendee presents an offline QR code containing a signed, time-bounded offline nonce tied to attendee_id and session_id When staff scans the QR while the device is offline Then the scan is stored locally with encrypted payload and timestamp When the device later syncs Then the server validates the QR signature and that the offline nonce has not been used before And creates or confirms a single active token for the attendee-session without violating one-device rules And subsequent sync attempts using the same offline nonce are rejected as replay with 409 and error code offline_nonce_replay And if a different device binding already exists, server follows the configured policy (step-up to rebind or block) before issuing any new token And all events are logged
Audit Trail, Alerts, and Reporting
"As an instructor, I want visibility into device lock events so that I can detect abuse and support attendees."
Description

Capture detailed events for first bind, challenge triggers, passes/fails, blocks, device switches, overrides, and token invalidations with timestamps, coarse IP/geo, and hashed device identifiers. Surface searchable logs and per-class dashboards with filters and CSV export. Provide optional real-time alerts to instructors (email/SMS/push) on repeated failed challenges or suspected link sharing, and optional courtesy notifications to attendees about successful device changes. Offer weekly/monthly summaries highlighting prevented misuse and challenge pass rates. Integrate with webhooks/SIEM. Respect data retention and privacy settings.

Acceptance Criteria
Event Logging: First Bind and Security Events
Given an attendee completes their first device bind for a class, When the bind succeeds, Then an event is written with fields: event_type=first_bind, timestamp=UTC ISO8601, class_id, attendee_id (UUID), join_link_id, hashed_device_id (SHA-256 salted), coarse_ip (IPv4 /24 or IPv6 /48), geo_country, user_agent_hash, policy_id Given a challenge is presented due to policy, When the challenge screen is shown, Then an event is written with event_type=challenge_trigger including reason and the same context fields Given the attendee submits the challenge, When validation completes, Then an event is written with event_type in {challenge_pass, challenge_fail} and result_reason Given access is blocked by policy, When the block decision is made, Then an event is written with event_type=access_block and block_reason Given a device switch is approved via step-up, When the bind is moved, Then an event is written with event_type=device_switch_approved including old_hashed_device_id and new_hashed_device_id Given an instructor/admin applies a manual override, When the override is saved, Then an event is written with event_type=override_applied including actor_id and reason_code Given a join token is invalidated or expires, When invalidation occurs, Then an event is written with event_type=token_invalidated and cause in {expired, revoked, rotated} Rule: Events are immutable, strictly time-ordered, and visible in the log UI and API within 3 seconds at p95
Searchable Logs and Per-Class Dashboard with CSV Export
Given an instructor views a class dashboard, When they filter by date range, event_type, outcome, attendee_id, hashed_device_id, coarse_ip, geo_country, and policy_id, Then the results reflect only matching events Rule: Filtered queries up to 10,000 events return within 2 seconds at p95 Rule: Instructors see only events for their classes; org admins can view all classes; attendees have no access Given a filtered result set is displayed, When Export CSV is requested, Then a CSV containing only the filtered events is generated with headers [timestamp, class_id, attendee_id, join_link_id, event_type, outcome, policy_id, hashed_device_id, coarse_ip, geo_country] and UTF-8 encoding Rule: CSV export begins within 5 seconds and completes for up to 100,000 rows within 60 seconds Rule: CSV and UI never include raw device identifiers or full IP addresses beyond the specified coarse granularity
Real-Time Instructor Alerts on Repeated Failures or Suspected Link Sharing
Given alerting is enabled for a class, When there are >= 3 challenge_fail events for the same join_link_id within 10 minutes, Then send an alert to the instructor via each enabled channel in {email, SMS, push} Given alerting is enabled, When suspected link sharing is detected (>= 2 distinct hashed_device_id or >= 3 coarse_ip for the same join_link_id within 15 minutes), Then send an alert as above Rule: Alerts include class name, event counts, time window, and a link to the filtered log view; they exclude PII and full IPs Rule: Throttle to at most 1 alert per class per 15 minutes per condition (failures, suspected_sharing) Rule: Record an event_type=alert_dispatched with channels, condition, and delivery_status for each channel Rule: If a channel provider returns a transient error, retry with exponential backoff for up to 1 hour
Courtesy Notifications to Attendees on Successful Device Change
Given attendee courtesy notifications are enabled, When an event_type=device_switch_approved is recorded, Then send a notification to the attendee via their preferred channel in {email, SMS} within 1 minute Rule: Notification includes class name, date/time (UTC and local), geo_country and coarse_ip, and a secure link to report "This wasn’t me" that opens a support flow Rule: If delivery fails permanently, record an event_type=notification_failed with reason; do not retry more than 3 times Rule: Attendees can opt out; when opted out, no notification is sent and an event_type=notification_opt_out is recorded
Weekly and Monthly Summaries of Device Lock Activity
Given summaries are enabled, When a reporting period ends (weekly and monthly), Then generate a summary containing counts of prevented misuse (access_block), challenge pass/fail rates, top classes by challenge volume, and trend charts Rule: Summaries are delivered within 24 hours of period end to instructors for their classes and to org admins for the org via email with a link to the dashboard Rule: Summaries include a downloadable CSV of period metrics; no raw PII or full IPs are included Rule: Users can opt out per frequency; opt-out is honored and logged with event_type=summary_opt_out
Webhooks and SIEM Integration for Audit Events
Given a webhook endpoint and secret are configured, When any audit event is written, Then POST a JSON payload to the endpoint within 5 seconds with HMAC-SHA256 signature in header X-CT-Signature and an idempotency key X-CT-Event-Id Rule: On non-2xx response, retry with exponential backoff for up to 24 hours; respect Retry-After for 429 Rule: Provide a replay mechanism to resend events for a date range scoped to the tenant and event types Rule: Support payload formats JSON (default) and CEF over syslog TCP/TLS for SIEMs; format is tenant-configurable per destination Rule: Record delivery outcomes with event_type=webhook_delivery_{success|failure} including attempt_count and last_status_code
Data Retention and Privacy Controls Applied to Audit Data
Given a tenant sets a retention period (30/90/365 days), When events exceed the retention window, Then they are purged and no longer available via UI, API, export, or webhook replay Rule: Only coarse IP/geo and hashed device identifiers are stored; raw device identifiers and full IPs are never persisted or exported Rule: Alerts, notifications, and summaries exclude PII beyond attendee first name and do not include full IPs or precise geo Given an attendee invokes data deletion, When the request is processed, Then their attendee_id is pseudonymized in historical events while aggregated metrics remain intact, and an event_type=privacy_erasure_processed is recorded Rule: All accesses to audit logs are themselves logged with actor_id, timestamp, and purpose for compliance
Accessibility, Localization, and Compliance
"As a global attendee, I want the verification flow to be accessible and localized so that I can complete it regardless of my abilities or location."
Description

Ensure all Device Lock screens and flows meet WCAG 2.2 AA: keyboard navigable, screen-reader semantic labels, sufficient contrast, and motion-reduced alternatives. Localize UI copy, SMS/email templates, and error messages for supported languages and right-to-left scripts. Provide non-SMS verification options for users without mobile numbers. Present transparent explanations of why verification is required and what data is used; obtain consent where required. Avoid prohibited or uniquely identifying fingerprinting techniques per platform policies (e.g., iOS/Android). Support data export/deletion requests and document retention durations.

Acceptance Criteria
Keyboard and Screen Reader Accessibility Compliance (WCAG 2.2 AA)
- Given a user navigating the Device Lock flow with keyboard only, when pressing Tab/Shift+Tab, then focus moves in logical order without traps and is visible with a focus indicator meeting WCAG 2.2 AA (≥3:1 contrast). - Given a modal/dialog opens, when it appears, then initial focus moves into the dialog, background content is inert, Esc closes the dialog, and focus returns to the trigger. - Given interactive controls (buttons, links, inputs, toggles), when activated with Enter or Space as appropriate, then they perform the same action as a pointer click. - Given form validation fails, when an error is shown, then the message is programmatically associated to the field (aria-describedby), announced by screen readers within 1 second, and placed inline in reading order. - Given common screen readers (VoiceOver, TalkBack, NVDA/JAWS), when navigating any control, then each has an accessible name, role, state/value that match the visible label and locale’s language attribute. - Given any time limit in the flow (e.g., code expiry), when the timer starts, then users are warned before expiry and can extend at least once by ≥60 seconds unless disallowed by tenant security policy (with rationale shown).
Visual Contrast and Reduced Motion Compliance
- Given any Device Lock screen, when rendered, then normal text meets ≥4.5:1 contrast and large text ≥3:1, UI components and focus indicators meet ≥3:1 against adjacent colors. - Given focus is visible, when moving focus sequentially, then the indicator remains within viewport and has sufficient size per WCAG 2.2 AA Focus Appearance guidance. - Given user prefers-reduced-motion, when the flow loads, then non-essential animations/transitions are disabled; no auto-scrolling/parallax; substituted transitions complete in ≤100ms. - Given any animated content, when displayed, then it does not flash more than 3 times per second and provides a pause/stop mechanism if it runs >5 seconds. - Given any motion-based interaction, when device motion is unavailable or disabled, then an equivalent non-motion control is available and discoverable.
Localization and Right-to-Left Support
- Given the user’s selected locale is supported, when starting Device Lock, then all UI strings, emails, SMS templates, dates, times, numbers, and plurals render correctly in that language. - Given an RTL locale (e.g., ar, he), when rendering, then layout and navigation are mirrored, icons with direction are flipped, caret and punctuation behave correctly, and mixed-direction text uses proper bidi controls. - Given an unsupported locale, when detected, then the default locale is used and a language switcher is available; no hardcoded untranslated strings appear. - Given pseudo-localization is enabled in QA, when rendering, then ≥95% of screens show no clipped/overlapped text with up to +30% string expansion at common breakpoints. - Given i18n linting runs, when building, then 0 hardcoded user-visible strings are reported and all strings are externalized with unique keys.
Non-SMS Verification Alternatives
- Given a user without a mobile number or with undeliverable SMS, when step-up verification is required, then at least two non-SMS options are offered: email one-time code/link and WebAuthn/passkey (or TOTP when WebAuthn unsupported). - Given the user chooses email, when the code/link is requested, then delivery occurs within 30 seconds; codes are 6–8 digits, expire within 10 minutes, allow ≤5 attempts, and resends are rate-limited to ≥30 seconds. - Given the user chooses WebAuthn/passkey, when registering/asserting, then flows complete per platform UX, with clear fallback to email/TOTP if unavailable or failed. - Given verification succeeds via any path, when returning to the booking/join flow, then the device is bound/revalidated equivalently to SMS and the user proceeds without re-prompt. - Given accessibility needs, when interacting with any alternative, then the controls are fully keyboard and screen-reader operable and localized.
Transparency, Explanation, and Consent
- Given Device Lock is initiated, when the first verification screen loads, then a just-in-time notice explains why verification is required, what data is used, retention duration, and who can access it, with links to policy. - Given consent is required by tenant policy or jurisdiction, when the notice is shown, then an unchecked consent checkbox is presented; proceeding is blocked until checked; consent is logged with user ID, timestamp, locale, and notice version. - Given consent is not required, when the notice is shown, then acknowledgement text and a link to learn more are presented; proceeding is allowed and the notice display is logged. - Given the user wants to review details, when clicking “What data is used?”, then a localized panel enumerates data categories (e.g., device model, OS version, storage state, IP region) and excludes unique hardware identifiers. - Given the user declines or cannot consent, when policy requires verification, then a safe alternative path is offered (e.g., contact host/manual check) and the session is not silently degraded.
Platform Policy Compliance: No Prohibited Fingerprinting
- Given iOS/Android platform policies, when collecting device signals, then prohibited identifiers (e.g., IMEI, MAC) and covert techniques (e.g., canvas/audio/battery fingerprinting) are not used. - Given device binding is needed, when permitted signals are insufficient, then the system falls back to user-mediated verification (e.g., passkey/email) rather than adding unapproved entropy sources. - Given mobile builds, when static/dynamic analysis runs, then 0 references to banned APIs are present and runtime logs show no access to restricted device info. - Given policy changes, when flagged, then a kill switch can disable specific signal collectors within 48 hours without requiring an app update. - Given release readiness, when passing QA, then a documented privacy review checklist is signed off and stored for audit.
Data Export, Deletion, and Retention Disclosure
- Given a data export request, when submitted via self-serve or admin console, then a machine-readable export (JSON/CSV) of device verification records and consents is generated within 5 minutes, including timestamps, IP region, device alias, and audit events. - Given a deletion request, when processed, then identifiable verification data is erased from active systems within 7 days and from backups within 30 days; tombstones prevent re-creation; outcomes are logged. - Given retention policies, when viewing settings, then retention duration for verification data is visible and configurable per tenant (0–365 days default 90), and shown in user-facing notices/templates. - Given operational events, when exports/deletions occur, then audit logs capture requester/actor, scope, time, and result; failures emit actionable error codes and notifications.

Silent Rotate

Auto-rotates the tokenized join link shortly before class and seamlessly updates the same SMS/email/calendar thread. Old links are invalidated, new links just work—reducing link-sharing and eliminating last-minute “wrong link” support pings.

Requirements

Time-based Token Rotation Engine
"As an instructor, I want the system to automatically rotate join links shortly before class so that only the latest link works and shared old links can’t be used."
Description

Implements a service that generates per-attendee, per-class join tokens and automatically rotates them a configurable number of minutes before class start. The engine invalidates previous tokens atomically, issues new tokens, and guarantees idempotent rotation even under concurrent triggers. Supports per-class rotation offsets, grace periods, and configurable token TTLs. Ensures tokens are cryptographically signed, non-guessable, and bound to booking and class session metadata. Exposes rotation status and webhooks/events for downstream systems. Designed to scale across peak rotation windows and to recover gracefully from failures with retry and backoff.

Acceptance Criteria
Per-Attendee Per-Class Token Generation and Binding
- Given a confirmed booking for attendee A in class session S, When a token is issued, Then the token is unique per (A,S), URL-safe, and contains at least 128 bits of entropy. - Given the token for (A,S), When the service verifies the signature, Then verification succeeds and the token is bound to booking_id, attendee_id, class_session_id, and rotation_version. - Given two different attendees A and B for the same session S, When tokens are issued, Then token(A,S) != token(B,S). - Given repeated token issue requests for the same (A,S) before any rotation, When a token is requested, Then the same current token is returned. - Given a token whose payload or signature is modified, When it is validated, Then validation fails and access is denied with 401 invalid_token.
Configurable Pre-Class Rotation Timing
- Given a class session S with rotation_offset=T minutes, When current_time reaches start_time(S) - T, Then a rotation for S is scheduled and executed within 60 seconds. - Given a class session S with a per-class rotation_offset override, When the rotation scheduler runs, Then the override value is used instead of the default. - Given no override on S, When the rotation scheduler runs, Then the system uses the global default rotation_offset. - Given rotation has been performed for S at version V, When the scheduler runs again before start_time(S), Then no additional rotation is performed (at-most-once per window).
Atomic Rotation with Grace Period Enforcement
- Given rotation occurs at time R for session S with grace_period=G minutes, When rotation executes, Then all pre-rotation tokens for S are marked expired at R and new tokens with rotation_version=V+1 are issued atomically. - Given a pre-rotation token for S, When it is presented at time t where R <= t < R+G, Then access is granted under grace policy and the request is recorded as grace_used=true. - Given the same pre-rotation token for S, When it is presented at time t >= R+G, Then access is denied with 401 invalid_token. - Given a post-rotation token for S (version V+1), When it is presented at time t >= R, Then access is granted.
Idempotent Rotation Under Concurrent Triggers
- Given N concurrent rotation triggers for the same session S and rotation window, When they execute, Then exactly one rotation_version is created and all triggers return the same rotation_version identifier. - Given concurrency as above, When inspecting tokens for any attendee in S, Then each attendee has exactly one valid post-rotation token. - Given a retry of the rotation request after success, When it executes, Then the system returns a successful idempotent result and does not create new tokens.
Token TTL and Validation Enforcement
- Given token_ttl policy is issuance_based=N minutes, When time >= token_issued_at + N, Then the token is rejected with 401 invalid_token. - Given token_ttl policy is class_end_based=D minutes, When time >= class_end_time + D, Then the token is rejected with 401 invalid_token. - Given a token for (A,S), When it is presented for a different class session or attendee, Then validation fails and access is denied. - Given a valid unexpired token for (A,S), When presented within TTL and grace policies, Then validation succeeds with p95 verification latency <= 50 ms.
Rotation Events and Webhooks Delivery
- Given a successful rotation for session S, When events are emitted, Then a RotationCompleted event is produced containing session_id, rotation_version, affected_attendee_count, and occurred_at. - Given webhook delivery to subscriber U fails with a non-2xx response, When retries are attempted, Then the system retries with exponential backoff (initial 1s, max 60s, jitter) up to 8 attempts and records attempt history. - Given duplicate deliveries occur, When the subscriber receives events with the same event_id, Then the payloads are identical and event_id is stable for de-duplication. - Given all retry attempts are exhausted, When delivery still fails, Then the event is moved to a dead-letter queue and is visible via the status API.
Rotation Status API and Observability
- Given a session S, When querying GET /rotation-status?session_id=S.id, Then the response includes current_rotation_version, scheduled_rotation_time, grace_period_minutes, last_rotation_at, and rotated_attendee_count. - Given a rotation is in progress, When querying status, Then progress percentage and in-flight metrics are returned and update at least every 5 seconds. - Given an attendee A in S, When querying status with attendee_id, Then the response shows current token version for A (without revealing the token) and whether grace is active. - Given an audit request for session S, When retrieving logs, Then rotation events, webhook attempts, and validation failures are available with timestamps and correlation IDs.
Threaded Comms Auto-Update (Email/SMS/Calendar)
"As a student, I want any last-minute link update to appear in the same email/SMS/calendar thread I already have so that I don’t miss it or wonder which message to trust."
Description

Automatically pushes the rotated link into the existing communication threads without creating new conversations. For email, sends an update using the original Message-ID threading headers and updates the calendar invite by reissuing the ICS with the same UID and incremented SEQUENCE. For SMS, sends a follow-up message from the same sender number within the same thread, referencing the class and including the new short link. Ensures consistent copy/templates, localized content, quiet hours compliance, and link preview behavior. Guarantees that recipients see the update in the same thread they already have, minimizing confusion and support contacts.

Acceptance Criteria
Email: Update Appears in Original Thread
Given an attendee received the class confirmation email with Message-ID=M and a known thread in their inbox When the join link is rotated within 15 minutes before class start Then an email update is sent using the same From/Reply-To as the original, with In-Reply-To=M and References including M, and unchanged Subject And the email renders the new join link in the body with consistent template copy And in Gmail, Outlook.com, and Apple Mail, the update appears in the same thread as the original And only one update email is sent per rotation per recipient, even on retry
Calendar: ICS Update Replaces Prior Invite
Given the original calendar invite was sent with UID=U and SEQUENCE=S When the join link is rotated Then a new ICS is issued with UID=U and SEQUENCE=S+1, METHOD=REQUEST, updated DESCRIPTION/LOCATION containing the new link And attendee list is unchanged, organizer is unchanged, and DTSTAMP is current And on Google Calendar, Outlook (desktop/web), and Apple Calendar, the existing event is updated in place without creating a duplicate And attendee RSVP statuses are preserved
SMS: Follow-up Message in Same Thread
Given an attendee received the original SMS confirmation from sender number X When the join link is rotated within 15 minutes of class start Then a follow-up SMS is sent from sender number X in the same thread, referencing the class name/date/time and including the new short link And messages exceeding 160 characters are concatenated with proper UDH and display as a single thread on iOS and Android And only one SMS update is sent per rotation per recipient, even on retry And opt-out compliance language/STOP handling is preserved
Quiet Hours: Channel-Specific Compliance
Given the recipient's quiet hours are configured as 10:00 PM–7:00 AM in their local time zone When the link rotation occurs during quiet hours Then SMS updates are not sent during the quiet hours window and are queued to send at the window end And email updates follow the configured quiet-hours policy (sent if allowed; otherwise queued), with decisions logged per recipient and channel And calendar ICS updates follow the same policy without creating duplicate calendar entries or extra notifications
Localization: Consistent Templates and Local Times
Given the recipient profile has locale=fr-FR and time zone=Europe/Paris When the update is sent Then the SMS and email templates render in French with dates/times formatted for fr-FR and Europe/Paris And currency, punctuation, and number formats match the locale And if a translation key is missing, the system falls back to en-US with a logged warning And template variables (class name, start time, instructor, short link) are populated consistently across channels
SMS Link Previews: Controlled Display
Given SMS link preview policy is set to Disabled for rotated join links When the SMS update with the new short link is sent to iMessage and Android Messages clients Then no rich link preview is displayed in either client And the link remains clickable and resolves correctly When the policy is set to Enabled Then a rich preview appears where supported without exposing the token to third-party crawlers
Idempotency: No Duplicate Updates or New Threads
Given the update send operation is retried with the same idempotency key due to a transient failure When email, SMS, and ICS updates are processed Then each recipient receives at most one update per channel and no additional threads or duplicate calendar entries are created And provider/MTA/message IDs are recorded once in audit logs with a single delivery status per channel And subsequent retries are acknowledged without re-sending
Per-Attendee Tokenization & Access Controls
"As a studio owner, I want each attendee to have a unique, controlled link so that shared links don’t grant unintended access and class capacity is protected."
Description

Issues tokens uniquely bound to the attendee’s booking, with optional device fingerprint and single-session concurrency limits. Enforces time-windowed access (e.g., open X minutes before start, expire after class end plus buffer) and geo/time anomaly checks. Detects potential link sharing via concurrent IP/device patterns and triggers soft challenges or blocks. Provides instructor/host tokens with elevated privileges and different lifecycles. Integrates with waitlist and last-minute seats so that when a learner is promoted, a valid token is immediately provisioned and others remain invalid.

Acceptance Criteria
Unique Token Issuance per Booking
Given a confirmed booking with booking_id and attendee_id When the booking is created or confirmed Then the system issues a cryptographically random token uniquely bound to that booking_id and attendee_id And the token is embedded in the attendee’s join URL And the token validates to exactly one active booking And attempting to use the token for any other booking_id responds 403 Unauthorized And the token is stored hashed at rest and includes a scoped TTL tied to the class lifecycle
Device Binding and Single-Session Concurrency
Given device_binding=true and concurrency_limit=1 for the class And an attendee has not yet joined this class When the attendee first joins with device_fingerprint=A Then the token is bound to fingerprint A for the active session And a second concurrent join using fingerprint=B is blocked with 409 Concurrency Limit Reached And if the first session ends or is inactive for grace_period=60s, the next join is allowed and the prior session is invalidated
Time-Windowed Access Control
Given class start_time=T, duration_minutes=D, open_window_minutes=15, expiry_buffer_minutes=10 When a tokenized join request occurs before T-15 minutes Then the request is denied with 403 Not Yet Open When a request occurs between T-15 minutes and T+D+10 minutes Then access is granted with 200 OK When a request occurs after T+D+10 minutes Then access is denied with 410 Expired (or 403 Expired)
Geo/Time Anomaly Detection and Soft Challenge
Given geo_anomaly_radius_km=500 and anomaly_interval_minutes=5 and challenge_mode=soft When two successive requests for the same token originate from IP geolocations >500 km apart within 5 minutes Then a soft challenge (one-time code via SMS/email) is required before access continues And on successful challenge within 5 minutes, access is granted And on failed/expired challenge, the session is blocked with 403 and the event is logged with reason=geo_anomaly
Concurrent IP/Device Link Sharing Enforcement
Given share_detection=true and concurrency_limit=1 When the same token is used concurrently from more than one distinct IP or device_fingerprint Then the newer session is soft-challenged and only one verified session remains active And if the challenge fails or 3 sharing anomalies occur within the class session, the token is blocked for the remainder of the class and an instructor dashboard alert is created
Instructor/Host Token Privileges and Lifecycle
Given a token issued with role=host When the host uses the join link Then access is allowed outside attendee windows (up to 60 minutes before and after class) and bypasses geo/time anomaly checks And host concurrency_limit is >=5 simultaneous sessions And the host can view and terminate attendee sessions for this class via the API And revoking a host token immediately terminates associated sessions
Waitlist Promotion Immediate Token Provisioning
Given a waitlisted learner is promoted to confirmed within 10 minutes of class start When the promotion event is processed Then a unique attendee token is generated and activated within 5 seconds And the attendee portal shows an active Join button using the new token within 5 seconds And non-promoted waitlisted learners have no active tokens; their join attempts return 403 And the promotion and token issuance are audit-logged with timestamps
Late Booking, Reschedule, and Cancellation Resilience
"As a late registrant, I want to receive a valid link right away and have it stay up-to-date if the class time changes so that I can join without confusion."
Description

Handles bookings or changes occurring after rotation time by immediately issuing fresh tokens and updating existing threads. On reschedule, revokes old tokens, schedules a new rotation for the new time, and sends updated ICS/email/SMS in-thread. On cancellation, invalidates all tokens and notifies attendees with a clear message. Consistently reconciles edge cases such as timezone shifts, multi-session series, and instructor swaps while preserving message threading and minimizing duplicate notifications.

Acceptance Criteria
Late Booking After Rotation Cutoff
Given a class instance has already rotated its join link and a learner books at or after the rotation time When the booking is confirmed Then a fresh, attendee-specific tokenized join link tied to the active rotation is issued within 10 seconds And an SMS and an email containing the valid link are sent within 30 seconds, using the existing thread if one exists, otherwise starting a new thread And a calendar invite is created/updated in place within 60 seconds using the same UID for the class instance And the new link is immediately usable (HTTP 200) and scoped to the correct class instance window And no more than one SMS and one email are sent for this booking event per attendee
Reschedule After Link Rotation
Given an upcoming class instance has already rotated its join link and the host reschedules the start time When the reschedule is saved Then all previously issued attendee and host tokens for that instance are revoked within 5 seconds (old links return HTTP 410) And a new rotation schedule is created for the new start time And attendees receive a single SMS and a single email in the existing threads with the new time and a fresh tokenized link within 2 minutes And the existing calendar event is updated in place using the same UID with an incremented SEQUENCE reflecting the new time And the new link is valid and the old link is invalid across all channels And an audit log records the reschedule and token revocations
Cancellation After Link Rotation
Given an upcoming class instance has already rotated its join link and the class is canceled When the cancellation is saved Then all attendee and host tokens for that instance are invalidated within 5 seconds (old links return HTTP 410) And attendees receive a single SMS and a single email in the existing threads with a clear cancellation message within 2 minutes and no join link And the calendar event is canceled in place by sending an ICS with the same UID and METHOD:CANCEL And attempts to access the old link display an informative cancellation message And no duplicate notifications are sent per channel for this cancellation event
Timezone Shift and DST Reconciliation
Given a class's timezone is changed or a DST transition affects the scheduled start before rotation fires When the change is saved Then the rotation trigger time is recalculated relative to the class's new local start time And at most one rotation occurs for the instance (no duplicate rotations) And outbound notifications show the correct start time in each attendee's local timezone And email/SMS updates reuse existing threads And the calendar event is updated in place (same UID, incremented SEQUENCE) without creating duplicate events
Multi-Session Series — Single Occurrence Reschedule
Given a learner is enrolled in a multi-session series and a single occurrence is rescheduled after its link rotation When the reschedule is saved Then only the affected occurrence's tokens are revoked and reissued; other occurrences' tokens remain valid And SMS/email updates reference only the affected occurrence and post in the same series thread And only the affected occurrence's calendar instance is updated in place (same UID/RECURRENCE-ID with incremented SEQUENCE) And attendees receive no more than one SMS and one email for this change
Instructor Swap After Rotation
Given the instructor for an upcoming class instance is changed after the join link rotation When the instructor swap is saved Then host tokens tied to the old instructor are revoked immediately (old host link returns HTTP 401/410) And the new instructor receives a fresh host tokenized link that is immediately usable And attendee links remain valid unless regeneration is required by the meeting backend; if regenerated, attendees receive updated links in existing threads within 2 minutes And SMS/email/ICS reflect the new instructor's name And an audit log records the instructor change and token actions
Duplicate Notification Suppression and Thread Preservation
Given any single state change event (late booking, reschedule, cancellation, timezone shift, or instructor swap) When outbound communications are dispatched Then each attendee receives at most one SMS and one email per event and one ICS update per instance And emails use consistent subject and threading headers (Message-ID/References or In-Reply-To) to remain in the same thread And SMS are sent from the same sender/number to remain in the same thread And retries due to transient failures do not create duplicates because messages are de-duplicated by event ID And all message-sending operations are idempotent on reprocessing
Admin Rotate & Reissue Console
"As support staff, I want a console to see and manage link rotations and resend or reissue tokens so that I can quickly resolve attendee access issues."
Description

Provides an internal dashboard for staff to view rotation status per class, see attendee token states, and take actions: force rotate, reissue a token, resend an update, copy links, or pause rotation for a session. Includes search and filters, role-based access controls, and audit trails of manual actions. Surfaces health indicators (delivery success rates, pending updates) and contextual tips for common support scenarios to speed resolution of “wrong link” tickets.

Acceptance Criteria
RBAC Access and Action Permissions
Given a signed-in user with role "Admin" or "Support Agent" When they navigate to the Admin Rotate & Reissue Console Then the console loads with HTTP 200 and permitted actions are enabled for their role And restricted actions are disabled with tooltips explaining required role Given a signed-in user with role "Instructor" or "Viewer" When they navigate to the console URL Then access is blocked with HTTP 403 and a friendly message is displayed and no data is leaked Given a "Support Agent" When they attempt Force Rotate Then the UI blocks the action with an authorization error And the event is logged in the audit trail as a denied action Given an "Admin" When they perform Force Rotate, Reissue, Resend, Copy Link, or Pause/Resume Then the action succeeds and an audit record is created with actor, role, timestamp, class ID, attendee ID (if applicable), action, and outcome
Class List: Search, Filters, and Health Summary
Given there are 1,000+ upcoming classes with varied instructors and rotation states When a user enters a keyword (e.g., "Yoga") and applies filters (date range, instructor, location, rotation state, health = At Risk) Then the results reflect the query accurately and return within 800 ms for 95th percentile Given a user clears filters When the page reloads Then the full, default list is shown sorted by start time ascending Given the list view displays health indicators per class When delivery success rate < 95% or pending updates > 5 Then the class row is flagged "At Risk" with an accessible label and tooltip showing metric breakdown Given a user clicks Export on the filtered list When the export completes Then a CSV with columns (Class ID, Start Time, Instructor, Rotation State, Health% Success, Pending Updates) downloads and matches on-screen results
Class Detail: Rotation Status and Attendee Token States
Given a user with access opens a specific class detail page When the page loads Then it shows rotation status (Scheduled/Rotated/Paused), last rotation timestamp, next scheduled rotation window, and countdown if < 2 hours Given attendees exist for the class When the attendee table renders Then each row shows attendee name, token state (Active/Pending Update/Invalidated/Reissued), last notification time per channel (SMS/Email/Calendar), and link domain Given a token state changes in the backend (e.g., reissued) When the page is open Then the UI reflects the change within 5 seconds without full page refresh Given the class is in Rotated state When an old link is tested Then it returns an invalid token response (HTTP 410 or app-equivalent) while the new link succeeds (HTTP 200)
Force Rotate Session Links
Given a class scheduled to start within the next 3 hours and auto-rotation not yet executed When an Admin clicks Force Rotate and confirms Then new tokens are generated for all attendees, old tokens invalidated, and update messages are queued within 5 seconds Given Force Rotate completes When attendees use the previously issued link Then access is denied with a clear "link expired/rotated" message and guidance to check latest message Given Force Rotate is triggered twice within 60 seconds When the second request arrives Then it is rejected as a duplicate with an idempotency notice and no additional tokens are created Given Force Rotate completes When viewing the class detail Then rotation status updates to Rotated, last rotation timestamp is set, health metrics refresh, and an audit record is stored including token hash prefixes (masked)
Reissue Token for a Single Attendee
Given an attendee with token state Active or Invalidated When an Admin selects Reissue and chooses delivery channels (SMS/Email/Calendar) Then a new token is generated only for that attendee, old token is invalidated, and selected channel messages are sent within 10 seconds Given an attendee lacks a verified channel (e.g., no SMS) When the Admin selects that channel Then the UI prevents selection with a validation message and suggests available channels Given Reissue completes When the attendee opens the newly issued link Then it joins the correct class room/session and the old link fails with a rotated/invalid message Given Reissue is performed When viewing audit logs Then an entry appears with actor, attendee ID, old/new token hash prefixes (masked), channels sent, and delivery outcomes
Resend Update and Copy Link
Given an attendee with an existing valid token When an Admin clicks Resend Update and selects SMS and Email Then the same token is resent on the selected channels and delivery outcomes are displayed in-line within 15 seconds Given an Admin clicks Copy Link on an attendee row When the action completes Then the attendee-specific URL with the current valid token is placed on the clipboard and a toast confirms success; the UI displays the token masked while the clipboard contains the full link Given Resend fails on a channel (e.g., SMS provider error) When the retry option is clicked Then the system retries with exponential backoff up to 3 attempts and logs outcomes per attempt in the audit trail
Pause and Resume Rotation for a Session
Given a class with auto-rotation scheduled When an Admin clicks Pause Rotation Then auto-rotation for that class is skipped for the current cycle and the class status shows Paused with a visible banner and reason Given a class is Paused When time passes into the usual rotation window Then no automatic token changes occur and no update messages are sent Given a class is Paused When an Admin clicks Resume Rotation Then the next scheduled rotation is recalculated and displayed; Force Rotate remains available during Pause Given Pause or Resume is executed When viewing audit logs Then an entry exists with actor, previous state, new state, timestamp, and optional reason
Delivery Reliability & Fallbacks
"As an operations manager, I want failed link updates to automatically retry or use a fallback channel so that students still receive the correct link before class begins."
Description

Monitors and improves deliverability of updates through retries, alternative channels, and short-link management. Tracks SMS delivery receipts and email engagement signals; if delivery is uncertain, triggers a fallback channel (e.g., email if SMS fails, SMS if email bounces). Manages branded short domains with per-token links, rate limiting, and anti-spam safeguards. Provides per-class delivery dashboards and alerting for high failure rates prior to class start.

Acceptance Criteria
SMS Retry and Email Fallback on Undelivered Rotate Update
Given a scheduled class with Silent Rotate enabled and a participant having a valid phone and verified email And the rotate update is initiated 15 minutes before class start When the system sends the SMS containing the participant’s per-token short link Then a "delivered" receipt must be received within 2 minutes or the SMS is marked uncertain And if the SMS is uncertain or failed, an email with the same tokenized link is sent within 1 minute And the system must not send more than 3 SMS attempts per participant, with exponential backoff (1m, 3m) And the participant’s delivery outcome is "Success" if either SMS delivered receipt is received or the link is clicked from any channel And all attempts, receipts, and timestamps are logged to the per-class delivery dashboard within 30 seconds
Email Bounce or No-Engagement Triggers SMS Fallback
Given a participant is opted into both email and SMS and not opted out of SMS When the rotate update email with a per-token short link is sent Then if a hard bounce is detected, an SMS fallback is sent within 1 minute And if no email open or link click is detected within 5 minutes and class start is in ≤ 15 minutes, an SMS fallback is sent And no more than 1 email and 1 SMS fallback are sent for this rotate event per participant And thread continuity is preserved by replying in the existing SMS/email thread where supported And the delivery outcome is "Success" if the SMS is delivered or the link is clicked; otherwise set to "Failed" 5 minutes before class if neither delivered nor clicked
Branded Short Domain Health Check and Auto-Fallback
Given an organization has configured a branded short domain When generating per-token links for a rotate event Then links use the branded domain over HTTPS with a valid certificate And if DNS resolution fails, TLS validation fails, or upstream returns 5xx for > 30 seconds, the system switches to the default ClassTap short domain within 30 seconds And redirect latency to the final join URL is ≤ 300 ms P95 and ≤ 600 ms P99 during the rotate window And domain health status and current domain (branded or fallback) are displayed on the per-class delivery dashboard
Per-Token Link Rotation, Invalidation, and Abuse Controls
Given a new rotate token is issued for a participant When the new token is activated Then all prior tokens for that participant and class are invalidated within 5 seconds And requests to invalidated tokens return HTTP 410 with a branded help message And valid tokens redirect with HTTP 302 to the current join URL and are scoped to a single participant And link access is rate-limited to 5 requests per minute per IP and 20 per hour per token; exceeding limits returns HTTP 429 and is logged And token identifiers provide ≥ 128 bits of entropy and expire 2 hours after class start
Outbound Message Rate Limiting and Anti-Spam Safeguards
Given a rotate event requires notifying multiple participants When dispatching SMS and email messages Then SMS send rate must not exceed the configured provider limit (default 30 msg/sec per sender) and must back off and retry on 429/420 with exponential backoff up to 3 times And no participant receives more than 1 message per channel within any 60-second window for the same rotate event And SMS content includes brand identification and opt-out language; noncompliant messages are blocked and surfaced on the dashboard And dispatch completes within 3 minutes for up to 2,000 recipients while honoring rate limits
Per-Class Delivery Dashboard and High-Failure Alerting
Given a class with pending or in-progress rotate updates When viewing the per-class delivery dashboard Then the dashboard displays counts and percentages by channel state (Queued, Sent, Delivered, Failed, Fallback Triggered, Clicked) updated at least every 60 seconds And failure rate is computed as (Failed + Uncertain>10m)/Sent and timestamped And if failure rate ≥ 10% with ≥ 20 recipients between T-30 and T-5 minutes before class, an alert is sent to the instructor via email and SMS within 1 minute containing a link to the dashboard And acknowledging the alert suppresses further alerts for 10 minutes unless failure rate increases by ≥ 5 percentage points And dashboard data exports to CSV and reconciles with message logs within ±1 count
Security, Audit Logging, and Compliance
"As a compliance lead, I want comprehensive logs and strong controls around link issuance and rotation so that we meet regulatory requirements and can investigate incidents with confidence."
Description

Applies encryption at rest and in transit for tokens and related metadata, uses HMAC/nonce protections, and stores minimal PII in links. Maintains immutable audit logs for token issuance, rotation, invalidation, and access attempts, with exportable reports for incident review. Implements configurable anomaly alerts, data retention policies, and compliance controls aligned to GDPR/CCPA and SOC 2, ensuring that security posture is upheld without degrading user experience.

Acceptance Criteria
Encrypt Tokens and Metadata at Rest and In Transit
Given the system stores join tokens and related metadata When data is written to persistent storage Then it is encrypted at rest using AES-256-GCM with keys managed by a KMS and rotated at least every 90 days Given an API or webhook transmits tokens or metadata When data is sent over the network Then TLS 1.2+ (prefer TLS 1.3) with PFS (ECDHE) is enforced and HSTS is enabled Given a service attempts to connect without strong TLS When a weak cipher, protocol below TLS 1.2, or invalid certificate is presented Then the connection is rejected and an audit event is recorded Given backups or exports contain token metadata When backups are created or restored Then backups are encrypted at rest and in transit using the same controls and keys are access-controlled via least privilege
Signed, Nonce-Protected, Minimal-PII Join Links
Given a join link is generated for a class session When the link is created Then the URL contains no direct PII (no name, email, phone) and only an opaque token and timestamp parameters Given a join link is generated When it is signed Then an HMAC-SHA256 signature is computed over token + timestamp + scope using a server-held key and appended as a signature parameter Given a client presents a join link When the server validates it Then the HMAC signature is verified, the nonce is checked for one-time use, the token scope matches the class/session, and the TTL has not expired Given a rotation occurs When a new token is issued Then the prior token is invalidated immediately and further requests using it fail with HTTP 401 and are logged as invalid attempts
Immutable Audit Logging for Token Lifecycle and Access
Given token lifecycle events (issuance, rotation, invalidation) and access attempts occur When these events happen Then an append-only audit record is written capturing event type, UTC timestamp, org_id, class_id, actor_id (or system), request_ip, user_agent, reason_code, and a hashed token reference (no raw token) Given audit records are stored When records are persisted Then they are protected via immutability controls (WORM or hash-chain with periodic anchor) and write/delete operations are denied except through retention policy enforcement Given auditors query logs When filtering by time range and fields Then results return within 2 seconds for up to 10k events and within 60 seconds for up to 100k events Given time synchronization is required When events are recorded Then system clocks are NTP-synced with max drift under 200ms and drift metrics are logged
Audit Log Export with Role-Based Access and MFA
Given an organization admin requests an audit export When the admin is authenticated and has the Audit.Export permission and active MFA Then the export UI/API allows selecting format (CSV/JSON), time range, event types, and fields without exposing raw tokens or PII Given an export job is submitted When the dataset is <= 100k events Then the export completes within 60 seconds and is available via a signed, time-limited download URL (<= 15 minutes) Given access to audit exports is sensitive When a user without the required role or without MFA attempts export Then the request is denied with HTTP 403 and an audit event is recorded Given an export is generated When it is downloaded Then the download is logged with requester identity, IP, timestamp, and checksum of the exported file
Configurable Anomaly Detection and Alerting
Given security anomalies must be detected When more than 5 invalid link attempts occur for the same class within 10 minutes from distinct IPs Then an anomaly alert is generated and delivered to configured channels (email, SMS, webhook) within 60 seconds Given rotation behavior may be abused When more than 3 rotations are triggered for a single session within 30 minutes Then an alert is generated with context (org_id, class_id, actor_id, counts) and recommended actions Given geo/IP changes can indicate compromise When access attempts for a single token originate from 3+ countries in 1 hour Then the token is auto-invalidated and an alert is sent Given organizations have different risk appetites When an admin updates thresholds or channels Then changes take effect within 5 minutes and are audited
Data Retention and GDPR/CCPA Deletion/Pseudonymization
Given a data retention policy is configured per organization When the retention window is set (30–730 days) Then audit records older than the window are purged automatically within 24 hours while preserving aggregate metrics Given a data subject access/deletion request is received When the subject is verified Then all direct PII related to the subject is deleted or pseudonymized in tokens/metadata within 72 hours, while retaining security logs with irreversible pseudonyms (salted hash) and no raw PII Given backups contain data subject information When a deletion request is processed Then backups are exempt from immediate purge but documented, and restoration procedures include re-applying deletions before making data accessible Given compliance reporting is required When exporting a deletion proof report Then the report includes request id, timestamps, scope of data affected, fields anonymized/deleted, and verification evidence
Security Controls Do Not Degrade User Experience
Given a join link is validated at click time When a participant opens the link Then server-side verification adds no more than 150ms p95 latency per request within the primary region and maintains 99.9% success rate for valid links Given a silent rotation occurs before class When the system updates SMS/email/calendar threads Then the new link appears in the same conversation/thread within 60 seconds and the old link shows a friendly expiration page with guidance, without exposing sensitive details Given an invalid or expired link is used When the participant clicks it Then they are redirected to a help screen that offers a one-tap path to the latest valid link (if authenticated) or prompts minimal, secure re-auth, and the event is logged Given accessibility requirements When the expiration/help page is rendered Then it meets WCAG 2.1 AA for contrast, focus order, and screen reader labels

Join Pass

Lets attendees save a dynamic Join Pass to Apple Wallet/Google Wallet with a time-aware Join button and QR fallback. Passes auto-refresh on rotation and work offline, making access frictionless even when users can’t find the original message.

Requirements

Wallet Pass Generation & Delivery
"As an attendee, I want to save my class pass to Apple Wallet or Google Wallet so that I can access class details and join with one tap without searching emails or texts."
Description

Generate per-booking Apple Wallet (PKPass) and Google Wallet passes that include class title, date/time, location or online meeting link, attendee name, instructor, and booking status. Provide Add to Apple Wallet and Save to Google Wallet actions on the confirmation screen and in SMS/email receipts, with deep-link fallbacks. Sign passes with platform-required certificates/keys, assign unique serials, and store minimal pass metadata for updates. Support single classes, series, and multi-spot bookings. Ensure delivery reliability with retry and link-expiry controls, and respect privacy by excluding sensitive data.

Acceptance Criteria
Add to Apple Wallet from Confirmation Screen (Single Booking)
Given a confirmed single-class booking on an iOS device When the user taps "Add to Apple Wallet" on the confirmation screen Then a PKPass is generated and signed with the platform Apple Wallet certificate And the pass includes class title, start date/time with timezone, venue address or "Online" with meeting link, attendee name, instructor name, and booking status And the pass has a unique serial number for this booking And the Wallet sheet presents and the pass installs successfully without duplicates (updates existing if previously installed) And no sensitive data (email, phone, payment details, internal notes) is included
Save to Google Wallet from Email/SMS with Deep-Link Fallback
Given a confirmed booking and a receipt delivered via email or SMS When the user taps "Save to Google Wallet" on an Android device with Google Wallet available Then a Google Wallet pass/object is created with class title, start date/time with timezone, venue address or "Online" with meeting link, attendee name, instructor name, and booking status And the pass is saved to the user's Google Wallet without errors When the same link is opened on an unsupported device/browser Then a responsive fallback page is shown with guidance and device-aware deep links (Apple pkpass on iOS, Google Wallet on Android)
PKPass Signing and Unique Serial Assignment
Given pass generation is requested for Apple Wallet When the pass payload is assembled Then it is signed using the configured Apple Wallet certificate/private key and validated before delivery And the pass is assigned a globally unique serial per booking (and per occurrence/spot where applicable) And if signing or validation fails, no pass is delivered, an error is logged with correlation ID, and the user sees a retry-safe message
Pass Content Accuracy and Privacy Exclusions
Given a booking exists When generating a wallet pass Then displayed fields exactly match the booking: class title, date/time with timezone, location (street address) for in-person or an https meeting/join link label for online/hybrid, attendee name, instructor name, and booking status (Confirmed/Cancelled/Waitlisted) And field formats meet Apple/Google schemas and localize to the booking locale And sensitive data (email, phone number, payment method/amount, health info, internal notes) is excluded from the pass payload
Series and Multi-Spot Booking Support
Given a booking for a series with N scheduled occurrences When generating passes Then one pass is generated per occurrence with occurrence-specific date/time and location And delivery surfaces provide per-occurrence save actions and an "Add all" option Given a booking with M spots for the same occurrence When generating passes Then M distinct passes are created (one per spot) with unique serials and attendee labeling (named attendees or "Spot X of M")
Delivery Reliability: Retry and Link Expiry Controls
Given pass generation or delivery to the client fails due to a transient error When the attempt fails Then the system retries up to 3 times with exponential backoff (1m, 5m, 15m) and records outcomes And if all retries fail, the user-facing link offers a manual regenerate option without creating duplicate serials Given a wallet pass link/token is issued When X days have elapsed since issuance (X=7) Then the link expires and returns HTTP 410 with a secure path to request a fresh link after re-authentication
Minimal Metadata Storage and Update Propagation
Given a pass has been issued When storing data for future updates Then only minimal metadata is persisted: booking_id, wallet_type (apple/google), serial/object_id, booking_status_hash, and last_synced_at (timestamps), encrypted at rest And no PII (email, phone, payment details) is stored in wallet metadata Given a booking status or schedule changes (e.g., cancel, reschedule) When the change is saved Then the system uses stored metadata to push an update to the existing pass within 60 seconds or flags for next sync if offline, without reissuing a new serial
Time-aware Action Button Logic
"As an attendee, I want the pass button to change to the right action at the right time so that I always know how to get into class or check in with minimal friction."
Description

Implement a server-driven rules engine that controls the primary action on the pass based on schedule context. Before the class, show Add to Calendar or View Location; within the configurable join window for hybrid/online classes, show Join Now to open the meeting URL; at the venue, show Show QR for check-in; after start, show Late Check-in if permitted; after end, show Class Ended. Enforce time zones, daylight saving changes, and instructor overrides. Ensure the action works with one tap from the pass and degrades gracefully if the device is offline.

Acceptance Criteria
Pre-Class Primary Action: View Location vs Add to Calendar
Given an in-person class and current time is before the server-configured join window When the pass is displayed Then the primary action label is "View Location" and a single tap opens the default maps app to the venue using the server-provided address or lat/long Given an online-only class and current time is before the join window When the pass is displayed Then the primary action label is "Add to Calendar" and a single tap opens the OS calendar add flow pre-filled with title, start/end, and event timezone Given a hybrid class and current time is before the join window When the pass is displayed Then the primary action label is "View Location" and the map deep link opens in one tap Rule: The primary action does not require more than one user interaction (no intermediary confirmations within the app)
Join Window Action: Join Now Opens Meeting URL
Given a hybrid or online-only class and current time is within the server-configured join window When the pass is displayed Then the primary action label is "Join Now" And a single tap opens the meeting URL in the native app if installed, otherwise in the browser And the meeting URL is the server-provided canonical URL Given the device is offline within the join window When the user taps "Join Now" Then the app surfaces the cached meeting URL with options to Copy and Open (deferred) without crashing And the action label remains "Join Now" and state is preserved until connectivity returns Rule: The action switches to "Join Now" no later than 60 seconds after entering the join window and reverts appropriately if the server updates the window
On-Site Check-in Action: Show QR
Given current time is within the server-defined check-in window and the server action is CHECK_IN When the pass is displayed Then the primary action label is "Show QR" And a single tap displays a scannable QR containing the server-issued booking token And the QR screen loads in under 500 ms on a mid-tier device Given the device is offline When the user taps "Show QR" Then the QR renders from cached token and can be successfully scanned by the ClassTap scanner to check in Rule: If the server updates the action away from CHECK_IN, the pass updates the label within 60 seconds
Post-Start Action: Late Check-in When Permitted
Given class has started and instructor allows late check-in within a server-configured grace period When the pass is displayed Then the primary action label is "Late Check-in" And a single tap triggers the late check-in flow: either opens the QR for late check-in or posts to the late check-in endpoint, as configured by the server Given instructor does not allow late check-in or grace period has elapsed When the pass is displayed Then the late check-in action is not shown and the next applicable action is rendered per rules Given the device is offline during permitted late check-in When the user taps "Late Check-in" Then the cached late check-in QR/token is shown and is accepted by the ClassTap scanner upon reconnection at the door
Post-End Action: Class Ended State
Given current time is after the server-reported class end time When the pass is displayed Then the primary action label is "Class Ended" And the button is visually disabled and non-tappable And no navigation occurs on tap Rule: If the server extends the end time, the pass removes the "Class Ended" state within 60 seconds and restores the correct action
Time Zone and Daylight Saving Enforcement
Given the event timezone is set by the organizer (e.g., America/Los_Angeles) When a user in any device timezone views the pass Then the join window, check-in window, and end time are computed using the event timezone and not the device timezone Given a class scheduled across a DST transition in the event timezone (e.g., starts at 01:30 during fall-back) When the join window opens Then the action transitions occur at the correct absolute instant accounting for the DST shift Rule: Server responses include timezone-aware timestamps (ISO 8601 with offset or Z) and the client honors them without applying additional device-local shifts
Instructor Overrides Precedence and Expiry
Given an instructor sets an override for the primary action with a target label and destination until a specified expiry timestamp When the pass is displayed within the override’s effective window Then the overridden action label and tap behavior are shown in place of the computed default And the change is reflected on the pass within 60 seconds of the override being published Given the override expires or is revoked by the instructor When the pass next refreshes Then the action reverts to the server-computed default within 60 seconds Rule: If the server rejects an override as invalid, the pass continues to display the last valid action and logs the error state (no broken or empty action shown)
Rotating QR Check-in Fallback
"As a front-desk staff member, I want to scan a secure QR on the attendee’s pass so that I can verify their booking even if links fail or connectivity is poor."
Description

Embed a unique QR code on the pass that encodes a short-lived, signed token tied to the booking, class, and device. The QR can be scanned by the ClassTap Host app or web scanner to confirm attendance, with replay protection and rate limiting. Rotate the token periodically when online and persist the last valid token for offline display. Prevent sharing by limiting scans per booking and invalidating tokens after successful check-in or after the time window. Provide human-readable backup code for manual lookups.

Acceptance Criteria
Signed, Short-Lived QR Token Encoding and Rotation
Given a confirmed booking has an active Join Pass and the device is online When the pass is opened Then the QR contains a signed, short-lived token including booking_id, class_id, device_id, iat, exp, nonce, contains no PII, and the signature verifies against the server public key Given the device remains online When 30 seconds elapse Then a new token is generated and displayed, replacing the prior token within 5 seconds Given the device is offline When the pass is opened Then the last unexpired token generated in the past 10 minutes is displayed Given a token is expired When it is scanned Then validation fails with reason "Expired" and attendance is not recorded
Online Scan Validation with Replay Protection
Given the Host app or web scanner is online When it scans a QR token Then it validates the signature, token freshness (current server time < exp), and that booking_id, class_id, and device_id match an existing, eligible booking Given a token has already been scanned successfully When the same token is scanned again Then the scan is rejected with reason "Token already used" Given the token payload or signature is tampered When scanned Then the scan is rejected with reason "Invalid signature" Given the booking is canceled, transferred, or otherwise ineligible When its token is scanned Then the scan is rejected with an appropriate ineligibility reason and attendance is not recorded
Post-Check-in Invalidation and Single-Use Enforcement
Given a booking has not yet been checked in and is within the configured check-in window When a valid token for that booking is scanned successfully Then the booking is marked "Checked in", all tokens for that booking are immediately invalidated, and the pass state updates to "Checked in" within 10 seconds Given any token for a booking that is already checked in When scanned Then the scan is rejected with reason "Already checked in" Given the configured check-in window has elapsed When any token for that booking is scanned Then the scan is rejected with reason "Outside check-in window"
Rate Limiting of Scan Attempts per Booking
Given any single booking When more than 10 scan attempts (valid or invalid) occur within 60 seconds across scanners Then subsequent attempts within that window are rejected with reason "Too many attempts" and the event is logged Given any single scanner device When more than 30 scans are attempted across bookings within 60 seconds Then subsequent attempts within that window are throttled with reason "Rate limited" Given repeated invalid scans for the same booking exceed 5 within 5 minutes When further scans are attempted Then scans are temporarily blocked for 2 minutes for that booking with reason "Temporarily locked"
Offline Display with Last Valid Token Persistence
Given the pass device is offline and has previously fetched a valid token When the pass is opened Then the last unexpired token is shown in the QR and its valid-until time is reflected on the pass Given the pass device returns online When the pass is reopened or receives a background update Then token rotation resumes within 5 seconds without user action Given the pass device is offline and no cached token exists When the pass is opened Then no QR token is shown and the backup code is prominently displayed for manual lookup
Manual Backup Code Lookup
Given a user cannot present a scannable QR When they present the backup code displayed on the pass Then the code format is 10-16 characters, grouped (e.g., AAAA-BBBB-CCCC), case-insensitive, excludes ambiguous characters (O, 0, I, 1), and maps to the booking Given a host enters a valid backup code in the Host app or web scanner When submitted Then the system returns the matching booking and allows check-in subject to the same eligibility and rate-limit rules as QR scans Given an invalid or expired backup code is entered When submitted Then the system responds "Code not found or expired" and does not record attendance
Real-time Pass Updates & Token Rotation
"As an attendee, I want my wallet pass to update automatically when class details change so that I always have the latest information without re-adding the pass."
Description

Push updates to Wallet passes when class details or booking status change, including start time, venue, instructor, waitlist promotion, cancellations, and transfer. Integrate with Apple Wallet push update APIs and Google Wallet real-time updates, manage certificates and issuer keys, and handle retries and throttling. Update pass fields, messages, and the time-aware action state, and rotate QR tokens on schedule or on-demand. Maintain versioning and audit logs to ensure traceability of every update.

Acceptance Criteria
Update Pass on Class Detail Change
Given a confirmed booking with a Join Pass saved in Apple Wallet or Google Wallet When the class start time, venue, or instructor is changed in ClassTap Then a push update is sent to both wallet platforms within 60 seconds And the pass fields (time, venue, instructor) reflect the new values And the time-aware action state is re-evaluated and updated accordingly And the pass version increments by 1 and no duplicate pass is created And an audit log entry records the update with before/after values and push response IDs
Waitlist Promotion Push Update
Given an attendee on a waitlist with a Join Pass showing status "Waitlisted" and a disabled Join action When the attendee is promoted to confirmed Then the pass status changes to "Confirmed" on both Apple and Google Wallet within 60 seconds And the Join action becomes enabled per the time window rules And the QR token rotates immediately and previous token is revoked And an audit log entry is created linking the waitlist promotion to the pass update And the pass version increments by 1
Cancellation and Transfer Notifications
Given a Join Pass for a booked attendee When the class is cancelled Then the pass shows status "Cancelled", the Join action is disabled, and the QR token is revoked And a cancellation message is displayed with refund/credit info when applicable And both Apple and Google Wallet passes receive the update within 60 seconds When the attendee is transferred to a different class Then the pass updates to the new class details and shows a "Transferred" banner And the previous class QR tokens are invalidated and not accepted by the scanner And audit logs capture cancellation/transfer events with correlating pass versions
Time-Aware Join Action State
Rule: Join action is Disabled when now < start_time - 15 minutes Rule: Join action is Enabled from start_time - 15 minutes to start_time + 30 minutes Rule: Join action changes to "Expired" after start_time + 30 minutes Rule: For hybrid/online classes with a join URL, the action label shows "Join Online" when Enabled; otherwise shows "Check In" Rule: Device timezone differences are accounted for using the class timezone to compute windows Rule: Changes in start_time trigger immediate re-evaluation of the action state on the pass
QR Token Rotation and Offline Fallback
Rule: QR token rotates on a fixed schedule every 5 minutes during the Enabled window and on-demand upon status changes (promotion, transfer, cancellation) Rule: Validation accepts only the current and immediately previous token for a maximum overlap of 10 minutes Rule: Pass displays the most recent token while offline; scanner validates tokens offline using signed, time-bounded payloads Rule: On cancellation or transfer, server marks all prior tokens as revoked; scanners reject them on next sync or immediately if online Rule: Token payload includes pass_id, class_id, attendee_id, expiry, and signature; no PII is embedded
Reliability, Rate Limits, and Credentials Management
Rule: Push updates use idempotency keys per pass update; duplicate deliveries do not create duplicate versions Rule: Transient failures are retried with exponential backoff up to 6 attempts; final failures go to a dead-letter queue with alerting Rule: Rate limiting respects Apple/Google quotas; backlog is queued and drained without exceeding provider thresholds Rule: Apple Wallet pass certificates are monitored and rotated at least 14 days before expiry with zero-downtime key rollover Rule: Google Wallet issuer keys are rotated without breaking existing passes; all API calls use the current active key Rule: Operational metrics (success rate, latency, retry count) and alerts are available via dashboard and emitted to logs
Versioning and Audit Logging
Rule: Each pass update increments a monotonically increasing version number stored on the pass and backend Rule: Audit log entry includes timestamp, actor (system/user), change type, before/after fields, target pass IDs, token version, and provider response IDs Rule: The system can reconstruct the pass state at any historical timestamp using versioned records Rule: Audit logs are immutable, tamper-evident, and retained for at least 13 months; access is RBAC-controlled Rule: A read-only endpoint exposes update history filtered by pass_id or booking_id
Offline Validation & Resilience
"As a studio staff member, I want to validate passes offline so that check-in continues smoothly during network outages or in low-connectivity locations."
Description

Enable check-in without internet by encoding a signed claim in the QR that includes booking id, class id, valid-from/until, and a nonce, verifiable offline with a public key embedded in the scanner. Queue check-ins for later sync, prevent double use with local caching, and handle clock drift with a small grace period. Ensure the pass itself fully renders offline with essential details and provides a confirm code for manual verification if scanning is unavailable.

Acceptance Criteria
Offline QR Signature Verification
Given the scanner device has no internet connectivity And a Join Pass QR encodes a signed claim containing booking_id, class_id, valid_from, valid_until, and nonce And the scanner has the correct public key embedded When the QR is scanned Then the signature is verified offline against the embedded public key And the payload fields are present and parse to valid formats And verification completes in <= 1 second on a mid-tier device And if signature verification fails, the scan is rejected with "Invalid pass" and no check-in is recorded
Local Double-Use Prevention (Offline)
Given the scanner is offline And a pass for booking_id X and class_id Y is successfully checked in When any pass for booking_id X and class_id Y is scanned again before sync Then the app blocks the check-in using a local cache And displays "Already checked in at [HH:MM]" And the block persists across app restarts until class end time or successful sync
Queued Offline Check-ins and Idempotent Sync
Given there are N offline check-ins queued on the device When connectivity is restored Then the device transmits the queued check-ins within 10 seconds And preserves the original local check-in timestamps And retries failed transmissions with exponential backoff until acknowledged And the server treats duplicate submissions idempotently (no duplicate attendance) And the local queue entries are only removed after acknowledgment is received
Clock Drift Grace Period Handling
Given the scanner device clock may drift by up to +/- 5 minutes from server time When a pass is scanned within [valid_from - 5 minutes, valid_until + 5 minutes] Then the check-in is accepted When a pass is scanned outside this extended window Then the check-in is rejected with "Not yet valid" or "Expired" accordingly
Offline Pass Rendering with Essentials
Given the user's device is offline When the Join Pass is opened in Apple Wallet or Google Wallet Then the pass renders without network calls using embedded assets and data And displays attendee name, class title, class date/time (with timezone), location, booking status, and a visible confirm code And the QR code is visible and scannable And the layout remains intact with offline image fallbacks
Manual Confirm Code Entry (Offline)
Given the scanner camera is unavailable or the QR is unreadable And the device is offline When staff selects "Enter Confirm Code" and inputs the code shown on the pass Then the app validates the code offline and maps it to booking_id and class_id And applies the same validity window and double-use rules as QR scans And upon success, records an offline check-in queued for sync And upon failure, displays "Invalid code" and records nothing
Rotated Token Acceptance (Offline)
Given the pass rotates its QR token periodically And the scanner is offline When any rotated token for a booking is scanned within its valid window Then the scan is accepted if that booking has not been checked in locally And the scan is rejected if that booking has already been checked in locally, regardless of token rotation And tokens with expired valid_until are rejected
Pass Lifecycle Management & Revocation
"As an attendee, I want my pass to reflect booking status changes instantly so that I can trust whether it’s valid to use for entry."
Description

Define lifecycle rules for issuance, activation, suspension, transfer, expiration, and revocation of passes tied to booking state. Auto-issue on confirmation; issue a holding pass for waitlisted users that auto-activates on promotion; mark as void on cancel/refund; transfer ownership on booking transfer; auto-expire after the class with configurable retention. Propagate lifecycle changes to Wallets via push, and surface clear status messaging on the pass.

Acceptance Criteria
Auto-Issue Active Pass on Booking Confirmation
Given a booking transitions from Pending to Confirmed after successful payment When the confirmation event is persisted to the system of record Then a Wallet pass is generated and provisioned to the attendee within 30 seconds And the pass displays status "Active" with class name, date/time, and venue And the QR payload encodes a valid, non-expired token bound to the booking and session And the pass renders with the last known state when the device is offline
Issue Holding Pass for Waitlisted Users and Auto-Activate on Promotion
Given a user is added to a class waitlist When the booking status is Waitlisted Then a Wallet pass is issued showing status "Waitlisted" with Join disabled and QR inactive And the pass includes messaging that seat is not yet confirmed When the user is promoted to Confirmed for the same class Then the existing pass auto-updates to status "Active" within 30 seconds via wallet push And, if push delivery fails, the pass updates on next open within 5 seconds
Void Pass on Cancel or Refund
Given a confirmed booking with an Active pass When the booking is cancelled by attendee or instructor, or a refund is executed Then the pass status updates to "Void" within 30 seconds and the QR token is revoked And the Join action is disabled and hidden from the pass And the revoked token fails validation at check-in with a clear "Voided" reason And the pass cannot be reactivated without a new confirmed booking
Transfer Ownership on Booking Transfer
Given a booking transfer from User A (current holder) to User B (recipient) is approved When the transfer is finalized in the system of record Then User A's pass updates to status "Transferred" (or "Void") and its QR token is revoked within 30 seconds And a new pass is issued to User B with status "Active" and a fresh QR token And both wallet updates are delivered via push with retries until success or 24 hours timeout And check-in only accepts User B's pass token after the transfer completes
Auto-Expire After Class with Configurable Retention
Given a class has an end time configured When current time reaches class end time Then associated passes switch to status "Expired" within 5 minutes and the Join action is disabled And expired pass QR tokens are rejected at check-in And the pass remains viewable for the configured retention period (default 30 days) with status "Expired" And after the retention period, the pass is removed from the active list or archived per platform capabilities
Propagate Lifecycle Changes to Wallets with Reliable Push
Given any pass lifecycle change (issue, activate, void, transfer, expire) When the change is committed to the system of record Then a wallet push update is enqueued and delivered with measured success rate ≥ 99.5% over a rolling 30 days And failed deliveries are retried with exponential backoff for up to 24 hours And, if the device push token is invalid, the pass state syncs on next open within 5 seconds And an audit log records the change, push attempts, and outcomes with timestamps
Token Rotation, Revocation, and Offline Behavior
Given an Active pass is displayed on a device When the pass is opened or the device orientation changes Then the QR token rotates at least every 60 seconds while remaining valid for scanning during its rotation window And if the pass is revoked (cancel/refund/transfer), subsequent tokens are immediately invalid and previously issued tokens fail validation And if the device is offline, the last issued unexpired token remains scannable for up to 10 minutes, after which it is rejected And scanners apply the latest downloaded revocation list so revoked tokens are blocked even when the attendee device is offline
Branded Pass Templates & Theming
"As a studio owner, I want the wallet pass to match my brand so that the experience feels professional and consistent with my other customer touchpoints."
Description

Provide white-label templates that inherit studio branding, including logo, brand colors, background image, and accent color, with dark mode-aware design. Allow per-organization configuration of displayed fields and ordering (e.g., show room number, instructor headshot). Ensure Apple Wallet and Google Wallet constraints are respected for text length and colors. Support localization of all labels and right-to-left languages.

Acceptance Criteria
Brand Colors and Logo Applied to Wallet Pass
Given an organization with uploaded logo asset and defined primary/accent brand colors When a Join Pass is issued for Apple Wallet and Google Wallet Then the logo renders within the designated logo area without stretching, pixelation, or background artifacts, and maintains aspect ratio on both platforms And the pass background and accent colors are applied, mapping to the nearest platform-supported values if out of gamut And the contrast ratio between foreground text and background is at least 4.5:1 in both light and dark modes And no ClassTap branding is visible anywhere on the pass
Dark Mode-Aware Theming
Given a device set to dark mode When the pass is viewed Then text, icons, and accent elements switch to a dark-mode palette ensuring minimum 4.5:1 contrast, and any provided dark-mode logo variant is used; otherwise an automatic safe inversion is applied And when the device is toggled back to light mode, the pass reverts to the light palette with no layout shift or truncation changes And these behaviors are consistent on both Apple Wallet and Google Wallet
Per-Organization Field Selection and Ordering
Given an admin selects a set of fields (e.g., room number, instructor headshot, class title, start time) and specifies their order in the Pass Template configuration When the configuration is saved Then the selection and order persist for the organization When a new pass is issued Then only the selected fields are displayed in the configured order And if a selected field is unsupported on a platform, it is moved to a supported section (e.g., back fields/supporting text) without validation errors
Text Length and Overflow Handling
Given field values exceeding platform-recommended lengths (e.g., long class titles or instructor names) When the pass is rendered Then values are truncated with an ellipsis according to the platform’s truncation rules, with no clipping, overflow, or wrapping outside the allowed area And the pass payload validates successfully on both platforms with zero errors related to text length
Localization and Right-to-Left Support
Given the user’s locale is set to Arabic When a pass is issued and viewed Then all static labels are displayed in Arabic using the organization’s translations (or default locale fallback), date/time and numbers follow the locale format, and the layout mirrors to right-to-left where applicable And if a translation for a label is missing, the system falls back to the organization’s default language without showing placeholder keys And the same behavior applies for other locales (e.g., en-US, fr-FR), with pluralization and capitalization rules respected
Background Image Support and Safe Cropping
Given an organization provides light and dark background images within documented size and format limits When the pass is rendered on Apple and Google Wallet Then the background image is applied and safely cropped within platform-defined safe areas without obscuring essential text or QR code And if the image exceeds size or aspect limits, a warning is presented at upload and a resized version is used automatically without degradation beyond platform guidelines And if no background image is provided, the pass falls back to solid brand colors without validation warnings
Platform Schema and Validator Compliance
Given a configured branded template When generating Apple Wallet (.pkpass) and Google Wallet (JWT/Save) payloads Then both payloads pass their respective official validators with zero errors and zero critical warnings And if an input (e.g., color or text length) violates a platform constraint Then a pre-issuance validation error prevents saving until corrected or an automatic compliant fallback is applied and logged

Abuse Insights

Provides a live audit trail of link opens with device fingerprint, IP city, and outcome (joined, blocked, step-up). Surfaces anomalies and can auto-enable stricter checks for that booking—helping admins spot sharing patterns and resolve issues in seconds.

Requirements

Open Event Tracking Pipeline
"As an admin, I want every access and outcome on a booking link recorded in real time so that I can see an accurate timeline and quickly identify suspicious behavior."
Description

Implements a low-latency, append-only pipeline to capture every booking-link interaction (open, join, blocked, step-up required, verification passed/failed) with timestamp, device identifier, IP-derived city/region, ASN, user agent, referrer, and optional UTM parameters. Provides SDK hooks for booking pages and server-side email redirect handlers to ensure events are recorded from both web and email entry points. Ensures idempotency and deduplication via event IDs, encrypts data at rest, and exposes a query API optimized for per-booking timelines and organization-wide aggregations. Targets sub-200 ms write latency and near-real-time availability so anomalies can be surfaced instantly in the admin console.

Acceptance Criteria
End-to-End Event Capture From Web and Email Entry Points
Given a booking page rendered with the SDK When a user opens a booking link Then an "open" event is recorded with event_id, booking_id, org_id, timestamp (UTC ISO-8601 with ms), device_id, ip_city, ip_region, asn, user_agent, referrer, and any present utm_* parameters Given an email booking link routed via the server-side redirect When the recipient clicks the link Then an "open" event is recorded with referrer="email" and preserved utm_* parameters Given a user successfully joins a session When the join completes Then a "join" event is recorded associated to the same booking_id and device_id Given access controls deny entry When the page blocks the user Then a "blocked" event is recorded for that booking_id and device_id Given step-up verification is required When the challenge is presented Then a "step_up_required" event is recorded; and When the user completes the challenge Then either a "verification_passed" or "verification_failed" event is recorded
Idempotent Write and Duplicate Suppression
Given the ingest API receives multiple writes with the same event_id within 24 hours When the requests are processed Then exactly one event is persisted and subsequent requests return a success with a dedup indicator Given two writes with different event_id but identical payload When processed Then two distinct events are persisted Given 100 concurrent retries of the same event_id due to client timeouts When processed Then at most one stored record exists for that event_id Given out-of-order arrival of the same event_id from different entry points When processed Then only one canonical record is stored
Low-Latency Ingest and Near-Real-Time Availability SLOs
Given steady load of 2,000 events/second and bursts up to 5,000 events/second When measuring end-to-end write latency Then p95 <= 200 ms and p99 <= 300 ms Given events are written to the pipeline When querying for those events via the query API Then 95% of events are visible within 2 seconds and 99% within 5 seconds of receipt Given ingestion pressure or transient retries When observed over a 10-minute window Then no more than 0.01% of events miss the p99 visibility target
Per-Booking Timeline Query Performance and Ordering
Given a booking_id with up to 500 events When requesting its timeline via the query API Then events are returned in ascending timestamp order with a stable secondary sort by event_id for identical timestamps Given deduplication at write time When the timeline is requested Then no duplicate event_id appears in the response Given pagination with limit=100 and a cursor When requesting pages Then each page returns within 150 ms p95 and 300 ms p99 and includes a next_cursor until all events are retrieved
Organization-Wide Aggregation Query Accuracy and Performance
Given an org_id and a 24-hour time window When requesting aggregations grouped by event_type, ip_city/ip_region, asn, referrer, and utm_source Then counts equal the totals obtained by scanning raw events with the same filters Given typical production load When calling the aggregation endpoint for up to 10 million events in range Then p95 response time <= 1,000 ms and p99 <= 2,000 ms Given filters for event_type, booking_page_id, referrer, and utm_* When applied to aggregations Then results reflect the filters and remain within the stated SLOs
Append-Only Storage Guarantees
Given a client attempts to update an existing event by event_id When calling the API Then the request is rejected (e.g., 405 Method Not Allowed) and no mutation occurs Given a client attempts to delete an event by event_id When calling the API Then the request is rejected and the original event remains retrievable Given repeated reads of the same event_id over time When the payloads are compared Then they are byte-identical, evidencing immutability
Encryption at Rest Compliance
Given events persisted to the primary data store When inspecting infrastructure configuration via provider APIs Then encryption at rest is enabled for all storage artifacts holding event data Given a key rotation operation is performed according to policy When new events are written Then writes succeed and new data is encrypted under the rotated key Given backups or snapshots are produced When examined via provider APIs Then they are also encrypted at rest
Device Fingerprinting & Session Correlation
"As a fraud analyst, I want opens correlated to stable device identifiers so that I can distinguish one person re-opening a link from sharing with multiple devices."
Description

Generates a privacy-preserving device identifier using limited-entropy signals (e.g., user agent, platform, timezone) plus a first-party persistence token to correlate repeated opens from the same device across a booking. Hashes and rotates identifiers on a configurable schedule, gracefully degrades when storage is blocked, and respects user consent settings. Associates events to devices and sessions, handles re-association after step-up verification, and exposes a consistent device_id for UI and rules engine consumption without storing sensitive raw attributes.

Acceptance Criteria
Initial Device ID Generation on First Open
Given a user opens a booking link for the first time on a device with storage available and consent granted When the booking page initializes the Abuse Insights client Then the system generates a device_id using only limited-entropy signals plus a random first‑party persistence token And the device_id is a 64‑character lowercase hex string And no raw device attributes are persisted at rest; only salted hashes or derived values are stored And the persistence token is stored in first‑party storage only and is readable by the same origin And subsequent opens on the same device within the rotation window produce the same device_id for that booking
Identifier Rotation Schedule Enforcement
Given rotation_period_days is configured to N days and a device_id was last generated at T0 When the user next opens the booking page at time T >= T0 + N days Then a new device_id is generated and persisted, and it differs from the previous device_id And the previous device_id is no longer emitted for new events And historical events remain queryable by their original device_id And the rotation timestamp is recorded for audit
Graceful Degradation When Storage Is Blocked
Given the browser blocks first‑party storage or the user has disabled cookies/local storage When the user opens the booking link Then the system issues an ephemeral, session‑scoped device_id computed from limited‑entropy signals and an in‑memory salt And no persistence token is written to storage And repeated requests within the same browser session reuse the same device_id, but a new browser session produces a different device_id And no errors are logged at error level; only an INFO event indicates degraded mode
Consent Respect and Revocation Handling
Given the consent state for fingerprinting is Not Granted When the user opens the booking link Then no persistence token is created and only a session‑scoped device_id is used And no raw device attributes are stored; only transient in‑memory computation occurs Given the consent state changes to Granted during the session When the next page view or significant interaction occurs Then a persistent device_id is generated and used for subsequent events Given consent is later Revoked When revocation is received Then any persistence token is deleted within 5 minutes and future events revert to session‑scoped device_ids And consent changes are captured in the audit log with timestamps
Event-to-Device and Session Association
Given a device_id is present (persistent or session‑scoped) When the user generates events (open, join, blocked, step‑up) Then each event is recorded with device_id and session_id And all events within a session share the same session_id And events across sessions share the same device_id until rotation occurs And querying a booking by device_id returns the ordered event timeline And the 95th percentile latency to fetch events by device_id for a single booking is <= 300 ms
Re-association After Step-up Verification
Given a user is prompted for step‑up verification due to risk When the user successfully completes step‑up Then subsequent events from the current browser are associated to the existing booking's canonical device_id And events produced during the verification flow are linked to that same device_id And if the device_id changed during verification due to storage reset, the system merges pre‑ and post‑verification events under a single canonical device_id within 60 seconds And an audit entry is recorded with reason = step_up_success and includes the prior and new device_id values
Consistent device_id Exposure to UI and Rules Engine
Given the UI or rules engine requests device information for a booking When events are returned or rules are evaluated Then each event includes a device_id matching the regex ^[a-f0-9]{64}$ And the device_id remains stable within its rotation window And APIs and exports expose only derived attributes (e.g., IP city) and never raw sensitive attributes (e.g., full IP, full user agent) And rules can reference device_id and derived risk signals without access to raw attribute values
Anomaly Detection & Scoring Rules
"As an operations manager, I want suspicious patterns automatically scored and explained so that I can act confidently without manually parsing raw logs."
Description

Evaluates incoming events in real time against configurable rules to compute an anomaly score and reason codes per booking. Detects patterns such as many distinct devices on one link, rapid IP-city changes, high open frequency, device churn after a failed step-up, and mismatches with historical behavior. Provides organization-level thresholds and safelists/blocklists, emits structured findings for the UI, and supports simulation mode for tuning. Designed for low false positives with explainable outputs that cite the exact rule triggers.

Acceptance Criteria
Distinct Devices per Link Detection
Given org rule many_devices with window=6h, threshold=3, weight=40 and a booking link A When the 3rd distinct device_fingerprint opens link A within the 6h window Then increment booking A anomaly_score by 40, add reason_code "many_devices" with evidence {count:3, window_hours:6, device_fingerprints:[...]}, and emit a structured finding within 500ms Given subsequent opens by additional distinct devices within the same window for link A When the rule is configured as one_shot=true (default) Then the rule does not trigger again for booking A during that window Given multiple opens from the same device_fingerprint When they occur within the window Then they do not increase the distinct count and do not trigger this rule Given the device_fingerprint differs only by minor browser/OS version When normalization is applied Then the opens are treated as the same device for counting
Rapid Geo‑IP City Switching
Given org rule rapid_geo_switch with window=15m, distinct_city_threshold=2, weight=30 When booking link A is opened from 2 or more distinct IP-derived cities within 15 minutes Then increment anomaly_score by 30, add reason_code "rapid_geo_switch" with evidence {cities:[...], ip_hashes:[...], window_minutes:15}, and emit a structured finding Given both opens resolve to the same metro area (geo_distance<=50km) or same ASN When evaluating distinct cities Then do not trigger this rule Given geo lookup confidence for an open is low (confidence<0.6) When computing distinct cities Then exclude that open from the distinct city count
Post-Step-Up Device Churn
Given org rule device_churn_after_stepup with window=30m, threshold=2, weight=35 and booking A with a failed step-up challenge at t0 When 2 or more distinct device_fingerprints open link A within 30 minutes after t0 Then increment anomaly_score by 35, add reason_code "device_churn_after_stepup" with evidence {since:t0, distinct_devices:2, window_minutes:30}, and emit a structured finding Given booking A has no failed step-up event When multiple devices open link A Then this rule does not evaluate or trigger
Historical Behavior Mismatch Scoring
Given user U has >=3 prior bookings in the last 12 months and baseline metrics are computed (devices_per_booking, cities_per_booking, open_rate) When current booking A deviates from any baseline metric with z_score>=2 under org rule history_mismatch with weight=25 Then increment anomaly_score by 25, add reason_code "history_mismatch" with evidence {metric:..., baseline:..., observed:..., z_score:...}, and emit a structured finding Given user U has <3 prior bookings When evaluating this rule Then do not trigger and record suppression reason "insufficient_history" in the finding
Safelist/Blocklist and Org Threshold Actions
Given a device_fingerprint, IP, email, or booking on the org safelist When evaluating rules for booking A Then exclude safelisted entities from negative scoring and do not trigger enforcement actions due to those entities Given an entity on the org blocklist interacts with booking A When any event is received Then set anomaly_score to org.max_score, add reason_code "blocklisted", emit action "block", and prevent joins Given org thresholds {caution:50, block:80} When booking A anomaly_score crosses 50 for the first time Then emit action "step_up" and mark booking A as requiring step-up on next join attempt Given booking A anomaly_score crosses 80 When evaluating thresholds Then emit action "block" and prevent further joins for booking A Given a safelisted entity conflicts with an active block action When evaluating precedence Then safelist overrides the block and clears the enforcement for that booking
Simulation Mode for Rule Tuning
Given organization O has simulation_mode=true When rules evaluate for booking A Then produce findings with simulated=true and simulated_anomaly_score, but do not change the live anomaly_score and do not emit enforcement actions Given simulation_mode=true When retrieving findings via UI or API Then both live and simulated findings are available and clearly labeled Given simulation_mode is toggled off When subsequent events arrive Then only live findings are produced and enforcement actions apply per thresholds
Explainable Findings Emission
Given any rule triggers for booking A When emitting a finding Then include fields {rule_id, reason_code, weight, delta_score, score_after, booking_id, org_id, rule_version, timestamp, evidence:{...}} and make it available to UI/API within 500ms of the triggering event Given multiple rules trigger on the same event When computing and emitting results Then emit one finding per rule and update the cumulative anomaly_score deterministically using configured rule order/weights Given a rule is suppressed by safelist When emitting findings Then emit a suppressed finding with suppressed=true and reason "safelist" without changing the live anomaly_score
Auto Step-up Verification & Booking-Level Enforcement
"As an admin, I want the system to require extra verification on risky bookings so that potential link sharing is stopped without blocking legitimate attendees."
Description

Automatically enables stricter checks for a specific booking when anomaly thresholds are exceeded, including SMS/email OTP, single-verified-device enforcement, temporary joins lock, and device allow/deny lists. Integrates with existing ClassTap SMS/email infrastructure, supports fallback from SMS to email, and provides time-bounded policies that auto-expire. Includes admin overrides with full audit logging and ensures enforcement does not disrupt payments or legitimate re-joins once verification succeeds.

Acceptance Criteria
Auto step-up policy applied on anomaly threshold breach (booking-scoped)
Given a booking with anomaly detection configured to trigger when ≥3 distinct device fingerprints or ≥2 distinct IP cities occur within 10 minutes When the anomaly threshold condition is met Then the system creates a booking-scoped enforcement policy with actions: require OTP, enable single-verified-device, and lock joins until verification completes And the policy applies only to the affected booking and not to other bookings or the customer account And an audit log entry is written with booking_id, trigger_reason, counts, and triggered_at timestamp And policy activation occurs within 2 seconds of the triggering event
OTP step-up with SMS primary and email fallback
Given a user with both phone and email on the booking and an active step-up policy When a join is attempted Then the system sends a 6-digit OTP via SMS using ClassTap messaging infrastructure and templates And if SMS delivery fails or no delivery receipt is recorded within 60 seconds, an email OTP is sent to the booking email using ClassTap email infrastructure And OTPs expire in 5 minutes and verification attempts are limited to 5 per hour per booking And successful OTP verification marks the current device fingerprint as verified for this booking and clears the temporary join lock And all message send and delivery events are logged to the booking audit trail
Single-verified-device enforcement for the booking window
Given a booking with step-up policy active and a device has successfully verified via OTP When subsequent join attempts occur within the policy window of 4 hours Then only the verified device fingerprint may join without re-verification And join attempts from other device fingerprints are blocked with reason single_device_enforced and offered the option to verify And the verified device may leave and rejoin unlimited times without further prompts within the window And IP or network changes on the verified device do not block joins
Temporary joins lock until first successful verification
Given a booking where step-up policy has just been activated When any attendee attempts to join before any device has verified Then the join is blocked with status verification_required and a prompt to complete OTP And upon the first successful OTP verification for the booking, the lock is lifted for the verified device immediately And if no verification occurs, the lock auto-expires after 15 minutes or upon policy expiry, whichever comes first And payment checkout, refunds, and waitlist actions remain fully available during the lock
Booking-level device allow/deny lists with instant effect and audit
Given an admin with permission manages a booking under step-up enforcement When the admin adds a device fingerprint to the booking allow list Then that device may join without OTP for the duration of the policy and the event is logged with admin_id, fingerprint, reason, and timestamp When the admin adds a device fingerprint to the booking deny list Then join attempts from that device are blocked even with a valid OTP and the event is logged with admin_id, fingerprint, reason, and timestamp And changes take effect within 1 second and are reversible with full audit history
Time-bounded policy auto-expiry and cleanup
Given a booking step-up policy with a configured TTL of 24 hours When the TTL elapses and no further anomalies are detected Then the policy automatically expires and all associated locks and single-device restrictions are removed And verified device entries for the booking are invalidated And an audit entry policy_expired is recorded with expired_at timestamp And subsequent joins proceed without step-up unless a new anomaly triggers a new policy
Admin override with full audit and no disruption to payments or legitimate re-joins
Given a booking with an active step-up policy When an admin overrides the policy to disabled via the console Then the change takes effect immediately and is logged with admin_id, previous_state, new_state, reason, and timestamp And users who have already verified can rejoin without interruption And users who are mid-checkout, payment confirmation, or refund flows are not blocked or errored by the override When the admin re-enables the policy Then subsequent joins again require step-up according to configuration and all actions are logged
Admin Audit Trail & Remediation Console
"As a support agent, I want a clear timeline and one-click remediation tools so that I can resolve access issues during class check-in without escalating."
Description

Delivers a live, filterable timeline per booking that shows link opens with device ID, IP city, and outcomes (joined, blocked, step-up), highlighting anomalies and their reason codes. Offers quick actions—block device, lift restrictions, regenerate link, mark as legitimate—to resolve issues in seconds. Supports streaming updates, role-based access, PII minimization (mask IPs, show city only), and export to CSV for dispute resolution. Optimized to load the most recent 500 events under one second and maintain real-time updates via SSE/WebSocket.

Acceptance Criteria
Load and Display Live Audit Trail (Last 500 Events)
Given a booking with 500 or more audit events When an authorized admin opens the Audit Trail & Remediation Console for that booking Then the most recent 500 events render in the timeline within 1.0 seconds at or below P95 on a cold load And each event row displays timestamp (UTC ISO-8601), device ID (hashed), IP city, and outcome (joined, blocked, step-up) And events flagged as anomalous are visually highlighted and include a machine-readable reason code And if auto-strict checks are active for the booking, a persistent banner shows the current enforcement state with a link to lift restrictions And older events are available via on-demand pagination without blocking initial render
Filter and Search Timeline
Given at least 200 events are loaded in the timeline When the admin applies any combination of filters (outcome, device ID, IP city, time range) or enters a device-ID substring search Then the timeline updates to reflect the filter within 300 ms at or below P95 without a full page reload And the active filters are shown as removable chips And clearing all filters restores the full 500-event view
Real-Time Streaming Updates
Given the console is open and connected via SSE/WebSocket When a new audit event for the booking is produced by the backend Then the event appears at the top of the timeline within 2 seconds end-to-end in at least 99% of cases And the stream auto-reconnects on network drop within 30 seconds with exponential backoff And duplicate events (by event ID) are not rendered more than once
Quick Actions: Block/Lift/Regenerate/Mark Legitimate
Given an authorized admin is viewing the console When the admin selects "Block device" on an event with a device ID Then subsequent link opens from that device for the booking are blocked and a new audit event "device_blocked" is appended with actor, timestamp, and reason And the UI reflects the block state within 2 seconds When the admin selects "Lift restrictions" for a previously blocked device Then future link opens from that device are allowed per normal policy and an audit event "restriction_lifted" is appended When the admin selects "Regenerate link" for the booking Then the previous access link is immediately invalidated, a new link token is generated, and an audit event "link_regenerated" is appended And the timeline records any attempts to use the invalidated link as "blocked (link_invalidated)" When the admin selects "Mark as legitimate" on an anomalous event Then the anomaly flag is cleared for that event and auto-strict checks are disabled for this booking going forward And an audit event "marked_legitimate" with actor and reason is appended
Role-Based Access and Permissions
Given a signed-in user with role "Owner" or "Admin" When they navigate to a booking's Audit Trail & Remediation Console Then they can view the timeline and perform all quick actions and exports Given a signed-in user with role "Instructor" or "Viewer" When they navigate to the console Then they can view the timeline but cannot perform quick actions or regenerate links, and export is disabled And action buttons are disabled or hidden and unauthorized attempts return HTTP 403 Given an unauthenticated user or a user outside the booking's organization When they attempt to access the console route Then access is denied with HTTP 401/403 and no timeline data is leaked
PII Minimization and Masking
Given any event displayed in the console Then the raw IP address is never rendered; only the geolocated city is shown And device identifiers are displayed as stable, non-reversible hashes And copying or export features do not expose raw IPs or other PII beyond city and masked IP (e.g., 203.0.113.xxx) Given an API consumer fetches data for the console Then responses exclude raw IP fields by default and include city and masked IP only
CSV Export for Dispute Resolution
Given an authorized Owner/Admin is viewing a filtered timeline When they click "Export CSV" Then a CSV is generated containing only the events that match the current filters, ordered by timestamp descending And the CSV includes columns: timestamp_utc, outcome, device_id_hashed, ip_city, anomaly_flag, reason_code, actor, action_type And the file is RFC 4180 compliant, UTF-8 encoded with header row, and downloads within 5 seconds for up to 10,000 events And no raw IP addresses are included; if present, IPs are masked And the export action is logged as an audit event with actor and timestamp
Privacy, Consent, and Data Retention Controls
"As a studio owner, I want privacy-friendly tracking with clear consent and retention controls so that I can use Abuse Insights confidently and compliantly."
Description

Provides organization-configurable consent messaging for tracking on booking pages, data minimization (city-level geolocation, hashed device IDs), encryption, and retention windows (e.g., 30–180 days) with automatic purge jobs. Honors Do Not Track where applicable, restricts access via roles and audit logs, and offers per-customer data export/deletion. Supplies policy text snippets and admin documentation to align with GDPR/CCPA requirements without blocking core Abuse Insights functionality.

Acceptance Criteria
Configurable Consent Messaging on Booking Pages
Given an org admin configures consent messaging and tracking categories in Privacy Settings When a first-time visitor loads any booking page Then a consent banner is displayed within 200ms of DOM ready with org-provided text and links to policy snippet Given the visitor has not consented When the page executes Then non-essential tracking for Abuse Insights is disabled and no client-side identifiers are stored except a strictly necessary session nonce Given the visitor provides consent for selected categories When they accept Then the selected categories are persisted with timestamp, consent version, language, and booking page ID Given consent is withdrawn via the banner link When the user opts out Then non-essential tracking is disabled immediately and client-side identifiers for those categories are deleted within 5 seconds Given consent state exists on the device When the same device visits another booking page of the same org Then the prior consent is respected and the banner is not shown unless the consent version changed Given consent is declined When Abuse Insights evaluates an event Then it continues functioning using minimized server-side data only and surfaces anomalies without blocking the booking flow Given an admin views Privacy Settings When they open Policy Snippet Preview Then localized GDPR/CCPA text renders with org name, contact, and retention window placeholders populated
Honor Browser Do Not Track (DNT)
Given a visitor's browser sends DNT:1 When any booking page loads Then non-essential tracking is disabled by default without prompting for consent Given DNT:1 When Abuse Insights records a security event Then only essential fields (timestamp, booking ID, city-level geolocation, hashed device ID) are stored and no client-side cookies are set Given DNT:1 When the visitor navigates across booking pages Then the consent interface displays “respects Do Not Track” copy and any override is off by default Given an admin exports audit events filtered to DNT traffic When records are reviewed Then each record includes DNT=true and contains no granular location or raw IP data Given DNT:1 When an anomaly is detected Then stricter checks may auto-enable for that booking without blocking the booking or exposing disallowed personal data
Data Minimization for Abuse Insights Signals
Given geolocation is derived from IP When the system stores location Then only city and country are persisted; no latitude/longitude or street-level data are stored Given device fingerprinting is enabled When a device identifier is computed Then the identifier is a salted, non-reversible hash that excludes names, emails, and exact IPs Given hashing salt rotation policy When the salt rotates Then prior hashes remain resolvable via versioned keys without revealing original identifiers Given event schemas for Abuse Insights When fields are persisted Then PII fields are limited to the minimum set required for outcomes and are listed in the data inventory Given schema governance is enforced When a developer attempts to add a new event field Then CI validation fails unless the field is tagged as essential with documented justification and approval
Retention Windows and Automatic Purge
Given an org sets a retention window between 30 and 180 days When the setting is saved Then the value is validated and stored per org with a default of 90 days if unset Given the nightly purge job runs at 02:00 UTC When records exceed the org's retention Then those records are hard-deleted or irreversibly anonymized and a purge audit entry is created with counts by type Given an org reduces retention from a higher value to a lower value When the setting is saved Then data older than the new threshold is queued for purge and removed within 24 hours Given purge completes When an admin views the Purge Report Then it shows timestamp, org, number purged, duration, and any failures with retry status Given retention boundaries exist When an admin attempts to set a value outside 30–180 days Then the system rejects the change with a validation error and retains the prior value
Role-Based Access Control and Audit Logging
Given org roles of Owner, Security Admin, Admin, Instructor, and Support When accessing Abuse Insights raw event data Then only Owner and Security Admin can view event details; others see aggregated counts without PII-reduced details Given a user with access views or exports Abuse Insights data When the action occurs Then an immutable audit log entry captures user ID, role, action, filters, timestamp, and IP city Given an unauthorized role attempts access When the request is made Then the system returns 403 and logs the attempt without exposing data Given audit logs exist When an Owner filters by user and date range up to 50k entries Then matching entries return within 2 seconds Given audit integrity requirements When logs are stored Then they are write-once or hash-chained and integrity verification passes during periodic checks
Per-Customer Data Export and Deletion (GDPR/CCPA)
Given an admin enters a customer's email or booking reference When requesting an export Then a downloadable package in machine-readable JSON/CSV is produced within 24 hours including Abuse Insights data for that subject Given an admin submits a deletion request with dual approval When confirmed Then all personal data for that subject is deleted or anonymized across primary stores within 7 days and from backups within 30 days, and a deletion certificate is generated Given the subject has active or past bookings When deletion is processed Then bookings are preserved for accounting but personal fields are replaced with pseudonymous placeholders and Abuse Insights links referencing the subject are removed Given an export or deletion completes When the action finishes Then a corresponding audit log entry is created and visible to Owner and Security Admin Given a subject is deleted When Abuse Insights processes new events for other users Then the system operates normally without errors or references to the deleted subject
Encryption In Transit and At Rest
Given data in transit When booking pages or APIs are accessed Then TLS 1.2+ with modern ciphers is enforced and HTTP is redirected to HTTPS Given sensitive fields (emails, device hashes, IP-derived city) When stored at rest Then they are encrypted using AES-256 or stronger with keys managed in a KMS and access restricted by role Given key rotation policy When a rotation occurs Then decryption continues without downtime and old keys are retired within 24 hours Given backups are created When backup files are written Then they are encrypted at rest and subject to the same retention and purge policies Given lower environments When plaintext access to sensitive fields is attempted Then automated checks block the change and alert security owners

Guest Convert

When a second device attempts access, show a friendly paywall to purchase a guest seat or request a transfer from the booking owner. Monetizes unauthorized sharing without derailing genuine attendees, keeping rosters accurate and revenue intact.

Requirements

Multi-Device Access Detection & Session Linking
"As a booked attendee, I want legitimate device switches to be recognized without blocking me so that I can join class if I swap devices while preventing unauthorized sharing."
Description

Detect and attribute simultaneous or sequential access attempts for the same booking from multiple devices, linking them to a single booking ID while distinguishing legitimate device switches from unauthorized sharing. Implement lightweight device fingerprinting, token-based session tracking, and time/IP heuristics that are privacy-compliant and configurable. Provide an enforcement API that flags second-device events and returns a decision (allow, warn, interstitial) with rationale. Ensure resilience across web and mobile clients, handle intermittent connectivity, and support instructor and kiosk exemptions. Integrate with existing authentication and class attendance systems without adding noticeable latency.

Acceptance Criteria
Graceful Device Switch (Same User, Short Interval)
Given a booking owner with bookingId={id} is active on DeviceA with sessionToken=tokenX and fingerprint=f1 And gracePeriodMinutes=10, overlapSeconds=60, idleTimeoutMinutes=2 are configured defaults When the same authenticated user opens the same booking on DeviceB within gracePeriodMinutes And DeviceB shares the same userId and either the same IP ASN or geofence distance <= 10km from DeviceA Then the Enforcement API returns decision="allow" and reasonCode="graceful_switch" with linkedSessionId referencing DeviceA's session And no interstitial is shown on DeviceB and DeviceA is soft-logged-out after overlapSeconds if both remain active And the attendance system maintains a single attendee record for the booking (no duplicates)
Second Device Detected: Interstitial Paywall Trigger
Given DeviceA is actively accessing bookingId={id} with publicIP=IP1 and fingerprint=f1 at time=t0 When DeviceB with fingerprint=f2 and publicIP=IP2 (IP2 != IP1 ASN or geofence > 10km) attempts access within the same session window Then the Enforcement API returns decision="interstitial" and reasonCode="second_device_detected" with payload including {bookingId, deviceIdB, ttlSeconds >= 120, correlationId} And DeviceA remains allowed with no throttling or disruption And the client renders the Guest Convert paywall within 300ms of receiving the decision And upon successful guest seat purchase or approved transfer callback, the next check for DeviceB within 3 seconds returns decision="allow" And the attendance system records DeviceB as a guest/transfer attendee linked to the original booking (no duplicate owner)
Cross-Platform Session Linking & Roster Consistency
Given the same authenticated user accesses bookingId={id} on Web (DeviceA) and later on Mobile (DeviceB) When DeviceB obtains a new sessionToken via refresh and presents device signals (UA, timezone, screen size) Then DeviceA and DeviceB are linked to a single booking session chain with linkConfidence >= 0.8 And test harness over >= 10,000 simulated events shows session linking accuracy >= 99.5% and duplicate attendance entries <= 0.1% And the audit trail includes {priorDeviceId, newDeviceId, linkConfidence, timestamp} for each link action And the link persists across app restarts and token rotations for up to 24 hours (configurable)
Enforcement API Performance & Latency Budget
Given the Enforcement API is invoked from web and mobile clients at 200 RPS (70% allow, 25% interstitial, 5% warn) under cold cache When requests are made with standard payload size <= 2KB over TLS 1.2+ Then p95 response time <= 150ms and p99 <= 300ms with error rate < 0.1% And end-to-end class join flow adds <= 50ms p95 compared to baseline (measured by client timing) And each response includes non-empty fields: {decision in [allow,warn,interstitial], reasonCode, rationale, correlationId} And API is available 99.9% over a rolling 30-day window, with retries idempotent via checkId
Instructor & Kiosk Exemptions
Given a user with role=instructor for classId={id} or a device marked kiosk=true for the venue When multiple devices attempt to access the same booking concurrently Then the Enforcement API returns decision="allow" with reasonCode in ["instructor_exempt","kiosk_exempt"] And no interstitial or warn prompts are shown on exempt devices And events are logged with exempt=true and excluded from abuse-rate metrics and automated enforcement And allowlists (userIds, deviceIds, CIDR ranges) are configurable and changes propagate to enforcement nodes within 60 seconds
Intermittent Connectivity: Warn and Escalate
Given DeviceA (owner) loses connectivity for <= 3 minutes and reconnects with a rotated token and clock skew within ±60s And DeviceB attempts access to the same booking during DeviceA's outage from a different IP and fingerprint When the sharing confidence score < 0.8 (configurable threshold) Then the Enforcement API returns decision="warn" with reasonCode="uncertain_second_device" and a verification challenge is triggered And if the challenge is not completed within 120 seconds, subsequent checks escalate to decision="interstitial" And no duplicate roster entries are created during the warn window, and all checks remain idempotent via correlationId/checkId
Privacy Compliance & Configurable Heuristics
Given lightweight fingerprinting is enabled (UA, timezone, screen metrics) and PII collection is disabled When a second-device check is executed for bookingId={id} Then captured data contains no PII, is retained <= 30 days by default, and honors tenant-level opt-out toggles And IP/time heuristics thresholds (gracePeriod, distanceKm, ASN match) are configurable per tenant with audited change logs And responses and logs redact IPs to /24 for IPv4 and /48 for IPv6, and user identifiers are tokenized And automated tests verify absence of PII fields and correct application of tenant overrides
Paywall Interstitial with Dual Options
"As a guest attempting access, I want a clear choice to purchase a seat or request the booking owner’s transfer so that I can join without disrupting the class."
Description

Present a branded, accessible interstitial when a second device is flagged, offering two clear paths: purchase a guest seat or request a transfer from the booking owner. Display class details, seat availability, pricing, policies, and countdowns for time-sensitive actions. Support localization, white-label theming, and A/B-tested copy. Maintain user context (class link, device, and state) during navigation, handle deep links from emails/SMS, and provide a graceful fallback if the user signs in as the booking owner. Track impressions, selections, and drop-off for analytics while meeting performance and accessibility standards.

Acceptance Criteria
Instant Guest Seat Checkout
"As a last-minute guest, I want to complete payment in a few taps so that I can secure a seat and join immediately."
Description

Enable a frictionless checkout for guest seats initiated from the interstitial, including real-time seat availability checks, price/tax calculation, discount rules, and fee transparency. Support Apple Pay, Google Pay, and saved cards via existing payment gateways with PCI-compliant tokenization. Ensure transactional integrity to prevent overselling and automatically assign the purchased seat to the accessing device/user upon success. Provide immediate confirmation, receipt issuance, and roster updates, with robust error handling, retries, and refund/cancellation policy adherence for failures or reversals.

Acceptance Criteria
Owner Transfer Request & Approval Flow
"As a booking owner, I want to quickly approve transferring my seat to someone else so that the right person can attend without friction."
Description

Implement a secure, time-bound workflow allowing the accessing device to request a seat transfer from the booking owner. Send actionable notifications via SMS, email, or push with deep links to a one-tap approve/deny screen showing class details and policy implications. Enforce studio-configured limits (e.g., transfer cutoffs, number of transfers, fee requirements) and maintain an auditable trail of requests and outcomes. On approval, reassign the seat, update roster and access tokens in real time, and notify all parties; on denial, direct the requester to purchase a guest seat. Guard against spam with rate limits and verification.

Acceptance Criteria
Studio Policy Configuration & Branding Controls
"As a studio owner, I want to set pricing and rules for guest access so that monetization aligns with my policies."
Description

Provide admin controls for studios to enable/disable Guest Convert, set guest seat pricing models (class price, fixed surcharge, dynamic), define maximum guest seats per booking, set transfer allowances and cutoff windows, and choose default action precedence. Allow customization of interstitial copy, tone, and brand theming, with localization and preview. Support role-based access to settings, environment-specific defaults, and safe deployment via feature flags. Expose configuration via API for white-label partners and ensure changes propagate in near real time without downtime.

Acceptance Criteria
Roster Synchronization, Notifications, and Analytics
"As an operator, I want rosters and reports to update automatically when guests convert so that attendance and revenue stay accurate."
Description

Automatically synchronize roster and attendance records upon guest purchase or transfer approval, preventing double-bookings and preserving capacity constraints. Send confirmations and updated calendar invites to guests, booking owners, and instructors, with receipts and check-in QR codes where applicable. Capture analytics including paywall impressions, conversion rates, transfer approval rates, incremental revenue, and drop-off points; provide exports and dashboards with cohort and class-level filtering. Support A/B testing of interstitial copy and pricing messages, and ensure GDPR/CCPA-compliant consent and data retention.

Acceptance Criteria

Family Cart

Book multiple children in a single, streamlined checkout. Each child gets their own eligibility check, pricing, and add-ons (e.g., mat rental, class packs), while you pay once and receive one organized confirmation. Seat holds apply per child to prevent double-bookings, family discounts are auto-applied, and everyone lands on the roster correctly—cutting time and errors for busy caregivers.

Requirements

Per-Child Eligibility & Profile Selection
"As a caregiver, I want to add multiple children to one booking and have each child checked for eligibility so that I don’t accidentally enroll an ineligible child."
Description

Support selecting multiple child profiles within a single cart. For each child, run age/grade/skill prerequisites and custom eligibility rules (e.g., date-of-birth cutoffs, membership status) against class configurations at search, add-to-cart, and checkout. Block ineligible enrollments with clear reasons and suggest eligible alternatives. Integrate with ClassTap’s profiles, guardian links, waivers, and class variant rules. Provide inline UI to add/manage child profiles and auto-fill required fields. Ensures compliance, reduces errors, and eliminates post-booking corrections.

Acceptance Criteria
Per-Child Seat Hold & Inventory Lock
"As a caregiver, I want seats held for each child during checkout so that I don’t lose spots while entering details."
Description

When a child is added to a class/slot, decrement availability and create an independent seat hold per child with a visible countdown. Holds must persist through page refresh, be tied to session/account, and release on expiry or item removal. Prevent a single child from holding multiple seats for overlapping time slots. Admin-configurable hold duration and concurrency-safe inventory updates across devices. Emit events for hold-created/released to keep waitlists accurate and maintain audit logs.

Acceptance Criteria
Auto Family Discounts & Pricing Caps
"As a caregiver, I want family discounts applied automatically when booking multiple children so that I pay the correct reduced total without codes."
Description

Implement a pricing engine that detects household relationships and applies configurable family rules: sibling discounts, tiered pricing, per-order caps, exclusions, and eligibility windows. Calculate per-child line items and show an itemized savings breakdown in cart and confirmation. Stack correctly with promos, memberships, and class packs while honoring tax rules. Provide an admin UI to define rules, simulation tools for testing, and change audit history. Increases conversion and reduces manual adjustments.

Acceptance Criteria
Per-Child Add-ons & Inventory
"As a caregiver, I want to choose different add-ons for each child so that each gets exactly what they need."
Description

Allow choosing add-ons per child (e.g., mat rental, t-shirt size, class pack) with independent pricing, eligibility, and inventory tracking. Support required vs optional add-ons, quantity limits, variants, and per-session vs term scope. Reflect add-ons on rosters and fulfillment lists and include them in taxation and reporting. Provide a child-grouped UI with clear subtotals and validation. Integrates with existing add-on catalog and stock systems to ensure accurate fulfillment.

Acceptance Criteria
Unified Payment & Itemized Confirmation
"As a caregiver, I want to pay once and receive one organized confirmation that shows details per child so that I can keep records easily."
Description

Process a single transaction for the entire family cart while generating itemized ledger entries per child for tuition, discounts, taxes, and add-ons. Support saved payment methods, split tender, installments, and SCA/3DS. Generate one consolidated receipt and one organized confirmation (email/SMS) with per-child summaries, calendar files, waivers, and studio policies. After payment, create separate enrollments and sync each child to the correct roster. Expose per-order and per-child webhook events for integrations and accounting exports.

Acceptance Criteria
Split Outcomes & Per-Child Waitlist
"As a caregiver, I want children who can enroll to be confirmed and others placed on the waitlist in the same flow so that I don’t have to start separate bookings."
Description

Support mixed outcomes within one checkout: confirm enrollments for available children while placing others on waitlists with clear status indicators. Collect waitlist preferences and payment rules (auto-charge on seat open, manual confirm) per studio policy. Notify guardians per child and update charges and confirmations to reflect actual outcomes. Maintain an audit trail for conversions from waitlist to enrollment and adjust inventory, rosters, and discounts accordingly.

Acceptance Criteria
Per-Child Cancellations, Transfers & Refunds
"As a caregiver, I want to change or cancel for one child without impacting the others so that I can manage each child’s schedule independently."
Description

Enable post-purchase management at the child level: cancel specific sessions, transfer to another class/slot, or refund selected line items without affecting siblings. Enforce studio policies for cutoff windows, change fees, and non-refundable components. Recompute family discounts when items change and apply adjustments or credits fairly. Update rosters, capacities, inventory, and waitlists in real time. Produce itemized refund receipts and exportable accounting reports.

Acceptance Criteria

AgeSmart Filter

See only classes each child is eligible for based on age, grade, or prerequisites. Toggle between kids to instantly filter schedules, get clear reasons when a class isn’t a fit, and see smart suggestions for the nearest eligible option. Fewer misbookings, less back-and-forth, and more confidence at checkout.

Requirements

Multi‑Child Profiles
"As a parent with multiple children, I want to save and switch between each child’s profile so that I can see the right classes for the right child without re-entering details each time."
Description

Enable account holders to create, edit, and select among multiple child profiles, each storing first/last name, date of birth, grade (optional), known prerequisites/skills, and relevant notes. Persist profiles securely across web and mobile booking surfaces, expose them in the booking flow for quick switching, and make them the single source of truth for eligibility checks. Support import from prior bookings, validation on entry (e.g., DOB formats, plausible ages), and localization for grade systems. Ensure data is available via internal APIs to drive filtering, reminders, and waitlists without duplicating entry.

Acceptance Criteria
Eligibility Rules Engine
"As a studio owner, I want to define clear eligibility rules for each class so that only appropriate students can book and staff don’t need to manually screen registrations."
Description

Provide a configurable, high‑performance rules service that determines class eligibility based on age, grade, and prerequisites. Support min/max age windows assessed at class date or term start, grade‑based rules with configurable cutoff dates (e.g., school year boundaries), prerequisite completion requirements, and optional buffers (e.g., within 30 days of turning required age). Return deterministic outcomes with machine‑readable reason codes and human‑readable messages. Include an admin UI to define rule templates per program, set timezones, and preview outcomes for sample profiles. Integrate with search, class detail pages, checkout, waitlists, and APIs, with caching and fallbacks to maintain fast responses under load.

Acceptance Criteria
Instant Child Toggle & Filter
"As a caregiver, I want to toggle between my children and see only the classes each is eligible for so that I can plan quickly without confusion."
Description

Add a responsive UI control to select a child profile and instantly filter the schedule to show only eligible classes, with options to view All, Eligible, or Not Eligible. Apply filters without page reloads, preserve state in URLs for sharable links, and default to the last‑used child for returning sessions. Ensure accessibility (keyboard navigation, ARIA labels), mobile readiness, and performance by reusing precomputed eligibility results. Integrate seamlessly with existing search facets (location, date, modality) and instructor pages.

Acceptance Criteria
Ineligibility Reason Transparency
"As a parent, I want to understand exactly why a class isn’t a fit so that I can make the right choice or take steps to become eligible."
Description

For classes where a selected child is not eligible, display clear, concise explanations and next steps (e.g., “Requires age 7 by Sep 1; your child turns 7 on Oct 2” or “Missing prerequisite: Level 1”). Provide consistent reason codes, localized message templates, and UI patterns (tooltips, inline badges, detail modals) that avoid exposing sensitive information to other users. Include computed deltas (days until eligible) and contextual CTAs (see alternatives, join waitlist) to reduce support inquiries and misbookings.

Acceptance Criteria
Smart Suggestions & Nearest Fit
"As a busy caregiver, I want helpful alternatives when a class isn’t eligible so that I can still book something that works without starting my search over."
Description

When a class isn’t a match, surface the nearest eligible alternatives ranked by proximity in age/grade requirement, time, location, and availability. Include options that become eligible soon (e.g., next session after birthday), related levels, sibling‑friendly time blocks, and waitlist options when appropriate. Respect existing capacity rules and instructor schedules, deduplicate across programs, and track impressions and click‑throughs for optimization. Provide API hooks and components to embed suggestions on class cards and detail pages.

Acceptance Criteria
Prerequisite Tracking & Verification
"As an instructor, I want prerequisites to be automatically verified so that only prepared students enroll and I spend less time checking records."
Description

Maintain a record of prerequisite completions and skill achievements per child, mapped to class requirements. Sync with attendance/completion events from ClassTap and allow admins to map classes to skills (e.g., Level 1 certifies Skill A). Auto‑validate prerequisites at booking, support manual admin overrides with audit logging, and accept external proof via uploads or API integrations. Show prerequisite status in the booking flow and update eligibility in real time as new completions are recorded.

Acceptance Criteria
Privacy & Consent Compliance for Minor Data
"As a privacy‑conscious parent, I want my child’s data handled securely and with consent so that I can trust the platform when booking classes."
Description

Implement parental consent capture and management for storing children’s personal data (DOB, grade), with clear purpose statements and granular controls. Encrypt sensitive fields at rest and in transit, restrict access via role‑based permissions, and minimize exposure in notifications. Support data subject requests (export/delete), region‑specific rules (e.g., COPPA/GDPR‑K), and retention policies. Perform age/eligibility calculations server‑side and log consent events for auditability.

Acceptance Criteria

Guardian eConsent

One-time, reusable e-sign waivers and consents per child (liability, photo release, medical, policies) that auto-attach to future bookings. Supports dual-guardian signatures when required, expiry and renewal reminders, and step-up prompts inside reminder messages—so rosters stay compliant without last-minute paperwork.

Requirements

Child-Guardian Profile Linking
"As a guardian, I want to link my children to my account and save their consents so that I don’t have to re-enter information for every class booking."
Description

Implement a unified profile model that links each child to one or more guardians, enabling reusable consents per child across all future bookings. Support multiple children per guardian, primary/secondary guardian roles, verified contact methods (email/SMS), and deduplication by unique identifiers. Integrate with the booking flow to pre-fill known data, with APIs/imports to onboard existing rosters. Ensure multi-tenant isolation for studios, PII minimization, and consent-scoped visibility so that instructors see only what’s necessary for class operations.

Acceptance Criteria
Compliant eSignature & Audit Trail
"As a studio owner, I want compliant e-signatures with an audit trail so that I can confidently demonstrate consent validity if issues arise."
Description

Provide legally compliant e-signature capture for liability, photo release, medical, and policy forms, with support for typed signature, drawn signature, and checkbox attestations. Record a tamper-evident audit trail including timestamp, IP/device metadata, signer identity, consent version, and hash. Generate non-editable PDFs or immutable records stored with encryption at rest and in transit, with role-based access controls and downloadable proof for studios. Align with ESIGN/UETA principles and support per-tenant branding and language localization.

Acceptance Criteria
Consent Template Management & Versioning
"As an administrator, I want to version and assign consent templates to specific classes so that the right forms are always collected without manual setup each time."
Description

Enable admins to create, brand, and manage consent templates (liability, photo, medical, policies) with dynamic fields, localization, and per-class/category assignment. Support versioning so new signings always use the latest template while preserving historical versions for previously signed records. Allow configuration of required/optional status, dual-guardian requirement, and default expiry duration per template. Provide preview, publish, and rollback controls with change logs.

Acceptance Criteria
Dual-Guardian Signature Flow
"As a guardian, I want an easy way to invite the second guardian to sign electronically so that we can complete required consents without paperwork or schedule coordination."
Description

Support workflows that require two guardian signatures for a child, including sequential or parallel invites via email/SMS, unique secure links, and real-time completion status. Handle partial completion, reminder cadence, and escalation rules. Validate identity per signer, capture separate audit trails, and mark a consent complete only when both signatures are recorded. Provide fallback administrator overrides with attestation and audit logging when policy allows.

Acceptance Criteria
Auto-Attach & Step-Up Prompts
"As a parent booking a class, I want to be prompted to sign only what’s missing so that I can finish quickly and avoid surprises at check-in."
Description

Automatically detect missing or expired consents during booking and attach existing valid consents to the reservation. If consents are missing, trigger step-up prompts embedded in confirmation and reminder emails/SMS with deep links to a mobile-friendly signing flow. Support inline prompts on the booking page and QR codes at check-in, updating roster compliance in real time without staff intervention.

Acceptance Criteria
Expiry, Renewal & Reminder Engine
"As an operations manager, I want automatic consent renewal reminders so that our rosters remain compliant without last-minute chasing."
Description

Allow per-template expiry rules (e.g., 12 months) and automatically schedule renewal reminders for guardians with configurable lead times and channels (email/SMS). On expiry, prevent check-in or booking completion per studio policy, with clear guidance and one-tap renewal links. Preserve historical records and display consent validity windows on profiles and rosters to keep compliance current.

Acceptance Criteria
Roster Compliance Dashboard & Actions
"As an instructor, I want a roster view that highlights missing consents so that I can resolve issues before class starts and avoid delays at check-in."
Description

Provide instructors and staff with a real-time roster view showing each child’s consent status (complete, missing, expired, pending dual signature), with filters, bulk resend of links, and export. Integrate compliance checks into attendance and check-in flows, including optional hard blocks for non-compliant attendees. Log all actions for audit and provide quick-view access to signed records when needed on-site.

Acceptance Criteria

Household Wallet

Share payment methods across guardians with optional spend caps per child, approval rules for higher-cost items, and automatic receipt tagging by child for reimbursements. Works with Apple Pay/Google Pay for one-tap checkout, keeping payments trusted, fast, and organized for split households.

Requirements

Household Linking & Roles
"As a guardian, I want to link another guardian and our children under one wallet so that we can both manage payments and rules without duplicating profiles or methods."
Description

Enable creation of a Household Wallet that links multiple guardians to one or more child profiles. Support role-based access (Owner, Co‑Guardian, Payer‑Only) with distinct permissions for adding/removing payment methods, setting spend caps, and approving purchases. Provide invitation flows via email/SMS, secure acceptance with identity verification, and the ability to merge existing ClassTap child/student profiles. Integrate with existing booking accounts so households can be selected during checkout. Handle edge cases such as guardian removal, transfer of ownership, and split households across studios while preserving data privacy. Ensure data model supports multiple households per guardian and per child without double-booking or misattribution.

Acceptance Criteria
Shared Payment Method Vault
"As a guardian, I want to add a payment method once and let authorized co‑guardians use it so that checkout stays fast and secure across all our devices."
Description

Implement a secure, tokenized payment vault at the household level that allows approved guardians to use shared payment methods (cards, ACH where supported, Apple Pay, Google Pay). Support device‑bound network tokens for Apple Pay/Google Pay while maintaining household‑level authorization controls. Allow defaults per guardian and per household, last‑4 display, and nickname/labeling. Enforce PCI‑DSS and SCA/3DS flows, retry logic, and graceful fallbacks to add a new method. Expose APIs/UI to restrict which guardians can use which methods. Ensure methods can be scoped to certain studios or global, and log all usage for auditability.

Acceptance Criteria
Per‑Child Spend Caps & Time Windows
"As a guardian, I want to set per‑child spending limits with time windows so that we can control our budget without manually tracking every booking."
Description

Provide configurable spend caps per child by transaction, daily, weekly, monthly, and custom date ranges. Allow optional category filters (class fees, passes/packages, add‑ons) and studio scoping. Enforce caps automatically at checkout with clear messaging, pre‑authorization checks, and cumulative tracking that resets on schedule. Include warnings when approaching limits, pro‑rate or exclude taxes/fees based on configuration, and update cap usage on refunds, cancellations, and no‑shows. Ensure caps are considered for waitlist auto‑promotions and recurring bookings, with deterministic outcomes and no partial overages.

Acceptance Criteria
High‑Value Purchase Approval Workflow
"As a guardian, I want high‑cost bookings to require my approval so that I can prevent unexpected charges while still allowing quick scheduling."
Description

Allow household owners to define approval rules based on thresholds, item types, studios, or classes. When a transaction triggers a rule, hold the seat for a configurable window, send approval requests via SMS/email/push to designated approvers, and allow one‑tap approve/deny with biometric confirmation where supported. Support multi‑approver logic (any‑one, all, fallback approver), expiration handling, and automatic release of holds on timeout. Persist an approval audit trail with timestamps, approver identity, and decision reason. Integrate with checkout so approval happens inline without losing cart state and so charges only capture upon approval.

Acceptance Criteria
Automatic Receipt Tagging & Reimbursement Export
"As a guardian, I want receipts automatically tagged by child and exportable so that reimbursements are quick and well documented."
Description

Automatically tag all receipts and invoices with child, class/session, studio, and payer metadata. Surface a household receipts view with filters by child, date range, studio, and status (paid/refunded). Provide export to CSV/PDF and share‑via‑email for reimbursement or FSA/HSA submission, including itemized lines and approval references. Ensure tags persist through refunds/partial refunds and support custom memo fields per child. Integrate with existing email/SMS receipts and allow administrators to resend tagged receipts without exposing full payment details.

Acceptance Criteria
One‑Tap Wallet Checkout
"As a guardian, I want one‑tap checkout that respects our wallet rules so that paying for classes is fast and error‑free."
Description

Integrate the Household Wallet into the booking flow to provide one‑tap checkout with Apple Pay/Google Pay or a saved method, pre‑selecting eligible payment options based on spend caps and approval rules. Autofill payer and household details, show clear cost breakdowns, and pre‑check cap availability before presenting biometric prompts to avoid declines. Support guest‑to‑account upgrade during checkout to attach the transaction to a household. Handle edge cases such as failed biometric auth, 3DS challenges, and switching households mid‑flow without losing the cart or seat.

Acceptance Criteria
Notifications & Audit Trail
"As a guardian, I want timely alerts and a clear activity history so that I can monitor spending and resolve issues quickly."
Description

Provide real‑time notifications for cap approaches/exceedances, approval requests, approvals/denials, successful payments, refunds, and failed charges. Support delivery via in‑app, email, and SMS with user‑level preferences. Maintain a tamper‑evident audit log for household actions (role changes, payment method use, cap edits, approvals) with export and retention controls to meet privacy regulations. Expose an activity timeline in the household dashboard and include correlation IDs on receipts and logs for supportability. Ensure notifications localize to user locale and respect quiet hours where configured.

Acceptance Criteria

Co‑Guardian Roles

Invite another caregiver and assign granular permissions—book, pay, view health notes, receive reminders, or manage pickups. Each guardian controls their own notification preferences while both see a unified family schedule. Reduces coordination friction and ensures the right adult gets the right messages.

Requirements

Co-Guardian Invitation & Account Linking
"As a primary guardian, I want to invite another caregiver to my child’s account so that they can help book classes and receive the right updates."
Description

Enable primary guardians to invite a co-guardian via email or SMS from the child profile or family settings. The invite flow includes tokenized links, account creation or linking for existing users, verification (email/phone), consent capture, and association to one or more children. Support revoking invitations and access, expiration of tokens, rate limiting, and audit logs of invite/accept events. Handle edge cases where the invitee already has a ClassTap account or is linked to another family, with clear conflict resolution. Ensure full white-label theming, localization, and accessibility. All linkage must integrate with ClassTap’s scheduling, payments, reminders, and waitlists so downstream permissions and routing are enforced consistently.

Acceptance Criteria
Granular Permission Matrix & Role Templates
"As a primary guardian, I want to assign exactly what a co-guardian can do so that I stay in control while sharing responsibilities."
Description

Introduce a permission system that controls co-guardian capabilities at a granular level: book classes, cancel bookings, join/leave waitlists, pay, view unified schedule, view/edit health notes, manage pickups, edit child profile, and manage notifications. Provide role templates (e.g., Full Guardian, Booking Only, Pickup Only) plus custom toggles per child. Enforce permissions server-side on all relevant APIs and in the UI (disabled controls, tooltips). Display permission context to users and return consistent error codes on denial. Include an admin API for studios to query effective permissions in white-label deployments. Maintain an auditable change log for role and permission updates.

Acceptance Criteria
Unified Family Schedule with Ownership Indicators
"As any guardian, I want a single view of our family’s class schedule so that I can coordinate without back-and-forth."
Description

Provide a consolidated calendar view that aggregates all booked classes, waitlist holds, and reminders for all children linked to the guardians. Indicate booking owner, designated pickup guardian, and payer attribution. Include filters by child, guardian, location, and class type; conflict warnings across children and guardians; and real-time updates when bookings change. Ensure timezone awareness, mobile responsiveness, and optional ICS export. Integrate with existing ClassTap scheduling and reminder services so changes propagate to notifications and instructor rosters without duplication.

Acceptance Criteria
Independent Payment Methods & Charge Controls
"As a primary guardian, I want the co-guardian to pay for their own bookings so that finances remain clear and controlled."
Description

Allow each guardian to maintain their own payment methods and billing details. Let the primary guardian set charge policies for co-guardians: allow/deny charging, per-transaction caps, monthly limits, class-type restrictions, and optional approval workflows. Attribute each transaction to the paying guardian, route receipts accordingly, and process refunds back to the original payer. Ensure compliance with PCI DSS via gateway tokenization (e.g., Stripe/Adyen), and handle failed payments, dunning, and chargeback notifications targeted only to the payer. Provide clear UI labels showing who will be charged and what policies apply. Expose payment attribution in reports and exports.

Acceptance Criteria
Per-Guardian Notification Preferences & Routing Rules
"As a co-guardian, I want to choose which messages I receive and how so that I get relevant updates without spam."
Description

Enable each guardian to configure notification preferences by event type (booking confirmation, reminder, waitlist release, cancellation, payment receipt, pickup confirmation, health note request) and by channel (SMS, email, push), with language, timezone, quiet hours, and verification status. Implement routing logic so messages go to the most relevant guardian based on role and context (e.g., pickup alerts to the assigned pickup guardian, payment receipts to the payer) with fallback recipients when required by policy. Deduplicate messages, provide delivery/read logs, and support studio branding. Ensure compliance with consent and opt-out regulations (e.g., TCPA/GDPR) and maintain per-guardian contact verification.

Acceptance Criteria
Health Notes Access Controls & Audit
"As a primary guardian, I want to control who can see and edit my child’s health notes so that privacy and safety are protected."
Description

Gate access to child health notes (allergies, medications, cautions) using the permission matrix with read vs. edit scopes and per-field sensitivity flags. Require explicit consent before sharing sensitive data with co-guardians and instructors. Provide an audit trail of all views and edits including actor, timestamp, and changes. Allow guardians to request updates and receive confirmations of changes. Limit instructor visibility to need-to-know fields during rosters and check-in. Support data retention, export, and deletion requests consistent with regional privacy laws, and mask sensitive fields in notifications where applicable.

Acceptance Criteria
Pickup Authorization & Check-in Handoff
"As an instructor, I want to verify authorized pickups quickly so that children leave with the right adult and I can focus on teaching."
Description

Manage authorized pickup contacts per child with time-bound and class-bound permissions that can be granted by either guardian if allowed. Allow assignment of a pickup guardian per booking. At check-in/out, provide instructors a quick verification flow with QR code or PIN, show authorized contacts on the roster, and capture a secure handoff confirmation. Notify the designated guardian upon pickup events or attempted pickups by unauthorized parties, with escalation paths. Log all handoff events for audit. Integrate with existing attendance/check-in modules and notification routing rules.

Acceptance Criteria

Sibling Swap

Easily transfer a booked seat from one child to another without calling the front desk. Eligibility and consents are rechecked automatically, price differences are handled as a quick credit/charge, and rosters plus reminders update instantly—preventing no-shows and keeping families flexible.

Requirements

Household Sibling Linking
"As a guardian, I want all my children recognized under one household so that I can quickly swap a booking between them without re-entering information."
Description

Enable guardians to designate children as siblings under a single household payer account and expose a reliable sibling selector during swap. The system must resolve identities across duplicate child profiles, confirm shared guardianship, and restrict swaps to children within the same payer/household and organization. Data model updates include a household entity linking guardian(s), payment methods, memberships/passes, and dependent child profiles with age, grade, and risk flags. The swap flow must only surface eligible siblings, mask PII per role, and gracefully handle missing or incomplete child profiles by prompting completion before proceeding.

Acceptance Criteria
Eligibility and Consent Recheck
"As an instructor-admin, I want eligibility and waivers rechecked automatically during a sibling swap so that compliance is maintained without manual review."
Description

On swap initiation, revalidate the target child against class eligibility rules (age/grade bands, skill prerequisites, roster caps by cohort, membership requirements) and verify all required waivers, medical info, and emergency contacts. If any consent or prerequisite is missing or expired, block the swap and present an inline flow to capture or renew it with timestamped, versioned records. Ensure provider-specific policies are respected and stored, and persist an eligibility decision artifact on the booking for auditability. The flow must be idempotent and performant, returning a decisive pass/fail with actionable remediation steps.

Acceptance Criteria
Pricing Delta and Payment Adjustment Automation
"As a guardian, I want any price difference handled automatically during a swap so that I don’t have to call the front desk to settle charges or credits."
Description

Upon selecting a target child, recompute the booking price using the child’s pricing context (age-tier pricing, memberships/passes, sibling discounts, taxes, and promo codes) and automatically settle the difference. If the target child’s price is higher, attempt a seamless charge using the household’s default payment method; if lower, issue a refundable credit to the household wallet or original payment instrument per provider policy. Generate itemized receipts/credit memos, update the ledger, and expose webhooks for accounting. Handle edge cases: partial authorizations, expired cards, pass consumption vs. refund, and tax recalculation. No double-charging and strict transactional integrity are required.

Acceptance Criteria
Conflict and Policy Guardrails
"As a guardian, I want the system to prevent swaps that would conflict with my child’s schedule or break studio policies so that I don’t create problems unintentionally."
Description

Enforce schedule and policy constraints before confirming a swap. Validate that the target child is not already booked for overlapping sessions, daily/weekly maximums are respected, and provider-defined swap windows (e.g., up to 2 hours before class) and swap limits per booking are enforced. Honor pass and bundle rules (e.g., non-transferable items) and sponsorship/grant restrictions. Provide clear, localized error states and a staff override capability with reason capture. The guardrail engine must be reusable and configurable per organization.

Acceptance Criteria
Instant Roster and Communications Sync
"As an instructor, I want rosters and reminders to update instantly after a sibling swap so that I know exactly who is attending."
Description

When a swap succeeds, atomically replace the participant on the class roster, update attendance lists, badges, and check-in artifacts, and propagate the change to all downstream communications. Regenerate and send updated SMS/email reminders and calendar invites to the correct guardian/child, notify instructors of the roster change, and update exports and integrations (e.g., CRM, payroll/attendance). Ensure messages avoid duplicate sends, respect quiet hours, and reflect the latest consent preferences. Provide real-time UI updates for staff and a webhook/event for external systems.

Acceptance Criteria
Audit Trail and Role-Based Controls
"As an owner, I want a complete audit trail and permissions around sibling swaps so that we remain compliant and can resolve disputes."
Description

Record a tamper-evident audit log for every swap including actor (guardian/staff), timestamp, original and target child, eligibility decision data, payment adjustments, and notifications sent. Expose RBAC to limit who can initiate swaps, approve exceptions, or view sensitive fields. Provide an easy-to-read change history on the booking and a downloadable report for compliance. Include privacy controls to redact child data from users without appropriate permissions and support data retention policies per organization and region.

Acceptance Criteria
Swap UX and API Surface
"As a platform partner, I want an API and polished UI for sibling swapping so that I can embed it in my branded experience with minimal work."
Description

Deliver a frictionless swap experience in the booking details view: a prominent Sibling Swap action, searchable sibling selector, real-time eligibility and price preview, explicit summary of changes, and one-tap confirmation with accessible error handling. Ensure mobile-first design, screen-reader compatibility, localization, and clear copy. Provide public/admin API endpoints and webhooks to initiate and monitor swaps programmatically, with idempotency keys and standardized error codes, enabling white-label partners to embed the flow. Include analytics events to measure usage, drop-off, and outcomes.

Acceptance Criteria

Family Waitlist

Join waitlists as a family with options to “keep together” or “okay to split.” When spots open, seats are held per child and sent via timed pay-to-claim links. Smart rules prioritize keeping siblings together when possible, filling classes fairly while reducing staff juggling.

Requirements

Multi-Child Waitlist Enrollment
"As a parent, I want to add all my children to a class waitlist in one flow so that I don’t have to submit separate entries and can manage our place together."
Description

End-to-end support for adding multiple children to a single waitlist entry from a family account. Captures child profiles, class selection, and per-child eligibility data (age, level, waivers). Validates schedule conflicts and prevents duplicate or overlapping entries. Persists a family-scoped waitlist record with child-level line items and positions. Integrates with ClassTap’s booking data model and guards against double-bookings across classes.

Acceptance Criteria
Keep-Together/Split Preference
"As a guardian, I want to choose whether my kids must attend together or can be split so that the system offers seats that match our needs without manual coordination."
Description

Allow families to specify whether siblings must be kept together or can be split across available spots. Store the preference per waitlist entry and enforce it during offer generation. If “keep together” is selected and insufficient seats are available, the family retains position until enough seats open. If “okay to split” is selected, partial offers are generated per child as seats become available, tracking remaining unmet seats. Support updating the preference after join, with audit trail and rules to avoid queue gaming.

Acceptance Criteria
Timed Pay-to-Claim Holds
"As a parent on a waitlist, I want to receive a timed link to claim and pay for my child’s seat so that I can secure the spot quickly without calling the studio."
Description

Automatically create time-bound seat holds when spots open and send secure, tokenized pay-to-claim links via SMS and email. Pre-reserve seats per child according to the family’s preference and class capacity. Configure hold duration per organization; show countdown in the checkout. On expiration or decline, release seats and advance the next eligible family. Prevent link reuse, enforce single-claim per hold, and deep-link to a pre-filled checkout with the correct children, class occurrences, and pricing.

Acceptance Criteria
Fairness Queueing and Promotion Engine
"As an administrator, I want a fair and transparent promotion process so that families trust the waitlist and staff spend less time resolving disputes."
Description

Implement a deterministic, auditable algorithm to prioritize families and promote children to holds. Preserve FIFO order at the child-entry timestamp while applying sibling cohesion rules that attempt to seat siblings together when possible. Handle edge cases such as partial capacity, class cancellations, and schedule overlaps. Enforce anti-gaming constraints (one active entry per child per class, join/leave throttles) and maintain an audit log of promotions, skips, and reasons. Provide configuration flags for tie-breakers where needed.

Acceptance Criteria
Staff Waitlist Management Console
"As a studio manager, I want tools to view and adjust family waitlists so that I can resolve edge cases and keep classes full with minimal effort."
Description

Provide an admin view to see class waitlists with family grouping, per-child status, preferences, and positions. Enable manual actions: promote/demote, override “keep together,” convert holds to bookings, resend or cancel offers, merge duplicate family entries, and add staff notes. Include filters, search, and export. Display real-time timers for active holds and a history of notifications and claim outcomes for support.

Acceptance Criteria
Branded Notifications and Preferences
"As an operator, I want customizable notifications so that families receive clear, on-brand instructions that drive timely claim conversions."
Description

Deliver white‑label SMS and email messages for waitlist join confirmations, offer sent, reminders, expiry, and outcome. Support per-organization templates, placeholders (child name, class, date, timer), sender branding, and localization. Respect user communication preferences and opt-outs, apply rate limits, and retry on transient failures. Track delivery and engagement metrics and surface them in the admin console.

Acceptance Criteria
Checkout and Payment for Multi-Child Claims
"As a parent, I want to pay once for all claimed seats so that the process is quick and I have a single receipt."
Description

Integrate waitlist claims with ClassTap’s checkout to allow claiming seats for one or multiple children in a single transaction. Pre-populate the cart with held seats, apply taxes, discounts, credits, and promo codes, and generate receipts. If payment fails, keep the hold until timer expiry and allow retry. Ensure PCI-compliant tokenization for stored methods and guard against double charges or race conditions when multiple offers exist.

Acceptance Criteria

QuickScan Kiosk

A dedicated, high-contrast kiosk view that displays the class QR, supports continuous scanning, and gives instant green/red feedback with attendee names. Staff see live counts, capacity, and status badges as scans happen, with a fast manual lookup fallback. Speeds lines, reduces errors, and keeps the roster accurate in real time.

Requirements

High-Contrast Kiosk UI
"As a front-desk staff member, I want a simple, high-contrast kiosk screen so that I can process check-ins quickly without visual clutter or mis-taps during rush periods."
Description

Provide a locked, full-screen, high-contrast interface optimized for check-in flow, showing class title, instructor, start time, capacity, and the class-specific QR for quick pairing or self-service access. The UI uses large typography, color-blind-safe palettes, and clear status badges to remain readable at distance and in bright environments. Includes screen orientation lock, inactivity dim/wake, guided setup, and single-app mode support on iOS/Android tablets and browser-based kiosks. Integrates with ClassTap class data and branding theming to preserve white-label consistency while minimizing on-screen distractions during busy arrivals.

Acceptance Criteria
Continuous Scanning Engine
"As a staff member, I want the kiosk to scan attendees continuously without extra taps so that lines move quickly and no one gets double-checked by accident."
Description

Enable continuous QR/barcode scanning via device camera with low-latency decoding, autofocus, glare mitigation, and frame de-duplication to support back-to-back scans without manual taps. Accept common 2D/1D symbologies and prioritize ClassTap signed QR payloads, rejecting unknown formats for security. Implement debounce and per-attendee rate limits to prevent double check-ins. Offline-ready with locally cached roster tokens and queued events that sync when connectivity returns. Designed for ≥4 successful scans per second under good conditions with resilient performance on mid-tier tablets.

Acceptance Criteria
Instant Validation & Feedback
"As a staff member, I want clear green/red feedback with attendee names and reasons so that I can resolve issues instantly and keep the line moving."
Description

On each scan, validate the token against the class roster, payment status, and booking state, then provide immediate, unambiguous feedback: green for successful check-in with attendee name, red for invalid/duplicate/wrong-class with a short reason, and amber for edge cases (e.g., waitlist, unpaid, late arrival). Display feedback for a brief, configurable duration with optional sound and haptic cues, ensuring PII fades after a few seconds. Persist check-in events with timestamps, device ID, and operator session; enforce idempotency to avoid duplicates and update the roster in real time. Target end-to-end validation latency under 300 ms online and graceful offline confirmation when using trusted cached data.

Acceptance Criteria
Live Capacity & Roster Sync
"As a studio manager, I want live counts and automatic waitlist handling so that capacity is accurate and we avoid overbooking during busy arrivals."
Description

Maintain a real-time connection to update capacity, checked-in counts, and waitlist status across all devices. Use websockets or server-sent events for push updates and apply optimistic concurrency with conflict resolution to prevent race conditions during simultaneous scans. Auto-promote waitlisted attendees when spots free up, respecting studio rules and payment requirements. Show always-current counters and status badges on the kiosk, prevent over-capacity check-ins, and reconcile any offline events on reconnect without creating duplicates.

Acceptance Criteria
Manual Lookup & Check-In Fallback
"As a front-desk staff member, I want a quick manual lookup and check-in option so that I can resolve edge cases when someone doesn’t have their QR or the code won’t scan."
Description

Provide a fast manual search to find attendees by name, phone, or email with tolerant matching and a ten-key optimized input. Allow manual check-in with visible status (paid, membership, drop-in, waiver needed) and capture an optional note when overriding errors (e.g., comp guest). Support creating an on-the-spot attendee placeholder and linking to payment flow on a companion device if required by studio policy. Operate in degraded mode with a cached roster when offline and automatically reconcile manual actions on reconnect with a full audit trail.

Acceptance Criteria
Device Registration & Access Control
"As an admin, I want to register and lock down kiosk devices to specific classes and roles so that check-in is secure and privacy-compliant."
Description

Add secure kiosk provisioning that binds a device to a location and class context using an admin QR or short-lived code, with role-based permissions limiting accessible classes and actions. Include a PIN-protected operator session, auto-lock on inactivity, and scoped tokens that can be remotely revoked. Minimize on-screen PII exposure (name only by default, no contact details) and allow privacy-safe display settings. Log all access and configuration changes for auditability, aligning with ClassTap’s white-label branding and security model.

Acceptance Criteria
Event Logging & Kiosk Analytics
"As a studio owner, I want visibility into check-in throughput and errors so that I can staff appropriately and reduce bottlenecks and mistakes over time."
Description

Capture structured events for scans, validations, manual overrides, errors, and throughput metrics (e.g., scans per minute, average validation latency, duplicate rate) with per-class and per-operator dimensions. Provide export to CSV and dashboard views within ClassTap to analyze peak times, staff efficiency, and error causes, enabling staffing and process improvements. Retain logs per data policy, redact sensitive fields, and ensure compliance with regional privacy regulations while supporting studio-branded reports.

Acceptance Criteria

Family Auto-Scan

One scan checks in linked family members from a single Join Pass. Applies per-child eligibility and consent checks, flags exceptions, and lets staff approve or deny specific children in one tap. Cuts lobby chaos for caregivers and keeps rosters compliant.

Requirements

Single-Pass Family Scan (QR/NFC)
"As a front-desk staff member, I want to scan one family pass to pull up all linked children so that I can check them in quickly without juggling multiple devices or profiles."
Description

Enable check-in of all linked children via a single scannable Join Pass that supports QR code and NFC. On scan, retrieve the guardian profile, associated minors, and active class context, then pre-populate per-child eligibility states. Include fast path performance (<500 ms local decode + <1 s server round trip), camera and external scanner support on iOS/Android/web kiosk, and debounce/rate-limit to prevent duplicate scans. Enforce site and time window constraints (e.g., scans allowed X minutes before/after class). Provide fallback to manual lookup when a pass is invalid or unreadable. Support white‑label theming for branded scan screens and messages.

Acceptance Criteria
Per-Child Eligibility & Consent Rules Engine
"As a program coordinator, I want the system to automatically check each child’s eligibility and consents so that staff approve only compliant attendees without manual cross-checking."
Description

Evaluate configurable per-child eligibility at scan time, including enrollment or drop‑in validity, age bands, membership/pack balance, waiver and consent statuses (liability, media, medical), emergency contacts, outstanding payments, and guardian-present requirements. Rules are class- and site-scoped, versioned, and return pass/fail with reason codes and recommended actions. Integrate with existing waiver, payments, CRM, and class scheduling modules. Surface clear green/yellow/red statuses to the UI and via API for automation.

Acceptance Criteria
One-Tap Child Approval UI with Exception Flags
"As a front-desk staff member, I want a clear list of each child with one-tap approve or deny options so that I can resolve exceptions quickly and keep the line moving."
Description

Provide a touch-optimized screen listing each child with status badges, exception summaries, and one-tap Approve/Deny controls. Require selecting a reason on deny from a configurable list and support partial approvals for families with multiple children. Show capacity position, waitlist position, and inline quick actions for payment/waiver completion. Offer bulk approve when all statuses are green. Confirmation view summarizes final roster updates. Ensure accessibility (WCAG 2.1 AA), large tap targets for lobby devices, and brandable light/dark themes.

Acceptance Criteria
Capacity & Waitlist Sync During Family Check-In
"As an instructor, I want the roster to update accurately when families are checked in so that the class stays within capacity and I can prepare materials appropriately."
Description

On approval, atomically allocate class capacity per child, move eligible children from waitlist when space is available, and enforce class caps to prevent overbooking. Handle sibling scenarios where some are approved and others remain waitlisted, with clear messaging. Update instructor rosters in real time, send webhooks for downstream systems, and ensure idempotent operations across multiple devices to avoid double-bookings. Block allocation when required payment or waiver steps are incomplete and provide retry flows.

Acceptance Criteria
Offline Check-In Queue with Conflict Resolution
"As a studio owner, I want staff to keep checking in families during internet outages so that classes start on time and data syncs correctly once we’re back online."
Description

Allow family scans and per-child approvals when connectivity is degraded or offline. Validate pass signatures and cached rules within a defined freshness window, queue actions locally with timestamps and device IDs, and display clear offline indicators and limits (e.g., max queue size or duration). On reconnection, synchronize in order with conflict detection (e.g., seat already taken) and provide guided resolution flows for staff. Use deterministic client operation IDs to prevent duplicate check-ins and ensure safe retries.

Acceptance Criteria
Immutable Audit Log for Compliance
"As an administrator, I want a detailed, immutable record of each family check-in so that we can demonstrate compliance and investigate incidents when needed."
Description

Capture a tamper-evident audit trail for each scan and child decision, including staff identity, device, location, timestamps, pass ID hash, rules evaluated and outcomes, approvals/denials with reason codes, overrides, and resulting roster changes. Store write-once events with tenant-configurable retention. Provide admin search, filtering, and export (CSV/JSON) while minimizing PII exposure via token hashing and masked identifiers. Ensure time sync and signed event digests for forensic integrity.

Acceptance Criteria
Secure Join Pass Tokens & PII Minimization
"As a privacy-conscious caregiver, I want our family pass to be secure and show minimal personal information so that our data is protected during check-in."
Description

Issue short-lived, signed Join Pass tokens (e.g., JWT/CBOR) encoding family ID and allowed scopes, with rotation and revocation controls. Support offline-verifiable signatures (EdDSA) and optional dynamic QR with rolling nonce to deter screenshots and replays. Enforce device rate limiting and replay protection via nonce caches. Limit on-screen data to the minimum necessary (e.g., first name, last initial, optional photo), honor tenant data residency, and align with COPPA/GDPR requirements.

Acceptance Criteria

Offline Sync Queue

Check-in works even when Wi‑Fi drops. Scans are timestamped and queued locally, then auto-synced on reconnection with conflict resolution to prevent duplicates. Keeps doors moving without risking double-bookings or lost attendance records.

Requirements

Offline Scan Capture & Local Queue
"As a front-desk operator, I want check-ins to be captured and queued when the network drops so that I can keep the line moving without losing attendance data."
Description

Enable the check-in flow to operate without connectivity by capturing scans and check-in actions locally and queuing them for later sync. Each queued item must include a deterministic operation ID, device ID, operator ID, class/session ID, member identifier, action type, and precise timestamps, and must persist across app restarts and low-power states. The queue must be encrypted at rest, support at least 10,000 events, enforce FIFO per user/class, and provide safeguards against data loss (atomic writes, crash recovery). Performance targets: acknowledge a scan within 100 ms and sustain 2+ scans/second. Integrates with the existing QR/barcode scanner and tap-to-check-in UI without altering the current online flow.

Acceptance Criteria
Automatic Background Sync & Retry
"As an instructor managing the door, I want queued check-ins to auto-sync when the internet returns so that I don’t have to manually manage uploads or risk missing records."
Description

Automatically detect connectivity restoration and begin background synchronization of queued events in batches with exponential backoff, jitter, and retry on transient failures. Preserve event order per user/class, support partial successes, and resume from the last confirmed offset. Sync must be idempotent using operation IDs, avoid blocking the UI, respect battery/data saver modes, and expose hooks for telemetry. Target: sync 1,000 events in under 60 seconds on a typical 4G/Wi‑Fi connection. Integrates with existing API endpoints or introduces a dedicated idempotent /checkins/sync endpoint.

Acceptance Criteria
Conflict Resolution & De-duplication
"As a studio owner, I want duplicates and over-capacity check-ins to be automatically resolved according to policy so that we avoid double-bookings and inconsistent records."
Description

Prevent double-bookings and duplicate attendance by enforcing server-side idempotency and deterministic conflict resolution. On sync, detect duplicate operations (same operation ID) and semantic duplicates (same member + class within defined window) and collapse them. If capacity limits are reached or waitlist rules apply, accept the earliest valid event by timestamp and policy, and set subsequent events to rejected/waitlisted with reasons. Provide clear resolution codes to the client for UI feedback and auditability.

Acceptance Criteria
Offline Roster & Entitlement Cache
"As a check-in attendant, I want roster and pass information available offline so that I can validate entries and handle edge cases even without Wi‑Fi."
Description

Maintain a secure, time-bounded local cache of today’s classes, rosters, memberships/passes, and eligibility rules required to validate check-ins offline. Include minimal fields needed for validation and messaging (e.g., remaining credits, pass expiry). Define TTLs and invalidation rules, and support a ‘tentative check-in’ mode when data is insufficient, flagging entries for review at sync time. Ensure cache encryption, size limits, and background prefetch when the app detects reliable connectivity before sessions begin.

Acceptance Criteria
Clock Drift Correction & Reliable Timestamps
"As an operations lead, I want accurate and consistent timestamps across devices so that attendance order and capacity rules are applied fairly and reliably."
Description

Mitigate device clock drift by maintaining a rolling server time offset and using monotonic clocks for local event ordering. Store both local and server-adjusted timestamps on events, and reconcile final authoritative times during sync to ensure consistent ordering across devices. Handle timezone changes and daylight savings safely, and fall back gracefully when offset is unknown by tagging events as ‘time-uncertain’ for conservative conflict policies.

Acceptance Criteria
Operator Feedback & Manual Controls
"As a front-desk operator, I want clear status indicators and simple controls so that I can trust the system and quickly intervene when something goes wrong."
Description

Provide clear in-app indicators for connectivity status, queue depth, last sync time, and error states, with unobtrusive toasts confirming offline captures. Include controls to trigger manual sync, pause syncing, and view or retry failed items. Offer an undo option for the last action within a short window and surface conflict outcomes after sync. Design for kiosk mode with large tap targets and accessibility compliance, ensuring no extra steps are required during high-traffic check-in.

Acceptance Criteria
Audit Trail & Admin Review Console
"As a studio administrator, I want an auditable history of offline check-ins and their sync outcomes so that I can investigate disputes and ensure compliance."
Description

Record a complete event lineage from offline capture through sync and resolution, including device, operator, timestamps (local and adjusted), outcomes, and conflict decisions. Expose an admin console view with filters (date, class, device, outcome), export capability, and per-event detail for troubleshooting. Enforce data retention and PII access controls aligned with compliance. Integrate with existing reporting pipelines to include ‘offline vs online’ source and resolution metrics.

Acceptance Criteria

Late Window Rules

Set grace periods and cutoffs that auto-mark late or no-show after the scan window closes. Triggers your chosen outcomes—credit return, pass decrement, fee, or waitlist release—without manual reconciliation. Creates clear, fair policies that reduce disputes and admin time.

Requirements

Configurable Late/No‑Show Windows
"As a studio owner, I want to set clear late and no-show time windows per class so that attendance is auto-classified consistently and fairly without manual tracking."
Description

Allow owners to define per-organization defaults and per-class overrides for check-in scan window, post-start grace period, late threshold, and no-show cutoff. Rules are time zone aware, support recurring schedules, and can vary by class type, location, instructor, and product (drop-in vs pass/membership). Enforce a hard close on the scan window that automatically transitions attendance states from On-time → Late → No-show without manual reconciliation. Provide validation (e.g., cutoff cannot precede start time), previews of effective policy, and API/CSV import for bulk updates. Ensure idempotency and deterministic outcomes for edge cases such as early check-ins, back-dated scans, multi-device scans, and daylight saving changes.

Acceptance Criteria
Outcome Rule Engine & Actions
"As an operator, I want late/no-show outcomes to trigger automatically based on my policies so that credits and fees are handled accurately without manual work."
Description

Implement a rules engine that maps time-based triggers (late threshold reached, scan window closed, no-show cutoff) to outcomes including credit return, pass decrement, late/no-show fee, and waitlist release. Support conditional logic (e.g., waive fee for first class, exempt memberships, apply different outcomes for class types), execution ordering, and retries with idempotency keys. Integrate with payments to place and capture fees securely, with configurable tax handling and receipts, and with entitlement systems to adjust passes and credits. Provide an admin UI to configure actions, preview impacts, simulate scenarios, and log decisions for auditability. Expose webhooks/events for external systems.

Acceptance Criteria
Attendance Scan Integration & Auto-Status
"As an instructor, I want the system to auto-mark students based on when they scan so that I don’t spend time reconciling attendance during class."
Description

Tie the late window rules into all check-in mechanisms (QR/NFC scan, roster tap, manual mark). Persist immutable scan timestamps and derive attendance status transitions in real time. Disable check-in attempts after the scan window closes unless user has override permissions. Handle offline scanning with queued sync, conflict resolution, and correct backfill behavior against cutoffs. Prevent double-bookings and duplicate scans, and surface clear UI states to instructors (e.g., Late, Window Closed). Provide role-based overrides with reason capture.

Acceptance Criteria
Policy Surfacing & Notifications
"As a student, I want to see and be reminded of the late/no-show policy and deadlines so that I can avoid fees and understand outcomes."
Description

Surface late/absence policies transparently across the booking journey: on class pages, at checkout, and in confirmation/Reminder SMS/email with localized times and clear cutoffs. Send outcome notifications when a fee is charged, a credit is returned, or a waitlist seat is released. Respect quiet hours, communication preferences, and localization. Provide template controls, per-brand theming for white-label embeds, and preview of policy language. Include in-app banners for impending cutoffs (e.g., “Check in within 5 minutes to avoid late fee”).

Acceptance Criteria
Dispute Management & Audit Trail
"As support staff, I want a clear audit trail and override tools so that I can resolve late/no-show disputes quickly and transparently."
Description

Record a complete, immutable audit trail of rule evaluations, timestamps, outcomes, payment attempts, and overrides. Provide an admin workflow to review disputes, waive or refund fees, restore credits, and annotate with reason codes. Changes must update reports and maintain referential integrity. Include exportable logs, role-based access, and SLA metrics to reduce support time and resolve edge cases fairly.

Acceptance Criteria
Waitlist Auto-Release & Seat Reallocation
"As a studio manager, I want seats to be auto-released to the waitlist when someone is late so that class capacity is maximized without manual intervention."
Description

When a booked attendee fails to check in by the configured pre- or post-start threshold, automatically release their seat to the next eligible waitlisted user based on priority rules. Notify the new attendee, require rapid confirmation if configured, and handle payment/credit adjustments accordingly. Respect capacity constraints, per-product policies, and prevent race conditions during high-demand drops. Expose configuration for release timing, confirmation windows, and exemptions.

Acceptance Criteria

Dynamic QR Shield

The class QR rotates every few seconds and is bound to session, location, and time window to block screenshots and early scans. Reuse attempts surface a friendly help prompt for the attendee and an alert for staff. Prevents ghost check-ins while keeping honest guests fast.

Requirements

Rotating QR Token Service
"As an instructor, I want the check-in QR to refresh automatically every few seconds so that screenshots and stale codes can’t be reused while my class lines move quickly."
Description

Build a server-driven service that generates cryptographically signed, time-sliced QR payloads that rotate every N seconds (configurable) and encode session_id, venue_id, valid_from/valid_to, and rotation_index. Tokens must be compact, tamper-evident (e.g., HMAC or EdDSA), and resilient to clock skew (±X seconds) while enforcing strict expiry to make screenshots unusable. The QR content resolves to a short URL with the token; image/SVG rendering must complete under 100 ms to ensure smooth auto-refresh on signage and host devices. Implement key rotation, secrets management, and replay-hardening via per-slice entropy and strict TTLs. Provide SDK hooks for web and native hosts to auto-refresh, prefetch the next code, and handle low-connectivity gracefully. Expected outcome: frictionless, secure rotating codes that are fast to render and impractical to reuse outside their time slice.

Acceptance Criteria
Time & Session Binding Validation
"As an attendee, I want my scan to instantly confirm the correct class check-in so that I don’t wait in line or worry about mistakes."
Description

Implement backend validation that verifies token signature, time window, session/venue bindings, and class schedule windows (open/close) before recording a check-in. Enforce idempotency per attendee and session, returning consistent success even on repeated valid scans while blocking ghost check-ins without an authenticated or verified attendee identity. Provide precise error codes for expired, wrong session, outside window, or malformed token to support tailored UX. Capture device, IP, and coarse telemetry for anomaly scoring without storing sensitive PII beyond policy. Ensure sub-200 ms end-to-end validation under expected load to keep the flow instant. Expected outcome: only legitimate, in-window scans for the correct class are accepted and recorded reliably.

Acceptance Criteria
Location & Proximity Enforcement
"As a studio owner, I want check-ins to be accepted only when attendees are on-site so that people can’t spoof attendance from elsewhere."
Description

Add configurable proximity checks that bind check-in validity to the class location via geofence radius, approved Wi‑Fi SSIDs, or optional BLE beacon presence. Respect user privacy by using coarse location with explicit consent and provide a code-entry fallback if location permissions are denied. Allow per-class configuration of enforcement level (strict, balanced, lenient) and thresholds for GPS accuracy/age. Surface clear responses when scans occur outside the permitted zone and log details for review. Expected outcome: remote or off-site scans are rejected while on-site guests pass seamlessly.

Acceptance Criteria
Reuse Detection & User Messaging
"As an attendee, I want clear, helpful messages when a QR doesn’t work so that I know exactly how to proceed without frustration."
Description

Detect screenshot/reuse attempts by identifying expired tokens, wrong-session tokens, or scans outside the allowed window and route users to friendly, brandable prompts with next steps. Provide tailored flows: suggest correct class page, show countdown until check-in opens, offer waitlist/standby, or direct to front desk for help. Localize copy, meet accessibility standards, and ensure messages render in under 200 ms. Track reason codes and conversion outcomes to inform tuning of windows and policies. Expected outcome: honest guests get clear guidance while bad-faith reuse is discouraged without creating friction.

Acceptance Criteria
Staff Alerts & Override Console
"As front-desk staff, I want to be notified of suspicious scans and have a quick override option so that I can keep lines moving and handle exceptions confidently."
Description

Provide real-time alerts to staff when suspicious scan patterns occur (e.g., repeated invalid tokens, off-site scans, burst traffic) with context like class, time, and anonymized device indicators. Build a lightweight console in the staff app/web to approve one-tap overrides with reason capture and optional ID note, respecting role-based permissions and auditability. Support configurable alert thresholds, quiet hours, and delivery channels (push, SMS). Rate-limit alerts to prevent noise and ensure they reflect actionable issues. Expected outcome: staff can quickly resolve edge cases and maintain flow while the system deters abuse.

Acceptance Criteria
Offline & Fallback Check-in
"As an instructor, I want a reliable fallback when the internet drops so that attendees can still check in and we can start class on time."
Description

Enable check-in continuity during connectivity issues with a rolling short code or QR derived from a time-based seed that can be queued and verified when service resumes. Provide an on-device cache of near-term token slices and a 4–6 digit rotating staff PIN for manual entry with limited validity to reduce abuse. Queue check-ins locally with conflict resolution and automatic sync, showing clear statuses (queued, synced, failed). Document operational procedures for instructors and front desk. Expected outcome: classes can start on time even when networks are flaky, without opening avenues for ghost check-ins.

Acceptance Criteria
Admin Controls, Branding & Reporting
"As an owner, I want to configure the QR rules and review results so that I can optimize security without hurting the guest experience."
Description

Add dashboard controls to enable Dynamic QR Shield per class/location, configure rotation interval, validity window, geofence radius, and allowed proximity methods. Provide brand customization of QR frame, error/help messages, and supported languages, with a preview mode. Include reports on scan volumes, acceptance rates, invalid/reuse reasons, and impact on no-shows, with CSV export and retention controls. Support A/B testing of rotation intervals and windows to balance speed and security. Expected outcome: operators can tune the shield to their context, maintain brand consistency, and measure outcomes.

Acceptance Criteria

Doorline Waitlist

A separate door poster QR lets walk-ins join the waitlist instantly with a lightweight profile and payment hold. When a no-show is confirmed, the next in line gets a pay-to-claim text and is auto-added on payment—filling last-minute seats without front-desk juggling.

Requirements

QR Doorline Waitlist Enrollment
"As a walk-in attendee, I want to scan a QR at the door to join the waitlist in seconds so that I can claim a seat if one opens without needing front-desk assistance."
Description

Generate per-class, white-labeled dynamic QR codes for door posters that deep-link to a mobile-optimized enrollment screen. The flow captures minimal required data (name, mobile number, email optional, consent/waiver) and obtains explicit consent for transactional SMS. It displays live class status, estimated wait time/queue position, and studio branding. The enrollment prevents double-booking by detecting overlapping bookings and existing roster status, deduplicates by phone/email, and supports captcha/rate limiting. On submit, the user is added to the waitlist with a lightweight profile and associated payment method placeholder, and receives a confirmation text. Integrates with ClassTap scheduling, user accounts, and branding theming, with localized copy, timezone handling, and accessibility compliance for on-site use.

Acceptance Criteria
Tokenized Payment Hold (Pre-Authorization)
"As a studio, I want a payment hold taken when a walk-in joins the waitlist so that only serious prospects remain and payment is frictionless when a seat opens."
Description

Collect a payment method during QR enrollment using PCI-compliant tokenization with support for major cards and Apple/Google Pay. Place a configurable pre-authorization hold (class price or deposit) with currency-aware amounts and SCA support where applicable. Holds are time-bound and automatically released on expiration, cancellation, or when the user is skipped. On successful claim, convert the hold to a capture/charge; on failure, retry per gateway rules and gracefully notify the user. Store non-PCI tokens only, log authorization IDs for reconciliation, and expose hold/charge state in the admin console. Handle edge cases (insufficient funds, expired cards, SCA challenges) and provide clear user messaging. Integrates with existing ClassTap payment provider abstraction and tax/fee configuration.

Acceptance Criteria
No-Show Detection and Seat Release Rules
"As an instructor, I want the system to automatically detect no-shows after a cutoff and free seats to the waitlist so that last-minute spots can be filled without manual juggling."
Description

Provide configurable no-show logic that frees seats to the doorline waitlist. Support multiple triggers: instructor marks attendance in-app, automated check-in window cutoff, and late grace period rules. When a registered attendee is not checked in by the cutoff, mark as no-show and release their seat(s) to the waitlist while respecting membership policies and cancellation terms. Prevent race conditions by locking capacity updates and honoring holds/refunds for the original attendee per policy. Surface real-time capacity changes to the waitlist queue and analytics. Includes safeguards to reverse a release if a late arrival is manually marked present within a short rollback window.

Acceptance Criteria
Pay-to-Claim Notifications with Countdown
"As a waitlisted attendee, I want a pay-to-claim message with a short timer so that I can quickly secure an open seat before others."
Description

When a seat becomes available, notify the next eligible person in the queue via SMS (and email fallback) with a secure, single-tap claim link. Enforce a configurable claim window (e.g., 5–10 minutes) with visible countdown and auto-expiry. If the window lapses or payment fails, automatically advance to the next person, with batching support when multiple seats free up. Messages use studio branding and templates, respect communication consent, and include opt-out keywords. Implement delivery status tracking, throttling, and retries. The claim link opens a streamlined checkout that confirms price, taxes/fees, and applies the stored payment hold for instant capture. All transitions are atomic to avoid double assignment.

Acceptance Criteria
Auto-Enrollment and Confirmation
"As a scheduler, I want successful payment to instantly enroll the attendee and send confirmations so that records stay accurate and the attendee is ready to attend."
Description

Upon successful claim and payment capture, automatically add the attendee to the class roster, decrement capacity, and remove them from other conflicting waitlists. Send immediate confirmation via SMS/email with class details, location, and check-in instructions; update calendar invites and reminder schedules. Reflect the change in the instructor dashboard and attendee profile in real time. Release or void any unused holds in the queue and log all state changes for audit. Ensure idempotency so repeated link clicks or double-submits do not create duplicates. Integrates with existing ClassTap roster management, reminders, and attendance systems.

Acceptance Criteria
Admin Controls and Queue Management
"As a studio owner, I want configurable rules and live queue controls so that the doorline waitlist aligns with my policies and on-the-ground operations."
Description

Provide studio-level and class-level settings to configure the doorline waitlist: enable/disable per class, max queue size, claim window duration, pre-auth amount, fees, tax handling, no-show cutoff/grace rules, and notification templates. Include a live queue view with actions to pause/resume, reorder, skip, manually invite, or block abusive users. Allow overrides to comp a seat or bypass payment hold for special cases. Expose status of each waitlister (joined, notified, claiming, paid, expired), delivery statuses, and payment states. Include permission controls for staff roles and a full audit trail of actions and seat assignments.

Acceptance Criteria
Waitlist Performance Analytics and Audit Logging
"As a studio owner, I want analytics on waitlist conversions and seats saved so that I can measure impact and optimize settings."
Description

Deliver reports and dashboards showing join-to-claim conversion, seats saved from no-shows, time-to-fill, revenue recaptured, average claim window utilization, notification delivery rates, and failure reasons. Provide exportable CSV and API access for BI tools. Maintain immutable audit logs for compliance and support, capturing user actions, policy changes, payment events, and message sends with timestamps and correlating IDs. Use these insights to A/B test claim windows and fees, informing studio optimizations.

Acceptance Criteria

Rule Canvas

A visual, drag‑and‑drop builder for prerequisite logic—combine blocks like Prior Class Completion, Certification Valid Within X Months, Age/Grade, Waiver on File, and Instructor Approval. Includes test mode and inline previews so admins can see exactly who qualifies before publishing. Cuts manual checks, prevents misbookings, and keeps rules consistent across classes and locations without writing a line of code.

Requirements

Visual Rule Canvas
"As an admin, I want to visually build eligibility rules without code so that I can create and maintain consistent prerequisites quickly and confidently."
Description

Provide a drag‑and‑drop, node‑based editor that lets admins assemble eligibility logic using blocks and AND/OR/NOT joiners. Include snap‑to‑grid, zoom/pan, grouping, inline block configuration, keyboard shortcuts (undo/redo/copy/paste), auto‑layout for readability, and an adaptive canvas for desktop and tablet admin use. Serialize rules to a portable JSON DSL compatible with the booking eligibility engine. Show live evaluation badges on each block when in test mode. Provide contextual help/tooltips, full keyboard accessibility, and localization‑ready copy. Autosave drafts and handle basic concurrent edit conflict resolution.

Acceptance Criteria
Prerequisite Block Catalog and Data Connectors
"As an admin, I want ready‑made, configurable blocks that pull from our records so that eligibility rules reflect real data without custom development."
Description

Offer a curated palette of configurable blocks: Prior Class Completion, Certification Valid Within X Months, Age/Grade, Waiver on File (with version), Instructor Approval, Membership/Pass Ownership, Time Since Last Attendance, Custom Attribute Check, Location Restriction, and Date Window. Each block exposes parameters with input validation and helpful defaults. Connect each block to authoritative ClassTap data sources (attendance history, certifications with expiry, user profile DoB/grade, digital waivers, approvals, passes/memberships). Support external data via webhook/API and CSV import with field mapping and normalization. Implement data freshness indicators, cache TTLs, and retry/backoff policies. Enforce tenant scoping and field‑level permissions so only authorized data is surfaced in the canvas and evaluations.

Acceptance Criteria
Eligibility Test Mode and Inline Preview
"As an admin, I want to simulate who qualifies before publishing so that I can catch mistakes and reduce support issues."
Description

Provide a non‑destructive test mode where admins can pick a specific attendee, enter an email/phone, or upload a sample roster to simulate rule evaluation. Display inline pass/fail per block with reason codes and missing‑data notes, plus an overall eligibility result. Allow date/time simulation (e.g., “as of next Monday”) to validate time‑bound rules like certification windows and age thresholds. Offer coverage insights for targeted classes (e.g., percentage of current roster that qualifies) and downloadable test reports for training and audit.

Acceptance Criteria
Checkout and Waitlist Enforcement & Messaging
"As a customer booking a class, I want clear guidance when I don’t meet prerequisites so that I know what to do next and avoid failed checkouts."
Description

Integrate compiled rules into checkout and waitlist flows to evaluate eligibility in real time for single and group bookings. Present clear, branded messaging when requirements are unmet, with actionable next steps (book prerequisite, sign waiver, request instructor approval). Support soft‑gate (warn) and hard‑gate (block) modes configurable per rule. Re‑evaluate on waitlist promotion, reschedules, instructor overrides, and data updates. Log all decisions with reason codes for support and analytics. Provide API hooks/webhooks for instructor approval workflows and external systems.

Acceptance Criteria
Assignment, Inheritance, and Targeting
"As an ops manager, I want to apply rules across classes and locations with exceptions so that I keep policies consistent without duplicating work."
Description

Allow rules to be assigned to classes, series, categories, and locations with inheritance and explicit overrides. Support org‑level defaults and per‑class exceptions. Provide an impact preview showing all classes affected before publishing, along with an effective date range scheduler. Ensure the booking engine resolves and applies the correct rule set per class/location at evaluation time, including fallbacks when no rule is assigned.

Acceptance Criteria
Templates, Versioning, and Publishing Workflow
"As a program director, I want versioned, reusable rule templates so that I can standardize policies and safely iterate."
Description

Enable saving rules as reusable templates with tags and search. Provide semantic versioning, change summaries, and side‑by‑side diffs of logic changes. Support draft, review, and publish states with optional approver gates and scheduled publishing. Allow rollback to prior versions and automatic deprecation of superseded rules. Notify impacted staff of pending changes and expose a class‑level changelog.

Acceptance Criteria
Audit Trail, Permissions, and Access Control
"As an owner, I want a clear audit trail and permissions around rule changes so that we remain compliant and can investigate issues."
Description

Record who created, edited, reviewed, and published each rule with timestamps and reason notes. Enforce role‑based access controls for creators, editors, reviewers, and viewers, including restrictions on sensitive blocks (e.g., age/grade). Provide exportable audit logs and integrate with existing organization audit reporting. Align with data protection policies and regional consent requirements for eligibility checks.

Acceptance Criteria

Cert Snap

Fast proof capture that lets attendees snap or upload certificates on mobile. Auto‑reads name, issue/expiry dates, and provider, then auto‑approves when matched to rules or routes to quick review when something’s off. Stores once and reuses across bookings, with renewal reminders baked into SMS/email. Reduces back‑and‑forth and keeps rosters compliant without slowing checkout.

Requirements

Mobile Certificate Capture & Upload
"As an attendee, I want to quickly snap or upload my certificate on my phone during checkout so that I can complete my booking without back‑and‑forth."
Description

Enable attendees to capture a certificate via mobile camera or upload images/PDFs during booking or from their account, with real‑time edge detection, crop/rotate, multi‑page support, file size/type validation, upload progress, and fallback for low connectivity. Integrates into the checkout flow without adding friction by allowing configurable gating (required before payment or allowed after provisional booking) per class. Ensures secure client‑side compression and transport over TLS, and tags each upload with booking, user, and class identifiers for downstream processing.

Acceptance Criteria
Auto‑Extraction (OCR) of Credential Fields
"As an instructor, I want the system to auto‑read key fields from uploaded certificates so that I don’t have to manually type or verify them."
Description

Automatically read name, provider, issue date, and expiry date from uploaded certificates using an OCR pipeline with template‑agnostic parsing, date normalization (locale/timezone aware), and confidence scoring per field. Supports multiple file formats, glare/noise handling, and retries. Returns structured data with field confidences and a redacted thumbnail for review. Includes fuzzy logic to match common provider names and normalizes provider aliases. Falls back to manual review when fields are missing, low‑confidence, or contradictory.

Acceptance Criteria
Rules Engine & Auto‑Approval
"As a studio owner, I want certificates to auto‑approve when they meet my rules so that rosters stay compliant without slowing checkout."
Description

Provide a configurable rules engine at organization, location, program, and class levels to define accepted providers, certificate types, minimum validity windows, and name‑match thresholds. On successful match, auto‑approve the credential and mark the booking compliant; otherwise, route to review with explicit failure reasons. Supports effective‑date versioning of rules, per‑class overrides, and actions (block checkout, allow provisional booking, waitlist only). Emits events/webhooks for approvals, rejections, and expirations for downstream integrations.

Acceptance Criteria
Reviewer Queue & Quick Triage
"As an admin, I want a fast review queue for exceptions so that I can resolve edge cases in seconds and keep classes moving."
Description

Deliver a lightweight admin queue to triage flagged certificates with side‑by‑side original and extracted data, inline field edits, quick approve/reject with canned reasons, request resubmission, and bulk actions. Shows confidence indicators, rule failures, and history for the user’s prior credentials. Provides keyboard shortcuts, SLA timers, and notification triggers to minimize turnaround time. All actions are recorded in an immutable audit log with actor, timestamp, changes, and booking linkage.

Acceptance Criteria
Credential Vault & Reuse Across Bookings
"As a returning attendee, I want my previously approved credentials to auto‑apply to new bookings so that I don’t have to re‑upload them."
Description

Store approved certificates in a secure, encrypted credential vault linked to the attendee’s profile, with deduplication, versioning, and provider/type metadata. Automatically reuse valid credentials across future bookings that require the same certificate, attaching them silently during checkout to avoid re‑upload. Allow attendees to view, replace, or remove credentials from My Account, and allow admins to revoke or force renewal. Enforce least‑privilege access controls and data retention policies aligned with org settings.

Acceptance Criteria
Renewal Reminders via SMS/Email
"As a program coordinator, I want automated renewal reminders via SMS/email so that attendees keep their certifications current."
Description

Schedule automated renewal reminders based on certificate expiry with configurable lead times (e.g., 60/30/7 days) and final grace window, delivered via existing SMS/email channels using brand templates. Messages include a secure deep link to update the credential on mobile with one tap. Support per‑org opt‑out, throttle limits, localization, and time zone alignment. Track delivery, opens, and completion, and automatically update booking eligibility based on renewal status.

Acceptance Criteria
Compliance Indicators in Rosters & Reporting
"As a front‑desk staff, I want clear compliance indicators in rosters and reports so that I can enforce policies and communicate status to attendees."
Description

Surface real‑time compliance status in class rosters with clear badges (Compliant, Pending Review, Expiring Soon, Expired, Rejected) and filters. Allow optional enforcement to block check‑in or payment capture for non‑compliant bookings per class policy. Provide exports and an API endpoint to pull compliance summaries, along with an audit trail of approvals/rejections and expiry changes. Include dashboards to monitor compliance rates and average review times.

Acceptance Criteria

Fit Check

A self‑serve eligibility checker shown on class pages and paywalls. Clearly explains what’s needed to book (e.g., “Complete Intro Yoga” or “Upload CPR card”) and offers one‑tap actions: upload proof, add prerequisite to cart, or request review. Removes guesswork, decreases abandonment, and builds trust for first‑time attendees.

Requirements

Eligibility Rules Engine
"As a studio owner, I want to configure eligibility rules per class using simple options and logic so that only qualified students can book without manual screening."
Description

Configurable engine to define and evaluate class-level eligibility criteria with support for prerequisite classes, membership tiers, signed waivers, age limits, certifications with expiry, and custom questionnaire gates. Provides AND/OR logic groups, effective/expiry dates, per-schedule overrides, multi-tenant templating, and localization. Evaluates in real time on class pages and paywalls, returning standardized status codes (eligible, action_required, under_review, expired) and human-readable reasons. Exposes an internal API for UI components and webhooks to trigger when eligibility changes. Includes caching for performance, rate limiting, and resilience against partial outages. All rule definitions and evaluations are versioned for traceability and safe rollouts.

Acceptance Criteria
Document Upload & Verification
"As a student, I want to upload proof with one tap from my phone so that I can satisfy requirements quickly and continue booking."
Description

One-tap capture and upload of proof artifacts (e.g., CPR card, ID, completion certificate) from mobile and desktop with support for photos and PDFs, client-side compression, and instant previews. Performs file validation, virus scanning, and metadata extraction (OCR for name and expiry) to auto-populate fields and pre-qualify submissions. Stores documents securely with encryption at rest and access controls, links them to the user profile, and flags duplicates or expired items. Routes submissions to an approval workflow with statuses (submitted, under_review, approved, rejected) and triggers notifications. Provides accessibility-compliant UI, retry logic for poor connectivity, and localized error messages.

Acceptance Criteria
Eligibility Status UI
"As a prospective attendee, I want a clear indicator of whether I’m eligible and what steps remain so that I can decide and act without leaving the page."
Description

Self-serve checker component embedded on class pages and paywalls that displays the user’s current eligibility state and exact next steps. Surfaces clear badges and copy for Eligible, Action Required, Under Review, and Expired, with contextual CTAs: upload proof, add prerequisite to cart, request review, or contact support. Supports guest users with a lightweight sign-in gate, progressive disclosure to reduce clutter, and full keyboard/screen-reader accessibility. Localizable content and studio-branding controls ensure white-label consistency. Emits analytics events for impressions, clicks, and conversion, and gracefully degrades if the rules API is unavailable.

Acceptance Criteria
One-Tap Add Prerequisite to Cart
"As a new user, I want to add the prerequisite class to my cart with one tap so that I can resolve eligibility and finish booking."
Description

Contextual CTA that, when a required intro course or package is missing, adds the correct prerequisite offering to the cart with one tap and preserves the user’s intended class context. Preselects the earliest available session that satisfies conflicts and location preferences, supports bundles and discounts, and warns on schedule clashes. Maintains deep links and cart state across sessions and devices, and records attribution to the originating class for analytics. Respects inventory and waitlist rules, and blocks checkout if prerequisites cannot be met by the target class date.

Acceptance Criteria
Instructor Review Console & Notifications
"As an instructor, I want a simple console to review and approve eligibility documents so that qualified students can book quickly."
Description

Back-office console for instructors and admins to review submitted documents and eligibility requests, approve or reject with comments, request resubmission, and set auto-approval rules by issuer or template. Provides filtering, bulk actions, SLAs with reminders, and escalation paths. Integrates SMS/email to notify students on status changes using studio-branded templates with rate limiting and unsubscribe compliance. Includes role-based access control, mobile-responsive UI, detailed activity logs, and exportable reports for audits and operations.

Acceptance Criteria
Auditability & Policy Transparency
"As a cautious first-time attendee, I want transparent requirements and decision reasons so that I trust the booking process and feel safe sharing documents."
Description

End-to-end audit trail capturing rule versions, evaluation inputs/outputs, reviewer decisions, timestamps, and notifications sent. Exposes a user-facing policy panel on class pages that explains prerequisites, acceptable proofs, review SLAs, expiry handling, and appeals, all customizable per studio. Provides downloadable logs for compliance, retention schedules, and consent tracking to build trust with first-time attendees and support dispute resolution.

Acceptance Criteria

Pathway Tracker

Guided paths that turn prerequisites into a clear progress bar. Suggests the next available prerequisite sessions that fit the attendee’s schedule, supports “Add All” to book required steps at once, and applies bundle pricing when rules allow. Converts ineligible interest into committed enrollments while keeping capacity optimized.

Requirements

Prerequisite Graph & Path Definition
"As a studio admin, I want to define structured learning paths with prerequisites so that learners can see exactly which classes they must take and in what order."
Description

Model class prerequisites as directed paths with support for ordered sequences, co-requisites, equivalencies, expiration windows, minimum score requirements, and instructor/admin overrides. Provide an admin UI to compose and version pathways per tenant, attach steps to existing classes/sessions, and publish changes safely with draft/preview. Enforce eligibility checks at search, booking, and check-in time via shared validation services. Expose APIs to import/export paths, migrate legacy rules, and sync with external LMS/CRM identifiers. Log audit trails for edits, and surface clear failure reasons when a user is ineligible. Integrate with ClassTap scheduling to reflect capacity and avoid double-bookings across steps.

Acceptance Criteria
Dynamic Progress Bar & Eligibility Indicator
"As an attendee, I want to see a clear progress bar and eligibility status on each class page so that I understand what I’ve completed and what I need to do next."
Description

Render a real-time, accessible progress bar on class and pathway pages that reflects completed, in-progress, and locked steps, with tooltips explaining lock reasons (e.g., unmet prerequisite, expired completion). Display remaining steps, estimated time/cost to completion, and support multiple concurrent pathways per learner. Make components mobile-first, themeable to white-label brands, and localizable. Link each step to detail pages and completion artifacts (attendance, assessments). Consume eligibility state from the prerequisite service and update instantly on new enrollments or cancellations.

Acceptance Criteria
Schedule-Aware Next-Step Suggestions
"As an attendee, I want the system to suggest the next prerequisite sessions that fit my schedule so that I can enroll without manually searching."
Description

Recommend the next available prerequisite sessions that satisfy eligibility and align with the attendee’s preferences (time windows, locations, modality, travel radius) and timezone. Filter out clashes with existing bookings and personal calendar blocks, consider transit buffers, and rank options by earliest completion or user preference. Provide fallback suggestions (nearby locations, alternative dates, equivalent classes) when ideal slots are full, and support quick actions to join waitlists. Expose a lightweight API to power suggestions in booking pages, emails, and SMS.

Acceptance Criteria
Add-All Bulk Booking with Conflict Resolution
"As an attendee, I want to add all required steps to my cart at once so that I can check out quickly without conflicts."
Description

Enable an “Add All” action to place all required steps for a pathway into the cart in a single flow, performing atomic eligibility checks, capacity holds, and payment authorization. Detect conflicts (time overlaps, location constraints, instructor caps) and provide guided alternatives (swap session, split across dates) before checkout. Reserve seats with expirations, prevent double-bookings across pathways, and commit all bookings in one transaction with rollback on failure. Support mixed modality sessions, attendee-specific pricing, and per-tenant policies for deposits or installments.

Acceptance Criteria
Bundle Pricing & Rule Application
"As a studio owner, I want bundle pricing to apply automatically when I book a pathway so that the total cost reflects pathway discounts."
Description

Apply pathway-specific bundle pricing when eligible steps are booked together or within a configured window. Support fixed-discount, percentage, and tiered pricing models; handle taxes, fees, promo codes, and membership entitlements. Display transparent savings breakdowns in cart, receipts, and reports. Recalculate on reschedules/cancellations with prorations and rule re-evaluation. Provide an admin rule builder with previews and guardrails to avoid stacking conflicts. Export pricing outcomes to finance reports and reconcile with payment providers.

Acceptance Criteria
Cross-Step Waitlist Orchestration
"As an instructor, I want the waitlist to coordinate across pathway steps so that students can move into open seats without breaking their sequence."
Description

Coordinate waitlists across all remaining pathway steps so that when a seat opens in one step, downstream bookings remain viable. Offer pathway-aware waitlist enrollment, prioritized holds, and automatic multi-step seat allocation when a compatible chain becomes available. Notify users via SMS/email with consolidated prompts to confirm or adjust multiple steps at once. Respect capacity, hold expirations, and instructor overrides, and avoid creating stranded enrollments that break sequence.

Acceptance Criteria

Timed Override

Permissioned, auditable overrides for edge cases. Managers can grant a one‑time or time‑boxed exception with a reason code, scope it to a specific class or series, and set auto‑expiry. Rosters display a subtle badge and follow‑up tasks (e.g., “Upload cert by 09/30”). Delivers flexibility without sacrificing control or compliance.

Requirements

Override Creation & Access Control
"As a studio manager, I want to create a one-time, permissioned override with a reason and scope so that I can handle justified exceptions without weakening our overall policies."
Description

Provide a manager-only workflow (UI and API) to create permissioned overrides with one-time or time-boxed duration, capturing reason code, scope, notes, and optional follow-up tasks. Enforce role-based access control (RBAC) so only authorized roles can create, edit, or revoke overrides within their tenant. Integrate with ClassTap’s booking and roster services to persist overrides as first-class entities with unique IDs and tenant isolation. Validate input (dates, scope, conflicts) and prevent creation of overrides that violate global policies (e.g., hard legal limits). Ensure overrides are traceable, editable until activation, and revocable with immediate effect.

Acceptance Criteria
Time-Boxing & Auto-Expiry
"As an operations lead, I want overrides to automatically expire at a set time so that exceptions don’t persist longer than intended."
Description

Implement a scheduling subsystem that activates overrides at start time and auto-expires them at end time, with idempotent jobs and recovery on service restarts. On expiry, re-enforce standard rules (capacity, prerequisites, payment) and trigger configured notifications to stakeholders. Support immediate start (one-time) and future-effective windows, with safeguards against backdating beyond audit policy. Expose status states (Scheduled, Active, Expired, Revoked) and update dependent systems (roster, waitlist, check-in) in real time.

Acceptance Criteria
Scoped Application Engine
"As a product engineer, I want a consistent way to determine which overrides apply to a booking event so that behavior is predictable across all entry points."
Description

Provide a rule-evaluation engine that applies overrides at decision points (booking, waitlist promotion, roster edits, check-in). Support granular scoping: specific attendee, class session, series, location, instructor, or combination. Define precedence and conflict resolution when multiple overrides might apply, and ensure evaluation is performant and cache-aware. Expose read APIs to query effective overrides for a given entity and time. Ensure consistency across web, mobile, and API clients.

Acceptance Criteria
Reason Codes & Policy Mapping
"As a compliance coordinator, I want standardized reason codes linked to policy gates so that overrides are consistent and reportable."
Description

Offer a configurable catalog of reason codes (e.g., Certification Pending, VIP, System Error) with optional required fields (e.g., document link, approver note). Require selection of a reason code when creating an override and map codes to the specific policy gates they may bypass. Provide analytics hooks to report on override frequency, by code, by staff, and by class. Localize labels and support tenant-level customization with sensible defaults.

Acceptance Criteria
Audit Trail & Compliance Reporting
"As a studio owner, I want a complete audit history of overrides so that we can demonstrate control and trace issues when needed."
Description

Record immutable audit events for the full override lifecycle (create, edit, activate, expire, revoke) including actor, timestamp, IP/device, before/after values, reason code, and scope. Provide searchable, exportable logs (CSV/JSON) with filters by date, user, class, and reason code. Enforce data retention policies per tenant and ensure logs are tamper-evident. Surface audit summaries in the admin UI and expose read-only endpoints for SOC/QA reviews.

Acceptance Criteria
Roster Badges & Follow-up Tasks
"As an instructor, I want to see which attendees are attending under an override and any follow-up tasks so that I can act accordingly before class."
Description

Display a discreet, accessible badge on rosters and booking details when an active override applies, with tooltip summarizing reason and expiry. Allow managers to attach follow-up tasks (e.g., upload certification by date, collect payment) with due dates, assignees (student or staff), and links to completion actions (document upload, invoice). Integrate tasks with reminder cadence and dashboard widgets for instructors and admins. Update badge state as tasks are completed or overdue.

Acceptance Criteria
Gate Overrides (Capacity, Cutoffs, Prereqs)
"As a front-desk coordinator, I want to let a member into a full class or without a pending cert just this once so that we can accommodate legitimate exceptions without breaking our rules."
Description

Define which policy gates an override can bypass, including capacity limits, booking/cancellation cutoffs, prerequisite certifications, and payment requirements. Ensure downstream systems handle bypass safely: annotate payments as deferred, mark prerequisites as pending, and prevent automatic penalties while override is active. On expiry, re-validate state and trigger required actions (e.g., invoice creation, task escalation). Maintain compatibility with waitlists by allowing explicit capacity overage and preserving seat accounting.

Acceptance Criteria

Compliance Ledger

A tamper‑evident audit trail of rule evaluations, documents, approvals, and check‑ins with timestamps and actors. Exports to CSV/PDF in accreditor‑friendly formats and fires alerts for upcoming expirations that could affect bookings. Makes audits painless and gives admins instant answers to “why was this blocked?”

Requirements

Append-only Compliance Ledger
"As a compliance administrator, I want every compliance-relevant action recorded immutably with timestamps and actors so that I can prove what happened and detect any tampering during audits."
Description

Implement a tenant-scoped, append-only event store that records all compliance-relevant events (e.g., rule_evaluated, document_uploaded, approval_granted, document_expired, booking_blocked, check_in) with immutable, tamper-evident guarantees. Each event must include a monotonic timestamp, actor identity, entity references (user, instructor, class, facility, booking), rule/version identifiers, correlation IDs, and an idempotency key. Events are chained using cryptographic hashes (e.g., SHA-256) to produce per-tenant hash chains; any mutation generates a detectable break. Storage must be write-once (or logically immutable with compensation events), encrypted at rest/in transit, and partitioned by tenant for scalability. Provide ingestion APIs/SDK hooks for all ClassTap services to emit ledger events synchronously with core transactions, with retry/backoff and at-least-once delivery. Include operational tooling for chain verification, backfill from existing logs, and drift detection. This forms the foundation for audits, exports, and explanations.

Acceptance Criteria
Rule Evaluation Trace Logging
"As an admin, I want a detailed rule evaluation trace for each booking attempt so that I can explain why a request was blocked or allowed and what evidence was considered."
Description

Capture and persist a detailed trace for every policy evaluation that influences bookings, check-ins, and payments holds. For each evaluation, store the rule set name and version, input fingerprints (PII-minimized), referenced documents and their states, decision outcome (allow/block/warn), reason codes, and latency metrics. Link traces to the originating booking attempt or user action via correlation IDs and surface a normalized schema to power explanations. Ensure redaction of sensitive payloads with reversible references to secure stores when needed. Provide APIs to fetch traces by booking ID, user ID, class ID, or time window and index for fast retrieval. This trace directly feeds the “Why Blocked?” view and export reports.

Acceptance Criteria
Evidence Document Lifecycle & Expiration Tracking
"As an instructor, I want to upload certifications and see their approval and expiration status so that my classes aren’t blocked due to lapsed credentials."
Description

Enable secure ingestion, storage, and lifecycle management of compliance evidence (certifications, waivers, IDs) with metadata (type, issuer, identifier, effective/expiration dates, reviewer, status). Support versioning with supersede relationships and approvals capturing approver identity, timestamps, and comments. Documents are stored in secure object storage with content hashes and size, linked to instructors, staff, classes, or facilities. All create/update/approve/expire actions emit ledger events. Implement automatic expiration computation and status derivation, with APIs to query current compliance state per entity and to block bookings when required artifacts are missing or expired.

Acceptance Criteria
Expiration Alerts & Booking Safeguards
"As a studio owner, I want proactive alerts for upcoming compliance expirations so that I can resolve issues before they disrupt bookings."
Description

Provide a scheduler that continuously evaluates upcoming expirations and compliance risks against configurable thresholds (e.g., 30/14/7 days). Generate actionable alerts with context (affected classes/bookings, required documents) and deliver via email, SMS, and in-app notifications, with acknowledgement, snooze, and escalation workflows. Expose webhooks for third-party systems. Integrate with booking flows to warn prior to expiration windows and automatically block bookings after policy-defined grace periods. All alert creation, acknowledgement, and suppression actions write to the ledger for auditability.

Acceptance Criteria
Accreditor-Friendly CSV/PDF Exports with Integrity Proofs
"As a compliance auditor, I want downloadable CSV/PDF reports in familiar formats with integrity proofs so that I can complete audits quickly and trust the data."
Description

Enable admins to export scoped slices of the compliance ledger and related evidence to CSV and branded PDF with filters by date range, entity, rule, decision outcome, and location. Map output columns and section layouts to common accreditor expectations and include localized timestamps and time zones. For integrity, provide a hash-chain summary and export manifest (export time, filters, chain head, and digital signature if configured). Support large exports via async jobs, progress tracking, and expiring download links. Include redaction options for PII based on role and export purpose; all exports are themselves logged as ledger events.

Acceptance Criteria
"Why Was This Blocked?" Explanation API & Admin View
"As a support agent, I want a clear explanation of blocked actions with specific next steps so that I can help users resolve issues on the first contact."
Description

Deliver a low-latency API that composes rule evaluation traces, document statuses, and policy definitions into a human-readable explanation with remediation steps. The response must include the decision outcome, key reasons, missing or expired evidence, responsible actor(s), timestamps, and links to upload documents or request approvals. Provide an embeddable admin UI panel on booking and user detail pages with consistent messaging, search, and deep links. Enforce permissions and redact content based on role. Target p95 latency under 300 ms for recent events via indexed storage and caching.

Acceptance Criteria
Role-Based Access, Redaction, and Retention Controls
"As a data protection officer, I want strict access controls and retention policies on the compliance ledger so that we meet privacy regulations without compromising auditability."
Description

Implement fine-grained RBAC for viewing, exporting, and administering the compliance ledger with roles such as Owner, Admin, Instructor, Staff, and External Auditor. Enforce field-level redaction for PII/sensitive data in APIs, UI, and exports, with configurable policies by tenant and jurisdiction. Provide retention policies (by document type and region), legal hold flags, and deletion workflows that preserve ledger integrity via tombstone/compensation events while keeping hash-chain verifiability. Include audit logs of all access and configuration changes, plus encryption key management and rotation procedures.

Acceptance Criteria

Gated Waitlist

Waitlists that respect prerequisites. Eligible attendees can join normally; ineligible users get a provisional spot with a deadline and guided steps to qualify. When a seat opens, pay‑to‑claim links only go to those who meet rules (or who completed requirements in time). Keeps last‑minute fills fair and compliant while maximizing utilization.

Requirements

Prerequisite Rules Engine
"As a studio admin, I want to define and enforce prerequisite rules per class so that only qualified attendees can join the waitlist and compliance and safety standards are maintained."
Description

Implements a configurable rules engine to define and evaluate class prerequisites used by the Gated Waitlist. Instructors or studio admins can attach prerequisite criteria per class (e.g., completed prerequisite classes, attendance history, tags/levels, age, signed waivers, active membership/pack, instructor approval, uploaded certifications). The engine evaluates eligibility in real time against user profiles, purchase status, attendance records, and optional external sources via API/webhooks. It returns a clear eligibility decision with human-readable reasons to support guided remediation. Integrates with ClassTap’s class catalog, user accounts, payments/memberships, and CRM integrations. Supports localization of messages, deterministic outcomes, auditability of rule evaluations, and graceful degradation when external data is temporarily unavailable.

Acceptance Criteria
Provisional Waitlist Enrollment with Guided Qualification
"As an ineligible attendee, I want to hold a provisional waitlist spot with clear steps to qualify so that I still have a fair chance to get into the class if I meet the requirements in time."
Description

Enables ineligible users to join a waitlist in a provisional state with a visible deadline to complete requirements. Presents a dynamic checklist of steps to become eligible (e.g., buy membership, enroll in prerequisite session, sign waiver, upload certification), with deep links into ClassTap flows and integrated payment checkout. Tracks progress, re-evaluates eligibility automatically upon step completion, and updates status in real time. Provides clear UI labels for provisional vs fully eligible states across web and mobile booking pages, respecting studio branding. Integrates with notifications to send targeted reminders and with the rules engine for continuous eligibility checks.

Acceptance Criteria
Eligibility Deadline & Hold Expiration Logic
"As a studio manager, I want provisional eligibility deadlines to be enforced and communicated so that the waitlist remains fair and seats are not blocked by users who do not complete requirements."
Description

Introduces configurable time windows for provisional holds, including defaults at the class level and per-user overrides by admins. On expiry, the system automatically releases the provisional spot, updates the queue position, and logs the event. Supports timezone-aware timers, daylight savings, and blackout periods (e.g., do not expire between 11pm–6am local). Sends scheduled reminders ahead of expiry via email/SMS and in-app, and updates the guided checklist countdown. Ensures fairness by preventing indefinite blocking and re-queues users according to defined business rules. Fully auditable with event timestamps for compliance and support.

Acceptance Criteria
Eligibility-Aware Seat Release and Invite Routing
"As a studio owner, I want seat-open invites to go only to users who meet prerequisites so that last-minute fills are fair, compliant, and maximize utilization."
Description

When a seat opens, the system identifies the next eligible waitlisters, prioritizing fully eligible users and those who completed requirements within their deadline. It routes pay-to-claim invites only to those eligible at send time, with batch handling for multiple openings, tie-breaking rules, and configurable invite windows. Integrates with ClassTap’s notification services to send branded, localized emails/SMS with dynamic content (position, expiry, steps remaining). Handles opt-outs, delivery failures, and throttling, and respects compliance guidelines (e.g., TCPA/GDPR). Maintains fairness and transparency by logging routing decisions and exposing invite status in the admin view.

Acceptance Criteria
Secure Pay-to-Claim Links with Atomic Booking
"As an attendee, I want a secure, single-use pay-to-claim link that guarantees my spot upon payment so that I can check out quickly without errors or double-bookings."
Description

Generates single-use, time-bound, user-bound claim links that lead directly to a secured checkout for the released seat. Enforces atomic booking: on payment success, the seat is reserved and the waitlist and class inventory update in a single transaction to prevent double-bookings. Includes token validation, rate limiting, device-agnostic access, and detection of link sharing. Supports payment holds/captures, refund and failure handling, idempotency keys, and instant confirmation messages. Integrates with ClassTap Payments, receipts, and reminder workflows, ensuring the spot is only confirmed for users who remain eligible at payment time.

Acceptance Criteria
Admin Oversight & Overrides with Audit Trail
"As support staff, I want tools to review and override waitlist eligibility and invites with full history so that I can resolve edge cases and keep classes full while maintaining accountability."
Description

Provides an admin console to view the waitlist with eligibility status, reasons, deadlines, invite history, and conversion outcomes. Enables permitted staff to adjust deadlines, re-order positions with justification, mark users as eligible, revoke provisional status, resend or cancel invites, and manually enroll a user. Includes role-based access controls, bulk actions, export, and a complete audit trail of changes and automated decisions to support dispute resolution and compliance. Integrates with ClassTap’s reporting and user management, and surfaces key metrics (fill rate, conversion by eligibility state, average time-to-fill) for operational insight.

Acceptance Criteria

AutoClaim

Let waitlisted attendees opt into automatic seat claiming within a chosen timeframe and price cap. When a seat opens, ClassTap instantly charges the saved payment method and confirms the spot—no taps required. Providers get reliable fills and fewer abandoned holds, while attendees never miss out due to timing.

Requirements

AutoClaim Opt-in with Time Window and Price Cap
"As a waitlisted attendee, I want to opt into automatic seat claiming with a time window and price cap so that I can secure a spot without constantly checking my phone."
Description

Enable waitlisted attendees to enroll in AutoClaim by selecting a claim window (e.g., until class start minus X minutes) and setting a maximum price they are willing to pay. The flow collects explicit consent to auto-charge a saved payment method and auto-confirm the spot if a seat opens within the defined parameters. Integrates into existing waitlist and booking UIs (web/mobile), showing the configured window, price cap, countdown, and the ability to edit or cancel before the window ends. Enforces timezone correctness, accessibility standards, and clear disclosures about charges and cancellation policy. Requires a saved payment method or prompts to add one. Persists preferences at the waitlist-entry level and optionally as user defaults. Provides APIs and backend persistence to store auto-claim state, window bounds, and cap, and guards against enabling AutoClaim for ineligible classes (e.g., invite-only).

Acceptance Criteria
Secure Payment Vaulting & SCA Handling
"As a waitlisted attendee, I want my saved payment method securely charged automatically and handle any necessary verifications so that my seat is confirmed instantly when available."
Description

Store and use tokenized payment methods (via PSP vaulting) for AutoClaim with PCI DSS SAQ-A compliance. Validate the payment method during opt-in (e.g., $0/low-value authorization) and capture the payment instantly when a seat opens. Implement 3D Secure/SCA step-up flows that can be completed asynchronously when required, including links in notifications to authenticate within a short hold period. Ensure idempotent charge attempts, retries with backoff on transient errors, and graceful fallback (skip to next candidate) on hard declines or expired cards. Support region-specific mandates, refunds, and receipts through the PSP. Log PSP response codes for troubleshooting and analytics.

Acceptance Criteria
Instant Seat Claim Orchestration
"As a platform operator, I want a robust seat-claim engine that allocates openings fairly and atomically so that we prevent double-bookings and fill classes reliably."
Description

Implement an event-driven engine that listens for seat-available triggers (cancellations, hold expirations, capacity increases) and evaluates eligible AutoClaim candidates in priority order (e.g., waitlist position, provider rules). Acquire a distributed lock on the class instance and seat allocation to ensure atomicity and prevent double-bookings. For each candidate within their active window and under price cap, attempt payment capture; on success, immediately create the booking and release the lock; on failure, proceed to the next candidate. Support configurable hold durations when SCA is needed, concurrency safety across nodes, idempotent operations, rate limiting, and transparent error handling. Expose operational metrics and logs for monitoring throughput, success rate, and time-to-fill.

Acceptance Criteria
Automated Notifications & Receipts
"As an attendee, I want clear notifications about AutoClaim actions and required steps so that I know when I’ve secured a seat or need to intervene."
Description

Provide SMS and email notifications for key AutoClaim events: opt-in confirmation, successful seat claim, payment failure, SCA authentication required, window expiring soon, price cap exceeded (not attempted), opt-out confirmation, and provider-side overrides. Templates are white-label branded per provider, localized, and customizable with variables (class name, time, price, links). Include deep links to authenticate payments, manage settings, or cancel AutoClaim. Ensure compliance with messaging regulations (e.g., TCPA/CAN-SPAM), provide unsubscribe preferences where applicable, and attach receipts or link to hosted receipts after successful charges. Track delivery/open/click metrics for operational insights.

Acceptance Criteria
Provider Controls & Policy Governance
"As a provider, I want granular control over AutoClaim policies and defaults so that the feature aligns with my pricing, cancellation, and customer experience strategy."
Description

Add provider-facing settings to enable/disable AutoClaim per class, series, or account default; configure default claim windows, price cap rules, SCA hold duration, and waitlist priority logic. Allow providers to set cancellation/refund rules specific to AutoClaim, blackout periods (e.g., no auto-claims within N minutes of start), and per-user limits (e.g., max auto-claims per week). Provide visibility into current AutoClaim enrollments, queued candidates, fill outcomes, and override actions (manually claim, skip, or pause). Enforce role-based access control, audit changes to settings, and expose reporting/exports for policy compliance.

Acceptance Criteria
Audit Trail, Refunds & Dispute Handling
"As support staff, I want complete audit logs and streamlined refund/dispute tools so that I can resolve issues quickly and maintain compliance."
Description

Record an immutable audit log of AutoClaim state transitions and payment attempts, including timestamps, actors, and PSP responses, viewable in admin tools for support. Implement refund and reversal workflows for scenarios such as class cancellations, mistaken auto-claims, or SCA failures post-hold, honoring provider policies and local regulations. Provide rapid lookups of evidence (notifications sent, authentication links, user consents) to assist with chargebacks. Support partial refunds, pro-rated fees, and automated refund triggers where configured. Define data retention and privacy controls for logs and receipts, with export capabilities for compliance and dispute packages.

Acceptance Criteria

FairQueue

A configurable, transparent ranking engine that blends join time with smart priorities like membership status, attendance streak, proximity, prerequisites, and “keep-together” group rules. Shows users their position and ETA to build trust, and uses round‑robin fairness to prevent the same person from always being first. Reduces support questions and aligns fills with your business goals.

Requirements

Priority Rules Configuration Engine
"As a studio owner, I want to configure how the waitlist ranks attendees using business rules so that class spots are filled according to my priorities."
Description

A configurable ranking engine that blends join time with weighted business factors such as membership status, attendance streak, proximity, prerequisite completion, and group rules. Admins can define per-class or template-based rule sets, adjust weights and tie-breakers, simulate outcomes, and preview rankings before publishing. Configurations are versioned with change history and safe rollbacks. The engine integrates with ClassTap scheduling, user profiles, passes, and attendance records, and exposes a deterministic API used by booking flows and waitlists. This enables transparent, goal-aligned fills while eliminating manual sorting and reducing admin time.

Acceptance Criteria
Real-time Queue Position and ETA Display
"As a waitlisted attendee, I want to see my position and estimated time to get a spot so that I know what to expect and can plan."
Description

User-facing components for web booking pages, embeddable widgets, and SMS/email deep links that show current position in queue, estimated time to promotion, and a concise explanation of factors influencing rank. Updates in real time as capacity or rules change, handles race conditions, and degrades gracefully on poor networks. Fully white‑label with branding, localization, and accessibility support. Builds trust, reduces support tickets, and encourages users to stay on the waitlist rather than overbooking alternatives.

Acceptance Criteria
Round‑Robin Fairness Scheduler
"As a community program coordinator, I want the queue to rotate priority among frequent joiners so that the same people don’t always get first access."
Description

A fairness mechanism that rotates priority among similarly ranked users across recurring classes and repeated promotions so the same person is not always first. Supports configurable fairness windows (per class, series, instructor, or organization), respects hard eligibility rules, and records fairness adjustments in the audit log. Includes simulation tools to forecast distribution effects and guardrails to avoid disadvantaging newcomers. Ensures equitable access while preserving business priorities.

Acceptance Criteria
Keep‑Together Group Handling
"As a parent booking for two children, I want our spots kept together so that we can attend the same class."
Description

Group-aware queuing that treats multi-seat bookings as a unit, calculating a composite score and only promoting when contiguous spots are available. Configurable policies allow admins to enable intelligent splitting as a fallback with explicit user consent, suggest alternate sessions with sufficient capacity, and prioritize smaller groups when space is tight. Integrates with capacity management, prevents accidental splits, and communicates decisions clearly to users.

Acceptance Criteria
Eligibility and Prerequisite Validation
"As an instructor, I want FairQueue to verify prerequisites and membership before ranking so that only eligible students get priority."
Description

Pre‑ranking checks that validate membership status, attendance streak thresholds, completion of prerequisites, age or skill constraints, and outstanding balance or waiver status. Supports hard blocks and soft preferences, with clear user messaging and admin override workflows. Pulls data from ClassTap profiles, passes, attendance, and external systems via API. Ensures only eligible users are ranked or prioritized, improving class outcomes and reducing last‑minute failures.

Acceptance Criteria
Auto‑Promotion with Payment and Hold Window
"As a waitlisted student, I want to be automatically offered a spot with an easy way to confirm and pay so that I don’t miss openings."
Description

Automated promotion workflow that offers open spots to the top‑ranked users, holds the seat for a configurable countdown window, and captures payment or deducts a pass upon confirmation. Sends branded SMS/email notifications with secure deep links, escalates to the next candidate on expiry or decline, and prevents double‑bookings via atomic reservations. Integrates with ClassTap payments, refunds, and reminders, and emits webhooks for downstream systems. Increases conversion from waitlist to attendance while reducing manual intervention.

Acceptance Criteria
Decision Audit Log and Explainability
"As a studio admin, I want to see why each attendee was ranked and promoted so that I can answer support questions and ensure fairness."
Description

A comprehensive audit trail capturing ranking inputs, weights, tie‑breakers, fairness rotations, eligibility results, promotion offers, expirations, user actions, and notifications. Provides admin tooling to view per-user explanations ("why this position") and an optional attendee-facing summary for transparency. Supports filtering, export, and retention policies with privacy controls. Reduces support load, improves trust, and enables compliance reviews and A/B evaluation of rule changes.

Acceptance Criteria

HoldGuard

Adaptive hold timers that flex with context: keep the standard 10‑minute window, shorten near class start, and auto‑extend when a user opens the pay sheet or passes verification. Visual countdowns set clear expectations, while expired holds auto‑cascade to the next in line. Prevents seat slippage without manual intervention.

Requirements

Context-Aware Hold Rules Engine
"As a student booking a popular class, I want the system to reserve my spot with a fair, context‑aware timer so that I don’t lose my seat due to timing edge cases or device switches."
Description

Implement adaptive seat-hold timers that default to 10 minutes, automatically shorten as the class start time approaches, and support configurable thresholds and overrides at the organization, location, and class levels. The timer is server-authoritative, persists across sessions/devices, and exposes a real-time state via API for clients to render synchronized countdowns. Holds are atomic and idempotent to prevent oversells under concurrency, support multi-quantity reservations, and are timezone-aware. Events are emitted on hold start, refresh, extension, and expiry, with graceful recovery after service restarts and guardrails for minimum/maximum durations.

Acceptance Criteria
Pay Sheet Open Extension Trigger
"As a payer at checkout, I want my hold extended when I open the payment form so that I have enough time to complete payment without losing my seat."
Description

Automatically extend an active hold when the user opens the payment sheet to reduce drop‑offs during checkout. The client emits a pay_sheet_opened signal that is verified server-side and applied once per hold (configurable), with caps on total extensions and maximum TTL. Aborted or closed payment sheets revoke the pending extension after a short grace period. All extensions are audited, rate‑limited, and resilient to duplicate events, ensuring consistent behavior across web and mobile flows.

Acceptance Criteria
Verified Identity/Payment Extension
"As a customer completing verification, I want my hold to be extended automatically once I pass the security check so that I’m not penalized for mandatory verification steps."
Description

Extend the hold duration upon successful identity or payment verification events (e.g., SCA/3DS/OTP), using webhook-driven, server-to-server confirmation from the payment provider. Apply a configurable extension amount with a hard cap, and do not extend on soft-declines or failed challenges. Protect against replay with signed webhooks and idempotency keys, and log all verification-driven extensions for audit. Store only minimal, tokenized references to remain compliant with privacy and PCI constraints.

Acceptance Criteria
Countdown Timer UI and Alerts
"As a user reserving a spot, I want a clear countdown that matches the actual hold so that I know exactly how much time I have before I lose the reservation."
Description

Render a synchronized visual countdown on booking and checkout screens that reflects the server-authoritative hold TTL with sub-minute accuracy. Support accessible live regions and clear status messages, localize time formats, and theme to match white‑label branding. Provide optional pre‑expiry nudges (banner/toast) and disable actions when the hold expires, prompting users to reattempt or join the waitlist. Ensure the countdown continues seamlessly across page reloads, app backgrounding, or device switches.

Acceptance Criteria
Waitlist Auto-Cascade Fulfillment
"As a waitlisted learner, I want to be automatically offered a seat when one becomes available so that I don’t have to constantly check and risk missing my chance."
Description

When a hold expires or is released, automatically cascade the freed seat to the next eligible person in the waitlist using fair, deterministic rules (e.g., FIFO with priority tiers). Issue time-bound offer holds with configurable windows, notify via email/SMS with deep links, and handle declines or expiries by iterating to subsequent waitlisters. Implement concurrency-safe allocation with transactional checks and comprehensive audit trails to prevent double allocation and ensure transparency.

Acceptance Criteria
Admin Controls, Policies, and Analytics
"As an admin, I want to configure hold policies and review hold performance analytics so that I can balance fairness, conversion, and operational needs across classes."
Description

Provide admin settings to configure default hold durations, start‑time proximity shortening thresholds, extension limits, and eligibility rules for extensions. Allow per‑class overrides and environment‑safe previews. Expose dashboards and exports for hold lifecycle metrics (created, extended, expired, converted), waitlist cascade performance, and drop‑off reasons, with filters by class, instructor, and channel. Enforce role‑based access and surface API endpoints for programmatic management.

Acceptance Criteria

Last‑Call Burst

In the final minutes before class, send offers to a small, smart batch (e.g., top 3) with first‑pay‑wins logic. Timers compress and cascades accelerate so empty seats are filled fast, with safeguards to prevent double‑booking. Works hand‑in‑hand with doorline QR waitlists to convert walk‑ins when digital claims lapse.

Requirements

Smart Last-Call Candidate Ranking
"As a studio manager, I want the system to automatically select the top few likely attendees for last‑minute offers so that empty seats are filled quickly without blasting our entire list."
Description

Implements a lightweight scoring engine to select a small, high-likelihood batch (e.g., top 3) of recipients for last‑minute seat offers. Inputs include historical show‑up rate, payment velocity, distance/proximity, past response time to urgent offers, waitlist position, member status, and explicit opt‑ins. The engine outputs a ranked list with ties broken deterministically. Integrates with ClassTap’s user profiles, past booking data, and notification preferences. Provides configurable cohort size, exclusion rules (e.g., already declined today), quiet‑hours overrides, and fallback behavior when fewer than the target number qualify. Improves fill rates by targeting users most likely to convert while minimizing spam and protecting sender reputation.

Acceptance Criteria
First‑Pay‑Wins Atomic Seat Allocation
"As an instructor, I want the seat to go to whoever completes payment first so that there are no double‑bookings or manual fixes before class starts."
Description

Ensures strict first‑pay‑wins logic with transactional safeguards so that the first completed payment claims the seat and all concurrent attempts are cleanly rejected or rerouted. Uses short‑lived claim tokens, per‑seat pessimistic locks, and idempotent payment intents to prevent double‑booking. Includes a brief configurable payment window (e.g., 2–3 minutes) with visible countdown and automatic release on timeout or payment failure. Integrates with ClassTap’s inventory, payment gateway, and waitlist so that released seats immediately trigger the next cascade step. Provides clear user feedback states (held, processing, success, expired) and audit logs for dispute resolution.

Acceptance Criteria
Expiring Offers with Accelerated Cascades
"As a front‑desk coordinator, I want offers to expire quickly and cascade automatically so that we can fill seats fast without manual intervention."
Description

Delivers time‑boxed offers with visible countdown timers that compress as class start approaches, automatically cascading to the next ranked cohort upon expiry or decline. Supports dynamic window lengths (e.g., 5 minutes then 3 then 1) and configurable maximum rounds. Tracks per‑recipient state (sent, opened, clicked, claimed, expired) to avoid duplicates and to trigger cascades only when capacity remains. Integrates with the ranking engine and seat allocation layer so that each cascade respects real‑time availability. Reduces idle time between rounds, maximizing the chance to fill last seats in the final minutes.

Acceptance Criteria
Multi‑Channel Delivery & Compliance Guardrails
"As a participant who opted into alerts, I want timely, concise last‑minute notifications on my preferred channel so that I can grab a spot without being spammed."
Description

Sends last‑call offers via SMS, email, and push (where available) with channel prioritization based on historical responsiveness and user consent. Implements per‑user and global rate limiting, quiet‑hour suppression with emergency overrides, opt‑out honoring, link tracking, and failover between channels if delivery fails. Templates support dynamic content (class name, start time, price, seat count, countdown link). Ensures compliance with regional messaging rules and logs send outcomes for analytics. Integrates with ClassTap’s notification service and branding to keep white‑label look and feel.

Acceptance Criteria
Doorline QR Waitlist Handshake
"As a walk‑in attendee, I want to scan a code and immediately know if I can claim an open seat so that I don’t wait in line only to be turned away."
Description

Connects in‑venue QR waitlists with the Last‑Call Burst workflow so walk‑ins can instantly queue and claim seats if digital offers lapse. Generates a short‑lived claim link upon QR sign‑up that respects first‑pay‑wins and cascade rules. Displays current countdown and availability to set expectations. Automatically promotes doorline users when a round expires or a token releases, with support for payment on device at the door. Synchronizes states to prevent conflicts between remote claims and walk‑ins. Accelerates conversion of physical foot traffic into confirmed bookings during the last minutes before class.

Acceptance Criteria
Instructor Controls & Live Monitor
"As an instructor, I want a simple dashboard to launch and oversee last‑call offers so that I can fill seats confidently without technical complexity."
Description

Provides a control panel to enable/disable Last‑Call Burst per class, set batch size, cascade rounds, minimum lead time, and optional last‑minute pricing or promo toggles. Includes a live monitor showing current round, recipients, countdowns, claims, failures, and remaining capacity with manual override actions (skip round, add recipient, cancel token). Offers presets by class type and saves defaults at studio level. Integrates with existing scheduling and class detail pages, respecting user roles and permissions. Reduces operational friction and builds trust through transparency and control.

Acceptance Criteria
Performance Analytics & Experimentation
"As a studio owner, I want to see which last‑call configurations perform best so that I can optimize fill rates and revenue over time."
Description

Captures and surfaces metrics such as send volume, open/click rates, conversion time, fill‑rate uplift, revenue per seat, no‑show deltas, and channel effectiveness. Breaks down performance by class type, time of day, and cohort size. Supports A/B configurations (e.g., batch size, timer lengths, message copy) with statistically sound comparisons. Exposes insights in the analytics tab and exports to CSV. Feeds learnings back into the ranking engine to improve future targeting. Enables data‑driven tuning of the Last‑Call Burst to maximize utilization and revenue.

Acceptance Criteria

KeepTogether

Group‑aware waitlisting for families and friends. Attendees choose “keep together” or “okay to split”; the system holds and offers the right number of seats accordingly, or presents clear partial‑claim options when only some seats free up. Minimizes back‑and‑forth and ensures fair, stress‑free fills for multi‑seat bookings.

Requirements

KeepTogether Selection UX
"As a parent booking for my family, I want to choose to keep us together or allow splitting so that the system knows how to offer seats when they become available."
Description

Add a mobile-first, accessible UI on class booking and waitlist sign-up that captures party size and a clear choice between “Keep group together” or “Okay to split.” Display explanatory copy about how holds and split offers work, enforce class-specific maximum party sizes, and validate input. Persist the selection with the waitlist record, including optional attendee names and contact preferences. Ensure the flow works for guest checkout and white-labeled themes, and that captured data is passed to the allocation engine and checkout to drive seat holds and messaging.

Acceptance Criteria
Group-aware Allocation Engine
"As a waitlisted attendee, I want the system to hold enough seats for my group when it’s our turn so that we can book without losing spots to others."
Description

Implement a server-side allocation engine that continuously evaluates seat availability and waitlist entries to create time-bound holds that honor group size and split preferences. For “Keep together,” only place holds when enough seats are available; for “Okay to split,” generate partial offers as seats open. Apply fairness rules (timestamp-based with tie-breakers), prevent large groups from blocking the queue indefinitely via configurable thresholds, and handle concurrent events, cancellations, and capacity changes without double-booking. Expose deterministic decision logs and operate idempotently across retries.

Acceptance Criteria
Partial-Claim Offers & Remainder Handling
"As a group organizer who allowed splitting, I want to accept some of the seats now and keep the rest waiting so that at least part of my group can attend without losing our place."
Description

When insufficient seats are available for a full group that opted to split, generate clear partial-claim offers that specify how many seats can be taken now and how many remain on the waitlist. Provide a simple selection step to assign available seats to specific attendees, keep the remainder in queue with preserved priority, and allow switching preferences (e.g., from keep-together to split) where permitted. Manage timers for held subsets, release unclaimed seats cleanly, and ensure pricing, discounts, and class policies reflect the number of seats actually claimed.

Acceptance Criteria
Hold-and-Offer Notifications with Deep Links
"As a waitlisted customer, I want a clear message with a one-tap link to claim my held seats so that I can check out quickly before the hold expires."
Description

Send branded SMS and email notifications when holds or split offers are created, including a secure deep link to claim seats, a visible countdown to hold expiry, and clear next steps. Provide follow-up reminders before expiration, respect user notification preferences and regional compliance, and degrade gracefully to alternate channels on delivery failure. Template content per white-label configuration and localize where available. Record delivery, open, and click events for audit and performance tracking.

Acceptance Criteria
Reserved Cart & Checkout Integration
"As the organizer for my group, I want to pay for our held seats in a single checkout so that I can confirm all spots before the timer runs out."
Description

Integrate seat holds into checkout so that reserved seats appear in a locked cart with an expiry timer synchronized to the allocation engine. Support paying for all seats in one transaction or, when enabled, inviting party members to pay their own shares without releasing the hold. Enforce capacity constraints, taxes, and discounts per seat, ensure idempotent payments, and auto-cancel holds on payment failure or expiry. Update class rosters in real time and trigger standard confirmations and reminders upon successful payment.

Acceptance Criteria
Instructor Controls & Overrides
"As an instructor, I want to configure and, when necessary, override group-aware waitlist behavior so that fills remain fair and aligned with my class policies."
Description

Provide admin settings at account and class levels to enable/disable KeepTogether, set default preference (keep vs split), define maximum party size, hold duration, fairness thresholds, and tie-breaker rules. Offer an instructor view of the queue that shows group size, preference, and timestamps, plus tools to manually allocate, merge, or split groups in edge cases. Include safeguards to prevent unintended over-allocation and record all overrides in an audit trail.

Acceptance Criteria
Analytics, Insights, and Audit Logging
"As a studio owner, I want insights into how KeepTogether affects conversions and attendance so that I can tune settings and demonstrate ROI."
Description

Capture and surface metrics such as waitlist conversion rate by group size and preference, average hold duration, expired holds, partial-claim utilization, and impact on no-shows. Provide exportable reports and basic dashboards, and store detailed event logs (allocation decisions, notifications, claims, expiries) to support dispute resolution and continuous improvement. Expose configuration-level comparisons to help tune defaults (e.g., hold window, maximum party size).

Acceptance Criteria

ChannelSmart

Delivers claim invites via the channel each user is most likely to see—SMS, email, push, or WhatsApp—with automatic fallbacks and localization. Respects quiet hours and urgency windows, optimizing send timing and content to maximize conversions. Fewer missed messages, more seats claimed on the first try.

Requirements

Predictive Channel Selection Engine
"As a studio owner, I want invite messages sent via the channel each customer is most likely to see so that more seats are claimed on the first attempt."
Description

Determine the highest-likelihood delivery channel (SMS, email, push, WhatsApp) per recipient for claim invites using engagement history, contact availability, device tokens, deliverability signals, and recent interaction context. Scores channels in real time when a seat becomes available, honors per-channel consent, and chooses the best eligible option. Integrates with ClassTap’s user profiles, waitlist events, and booking flows, embedding a signed deep-link to the claim page. Provides idempotency to avoid duplicate notifications if a claim is completed, and logs decision reasons for auditability. Expected outcome: higher first-attempt claim conversions and fewer missed invites.

Acceptance Criteria
Multi‑Channel Fallback Orchestration
"As a waitlisted student, I want to receive a claim invite via an alternative channel if the first one fails so that I don’t miss time‑sensitive openings."
Description

Automatically retry claim invites across alternative channels when the primary attempt fails, times out, or is not engaged within a configured window. Supports provider failure detection (bounces, undelivered, throttling), soft vs. hard retry policies, escalating to the next eligible channel with configurable delays and maximum attempts. Ensures deduplication and idempotent claims: suppresses further sends once the seat is claimed or the invite expires. Captures full event telemetry (sent, delivered, opened/read where available, clicked, claimed) and updates recipient contact health in ClassTap.

Acceptance Criteria
Quiet Hours and Urgency Windows
"As a customer, I want messages to respect my quiet hours but still receive urgent last‑minute openings near class time so that I am not disturbed unnecessarily yet can act when it matters."
Description

Respect tenant- and user-level quiet hours by suppressing non-urgent sends during local nighttime and only delivering within allowable windows. Detect recipient timezone from profile, class location, or last known interaction, and adjust scheduling accordingly. Support urgency windows for last‑minute seat openings (e.g., within 3 hours of class) that permit respectful overrides for explicitly opted-in users. Provide admin controls for rules, exceptions, and blackout dates, and ensure compliance with regional do‑not‑disturb regulations. All scheduling constraints are enforced across all channels and fallbacks.

Acceptance Criteria
Localization and Template Personalization
"As an international customer, I want invite messages in my language and in a format that fits the channel so that I can quickly understand and claim my spot."
Description

Localize invite content and transport‑specific templates for SMS, email, push, and WhatsApp using an i18n catalog with fallback languages. Support merge fields (class name, date/time in local format, instructor, studio, location/map link), conditional content per channel (length limits, media, WhatsApp approved templates), and right‑to‑left rendering where applicable. Validate templates at publish time, automatically shorten and safely truncate SMS, and embed signed tracking links compatible with each channel. Integrates with ClassTap branding to ensure white‑label consistency on all touchpoints.

Acceptance Criteria
Send‑Time Optimization
"As a studio owner, I want the system to schedule invites when recipients are most likely to engage so that claim conversions improve without manual tuning."
Description

Optimize send time for each invite by modeling historical engagement patterns, recipient availability, and proximity to class start while honoring quiet hours and urgency rules. Choose the best time within an allowed window; fall back to immediate send for high‑urgency events. Provide A/B testing and holdout groups to measure lift, and guardrails to prevent bunching or provider rate‑limit breaches. Expose per‑tenant controls to enable/disable and set optimization windows, with transparent reasoning in logs and analytics.

Acceptance Criteria
Consent, Compliance, and Opt‑Out Management
"As a recipient, I want clear opt‑in and opt‑out controls for each channel so that I can control how I’m contacted and trust the communications I receive."
Description

Centralize per‑channel consent state, capturing double opt‑in where required (e.g., WhatsApp), honoring STOP/HELP keywords for SMS, unsubscribe links for email, and system‑level DND lists. Store auditable records (timestamp, channel, source, IP/user agent), apply regional rules (e.g., GDPR/CCPA data minimization and purpose limitation), and suppress messaging for non‑consented channels in both primary and fallback flows. Provide self‑serve preference center links in messages and in the booking UI, and expose APIs/webhooks to sync consent with external CRMs.

Acceptance Criteria
Delivery Analytics and Conversion Attribution
"As a studio owner, I want to see which channels and timings drive successful claims so that I can tune settings and improve results over time."
Description

Provide dashboards and exports showing end‑to‑end performance by channel and strategy: send, delivery, open/read (where available), click/tap, and claim conversion, attributed to the last or best‑performing touch. Ingest provider webhooks and receipts for SMS, email, push, and WhatsApp; reconcile with internal events to compute latency and fallout per step. Surface insights such as top channels per segment, effective fallback paths, and optimization lift. Offer per‑invite and aggregate views, with filters by class, instructor, location, and time. Expose metrics via API for BI tools.

Acceptance Criteria

Demand Pulse

A live, color-coded heatmap that predicts conversion likelihood by day and hour—filter by location, room, class type, and audience. Instantly spot hot hours to double down and cold zones to avoid. See expected fill-rate lift and confidence so you can move or launch classes with clarity and fewer experiments.

Requirements

Live Heatmap Visualization
"As a studio owner, I want a live heatmap of predicted demand by hour and day so that I can quickly spot high-opportunity times and avoid low-performing slots."
Description

A responsive, color-coded grid that visualizes predicted conversion likelihood by day and hour for selected entities. Each cell displays key metrics (predicted conversion %, expected fill-rate lift vs baseline, confidence) with tooltips for historical context (bookings, cancellations, waitlist, no-shows). Supports weekly and custom date ranges, timezone awareness, and mobile/desktop layouts. Provides fast interactions (initial render under 1.5s on typical org datasets; sub-300ms filter updates with client-side virtualization). Includes accessible colorblind-safe palette, legends, keyboard navigation, and aria labels. Integrates with ClassTap’s scheduling context so clicking a cell opens detail and actions relevant to that slot.

Acceptance Criteria
Filter & Segmentation Engine
"As a location manager, I want to filter demand by room, class type, and audience segment so that I can tailor scheduling decisions to my context."
Description

Multi-dimensional filters to refine demand signals by location, room, instructor, class type, format (in-person/hybrid), audience segment (new vs returning, member vs drop-in, age bracket), capacity band, and price tier. Supports multi-select, inclusion/exclusion, and date/season toggles (e.g., holidays). Enables saved segments with friendly names, default views per role, and deep-linkable URLs for shareable, permission-respecting views. Persists last-used filters per user. Ensures performant queries via indexed back-end endpoints and client-side caching.

Acceptance Criteria
Predictive Demand Scoring Pipeline
"As an analyst, I want accurate, explainable demand scores with confidence so that I can trust the predictions and plan staffing and capacity."
Description

A scalable data pipeline that ingests historical bookings, views, waitlists, payments, cancellations, and no-shows; enriches with seasonality, time-of-day, local holidays, and optional external signals (e.g., weather). Produces per-slot predictions: conversion likelihood, expected fill-rate lift versus current schedule, confidence interval, and sample size. Nightly model retraining with incremental updates every 15 minutes; model versioning, A/B rollouts, and fallback heuristics if the model is unavailable. Monitors drift and accuracy with alerts. Ensures privacy via aggregation, pseudonymization, and compliance with applicable data regulations.

Acceptance Criteria
What‑if Scheduling Simulator
"As an instructor, I want to simulate moving or launching a class at different times so that I can choose the slot with the best attendance and minimal conflicts."
Description

Interactive tool to test moving or launching a class into candidate time slots and compare predicted outcomes side-by-side. Shows projected enrollment curve, revenue impact, capacity utilization, likelihood of cannibalization of adjacent classes, waitlist absorption, and no-show risk. Performs conflict checks (instructor, room, location) and honors scheduling constraints (buffers, setup/teardown). Exposes assumptions and sensitivity toggles (price, capacity, promo). Supports exporting scenarios and saving drafts tied to specific classes or templates.

Acceptance Criteria
Actionable Recommendations & One‑Click Scheduling
"As a scheduler, I want actionable time-slot recommendations and one-click class creation or moves so that I can act on insights without duplicating effort."
Description

Surfaced recommendations for top time slots within the current filter context, each with expected fill-rate lift, confidence, and rationale. For existing classes, suggests move options with automated conflict resolution and impact preview; for new classes, offers pre-filled creation flows. Provides one-click actions that create or reschedule classes, place tentative holds on rooms, update reminders, notify enrolled attendees of changes, and roll back on failure. Tracks outcomes of accepted/ignored recommendations to continuously improve the model.

Acceptance Criteria
Role‑Based Access, Privacy & Audit
"As an org admin, I want role-based access, privacy controls, and audit logs so that sensitive data is protected and changes are traceable."
Description

Enforces granular permissions so org admins can view all demand data, location managers are scoped to their sites, and instructors see only their classes and rooms. Masks or aggregates sensitive metrics for restricted roles. Controls export/share abilities (CSV, PDF, image) with branding options and watermarks. Logs viewing, exporting, scenario creation, and scheduling actions with timestamp, actor, and context for traceability; provides retention and export of audit logs. Integrates with existing ClassTap authentication, supports SSO and optional 2FA.

Acceptance Criteria

SlotSense

When creating or moving a class, get the top suggested time slots ranked by predicted utilization. SlotSense weighs instructor availability, room conflicts, seasonality, past waitlists, and commute patterns, then applies your pick in one tap—publishing a schedule that fills faster with less back-and-forth.

Requirements

Signal Aggregation & Data Pipeline
"As a studio owner, I want SlotSense to consider all relevant signals (availability, rooms, history, seasonality, commute) so that suggested time slots reflect real-world constraints and demand."
Description

Build a real-time, multi-source data pipeline that unifies instructor availability (ClassTap profiles and connected calendars), room resources, historical bookings, waitlists, seasonality patterns (weekday/term/holiday effects), location data, and inferred commute times between consecutive classes. Implement ETL to normalize time zones, class durations, capacities, buffers, and resource identifiers; deduplicate and reconcile conflicts; maintain freshness SLA < 5 minutes for availability/resource changes and daily refresh for historical features. Provide a feature store for model inputs (e.g., trailing fill rates, lead-time-to-fill, no-show probabilities, demand by hour/weekday/season, room utilization, instructor travel time constraints). Enforce privacy by limiting geodata to corridor-level travel times, hashing PII, and honoring account data-retention settings. Expose a query service for the SlotSense engine and cache hot signals for <200ms reads.

Acceptance Criteria
Conflict-Aware Slot Generation
"As an instructor, I want SlotSense to only show conflict-free times that respect my buffers and travel needs so that I can schedule confidently without manual checking."
Description

Generate feasible candidate time slots for new or moved classes by intersecting instructor availability, room calendars, business hours, blackout dates, and class constraints (duration, capacity, setup/teardown buffers, recurrence rules). Respect travel and turnaround time between an instructor’s adjacent classes across locations; detect and exclude slots that cause resource or overlap conflicts. Handle edge cases: daylight saving changes, cross-time-zone instructors, hybrid classes with room + virtual resource, and minimum lead time before start. Produce a ranked-ready candidate set per location with metadata (resources required, applied constraints, conflict reasons if excluded) within 500ms for a typical week view.

Acceptance Criteria
Utilization Prediction & Ranking Engine
"As a studio manager, I want the best time slots ranked by predicted fill so that our schedule fills faster with less back-and-forth."
Description

Develop a scoring service that predicts expected utilization for each candidate slot and returns a ranked list. Features include historical fill curves, waitlist pressure, seasonality (weekday, month, school term, holidays), price elasticity signals, neighborhood demand by time-of-day, instructor popularity, and cold-start priors by category. Incorporate constraints as penalties (e.g., short lead time, atypical hours) and allow business-weighted objectives (maximize utilization, minimize idle room gaps, reduce instructor travel). Provide an API returning top N suggestions with score, confidence, and key drivers. Latency target < 300ms for 200 candidates. Fallback to rule-based heuristics when history is sparse.

Acceptance Criteria
One-Tap Apply & Publish
"As a community center coordinator, I want to apply the chosen slot in one tap and publish immediately so that I can finalize schedules without extra admin steps."
Description

Implement UI and backend actions to apply a selected suggestion in one tap: create or update the class session(s), reserve room resources, update instructor calendars, and publish to the branded booking page. For moves, surface impact preview (enrollments affected, waitlist transfers, outstanding payments) and support automated notifications via SMS/email with templated messaging. Respect ClassTap’s cancellation/reschedule policies, require confirmations where configured, and provide atomic rollback on failure. Support single, series, or partial-series application with bulk updates. Ensure end-to-end completion under 2 seconds for single-class operations.

Acceptance Criteria
Explainability & Confidence Indicators
"As a small studio owner, I want to see why a time is recommended so that I can trust the suggestion and explain it to my team."
Description

Display transparent rationale for each suggested slot to build trust and speed decisions: show top drivers (e.g., “High local demand Tue 6–7pm,” “Short commute from prior class,” “No room conflicts”), predicted utilization range with confidence, and trade-offs (e.g., “10% lower utilization but keeps instructor free Friday”). Provide quick filters (avoid late nights, prefer studio A, 60–90 min only) that re-rank suggestions. Include a “Why not?” view for excluded times with specific conflict reasons. Persist user dismiss/accept feedback for learning without exposing PII.

Acceptance Criteria
Continuous Learning & Performance Measurement
"As a product owner, I want SlotSense to learn from outcomes and show measurable impact so that we can continuously improve utilization and reduce no-shows."
Description

Instrument end-to-end metrics and a feedback loop: suggestion acceptance rate, time-to-fill, show-up rate, waitlist conversion, schedule changes avoided, and utilization delta vs manual scheduling. Enable offline model retraining pipelines and periodic evaluation with backtests and A/B tests (e.g., top-3 SlotSense vs control). Provide dashboards per account and global, plus alerting when performance regresses. Capture labeled outcomes from user overrides, rejections, and successful fills to update features and improve cold-start priors.

Acceptance Criteria
Admin Controls, Constraints & Permissions
"As an account admin, I want to configure constraints and permissions for SlotSense so that suggestions align with our policies and only authorized staff can publish changes."
Description

Provide account-level settings and per-instructor controls to guide SlotSense: business hours by location, blackout dates, minimum lead time, max classes per day, required buffers, preferred rooms, commuting mode assumptions, target utilization thresholds, and objective weighting (fill-rate vs travel vs gaps). Respect roles and permissions so only authorized users can apply schedule changes; log all suggestions viewed/applied with audit trails. Offer API and UI to pin or block times, set recurring constraints, and export suggested schedule drafts for review.

Acceptance Criteria

EventAware

Enrich forecasts with local signals—school breaks, holidays, major events, even weather alerts. EventAware flags risky hours before you publish, proposes safer alternatives, and auto-adjusts confidence bands so your calendar rides demand waves instead of fighting them.

Requirements

Multi-Source Event Data Ingestion
"As an operations manager, I want ClassTap to automatically pull reliable local event data so that I don’t have to manually track holidays and city events that affect my classes."
Description

Build and operate connectors that continuously ingest and normalize local signals (public holidays, school district calendars, major city events, venue schedules, and weather alerts) into a unified EventAware schema. Implement scheduled fetches, webhook listeners where available, deduplication, and data quality checks, with fields for event category, location geometry, start/end, expected attendance/severity, and source provenance. Cache results with TTLs, handle API rate limits and failures with retries/fallbacks, and align ingested events to ClassTap tenants and locations by geo metadata. Expose a standardized internal event feed for downstream scoring and forecasting pipelines.

Acceptance Criteria
Geospatial Matching & Impact Scoring
"As a studio owner, I want nearby events evaluated for their likely impact on my class times so that I can schedule around disruptions and capitalize on demand spikes."
Description

Match ingested events to classes using geospatial proximity, travel-time estimates, and temporal overlap, then compute an impact score representing expected demand uplift or suppression. Incorporate distance decay, event scale, category (e.g., marathon, school break, storm), historical correlations, day-of-week effects, and timing (lead time vs. last-minute) into a tunable scoring model. Provide configurable thresholds per tenant/location and return reason codes and confidence for transparency. Deliver a low-latency scoring service with batch and on-demand modes, backed by tests and monitoring.

Acceptance Criteria
Forecast Adjustment & Confidence Band Tuning
"As a growth analyst, I want forecasts that reflect local events so that our staffing and capacity decisions align with real-world demand patterns."
Description

Integrate event impact scores into the existing demand forecasting service to adjust point forecasts and widen or tighten confidence intervals accordingly. Apply uplift/suppression factors with guardrails (caps, minimum confidence) and produce backtestable outputs. Log attribution per adjustment, support fallback to baseline forecasts when signals are weak, and expose an API returning adjusted forecasts plus variance bands for each class slot. Provide offline evaluation scripts and dashboards to track accuracy and the incremental value of EventAware adjustments.

Acceptance Criteria
Publishing Guardrails & Safer Alternatives
"As an instructor, I want to be warned about risky class hours and be offered better alternatives so that I can avoid low attendance and cancellations."
Description

Intercept schedule publishing (dashboard and API) to flag risky class times based on impact scores and confidence, showing clear reason codes (e.g., weather alert, road closures, school break). Generate and rank safer alternative time slots that respect instructor availability, room capacity, existing bookings, and travel buffers. Provide one-click replacement or bulk-apply, plus the ability to override with acknowledgment. Maintain low-latency evaluations to keep the publish flow responsive and record accepted/ignored suggestions for learning.

Acceptance Criteria
Event Overlay & Explainability UI
"As a scheduler, I want a clear visual overlay of events and their effects so that I can quickly understand why a time slot is flagged and decide what to do."
Description

Enhance the calendar and forecasting views with an event overlay that visualizes nearby events, predicted impact intensity, and time windows. Offer filters by event type and severity, tooltips with source and distance, and a before/after forecast preview for each class slot. Provide an adjustable sensitivity control and a what-if sandbox to compare schedule options. Ensure responsive, accessible UI that localizes timezones and formats, includes loading/error states, and surfaces links to original sources for verification.

Acceptance Criteria
Event-Aware Notifications & Reminders
"As a participant, I want timely reminders that account for local disruptions so that I arrive prepared and on time."
Description

Modify SMS/email reminder timings and content when impactful events are present (e.g., send earlier reminders before road closures or storms, include travel advisories or parking notes). Respect user communication preferences and compliance (opt-outs, regional regulations). Automatically update reminders if a class is rescheduled due to EventAware suggestions, include dynamic tokens referencing relevant events, and provide preview/testing tools. Track delivery and engagement metrics to assess effectiveness.

Acceptance Criteria
Admin Controls, Overrides & Audit
"As an account admin, I want to configure EventAware to our context and override edge cases so that we maintain control while benefiting from automation."
Description

Provide tenant-level settings to enable/disable specific data sources, configure sensitivity thresholds, catchment radius, blackout dates, and event categories. Allow manual event creation/edits and per-event or per-class overrides of impact scores with expiration. Gate actions with role-based permissions and write an immutable audit trail of ingestions, score changes, overrides, publish decisions, and accepted suggestions to support supportability and compliance.

Acceptance Criteria

MicroShift

Small start-time tweaks, big impact. MicroShift recommends 5–20 minute adjustments to align with school drop-offs, transit arrivals, and neighboring class end times. Preview the expected lift in on-time arrivals and reduced no-shows before you commit.

Requirements

Context-Aware Data Feeds
"As a studio owner, I want ClassTap to consider nearby transit and school schedules so that recommended start times match when my clients can actually arrive."
Description

Implements connectors to ingest and normalize local time-based signals—public transit GTFS arrivals near each venue, school drop-off/pick-up windows by district, and adjacent ClassTap class end times within the same location—mapped to venue geofences and time zones. Provides a resilient availability signal service with configurable refresh cadence, caching, and graceful degradation when external feeds are stale, enabling MicroShift to generate reliable recommendations without blocking core scheduling flows.

Acceptance Criteria
MicroShift Optimization Engine
"As an instructor, I want smart start-time tweaks that won’t create conflicts so that I can improve punctuality without manual trial and error."
Description

Delivers a rules- and model-driven engine that proposes 5–20 minute start-time adjustments for eligible classes, respecting instructor and room availability, buffer policies, existing reservations, and blackout constraints. Produces a ranked set of candidates with predicted impact on on-time arrivals and no-shows, including confidence intervals and rationale codes, and exposes APIs for the UI to fetch recommendations, validate constraints, and commit selected changes.

Acceptance Criteria
Impact Preview & Simulation UI
"As a studio manager, I want to preview the impact of a suggested shift so that I can choose the option with the biggest upside and least disruption."
Description

Adds an interactive preview panel on schedule and class edit screens to compare baseline versus proposed start times, visualizing expected lift in on-time arrivals, reduced no-shows, affected attendees, and any conflicts. Supports side-by-side alternative comparison, risk warnings for low-confidence predictions, and mobile-responsive, accessible controls to aid quick, informed decision-making before committing a shift.

Acceptance Criteria
Safe Rescheduling & Notifications
"As a coordinator, I want MicroShift changes to be applied safely with automatic notifications so that attendees aren’t surprised and operations stay conflict-free."
Description

Implements a one-click commit workflow that applies the selected MicroShift, updates internal calendars, enforces conflict checks to prevent double-bookings, and triggers branded SMS/email notifications with clear change details and updated calendar attachments for attendees and instructors. Includes configurable lead-time thresholds, automatic fee waivers for rescheduled sessions, waitlist revalidation, and a reversible rollback within a defined window to minimize operational risk.

Acceptance Criteria
A/B Experimentation & Outcome Measurement
"As a product admin, I want to measure the real-world impact of MicroShift so that we can prove value and tune the recommendation strategy."
Description

Introduces lightweight experimentation controls to run MicroShift versus control across comparable classes or time periods, capturing on-time arrivals, no-shows, late check-ins, and cancellations. Attributes lift to shift magnitude and contextual signals, and surfaces results in analytics with cohort filtering and export to refine recommendation strategies and prove ROI.

Acceptance Criteria
Permissions & Audit Trail
"As an owner, I want controls and traceability over schedule changes so that our team stays accountable and we can resolve disputes."
Description

Enforces role-based permissions so only authorized users can view recommendations or apply shifts, and records an immutable audit trail of proposed shifts, approvals, rejections, notifications sent, and rollbacks with timestamps and actor identity. Displays audit entries in class history and provides export for compliance and support inquiries.

Acceptance Criteria

Cadence Fit

Optimize recurring series for retention, not just first-class fills. Cadence Fit models attendance decay and cohort behavior to propose the best weekly rhythm (e.g., Tue/Thu 6:10pm for 6 weeks), then auto-suggests next-term times that keep momentum—minimizing churn between cycles.

Requirements

Attendance Decay Modeling Engine
"As a studio owner, I want reliable predictions of attendance decay for different schedule options so that I can choose cadences that maximize retention and revenue."
Description

Implements a predictive engine that models week-over-week attendance decay for recurring class series using historical booking, attendance, cancellation, and no-show data from ClassTap. The engine ingests signals such as day/time, class type, instructor, location, capacity, waitlist length, seasonality, and cohort size to forecast retention curves for candidate schedules. It supports cold-start scenarios via configurable heuristics and global priors when data is sparse, and continuously retrains with new outcomes to improve accuracy. Outputs include projected attendance per week, expected churn, confidence intervals, and overall retention score for each cadence. Integrates with the scheduling service, inventory/capacity module, and analytics pipeline, with guardrails for data privacy and opt-outs at the account level.

Acceptance Criteria
Cohort Affinity & Segmentation
"As an instructor, I want the system to recognize when my students tend to attend on specific days and times so that proposed schedules match their real availability and habits."
Description

Clusters students into behavioral cohorts based on attendance history, preferred days/times, commute radius, time zone, and class type affinity to identify "sticky" rhythms (e.g., Tue/Thu evenings). Builds a calendar-affinity profile per class and per instructor to detect patterns such as school-term alignment or holiday dips. Exposes cohort-level constraints (e.g., cannot attend Fridays after 6pm) and feeds these as features to the modeling engine and optimizer. Integrates with existing user profiles, tags, and CRM exports without storing external PII beyond what ClassTap already maintains. Provides configurable thresholds for minimum cohort size to avoid overfitting.

Acceptance Criteria
Schedule Optimizer & Proposal Generator
"As a program director, I want a ranked list of feasible schedules with clear retention and revenue scores so that I can confidently pick the best cadence without manual spreadsheet work."
Description

Generates and ranks candidate recurring schedules (e.g., 2x per week for 6 weeks at 6:10pm) under real-world constraints. Consumes instructor/room availability, blackout dates, holidays, capacity, and cohort affinity to produce the top N proposals with predicted retention, fill rate, and revenue impact. Each proposal includes an explanation of key drivers (e.g., Tuesday/Thursday pattern aligns with cohort affinity; avoids holiday week) and conflict checks against existing bookings to prevent double-booking. Exposes an API and admin UI endpoint to request proposals for a class template and write back the selected schedule to publish.

Acceptance Criteria
Next-Term Auto-Rollover Suggestions
"As a studio manager, I want smart next-term suggestions that keep my cohorts together so that I reduce churn between cycles and simplify scheduling."
Description

Monitors active series approaching completion and automatically proposes next-term start dates and times that maintain cohort momentum based on predicted retention and calendar continuity. Supports pre-enrollment with seat priority for current attendees, optional auto-creation of the next series draft, and configurable lead-time windows for notifications. Integrates with payment plans and credits to carry over unused passes where permitted, and with reminders to nudge cohorts to rebook. Provides toggles for one-click publish or manual approval, with audit logs for all rollover actions.

Acceptance Criteria
Demand Signals Integration (Waitlist & No-Show)
"As a data-informed owner, I want the optimizer to account for waitlists and no-show patterns so that proposed schedules reflect true demand and reliability."
Description

Augments predictions by incorporating real-time demand signals such as waitlist length, late cancellations, and no-show rates per day/time to adjust expected fill and retention. Applies decay-weighted recency to emphasize recent trends and introduces caps and smoothing to avoid overreacting to anomalies. Provides a data contract with the waitlist and attendance subsystems and surfaces the contribution of each signal in the proposal explanations. Includes monitoring dashboards and alerting when signal feeds degrade or drift.

Acceptance Criteria
Compare View & One-Click Apply
"As an administrator, I want to quickly compare schedule options and publish the winner with one click so that I can move from insight to action without extra tools."
Description

Delivers an admin interface to compare up to five schedule proposals side-by-side, showing key metrics (predicted retention, expected revenue, average class fill, conflicts avoided, confidence). Supports what-if adjustments (e.g., shift start time by 10 minutes, swap day) with instant re-scoring. Enables one-click apply to create the selected recurring series, reserve resources, generate the branded booking page, and optionally trigger pre-enrollment invitations. Includes role-based permissions, audit trail, and export of proposals to CSV/PDF for stakeholder review.

Acceptance Criteria

Instructor Match

Personalized heatmaps per instructor reveal when each teacher overperforms the average. Instructor Match pairs the right instructor with the right hour based on historical pull, ratings, and audience segments—lifting conversion without adding more classes.

Requirements

Unified Performance Data Pipeline
"As an operations manager, I want a reliable, up‑to‑date dataset of instructor and time‑slot performance so that recommendations and heatmaps are accurate and trustworthy."
Description

Build a robust data pipeline that aggregates and normalizes historical and real‑time signals needed for Instructor Match, including bookings, conversions, ratings, attendance, cancellations/no‑shows, waitlist sizes, class types, locations, modalities, price points, promotions, and audience segments. Implement de‑duplication, schema versioning, and quality checks (freshness, completeness, outlier detection). Compute derived features such as slot performance vs studio baseline, instructor lift by segment, and time‑of‑day seasonality. Backfill at least 12 months of data where available and update incrementally near real‑time. Enforce PII minimization and anonymization for attendee data while preserving analytic utility. Expose standardized feature tables for downstream analytics, heatmaps, and the recommendation engine.

Acceptance Criteria
Instructor Heatmap Analytics
"As a studio owner, I want to see when each instructor overperforms the average so that I can schedule them during high‑impact hours."
Description

Provide a per‑instructor heatmap that visualizes relative performance across days and time slots, highlighting over/under‑performance versus selected baselines (studio average, instructor personal average, class‑type average). Include filters for location, class type, modality (in‑person/hybrid), audience segment, and date range. Offer tooltips with key metrics (conversion rate, attendance, revenue per slot, waitlist depth) and confidence indicators. Support quick export (CSV/PNG), responsive layout, keyboard navigation, and accessible color palettes. Integrate seamlessly within the ClassTap analytics area and link out to scheduling actions for discovered high‑impact windows.

Acceptance Criteria
Matchmaking Recommendation Engine
"As a scheduler, I want ranked instructor suggestions for a given time slot so that I can improve bookings without adding more classes."
Description

Develop a recommendation service that scores and ranks instructor–time‑slot pairings by predicted conversion uplift and attendance, using historical performance, ratings, audience segments, seasonality, and real‑time demand signals (e.g., waitlists). Provide reason codes and confidence scores for transparency. Support cold‑start handling for new instructors and sparse data scenarios via similarity and heuristic backoffs. Expose a low‑latency REST API (<500 ms p95) for fetching ranked recommendations per slot or generating an optimized weekly schedule. Allow configurable weighting of objectives (conversion, revenue, no‑shows) at the studio level.

Acceptance Criteria
Constraints and Fairness Rules Engine
"As a studio coordinator, I want the system to honor availability and fairness rules so that recommended schedules are practical and equitable for our instructors."
Description

Implement a constraints framework that ensures recommendations are feasible and equitable: instructor availability, certifications/class‑type eligibility, maximum weekly hours, required rest/travel buffers between locations, pay band constraints, class caps, and conflict avoidance with existing bookings. Support both hard constraints (must not violate) and soft constraints (penalties in optimization), with studio‑level configuration. Include fairness balancing to prevent over‑allocating popular slots to a small subset of instructors and provide override capabilities with justification and audit logging.

Acceptance Criteria
Scheduling UI Integration
"As a scheduler, I want to apply Instructor Match recommendations within the calendar so that I can act quickly without leaving my workflow."
Description

Embed Instructor Match recommendations directly into the ClassTap calendar and class creation flows. Surface inline suggestions on empty or underperforming slots, with one‑click assign/apply actions, preview of expected impact, and conflict checks. Enable bulk application of recommendations, change tracking with undo, and instructor notification workflows (propose/accept/decline). Ensure mobile‑first responsiveness and parity with existing scheduling features, including double‑booking prevention and waitlist awareness.

Acceptance Criteria
Outcome Measurement and A/B Testing
"As a business owner, I want to measure the impact of using Instructor Match so that I can decide whether to roll it out across all locations."
Description

Introduce an experiment and reporting layer to quantify uplift from Instructor Match. Support A/B or holdout scheduling comparisons, automatic metric collection (conversion rate, attendance, revenue, no‑show rate) and segment‑level breakdowns. Provide significance testing, guardrail metrics, and experiment governance to avoid harmful degradation. Deliver dashboards and exports that attribute impact to recommendations, instructors, and time windows, enabling iterative tuning of engine weights and operational decisions.

Acceptance Criteria
Privacy and Access Controls
"As an instructor, I want assurances that my performance data is used appropriately and shared only with the right people so that I feel comfortable participating in optimization."
Description

Add role‑based access controls and privacy protections for performance analytics. Limit visibility of instructor‑level metrics to authorized roles (owners/coordinators) and provide instructors with appropriately scoped views of their own data. Implement consent and policy notices, data retention settings, and audit logs of access/overrides. Prevent exposure of sensitive attendee information through aggregation and anonymization while maintaining explainability for recommendations.

Acceptance Criteria

GapFill

Identify idle 30–90 minute room gaps and auto-generate pop-up sessions that fit emerging demand pockets. GapFill suggests class formats, titles, and pricing with an expected revenue delta vs. leaving the slot empty, so you can monetize downtime in two clicks.

Requirements

Smart Gap Detection (30–90 Min)
"As an operations manager, I want the system to identify viable 30–90-minute gaps across rooms and instructors so that I can monetize idle time without scheduling conflicts."
Description

Detect continuous idle slots between 30 and 90 minutes across rooms and instructors by scanning the live ClassTap schedule. Apply business rules for setup/teardown buffers, instructor availability, equipment constraints, operating hours, and blackout dates to ensure only viable gaps are surfaced. Update in near real time on new bookings, cancellations, or overrides; prevent double-bookings via atomic holds and conflict checks. Expose a stable API and UI feed of candidate gaps to downstream GapFill modules. Support timezone correctness, multi-location calendars, and recurring events. Log detection decisions for audit and tuning.

Acceptance Criteria
Demand Forecast & Class Suggestions
"As a studio owner, I want data-driven suggestions for what class to run in each gap so that I can maximize attendance and revenue."
Description

Generate data-driven class format and title suggestions for each eligible gap using signals: historical attendance by time/day, search/landing activity, waitlists, booking velocity, instructor popularity, and seasonality. Provide ranked suggestions with rationale, expected attendance range, and target audience. Fall back to catalog heuristics when data is sparse. Integrate with ClassTap’s class templates and taxonomy; respect instructor qualifications and room capabilities. Allow operator configuration with tunable weights and exclusions.

Acceptance Criteria
Dynamic Pricing & Revenue Delta
"As a business owner, I want a recommended price and clear revenue impact for each pop-up so that I can decide quickly whether to publish."
Description

Compute recommended price and expected revenue delta versus leaving the slot empty for each suggestion. Incorporate capacity, forecasted attendance, instructor payout rates, room costs, fees, taxes, and discounts. Show confidence bands and breakeven occupancy. Support multi-currency, inclusive/exclusive tax modes, and promo stacking rules. Persist inputs and calculations for audit; expose API for price override with real-time recalculation.

Acceptance Criteria
Auto-Generate Session Details
"As an instructor, I want session details auto-filled to fit the gap so that I can publish with minimal edits."
Description

Auto-generate a complete draft session pre-filled to fit within the selected gap: title, description, cover image, duration honoring buffers, capacity, room, instructor, equipment, enrollment window, cancellation policy, and payment settings. Ensure compliance with brand themes and white-label settings to produce a ready-to-publish booking page. Validate against conflicts and policy constraints before allowing publish. Allow quick edits with guardrails to keep within the gap.

Acceptance Criteria
Two-Click Publish & Sync
"As a studio manager, I want to publish a suggested pop-up in two clicks with calendars and booking pages synced so that I can act quickly."
Description

Enable publishing of a GapFill session in two clicks: review suggestion, confirm price, publish. On publish, atomically create the session, hold the room/instructor, generate the branded booking page and SEO-safe URL, sync to all calendars (web, iCal, Google), and enable secure payments. Provide a reversible draft state and a one-click unpublish within a grace window. Emit webhooks and analytics events for downstream systems.

Acceptance Criteria
Waitlist Tap & Targeted Notifications
"As a coordinator, I want GapFill to notify waitlisted and likely attendees automatically so that the pop-up fills fast with minimal manual outreach."
Description

Automatically target interested customers to fill the pop-up: surface relevant waitlists and high-intent segments, generate SMS/email invites with personalized links and optional incentives, and throttle sends to prevent spam. Respect opt-in and regional messaging compliance. Track deliveries, clicks, and conversions; auto-close the campaign when capacity is met. Support RSVP holds and priority access windows for waitlisted users.

Acceptance Criteria

Product Ideas

Innovative concepts that could enhance this product's value proposition.

TapPass Express

Save cards and enable Apple/Google Pay for one-tap rebooking, completing checkout in under 10 seconds and boosting repeat conversions.

Idea

Link Locker

Issue unique expiring join links tied to each booking; auto-rotate before class and block reused links, cutting link-sharing and late support pings.

Idea

Family Flex Profiles

Let caregivers create child profiles, share payment methods, and apply age-based eligibility and waivers in one flow, removing friction for multi-kid bookings.

Idea

Roster QR Roll-Call

Display a class QR; attendees scan to check in, instantly updating rosters and triggering waitlist auto-fill or credit rules.

Idea

Prereq Gatekeeper

Enforce prerequisites by requiring proof upload or prior class completion before booking, with a drag-and-drop rule builder for admins.

Idea

Smart Fill Waitlist

Auto-promote waitlisters via timed SMS with pay-to-claim links and a 10-minute hold window, keeping seats filled without staff juggling.

Idea

Heatmap Hours

Forecast high-conversion class times from past attendance and local calendars, suggesting slots that raise utilization by surfacing demand pockets.

Idea

Press Coverage

Imagined press coverage for this groundbreaking product concept.

Want More Amazing Product Ideas?

Subscribe to receive a fresh, AI-generated product idea in your inbox every day. It's completely free, and you might just discover your next big thing!

Product team collaborating

Transform ideas into products

Full.CX effortlessly brings product visions to life.

This product was entirely generated using our AI and advanced algorithms. When you upgrade, you'll gain access to detailed product requirements, user personas, and feature specifications just like what you see below.