Product Requirements Document
Enable clubs to manage their coaching staff via an academy entity, offer bookable private/group lessons, sell lesson packages (simple, mixed, and recurring), and track commissions. The academy is an independent entity that can span multiple facilities.
Enable clubs to manage their coaching staff via an academy entity, offer bookable private/group lessons, sell lesson packages (simple, mixed, and recurring), and track commissions. The academy is an independent entity that can span multiple facilities.
For Clubs
Clubs currently manage coaches informally — spreadsheets, WhatsApp groups, manual scheduling. There's no way to track lesson revenue, coach utilization, or commissions. Coaches can't see their own schedules without asking the front desk.
For Players
Players wanting a lesson have to call or message the club, ask who's available, negotiate a time, and pay in person. There's no self-service way to browse coaches, see availability, and book a lesson online.
For Coaches
Coaches have no visibility into their schedule, earnings, or upcoming lessons. They rely on the club to relay booking information.
Admin can create an academy entity that spans one or more facilities, then manage coach profiles within it. Coaches belong to the academy and inherit access to all linked facilities. Supports freelance (commission-only) and in-house (salary + commission) employment types. Commission can be a flat amount or percentage.
As admin, I want to Create an academy for my club — set name, description, and link one or more facilities
As admin, I want to Manage academy focus areas (e.g., 'Beginners', 'Competitive', 'Kids') to categorize lessons
As admin, I want to Create a coach profile within the academy — set title, bio, photo, specialties, lesson rate, employment type (freelance/in-house), salary (for in-house), and commission (flat amount or percentage)
As admin, I want to Edit or deactivate a coach profile without removing the team member
As admin, I want to See a list of all coaches with their status, lesson rate, employment type, and active lesson count
As admin, I want to Set each coach's available hours per facility (weekly schedule, similar to court schedules)
Admin can create, edit, and cancel lessons on behalf of players. Lessons reserve a court and a coach for a time slot. Supports private (1-on-1) and semi-private (small group) lessons. Lessons can have a focus area from the academy's defined list.
As admin, I want to Create a lesson by selecting a coach, court, date/time, duration, focus area, and player — price auto-calculated from coach's lesson rate
As admin, I want to System prevents double-booking a coach or court (conflict detection for both)
As admin, I want to Edit a lesson — change court, time, or player. Cancel with optional refund
As admin, I want to Create a semi-private lesson with multiple players (2-4), price split or per-player
As admin, I want to Lessons appear on the main calendar alongside regular bookings, visually distinct (different color/badge)
Academy can offer lesson packages — session banks (buy N sessions at a discount) and monthly recurring packages with auto-generated lessons. Packages support mixed session types (e.g., 4 private + 2 semi-private) and can be academy-wide or coach-specific.
As admin, I want to Create a session-bank package — name, items (mixed lesson types with session count + duration), total price, validity period (e.g. '10 sessions for $450, valid 90 days')
As admin, I want to Create a recurring monthly package with a schedule — system auto-generates lessons each billing period
As admin, I want to Assign a purchased package to a player and track remaining sessions per item type
As admin, I want to When creating a lesson, optionally deduct from a player's active package instead of charging individually
As admin, I want to See all active packages, their utilization per session type, and approaching expirations
A dedicated calendar view filtered to a single coach, showing their lessons, availability, and off-hours. Accessible by admins (and optionally by the coach themselves).
As admin, I want to View a coach's calendar showing all their lessons for a day/week, with open slots visible
As admin, I want to Create a lesson directly from the coach calendar by clicking an open slot
As coach, I want to Log in and see my own lesson schedule for the day/week (read-only or limited actions)
Track lesson revenue, coach utilization, and commission payouts. Reports differentiate in-house coaches (salary + commission) from freelance (commission only).
As admin, I want to See lesson revenue broken down by coach, time period, and lesson type (private vs semi-private)
As admin, I want to See each coach's total hours, lesson count, earned commission, employment type, and salary for a period
As admin, I want to Export commission report for payroll processing
Player-facing page where users browse coaches, view profiles, and book a lesson directly. Follows the same frictionless flow as court booking (no login required until payment).
As player, I want to Browse a list of coaches on the facility page — see photo, name, title, specialties, and lesson rate
As player, I want to View a coach's profile with bio, available times, and a 'Book Lesson' button
As player, I want to Select a time slot from the coach's availability and complete the booking with payment (same frictionless flow as court booking)
user_facility_rolesmodifyExisting — role 'pro' renamed to 'coach'. Team members with role 'coach' are coach candidatesiduser_idfacility_idrole (owner/admin/manager/coach/member/guest)academiesnewAcademy entity — independent org that can span multiple facilitiesid (UUID PK)name (text)description (text)logo_url (text)owner_facility_id (FK → facilities) — the facility that created the academycreated_at (timestamptz)academy_facilitiesnewMany-to-many link between academies and facilitiesid (UUID PK)academy_id (FK → academies)facility_id (FK → facilities)UNIQUE(academy_id, facility_id)created_at (timestamptz)academy_focus_areasnewFocus areas for the academy (e.g., Beginners, Competitive, Kids)id (UUID PK)academy_id (FK → academies)name (text)is_active (bool)sort_order (int)created_at (timestamptz)coachesnewCoach profiles — belongs to an academy, inherits linked facilities. Supports freelance (commission-only) and in-house (salary + commission) employment typesid (UUID PK)user_id (FK → auth.users)academy_id (FK → academies, NOT NULL)employment_type (text) — 'freelance' | 'in_house'salary_amount (int, nullable) — base monthly salary for in-house coachestitle (text) — e.g. 'Head Coach', 'Padel Pro'bio (text)photo_url (text)specialties (jsonb) — e.g. ['padel', 'beginners', 'competitive']lesson_rate_amount (int) — default per-hour ratecommission_type (text) — 'flat' | 'percentage'commission_value (numeric) — flat amount in cents or percentageis_active (bool)created_at (timestamptz)coach_schedulesnewWeekly availability for each coach per facility (same pattern as court_schedules)id (UUID PK)coach_id (FK → coaches)facility_id (FK → facilities)day_of_week (int 0-6)start_time (time)end_time (time)is_available (bool)UNIQUE(coach_id, facility_id, day_of_week)lessonsnewIndividual lesson bookings — links a coach, court, player(s), and time slot. Supports focus areas.id (UUID PK)coach_id (FK → coaches)facility_id (FK → facilities)court_id (FK → courts)booking_id (FK → bookings, nullable) — links to a court bookinglesson_type (text) — 'private' | 'semi_private'max_players (int)description (text)focus_area_id (FK → academy_focus_areas, nullable)custom_focus_area (text, nullable)start_time (timestamptz)end_time (timestamptz)duration_minutes (int)price_amount (int)commission_amount (int) — calculated at creationstatus (text) — 'scheduled' | 'completed' | 'cancelled' | 'no_show'notes (text)player_package_id (FK → player_packages, nullable)created_at (timestamptz)lesson_playersnewPlayers in a lesson (for semi-private lessons with multiple players)id (UUID PK)lesson_id (FK → lessons)user_id (FK → auth.users, nullable)name (text)email (text)is_primary (bool)lesson_packagesnewLesson packages — session banks or recurring monthly. Supports mixed session types via package_items.id (UUID PK)academy_id (FK → academies)facility_id (FK → facilities, nullable) — null = academy-widecoach_id (FK → coaches, nullable) — null = any coachname (text) — e.g. '10-Session Pack'description (text)package_type (text) — 'session_bank' | 'recurring'price_amount (int) — total package pricebilling_period (text, nullable) — 'monthly' | 'quarterly' (for recurring)valid_days (int, nullable) — expiry window from purchase (for session_bank)schedule (jsonb, nullable) — recurring schedule definitionis_active (bool)created_at (timestamptz)package_itemsnewItems within a package — supports mixed session types (e.g., 4 private + 2 semi-private)id (UUID PK)package_id (FK → lesson_packages)lesson_type (text) — 'private' | 'semi_private'session_count (int)duration_minutes (int)player_packagesnewPurchased packages — tracks a player's package status and Stripe referencesid (UUID PK)package_id (FK → lesson_packages)user_id (FK → auth.users)facility_id (FK → facilities)purchased_at (timestamptz)expires_at (timestamptz, nullable)status (text) — 'active' | 'exhausted' | 'expired' | 'cancelled'stripe_subscription_id (text, nullable)stripe_payment_intent_id (text, nullable)created_at (timestamptz)player_package_sessionsnewPer-item session tracking within a purchased packageid (UUID PK)player_package_id (FK → player_packages)package_item_id (FK → package_items)sessions_remaining (int)sessions_used (int)| Method | Path | Description |
|---|---|---|
| GET | /api/admin/academies | List academies for the facility |
| POST | /api/admin/academies | Create an academy |
| PATCH | /api/admin/academies/[id] | Update academy details |
| GET | /api/admin/academies/[id]/facilities | List linked facilities |
| POST | /api/admin/academies/[id]/facilities | Link a facility |
| DELETE | /api/admin/academies/[id]/facilities | Unlink a facility |
| GET | /api/admin/academies/[id]/focus-areas | List focus areas |
| POST | /api/admin/academies/[id]/focus-areas | Create a focus area |
| PATCH | /api/admin/academies/[id]/focus-areas/[faId] | Update a focus area |
| DELETE | /api/admin/academies/[id]/focus-areas/[faId] | Delete a focus area |
| GET | /api/admin/coaches | List all coaches for a facility |
| POST | /api/admin/coaches | Create a coach profile |
| GET | /api/admin/coaches/[id] | Get coach detail |
| PATCH | /api/admin/coaches/[id] | Update coach profile |
| GET | /api/admin/coaches/[id]/schedule | Get coach weekly schedule |
| PUT | /api/admin/coaches/[id]/schedule | Update coach weekly schedule |
| GET | /api/admin/lessons | List lessons (filters: coach, date, status) |
| POST | /api/admin/lessons | Create a lesson (+ linked booking) |
| PATCH | /api/admin/lessons/[id] | Update / cancel a lesson |
| POST | /api/admin/lessons/[id]/players | Add player to lesson |
| DELETE | /api/admin/lessons/[id]/players | Remove player from lesson |
| GET | /api/admin/lesson-packages | List packages |
| POST | /api/admin/lesson-packages | Create a lesson package |
| PATCH | /api/admin/lesson-packages/[id] | Update a lesson package |
| GET | /api/admin/player-packages | List player packages |
| POST | /api/admin/player-packages | Assign/purchase a package |
| PATCH | /api/admin/player-packages/[id] | Update player package status |
| POST | /api/admin/player-packages/[id]/generate | Generate lessons for recurring package |
| GET | /api/admin/player-subscriptions | List a facility's academy subscriptions (replaces the removed /api/admin/academy-reports) |
| GET | /api/v1/facilities/[slug]/coaches | Public: list active coaches |
| GET | /api/v1/facilities/[slug]/coaches/[id] | Public: coach detail + availability |
| GET | /api/v1/facilities/[slug]/lesson-packages | Public: list active packages |