Use this file to discover all available pages before exploring further.
FocusFlow’s data model is defined entirely in src/types.ts and follows a TypeScript-first design philosophy. Every entity that crosses the React ↔ Firestore boundary is a plain TypeScript interface — no class hierarchies, no ORM abstractions. This keeps serialisation to JSON trivial and ensures that the shape of what is stored in Firestore is always exactly what the TypeScript compiler has verified. The sections below document every major interface, its fields, and how the entities relate to one another.
The role discriminator used throughout the app to gate access to dashboards, filter data queries, and determine which Firestore documents a user can read or write.
interface Exercise { id: string; name: string; category: string; // "Pecho", "Espalda", "Piernas", "Hombros", "Brazos", "Cardio" description?: string; coachId?: string; // Scopes the exercise to a specific coach's library}
Exercises are stored in the global fit_exercises collection but are filtered by coachId at the dashboard level, so each coach only sees their own custom exercises plus the platform defaults (where coachId is absent).
interface ExerciseSet { setIndex: number; targetReps: string; // e.g. "8-10" or "12" achievedReps?: number; weightUsed?: number; completed: boolean; skipped: boolean; targetRpe?: string; // e.g. "@6.0", "9"}
ExerciseSet records appear in two contexts: as the prescribed template inside a RoutineExercise.sets[] and as the athlete’s live performance log inside ActiveWorkoutSession.exercises and WorkoutSummary.loggedExercises.
When startDate and endDate are set, isActive is dynamically overridden at render time using useMemo — it is true only when today’s date falls within the date range.
Weight logs are stored as { [clientId: string]: DailyWeight[] } under the fit_weight_logs key. Only one entry per date per client is retained — a new log for the same date overwrites the previous one.
interface PlicometriaLog { id: string; clientId: string; date: string; // YYYY-MM-DD weight: number; // Current body weight in kg protocolId: "3-fold" | "4-fold" | "7-fold" | "yuhasz"; // Skinfold measurements (mm) — fields present depend on the protocol pectoral?: number; abdominal?: number; musloAnterior?: number; triceps?: number; suprailiaco?: number; biceps?: number; subescapular?: number; axilarMedio?: number; // Calculated outputs sumaPliegues: number; densidadCorporal: number; porcentajeGrasa: number; masaGrasa: number; // kg masaMagra: number; // kg createdBy: "coach" | "client"; createdAt: string; // ISO string}
The skinfold fields that are populated depend on the selected protocolId. For example, "3-fold" uses pectoral, abdominal, and musloAnterior for males. All calculated fields (sumaPliegues, densidadCorporal, porcentajeGrasa, masaGrasa, masaMagra) are derived by the client-side formula engine at entry time and stored pre-calculated.
Measurement logs are stored as { [clientId: string]: BodyMeasurements[] } under fit_measurements_logs. When a review is submitted, its measurements object is automatically merged into this log for the matching date.
photos and feedbackPhotos are not persisted to Firestore due to document size constraints. They are stored exclusively in localStorage via the fit_offline_backup_fit_reviews key. The reconciliation logic in loadFromCloud always restores these fields from local backup when merging cloud and local records. Use driveFolderUrl to link to full-resolution files stored in Google Drive.
All entities are stored as individual JSON documents inside the single Firestore collection coaching_data. Each document key corresponds to one of the 16 SYNC_KEYS. The document payload is the entire serialised array (or map) for that entity type.
{ "payload": "<JSON-serialised array or map>", "updatedAt": "2024-11-15T10:32:00.000Z"}
This single-document-per-collection pattern means all reads and writes for a given entity type operate on the complete array. This simplifies query logic (no where clauses needed) and minimises Firestore read costs, but means large collections (e.g. fit_summaries with many clients) should be monitored for document size as Firestore enforces a 1 MiB per-document limit.