PRD 02 — Classes (catalogue, settings, bookings)
Status: draft · Priority tier: P0 · Size: L · Depends on: Foundation (auth/roles/business, existing), Locations & Facilities, Pricing Plans (packages/memberships), Customers, Schedule (PRD 03)
1. Summary
The class catalogue: categories and sub-categories, a 4-step class wizard (with draft save), difficulty levels, studio-wide class rules (timetable window, slots-left display, booking window, check-in, late cancel, penalty strikes, refund-credit validity) and the class bookings list with a per-booking drawer. A class is the reusable template; dated sessions live in PRD 03. Without it nothing can be scheduled or sold.
2. Problem & goals
Studio owners need to define what they teach once, set how customers may book and cancel it, and see who is booked. Goals:
- Create and publish a class in <= 8 clicks plus typing (original: ~8).
- Every booking rule has one studio-wide default and can be overridden per session (PRD 03) — no rule is hard-coded.
- Bookings list answers "who is booked today / this week" in <= 2 filter changes. Non-goals: third-party class marketplace (ClassPass) bookings; session scheduling (PRD 03); package/membership authoring (Pricing Plans PRD); public storefront pages (Storefront PRD).
3. Users & roles
- Owner/admin: full catalogue, settings, bookings.
- Manager/front desk: manage classes and bookings; settings depends on role permission.
- Instructor/staff: view their own sessions' bookings; no catalogue edit (guess).
- Customer: indirect — sees the published class, slots-left, and is bound by booking/cancel rules.
4. Scope
In (v1)
- must: category CRUD + reorder, sub-category; class list grouped by category with status/category filters and search.
- must: 4-step class wizard (details, images, what to bring, pricing options); draft, edit, duplicate, set inactive, delete.
- must: pricing: free or paid; direct price per pricing group; accepted memberships and packages; refund method.
- must: class settings (timetable weeks/start, slots-left display, booking window, late-cancel hours, refund-credit validity).
- must: class bookings list (filters) and booking drawer (No show, Cancel booking, event log).
- should: levels CRUD; penalty strike; auto check-in + window; SEO fields + slug; 4:3 image crop; video URL; custom cancellation policy; show reviews toggle; session roster actions (email/SMS class, download list, audit trail).
-
could: refund-credit validity; rich-text description toolbar beyond basics. Later (v2+)
-
should: waitlist (original timetable legend shows "Waitlisted"; config not observed). Out
-
ClassPass integration (third-party, no clean-room API need).
- Plan-count limits on classes (billing tie-in; pricing tier: TBD).
5. User stories
- US-02-01 As an owner, I want to group classes into categories and sub-categories so that the catalogue and storefront stay organised.
- US-02-02 As an owner, I want a guided wizard that blocks Next until required data is valid so that I never publish an incomplete class.
- US-02-03 As an owner, I want to save a half-finished class as a draft so that I can continue later.
- US-02-04 As an owner, I want to set a free class, a direct-payment price, or credit-based access (membership/package) so that customers can pay in the way I sell.
- US-02-05 As an owner, I want studio-wide rules (booking window, late cancel, slots-left display) so that I do not configure every session.
- US-02-06 As a front desk user, I want to find a booking by customer/date/class/status so that I can help at the door.
- US-02-07 As a front desk user, I want to mark a no-show or cancel one booking from a drawer so that attendance and credits stay accurate.
- US-02-08 As an owner, I want to define difficulty levels so that customers can filter classes.
6. Functional requirements
| ID | requirement | priority | evidence |
|---|---|---|---|
| FR-02-01 | Class list shows classes grouped into collapsible category rows (name, item count); card shows name, duration, mode tag (onsite/online), status badge (Active/Hidden/Draft), created date. | must | S21 |
| FR-02-02 | List filters: free-text search, Status (Active/Inactive/Draft), Category. | must | S21, S21h |
| FR-02-03 | Category CRUD: add (inline name, persisted only once named), rename, delete, drag-reorder; sub-categories under a category. | must | S21, S21e, S21i, F12 |
| FR-02-04 | Deleting a category with classes is blocked or requires reassignment (assumption; original not observed). | should | F12 |
| FR-02-05 | Class card menu: Edit, Duplicate, Show/hide store listing, Set inactive, Delete; draft card: Continue, Delete. Card buttons: View Schedule (opens PRD 03 calendar filtered to class), View Pricing Plans (opens wizard step 4). | must | S21c, S21f, S21g |
| FR-02-06 | Delete confirmation states the class cannot be recovered and that already-scheduled sessions are NOT cancelled. | must | S21d |
| FR-02-07 | Wizard step 1 fields: name (<=100, required, unique per business, error on duplicate), short description (<=100), rich-text description (<=1000, required), category (required), sub-category, duration + unit (required, >0), level, mode onsite/online, "show on online store" toggle (default off), custom cancellation policy (collapsible). | must | S22, S22e, F10 |
| FR-02-08 | SEO block: page title (<=70), description (<=320), slug auto-derived from name and editable, with live preview of public URL. | should | S22c |
| FR-02-09 | Step 2: at least one image (JPG/PNG/GIF, <10 MB), fixed 4:3 crop modal, first image is cover, extra images optional; optional video URL. | must | S22g, S22g2 |
| FR-02-10 | Step 3: "what to bring" yes/no; yes opens an add-items drawer; items reorderable. | should | S22h, S22h2 |
| FR-02-11 | Step 4: Free or Paid. Paid: optional direct-payment price per pricing group (+ "set as default option"), refund method (no refund / refund as credits / store-credit wallet), assign memberships, assign packages (search, select all, grouped by category). Free classes cannot be covered by package credits. | must | S22i, S22j, S22k, S22l, part 08 |
| FR-02-12 | Wizard chrome: step list with completion %, Back/Next (Next disabled until step valid), Preview, Save as draft, "saved N min ago"; final action "Add" publishes as Active. | must | S22, F10 |
| FR-02-13 | Edit uses the same wizard (Save & Exit); changes to a class do not rewrite past sessions/bookings (assumption). | must | S23 |
| FR-02-14 | Levels: list with add (drawer), delete, drag-reorder; seed defaults Beginner, Intermediate, Advanced, Open to all. Deleting an in-use level is blocked or clears the field on classes (open question). | should | S24, S24b |
| FR-02-15 | Setting: timetable shows N weeks (default 2) of sessions; starts Today or on a chosen date. | must | S24 |
| FR-02-16 | Setting: show slots left on timetable and checkout; mode Always or only when <= N remain; optional "include total capacity" (e.g. 3/12). | must | S24 |
| FR-02-17 | Setting: show ratings/reviews on storefront (applies only if reviews exist; reviews feature is out of this PRD). | could | S24 |
| FR-02-18 | Setting: booking window — earliest: Anytime or N hours/days before start; latest: until start or N before start. | must | S24 |
| FR-02-19 | Setting: auto check-in toggle + earliest check-in window (Anytime or N hours before). | should | S24 |
| FR-02-20 | Setting: late-cancel window N hours before start; cancelling inside the window is a "late cancellation". | must | S24 |
| FR-02-21 | Setting: penalty strike — when ticked, a late cancel/no-show by a member on an unlimited-credit plan records a strike (strike consequences are defined by Memberships PRD). | should | S24 |
| FR-02-22 | Setting: validity of refunded credits (N + unit months/days) used when a session is cancelled and credits are returned. | could | S24 |
| FR-02-23 | Settings page: Save button disabled until a value changes; one settings record per business; session-level overrides in PRD 03 take precedence. | must | F11 |
| FR-02-24 | Class bookings list: search by customer, date-range presets (Today, Yesterday, Last 7/30/90 days, This/Last month, Last year, Till date, exact date, custom), filters Location, Staff, Status (Upcoming/In progress/Completed/Cancelled), Class; page size 50; empty state. | must | S20, S20b-d |
| FR-02-25 | Session roster page: header (status, class, instructor, date/time, location/room), tabs Booked (n/capacity) and Cancelled, search, sort, status filter (Completed, No show), row = customer, payment option, booked-at, added-by, status. | must | S209i, S209k |
| FR-02-26 | Roster Actions menu: email class, SMS class, edit class (session), cancel class, download list, view audit trail. | should | S209j |
| FR-02-27 | Booking drawer: booking ref, customer link, payment card (status, option, transaction id), attendees, actions No show / Cancel booking, events log (emails sent, status changes with actor). | must | S209l |
| FR-02-28 | Add booking to a session (customer, attendees/pax, internal note, notify staff) is reachable from the roster; spec lives in PRD 03. | must | S209g, S209h |
| FR-02-29 | Class/booking changes emit notifications (payment confirmation, completed) via the Notifications PRD. | should | S209l |
7. Screens
| Our screen | Modelled on | States |
|---|---|---|
| Class list | S21 | empty (one default category, 0 items), loading skeleton, filled, filtered-empty, delete confirm, error/retry |
| Class wizard (create/edit) | S22, S23 | each step empty/invalid/valid, crop modal, add-items drawer, save error (duplicate name), saving |
| Class settings | S24, S24b | default, dirty, saved toast, add-level drawer |
| Class bookings list | S20 | empty, loading, filled, filters open |
| Session roster + booking drawer | S209i, S209l | empty ("no bookings"), filled, no-show confirm, cancel confirm |
8. Flows
Create class: List > Add Class (2 clicks) > step 1 (name, desc, category, duration) > Next > image + crop > Next > bring Y/N > Next > Free/Paid (+ plans) > Add. Target <= 8 clicks + typing. Edges: duplicate name toast; draft cards omitted from session class-search; free class excludes package credits; navigating away offers Save as draft. Settings: open > change > Save (disabled until dirty). Mark no-show: bookings list > row > drawer > No show (<= 3 clicks).
9. Data model (guesses marked *)
- ServiceCategory(id, type=class, name, sort, parent_id* for sub-category)
- Class(id, name, slug, short_desc, description, category_id, subcategory_id, duration_min, level_id, mode, listing_visible, status draft|active|inactive, images[], video_url, bring_items[], cancel_policy, seo_title, seo_desc, pricing_type free|paid, direct_prices[{pricing_group, price}], refund_method, membership_ids[], package_ids[])
- ClassLevel(id, name, sort)
- ClassSettings(business_id, timetable_weeks, timetable_start, show_slots_left, slots_mode, slots_threshold, show_total_capacity, show_reviews, book_earliest, book_latest, auto_checkin, checkin_earliest, late_cancel_hours, penalty_strike, refund_credit_validity)
- ClassBooking(ref, session_id, owner_customer_id, attendees[], payment_option, transaction_id, status booked|completed|no_show|cancelled, late_cancel*, added_by, events[]) Relations: Class 1-n Session (PRD 03); Session 1-n ClassBooking.
10. Business rules & edge cases
- Class names unique per business (case-insensitive*).
- Resolution order for booking/cancel/check-in rules: session override > class settings > none.
- A class with status draft/inactive cannot receive new sessions or storefront listing; existing sessions are unaffected.
- Price per pricing group falls back to the default group.
- Late cancel: cancellation after (start - late_cancel_hours) is flagged; credit-return vs forfeit policy: see open questions.
- Refunded credits expire after the configured validity.
- Slots-left display never reveals capacity unless "include total" is on.
- Deleting a class does not cancel its sessions; bookings stay visible.
11. Permissions
| Action | Owner | Manager | Front desk | Instructor |
|---|---|---|---|---|
| Catalogue CRUD | yes | yes | no | no |
| Class settings | yes | yes* | no | no |
| View bookings | all | all | all | own sessions* |
| No-show / cancel booking | yes | yes | yes | no* |
| Role matrix to be driven by the existing/future Roles PRD; * = assumption. |
12. Acceptance criteria
- Given blank wizard step 1, when required fields are missing, then Next is disabled; when all valid, Next enables.
- Given a class named "Yoga", when I create another "yoga", then save fails with a name-exists message and no record is created.
- Given an uploaded image, when I confirm the 4:3 crop, then the cropped image is stored as cover.
- Given step 4 Free, then package/membership assignment is not offered.
- Given a published class with scheduled sessions, when I delete it, then the confirm text says sessions are not cancelled and sessions remain.
- Given late_cancel_hours = 12, when a customer cancels 11h before start, then the booking is marked late cancelled.
- Given slots mode "<= 3 remain" and 5 remaining, then the customer sees no count; at 3 remaining sees "3 left".
- Given settings unchanged, then Save is disabled.
- Given a Completed session, when I open a booking and choose No show, then status becomes No show and an event is logged with my name.
- Given a draft class, then it does not appear in the session class picker.
13. Dependencies & open questions
Depends: PRD 03 (sessions), Pricing Plans, Locations, Customers, Notifications, Roles. Open questions
- Waitlist: enabled per class/session? Not observed (only a "Waitlisted" legend on storefront).
- Does late cancel return credits or forfeit them? Not observed; penalty-strike consequences not observed.
- Sub-category behaviour on storefront and deletion rules not observed.
- Online class: how is the meeting link delivered? Not observed (mode is only a tag).
- Do class edits propagate to future sessions? Not observed.
- Level delete when in use; instructor permissions not observed.
- Review feature scope (toggle exists, no reviews screens in recon).
14. Evidence
See evidence/evidence.md.
