# Sports Implemented State ## Surface - `/admin/sports` now renders a Ballbox-local admin UI for coaches, open matches, and classes. - `/api/sports` now returns DB-backed sports data instead of only documenting a planned shell. - `/classes` now renders the first public student-facing sports surface. - `/classes-by-date` now renders a coach-availability-driven reservation surface that starts by asking for a zone and then filters visible clubs / slots to that area. - `/classes/[offerId]` now shows offer detail, visible ATC public-read slots when a local offer is linked, and a local request form that lets the student choose one slot or fall back to any schedule / place. - `/classes/me` now provides a small read-only student request history view filtered by email for demo follow-up. - `/classes` and `/classes/[offerId]` now render Ballbox-local offer data first, then hydrate ATC public-read context asynchronously from cached host-app APIs so first paint is not gated by ATC response time. - `/classes` offer-list SSR no longer waits on ATC sportclub-summary fetches for club-name display, and `/classes-by-date` now parallelizes ATC club/day lookups behind a short shared server cache so the calendar avoids serial public-read latency before first byte. - `/coaches` now starts with `Sign in`, and only moves to `Sign up` when the user does not have an account yet. - `/coaches` sign-up first asks whether the account is `Coach` or `Club`, then asks only for name, email, and password. - `/coaches/settings` now opens on a coach workspace split into `Calendar`, `Performance`, `Alumnos`, and `Horarios y Clases`: calendar shows the current week in an hour-by-hour class matrix, groups simultaneous reservations into one individual or group class, surfaces each student's basic profile data (name, sexo, edad, categoria), marks which reservations are paid vs pending, and starts with a large `Agregar clase` CTA that takes the coach into `Alumnos`; `Performance` shows club-level results plus weekly earnings and student consistency rows, while `Horarios y Clases` auto-saves club selection, availability, packages, and Mercado Pago setup without manual save buttons and no longer shows the club's court-fee pricing to the coach. Pending autosave writes are also flushed if the coach leaves the page before the debounce finishes. - `/coaches/settings` now also lets the coach create new students, assign Ballbox players to concrete occupied slots, repeat those bookings weekly in one action, and keep a student roster with WhatsApp / Telegram contact fields; inside `Alumnos`, the default state is the student table, and `Agregar clase` opens a wide inline composer instead of a side-by-side stats panel. - `/clubs` now opens as a club-only service home right after club sign-in/sign-up, showing service cards where `Entrenadores` is the active path into the existing club coaches workspace and the rest stay marked `Proximamente`. - `/clubs/coaches` now opens on a club workspace with top-level `Calendar`, `Analytics`, `Sedes`, and `Profesores` sections: calendar shows the current week's coach availability/reservations with sede/coach/court filters plus quick manual class loading, analytics shows professor/reservation money splits, `Sedes` handles venue creation and quick venue reservation settings, and `Profesores` handles invite links plus the club coach table. - `/clubs/coaches` now checks the club session during page render too, so the `Entrenadores` card cannot land on a client-only shell that later bounces authenticated club users back to `/coaches`. - `/clubs/coaches` now opens on a club workspace with top-level `Calendar`, `Analytics`, `Sedes`, and `Profesores` sections: calendar now focuses on one sede at a time, switches between `Disponibilidad` and `Reservas`, uses clickable sede/day/club-coach tags instead of dropdowns, assigns each coach-enabled court its own color, and shows the selected day with all coach-enabled courts as columns so clubs can see half-hour gaps per court without selecting a court filter; coaches assigned with `Asignar todas las canchas` are treated as flexible coverage and occupy one free court per half-hour, not every court at once; quick manual class loading and pending requests open from dedicated action buttons above the calendar, and manual class creation now requires selecting an active coach package while still allowing inline student creation and weekly repeats; analytics shows professor/reservation money splits, `Sedes` now starts with a large `Agregar sede` action, keeps the creation form behind that CTA, and lists all venues in a simpler table with a deep-link into full venue editing, and `Profesores` handles invite links plus the club coach table. - `/clubs/coaches` now checks the club session during page render too, so the `Entrenadores` card cannot land on a client-only shell that later bounces authenticated club users back to `/coaches`. - `/clubs/venues/[venueId]` now gives each venue its own configuration screen, with the same shared club navbar and a guided step-by-step layout where base settings, coach hours, reservation pricing, courts, and venue-specific coach assignment are all visible without hidden accordions; weekly coach hours and coach-enabled court selection stay on-screen by default, and each coach can either float across all enabled courts with `Asignar todas las canchas` or hold one fixed court inside that venue. - Existing club/venue setting edits now auto-save in place and clickable panels/links use stronger accent styling to separate actions from read-only information. Pending autosave writes are also flushed on navigation/unmount so quick page changes do not drop venue edits. - Authenticated coach/club screens now share the same top navbar with section tabs plus a profile-initial menu for sign out; the old corner text links and dedicated explainer hero panels are gone, and the shared navbar now exposes explicit nav labels, `aria-current`/pressed state, and a screen-reader label on the profile trigger. - Sports auth/request/venue flows now also announce key feedback through semantic live regions: `/coaches` sign-in/sign-up errors use `role="alert"`, `/classes/[offerId]` request success/error copy is announced, and `/clubs/venues/[venueId]` autosave state is exposed as a live status badge for screen-reader users. ## Model - Ballbox persists `Coach`, `OpenMatch`, and `Class` in Prisma/Postgres. - `Coach` may belong to a `Club`. - `Coach` now also stores an email, a password hash, a club-selection mode, and joins to clubs via `CoachClub`. - Ballbox now derives coach account affiliation from whether that coach belongs to a primary `Club`. - `Coach` can now also belong to one `Venue` inside that club. - `Coach` can now also have one optional assigned `VenueCourt` inside that venue; when it is null, the coach is intentionally flexible across all enabled courts and the calendar allocates that coach to one free court per half-hour. - `Coach` now also stores a Mercado Pago placeholder handle and reusable `CoachSalesPackage` rows for price, duration, class type, and max-student setup. - Ballbox now also persists `CoachStudentBooking` rows so a coach or club can block a real date/time with an existing `Player`, optionally assign a court, and keep lightweight follow-up tied to that student. - `Player` now also stores optional `whatsappPhone` and `telegramHandle` fields so coaches can message tracked students from their roster. - Ballbox persists `CoachAvailability` weekly ranges (day-of-week + time range + timezone). - Coach availability writes are now validated against the assigned venue's coach hours or the union of the selected external clubs' enabled venue hours. - For independent coaches, external-club venue hours are now reduced by the availability already claimed by club coaches in that same venue, so club coaches keep priority and external coaches only see remaining time. - `OpenMatch` and `Class` belong to a `Venue`. - `Venue` now also stores one opening time, one closing time, weekly half-hour coach-availability ranges, whether that venue accepts external coaches, a reservation price for coach classes, recurring hourly price overrides on top of that base, a club-coach-only discount over that reservation fee, and a late-cancellation window in hours. - `VenueCourt` persists the per-court setup for covered/open courts plus whether coaches can teach on that court. - Ballbox now also persists `ClassOffer` and `ClassRequest` locally. - `ClassOffer` belongs to a Ballbox-local `Coach` and `Venue`; `ClassRequest` belongs to a `ClassOffer`. - `ClassRequest` now stores either a concrete selected slot snapshot or a flexible-selection fallback mode. - Clubs now only store ATC sportclub ids; club metadata is hydrated from ATC at runtime for availability and display. - ATC public-read does not expose a stable slot id today, so Ballbox persists a slot snapshot (`start`, duration, price, club id, court id) and revalidates that snapshot against ATC again when the request is submitted. - ATC public-read lookups are now cached briefly on the server because the visible availability query is shared across visitors; without that cache, Ballbox would repeat the same ATC fetch for each page load. ## APIs - Sports route handlers and `/admin/sports` page now call dedicated sports backend modules directly (`lib/sports-backend-events.ts`, `lib/sports-backend-coaches.ts`) instead of importing sports access through `lib/ballbox-store.ts`. - Classes pages, route handlers, and shared class helpers now call `lib/classes-backend.ts` directly for offer/request reads and writes instead of importing that runtime access through `lib/ballbox-store.ts`. - `/api/sports` - `/api/classes/offers` - `/api/classes/offers/[offerId]` - `/api/classes/requests` - `/api/account/session` - `/api/coaches/accounts` - `/api/coaches/invites/[token]` - `/api/coaches/session` - `/api/coaches/logout` - `/api/coaches/me` - `/api/coaches/availability` - `/api/coaches/clubs` - `/api/coaches/students` - `/api/coaches/students/players` - `/api/clubs/accounts` - `/api/clubs/invites` - `/api/clubs/session` - `/api/clubs/logout` - `/api/clubs/me` - `/api/clubs/coaches` - `/api/clubs/coaches/[coachId]` - `/api/clubs/manual-classes` - `/api/clubs/players` - `/api/clubs/venues` - `/api/clubs/venues/[venueId]` - `/api/admin/sports/operations` - `/api/admin/sports/coaches` - `/api/admin/sports/coaches/[coachId]` - `/api/admin/sports/open-matches` - `/api/admin/sports/open-matches/[matchId]` - `/api/admin/sports/classes` - `/api/admin/sports/classes/[classId]` ## Browser Coverage - Playwright covers `/admin/sports` create, edit, and delete flows for coaches, open matches, and classes. ## Current Gaps - Coach experience thesis is still being validated through an online form; Ballbox does not yet have enough field evidence to lock the first sports workflow. - ATC scope is still public-read only; no admin/write ATC, booking writes, or ATC teacher dependency. - The selected slot is still a local lead preference, not a confirmed reservation; ATC availability can move between render and submit, and Ballbox rejects stale selections when revalidation no longer finds the slot. - ATC is still an external dependency with variable latency, so Ballbox now uses a short timeout and async hydration instead of delaying the initial HTML while waiting for ATC. - No player registration/attendance links yet. - No operator request inbox yet. - Coach login remains demo-grade (shared password + email) and should not be treated as production auth.