Tech Stack
Athlora is a non-monolithic athletics coaching application: a browser SPA, a REST API, and PostgreSQL are separate services. The shipped implementation covers a focused catalogue of timed track races, hurdles, measured jumps and throws, high jump, and 4 x 100m relay alongside the original legacy 100m contract, plus shared cross-club fixtures, public statistics/schedules/reports, offline logging, club branding, and the console assistant. Multi-events and automated season scheduling remain future work.
Implemented Stack
| Layer | Tool | Why |
|---|---|---|
| Frontend framework | React + Vite (TypeScript, strict) | Fast dev/build, strict typing, standard React data flow |
| Styling | Plain CSS (variables + modules) | Design tokens from approved mockups, no runtime dependency |
| Landing visuals | Three.js + React Three Fiber | One scroll-driven, procedural stadium tunnel and athletics track camera shot with a continuous first-person-to-track-flight handoff and performance-graph morph |
| Fitness body viewer | Three.js + React Three Fiber + Drei | On-demand static anatomical viewer for persistent injury mapping with topology-bound surface heat maps |
| Backend | Node.js + Express (TypeScript) | Small hand-written REST API, shares TS types with the frontend |
| Database | PostgreSQL | Relational results/log data; UUID PKs enable offline-safe inserts |
| Auth | Auth0 | Never hand-roll auth; hosted identity + verified JWTs |
| Weather | GraySky | Keyless current/daily forecast normalized to metric units, cached ten minutes |
| Venue search/maps | Nominatim + OpenStreetMap | Explicit server-proxied venue lookup and read-only attributed map previews; no tile/map library |
| Offline storage | IndexedDB via Dexie | Promise-friendly store mirroring timeline_entries |
| PWA | vite-plugin-pwa | Service worker + manifest for offline shell |
| Realtime | Socket.IO | Live broadcast of new/edited entries to event viewers |
| Charts | Native SVG and CSS | PB/SB progression and comparison visualisations without a charting dependency |
| Unit/component tests | Vitest, React Testing Library | Fast component + pure-logic tests |
| API tests | Supertest | Endpoint happy paths + validation/error paths |
| E2E tests | Playwright | Cross-cutting browser flows and accessibility checks |
| Coverage reports | Vitest V8 coverage | JSON summaries rendered as a short Gitea Actions Markdown table |
| CI/CD | Gitea Actions | Lint, typecheck, test, build, coverage, and credential-gated E2E jobs on every push/PR |
| Hosting | Vercel (frontend), Render (backend) | Static SPA hosting + API hosting |
| Docs site | Docusaurus on Cloudflare Pages | Versioned docs: setup, API, schema |
| Area | Technology | How Athlora uses it | Why it fits Athlora |
|---|---|---|---|
| Frontend | React 18, Vite 6, strict TypeScript | The coach console, roster, events, dashboard, live logger, results, and account screens. | A fast SPA keeps the track-side logger responsive, while strict types keep the multi-discipline DTOs aligned with the API. |
| Styling | CSS variables and CSS modules | Shared tokens, component styles, responsive layouts, console themes, and weather effects. | The approved Athlora visual language is encoded once without adding a runtime styling dependency to a mobile-focused application. |
| API | Node.js, Express 5, strict TypeScript | JSON API under /api/v1, resource routes, validation, and error responses. | The API stays independently deployable while remaining small enough for explicit coach-ownership and event-lifecycle rules. |
| Database | PostgreSQL on Neon, pg | Coach-owned athletes, events, participants, timeline entries, results, and deletion tombstones. | Relational constraints and transactions protect the link between a live entry, derived result, placing, PB, and SB. UUIDs also prepare the model for future offline writes. |
| Migrations | Checksum-tracked SQL migrations | Creates and evolves the production schema before API startup. | Results history must not depend on manual schema changes; checksum verification detects a changed migration before it damages a season's data. |
| Authentication | Auth0, @auth0/auth0-react, jose | Universal Login in the SPA and JWT verification in the API. | Coaches do not need Athlora-managed passwords. Auth0 handles identity flows while the API maps a verified subject to one local coach workspace. |
| API protection | Helmet, CORS, ownership middleware | Security headers, origin allow-listing, authenticated user resolution, and non-enumerating resource checks. | A coach must never be able to discover or modify another coach's athletes, entries, or results. |
| Weather | GraySky Free | Event-day forecasts from up to ten daily records and the console's current-weather readout, both proxied by the API. | No provider account, API key, or environment variable. Shared caching, nullable metrics and safe failure handling support track-side use. |
| Venue search/maps | Nominatim + OpenStreetMap | Server-side native-fetch venue lookup, existing persisted coordinates, and an iframe/external-link preview. | Avoids shipping provider credentials or a heavyweight interactive map dependency while retaining attribution, keyboard use, mobile layout, and manual coordinates. |
| Offline storage | IndexedDB via Dexie | Offline action queue for create/edit/undo actions when network is unavailable. | Promise-friendly store with typed transactions, scoped per account/workspace/event/device for offline-first live logging. |
| PWA | vite-plugin-pwa | Service worker for app shell caching and API response caching. | Installable coach console with offline shell and deterministic queue drain on reconnect. |
| Unit and component tests | Vitest, React Testing Library, jsdom | Result rules, API wrappers, components, forms, mutations, and accessibility interactions. | Most correctness risks are in calculations and state transitions, so fast focused tests provide feedback before a coach uses the logger. |
| API tests | Supertest | HTTP contracts, validation, ownership, lifecycle guards, and error behavior. | The frontend relies on predictable status codes and error envelopes when handling stale corrections and closed events. |
| End-to-end tests | Playwright, axe-core/playwright | Anonymous checks plus authenticated desktop/mobile vertical-slice, multi-discipline, public, and accessibility tests. | The real workflow crosses Auth0, the SPA, the API, and PostgreSQL; browser tests verify that a coach can complete it at a desk or track-side. |
| Documentation | Docusaurus | Versioned setup, architecture, API, schema, and process documentation. | The stack has several services and environment boundaries, so executable team documentation prevents setup knowledge staying with one contributor. |
| CI | Gitea Actions | Separate frontend, backend, docs, coverage, and credential-gated E2E jobs on push and pull request. The coverage job prints a short Markdown summary. | A feature is not complete if it breaks a different service in the monorepo; CI verifies each deployable before merging and makes source-coverage gaps visible without an initial threshold. |
| Hosting | Vercel, Render, Cloudflare Pages | SPA, API, and documentation deployments respectively. | Independent hosting matches the architecture and lets the public documentation remain available without exposing the API or database. |
Implemented Supporting Libraries
-
Dexie: wraps IndexedDB with a typed, promise API and explicit transactions — the cleanest fit for an offline-first write queue.
-
Socket.IO: reliable fallbacks (polling) and rooms make per-event broadcast trivial and resilient.
-
GraySky: no account or key; the keyless endpoint returns US-customary current/daily data, normalized server-side to metric units with ten-minute caching and linked attribution in both weather surfaces.
-
Auth0: hosted login (sign up, social, password reset) plus JWT verification middleware; keeps credentials and user data out of our code.
-
Lazy-loaded R3F landing stage: one fixed decorative canvas renders the procedural tunnel, stadium, shared track, runner signals, and performance ribbon. It keeps camera state in mutable refs, uses reusable Three vectors/curves, limits DPR, pauses while hidden, and lowers detail on compact displays.
-
Three.js / React Three Fiber / Drei: on-demand anatomical body viewer for persistent injury mapping with topology-bound surface heat maps.
-
@google/genai: Google Gemini SDK for the Live voice assistant, providing the
BidiGenerateContentConstrainedWebSocket API and tool-call interception. -
qrcode: QR code generation for public logger link sharing.
-
pdf-lib: client-side PDF generation in the SPA for downloadable public statistics reports and assistant-generated PDF reports.
-
dotenvloads server-only local configuration; browser configuration is restricted to publicVITE_*values. -
tsxprovides the API's watch-mode development server without a separate build step. -
@testing-library/user-eventexercises real keyboard and pointer interactions for controls used during event logging. -
@axe-core/playwrightchecks serious and critical accessibility violations in the browser suite.
Responsive Overlay Convention
All authenticated dialogs (add, edit, correction, confirmation) use the shared <Modal> component. Layout rules:
- Desktop (≥768px): Centered card with
max-width: 560px,max-height: 90vh, and vertical scroll only when content exceeds the viewport. - Mobile (
<768px): Full-screen sheet with safe-area insets. No border radius, no shadow, no backdrop padding. - Body scroll lock:
document.body.style.overflowis set to'hidden'while any modal is open and restored on close. - Forms inside Modal: Always
width: 100%. Never use hardcoded widths that exceed ~512px (560px minus 24px padding each side). - Action buttons: Stack vertically (
flex-direction: column) below 620px withwidth: 100%; min-height: 44pxfor touch targets. - Focus management: Auto-focuses first input on open, restores focus to trigger on close, traps Tab within the dialog, Escape dismisses unless
closeDisabled. - Accessibility:
role="dialog",aria-modal="true",aria-labelledby,aria-busyduring saves.
Planned Stack
There are no currently deferred packages. The remaining product capabilities — multi-events and automated season scheduling — are product features rather than selected technologies; their implementation will be documented when their contracts are agreed.
The complete direct-dependency register, including versions, licenses, sources, purposes, and operational notes, is maintained in Third-party software and services.
Deliberate Constraints
- The shipped catalogue contains 100m, 200m, 400m, 800m, 1500m, 100m hurdles, 400m hurdles, long jump, high jump, triple jump, javelin, discus, shot put, and 4 x 100m relay. Multi-events and automated season scheduling remain out of scope until their contracts are agreed; each added capability requires coordinated validation, UI, schema, derivation, placing, PB/SB, and test changes.
- The frontend and backend remain separate services. A fused framework is intentionally not used.
- Derived results remain server-authoritative. A manual override is audited rather than replacing the original timeline record.
- No third-party service receives the Auth0 Management API secret except the backend; it is never exposed through the frontend build.
AI declaration
This document was created or updated with the assistance of OpenCode[openai/gpt-5.6-terra].