Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/piratta/gymApp/llms.txt

Use this file to discover all available pages before exploring further.

FocusFlow is built as a layered, offline-first single-page application. The React 19 frontend renders one of three role-specific dashboards — CoachDashboard, ClientDashboard, or AdminDashboard — based on the authenticated user’s UserRole. All global application state is owned by a single App.tsx root component and flows down as props. Persistence is handled by a two-tier system: Firebase Firestore is the source of truth for cloud-synced data, while safeStorage (a hardened localStorage wrapper with an in-memory fallback) provides transparent offline resilience. Firebase Auth manages session identity, with anonymous sign-in as a zero-friction fallback and Google OAuth for Workspace integrations.

Architecture Layers

Presentation Layer

React 19 (Vite, ESM). Three dashboards rendered based on UserRole: CoachDashboard, ClientDashboard, and AdminDashboard. Routing is performed inline in App.tsx — no third-party router is used; the authenticated user’s role field determines which component tree is mounted.

State Management

All global state lives in App.tsx via useState and useEffect. Firebase data is loaded at startup via loadAllFromCloud() and written back reactively via saveToCloud() whenever a state slice changes and isSyncingCloud is false.

Persistence Layer

Cloud: Firebase Firestore under the coaching_data collection, one document per SYNC_KEY. Offline: localStorage via safeStorage with automatic in-memory fallback. Dirty-key tracking ensures no write is silently lost while offline.

Authentication

Firebase Auth with onAuthStateChanged. If no session is found, signInAnonymously() is called automatically so Firestore rules are always satisfied. Google OAuth (signInWithGoogleWorkspace) provides access tokens for Google Drive and Sheets integrations.

Component Structure

FocusFlow’s component tree is rooted at App.tsx, which mounts the appropriate dashboard after authentication resolves.

Root & Auth

  • App — global state, Firebase bootstrap, sync engine
  • LoginForm — credential entry, password reset flow
  • NotificationCenter — real-time in-app notification bell

Role Dashboards

  • CoachDashboard — 8-tab coach workspace
  • ClientDashboard — mobile-first athlete workspace
  • AdminDashboard — platform management console

Shared Feature Components

Shared components in components/ (root), used by one or both dashboards:
  • RoutineBuilder — drag-and-drop routine editor
  • InteractiveTraining — live workout session runner
  • PlicometriaModule — skinfold body-composition calculator
  • AgendaCalendarView — event scheduling calendar
  • ProgressCharts — Recharts metric dashboards
  • CalendarView — athlete’s workout schedule
  • CoachClientNotes — coach private notes panel
  • SearchableExerciseDropdown — exercise search widget

Coach Tab Components

Namespaced under components/coach/:
  • AgendaTab — agenda management tab
  • AthleteCompletedSessionsView — completed session history
  • AthleteReviewsView — client review management
  • AthleteStatsView — athlete statistics view
  • BillingTab — billing and subscription management
  • ExercisesTab — exercise library management
  • ProfileTab — coach profile settings
  • TemplateHandmadeEditor — custom template editor
Namespaced under components/client/:
  • ClientProgressTab — client-side progress overview
All dashboard components receive their data exclusively via props from App.tsx. No component fetches from Firestore directly — the data layer is fully centralized in the root component.

Data Flow

The following describes the end-to-end lifecycle of data in FocusFlow, from login to cloud persistence.
1

Authentication

main.tsx bootstraps the app. onAuthStateChanged fires — if no user session exists, signInAnonymously() resolves the whenAuthReady promise so that Firestore operations can proceed immediately.
2

Cloud Bootstrap

App.tsx calls loadAllFromCloud(), which fires loadFromCloud() in parallel for all 16 SYNC_KEYS. Each key is read from Firestore with a 15-second timeout, reconciled with the local localStorage backup, and the merged result is written back to both stores.
3

State Hydration

All 16 state slices — users, routines, reviews, messages, etc. — are populated from the resolved cloud data. isSyncingCloud is set to false, unblocking reactive save effects.
4

Role-Based Rendering

App.tsx inspects currentUser.role and renders the matching dashboard (CoachDashboard, ClientDashboard, or AdminDashboard), passing state slices and action handlers as props.
5

User Actions → Reactive Saves

Every user action (e.g. completing a workout, sending a message) updates the relevant React state slice. A corresponding useEffect detects the change (via reference inequality) and calls saveToCloud(key, data).
6

Offline Write Queue

saveToCloud always writes to localStorage first. If the Firestore write fails or times out, the key is added to the fit_cloud_dirty_keys set. The dirty count is polled every 1.5 seconds and displayed as a sync indicator in the header.
7

Reconnection Sync

When the browser fires a window online event, syncOfflineDataToCloud() iterates all dirty keys, reads their local backups, and re-attempts Firestore writes. Each successful key is removed from the dirty set.

Technology Choices

React 19 + Vite

Vite’s ESM-native dev server and optimised production build pipeline provide near-instant HMR. React 19’s concurrent renderer enables smooth UI during async cloud bootstrap.

TypeScript

All entities are strongly-typed via src/types.ts. The TypeScript compiler catches schema mismatches between Firestore payloads and UI components at build time, not at runtime.

Tailwind CSS 4.0

Tailwind 4’s CSS-variable-based design token system powers FocusFlow’s four visual themes (Dark Cosmic, Emerald Athletic, Cyberpunk Neon, Iron Crimson) without shipping separate stylesheet bundles.

Firebase Firestore

Firestore’s schemaless NoSQL model suits FocusFlow’s flexible entity shapes (e.g., variable skinfold fields per protocol). The single-document- per-collection pattern keeps queries simple and avoids Firestore read-cost multiplication.

Recharts

Recharts provides composable, React-native SVG chart primitives for weight evolution, training volume, body measurements, and compliance rate visualisations, all driven directly from Firestore-loaded arrays.

Motion

Motion (from motion/react) powers tab transitions, loading skeletons, and micro-interactions throughout both dashboards with minimal bundle overhead over a manual CSS approach.

Build docs developers (and LLMs) love