BikeControl (SwiftControl)
Use Zwift Click, Zwift Play, Shimano Di2, or any Bluetooth controller with MyWhoosh, Rouvy, Zwift, and more. Free to try on iOS, Android, Windows, and macOS.
Webapp de entrenamiento — registrá tus series, mirá tu progreso.
Translation pending
Sports & fitnessJavaScript · SwiftGitHub @LagartoJuancho17OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
Trabajo Practico: Desarrollo de una Aplicacion SaaS con Next.js y Firebase Este repositorio proporciona una base tecnica para el desarrollo de una aplicacion web de tipo SaaS utilizando Next.js, Firebase Authentication, Firebase Admin SDK, Firestore y Tailwind CSS. El trabajo practico debera realizarse en grupos de 2 integrantes. Cada grupo debera definir una propuesta propia de aplicacion, disenar su modelo de datos, implementar las rutas y componentes necesarios, y desarrollar una funcionalidad principal que permita a los usuarios autenticados gestionar informacion persistente.Read the full README ↗
SiezaGym es una plataforma integral de entrenamiento de fuerza, hipertrofia y acondicionamiento físico diseñada para atletas, entrenadores y administradores. Combina una aplicación web moderna (Next.js 16) con una aplicación nativa de iPhone (SwiftUI / iOS 18+), ambas conectadas en tiempo real a la misma base de datos Firebase Firestore.
Toda la lógica de entrenamiento, cálculo de marcas (1RM), registro de series, distribución de grupos musculares y seguimiento de progreso es compartida y coherente entre plataformas: lo que registrás en el gimnasio desde el iPhone impacta inmediatamente en la web y viceversa.
SiezaGym opera con un modelo de tres roles con permisos granulares y vistas adaptadas a cada necesidad:
La aplicación web está desarrollada sobre las últimas especificaciones del ecosistema React y Node:
@dnd-kit/sortable para la reordenación fluida de ejercicios en el creador de rutinas.firestore.rules) basadas en identidad y relaciones coach-alumno.HTTP-only seguras (__session).scripts/seedExercises.mjs)./api/session/login que genera una Cookie de Sesión HTTP-only de Firebase (__session).getCurrentUser() en lib/firebase/session.js, permitiendo renderizado en el servidor sin destellos de carga ni redirecciones cliente innecesarias./dashboard/coach o /admin).lib/)La lógica de negocio está completamente separada de las vistas:
lib/routines/: Creación, edición, duplicación, prescripciones parecidas vs rampa por serie, y ordenamiento de rutinas.lib/workout/: Estado activo del entrenamiento, temporizadores, sonido y cálculo de volumen.lib/sessions/: Registro de entrenamientos finalizados, cálculo de rachas continuas y estadísticas semanales.lib/coach/: Gestión de invitaciones, desvinculación y lectura de perfiles de alumnos.lib/epley.js: Algoritmo matemático unificado para la estimación de 1RM.lib/home/metrics.js: Ponderación de esfuerzo, cálculo de calorías (fórmula MET) y balance empuje/tracción./)/rutinas y /rutinas/nueva)RoutineComposer):
customExercises) especificando nombre, músculos implicados, patrón motor y equipamiento.4 × 10).12 reps @ 60kg, 10 reps @ 70kg, 8 reps @ 80kg).@dnd-kit)./rutinas/[id])RoutineScreen): El detalle de la rutina y la sesión en vivo conviven en la misma interfaz:
localStorage (activeWorkout); si se cierra la pestaña accidentalmente, el entrenamiento no se pierde./sessions./historial y /progreso)/historial/[id]), se detalla cada serie, peso, reps y el 1RM estimado alcanzado./progreso):
/progreso/[exerciseId]):
/perfil)Ubicado en /dashboard/coach, optimizado para escritorio y accesible para usuarios con isCoach: true:
/dashboard/coach/alumnos/[studentId]):
Semana 3) y notas específicas.Ubicado en /admin, accesible únicamente para los correos configurados como administradores:
La carpeta /ios contiene la aplicación nativa en SwiftUI para el alumno. Habla directamente con el mismo Firebase Firestore que la web, sin capas intermedias ni bases de datos duplicadas.
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ SiezaGym Web (Next.js) │ │ SiezaGym iOS (SwiftUI) │
│ - App Router │ │ - Swift 6 / iOS 18+ │
│ - React 19 │ │ - ActivityKit & WidgetKit │
│ - Firebase Client & Admin SDK │ │ - HealthKit (Apple Salud) │
└────────────────┬────────────────┘ └────────────────┬────────────────┘
│ │
│ Firebase Firestore │
└──────────────► & Auth ◄───────────────┘
SWIFT_DEFAULT_ACTOR_ISOLATION = YES, Main Actor por defecto).firebase-ios-sdk (v12) y GoogleSignIn-iOS (v9).project.yml. Toda la configuración de compilación, targets, bundles y capacidades se gestiona desde el archivo YAML para evitar conflictos de merge en .pbxproj.Models/: Modelos de datos inmutables y conformes a Sendable (Exercise, Routine, WorkoutSession, UserProfile).Domain/: Funciones matemáticas y reglas de negocio puras, sin dependencias de Firestore ni SwiftUI (port idéntico de lib/ de la web: HomeMetrics, Epley, TrainingCalendar, RoutineSummary, RestTimer).Services/: Repositorio de Firestore (GymRepository), servicio de autenticación y estado reactivo global (GymStore).DesignSystem/: Paleta SIEZA sincronizada con el CSS de la web mediante ios/scripts/sync-theme.mjs.Features/: Pantallas modulares (Inicio, Rutinas, Entrenamiento, Historial, Progreso, Perfil).SiezaGymWidgets/: Extensión de widgets y actividades en vivo.UserDefaults (sieza.onboarding.completed.v1).Actividad de hoy se conecta a HealthKit para leer:
activeEnergyBurned).stepCount).distanceWalkingRunning).Activity<WorkoutActivityAttributes> de ActivityKit:
Text(timerInterval:)), lo que garantiza cero consumo excesivo de batería.Serie 2 de 4), el peso y las repeticiones.TerminarSerieIntent): El usuario puede pulsar el botón de "Terminar serie" directamente desde la Dynamic Island o la pantalla de bloqueo para registrar la serie sin desbloquear el teléfono.App Groups.SnapshotStore) con atributo kSecAttrAccessibleAfterFirstUnlock. La app principal deposita un snapshot ligero de datos y el widget lo consume instantáneamente sin requerir sesión de Firebase ni exceder los límites de memoria de WidgetKit.RestTimer.swift): Se inicia en 90 segundos entre series y se sincroniza con el estado de la rutina.AsyncImage no anima GIFs remotos en iOS. La app utiliza ImageIO nativo para extraer los frames y renderizarlos mediante UIImageView con caché en memoria.img.youtube.com/vi/<id>/mqdefault.jpg).| Colección / Ruta | Descripción | Acceso / Reglas de Seguridad |
|---|---|---|
/users/{uid} | Perfil de usuario, peso corporal, rol, referencias al coach. | Lectura: propio usuario o coach vinculado. Escritura: propio usuario (protegiendo campos de rol). |
/users/{uid}/customExercises | Ejercicios propios creados por el usuario. | Lectura: propio usuario o su coach. Escritura: propio usuario (validando estructura muscular). |
/exercises/{exerciseId} | Catálogo maestro de 94 ejercicios (nombre, músculos, GIFs, equipamiento). | Lectura: todos los usuarios autenticados. Escritura: restringida (solo Admin SDK). |
/routines/{routineId} | Rutinas creadas por atletas o entrenadores. | Lectura y escritura: únicamente el propietario (ownerId == auth.uid). |
/assignments/{assignmentId} | Rutinas congeladas asignadas de un entrenador a un alumno. | Lectura: entrenador o alumno asignado. Escritura: únicamente el entrenador vinculado. |
/sessions/{sessionId} | Registro inmutable de entrenamientos completados con detalle serie por serie. | Lectura: atleta propietario o su entrenador. Creación: atleta autenticado (máx 40 ejercicios). |
/coaches/{coachId}/students/{studentId} | Registro de relación formal entre profesor y alumno. | Lectura: entrenador propietario. Escritura: sólo transacciones seguras del servidor. |
/invites/{code} | Códigos temporales de 6 caracteres para vinculación. | Lectura: autenticados. Creación: entrenador autenticado. Canje: Server Action seguro. |
/mfaChallenges/{challengeId} | Desafíos OTP de 6 dígitos para autenticación por correo. | Acceso totalmente bloqueado a clientes. Solo gestionado por Firebase Admin SDK. |
La plataforma implementa algoritmos idénticos en JavaScript (lib/) y Swift (Domain/):
Estimación de 1RM (Fórmula de Epley): $$\text{1RM} = \text{Peso} \times \left(1 + \frac{\text{Reps}}{30}\right)$$ (Si $\text{Reps} = 1$, $\text{1RM} = \text{Peso}$. Las series marcadas como falladas se excluyen).
Gasto Calórico Estimado (MET): $$\text{Calorías (kcal)} = \text{MET (5.0)} \times \text{Peso (kg)} \times \text{Horas de entrenamiento}$$ (Si el perfil no registra peso, se utiliza un estándar de 75 kg con advertencia visible en UI).
Reparto y Distribución Muscular:
Cada ejercicio almacena un diccionario muscleWeights que suma 1.0. El impacto de una sesión en cada grupo muscular se calcula multiplicando el tonelaje levantado ($\text{Peso} \times \text{Reps}$) por el coeficiente de participación de cada músculo.
Cálculo de Racha (Streak):
Basado en días locales consecutivos con al menos una sesión terminada. Los cálculos normalizan la fecha a la zona horaria de Argentina (America/Argentina/Buenos_Aires).
SiezaGym/
├── app/ # Next.js 16 App Router
│ ├── (app)/ # Rutas privadas de la aplicación
│ │ ├── page.js # Portada / Home del atleta
│ │ ├── rutinas/ # Listado, nueva rutina y [id] detalle/entrenamiento
│ │ ├── historial/ # Listado de entrenamientos y [id] detalle de sesión
│ │ ├── progreso/ # Dashboard de progreso y [exerciseId] evolución 1RM
│ │ ├── perfil/ # Perfil, ajustes de tema y vinculación con coach
│ │ └── layout.js # Layout base con temas y estilos
│ ├── admin/ # Panel de operaciones del Administrador
│ ├── dashboard/coach/ # Panel del Entrenador (Roster, alumnos, invitaciones)
│ ├── api/ # Endpoints HTTP (MFA, sesión con cookies)
│ ├── globals.css # Estilos globales y tokens base
│ └── design2.css # Sistema de diseño SIEZA / Design2
├── components/ # Componentes modulares de React
│ ├── design2/ # Componentes visuales del sistema SIEZA (Header, TabBar, etc.)
│ ├── coach/ # Vistas y componentes del entrenador
│ ├── progress/ # Gráficos Recharts y tablas de marcas
│ └── routines/ # Creadores de rutinas y formularios de ejercicios
├── lib/ # Lógica de dominio pura y servicios backend
│ ├── admin/ # Métricas y control de acceso de admin
│ ├── assignments/ # Lógica de asignación de rutinas coach-alumno
│ ├── coach/ # Invitaciones y vinculación
│ ├── exercises/ # Catálogo global y categorización de ejercicios
│ ├── firebase/ # Configuración de Firebase Client y Firebase Admin SDK
│ ├── home/ # Métricas de la portada y volumen semanal
│ ├── routines/ # Prescripciones, cálculo de duración y armado
│ ├── sessions/ # Gestión de sesiones y algoritmo de racha
│ └── epley.js # Algoritmo de 1RM
├── ios/ # Aplicación Nativa para iPhone (SwiftUI)
│ ├── project.yml # Especificación declarativa del proyecto (XcodeGen)
│ ├── SiezaGym/ # Código fuente de la app nativa
│ │ ├── Models/ # Entidades Sendable de Swift
│ │ ├── Domain/ # Lógica de negocio pura (HomeMetrics, Epley, etc.)
│ │ ├── Services/ # GymRepository, GymStore, Firebase iOS SDK
│ │ ├── DesignSystem/ # Tokens SIEZA sincronizados
│ │ └── Features/ # Vistas SwiftUI por pestaña y pantalla
│ ├── SiezaGymCompartido/ # Código compartido entre App y Extensión de Widgets
│ ├── SiezaGymWidgets/ # WidgetKit y Live Activities (Dynamic Island)
│ ├── SiezaGymTests/ # Tests unitarios en Swift
│ └── scripts/ # Scripts de sincronización de temas, configs y build
├── firestore.rules # Reglas de seguridad para Firestore
├── scripts/seedExercises.mjs # Script de migración y siembra de catálogo de ejercicios
├── tests/ # Suites de pruebas con Vitest
└── package.json # Dependencias y scripts de Node
Crear un archivo .env.local en la raíz del proyecto con la siguiente configuración:
# Firebase Client SDK
NEXT_PUBLIC_FIREBASE_API_KEY=tu_api_key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=tu_proyecto.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=tu_proyecto_id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=tu_proyecto.firebasestorage.app
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=tu_sender_id
NEXT_PUBLIC_FIREBASE_APP_ID=tu_app_id
# Firebase Admin SDK (Server-Side)
FIREBASE_PROJECT_ID=tu_proyecto_id
FIREBASE_CLIENT_EMAIL=firebase-adminsdk-xxx@tu_proyecto.iam.gserviceaccount.com
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\ntu_clave_privada\n-----END PRIVATE KEY-----"
# Proveedor de Correo para MFA (Opcional en desarrollo local)
RESEND_API_KEY=re_tu_clave_resend
RESEND_FROM="SiezaGym <[email protected]>"
# Instalar dependencias
npm install
# Sembrar el catálogo de 94 ejercicios en Firestore (solo la primera vez)
npm run seed:exercises
# Iniciar el servidor de desarrollo
npm run dev
La aplicación web estará disponible en http://localhost:3000.
brew install xcodegen).Para evitar exponer claves privadas en repositorios públicos, el archivo GoogleService-Info.plist se descarga dinámicamente usando las credenciales del Admin SDK ya configuradas en el entorno:
# Desde la raíz del repositorio:
node --env-file=.env --env-file=.env.local ios/scripts/fetch-google-service-info.mjs
cd ios
xcodegen generate
open SiezaGym.xcodeproj
Para desplegar en un dispositivo real con cuenta de desarrollador gratuita:
cp Local.example.xcconfig Local.xcconfig
# Editar Local.xcconfig e ingresar tu Apple Development Team ID
./scripts/run-on-device.sh
(En el iPhone, aprobar el certificado de desarrollador en: Ajustes › General › VPN y gestión de dispositivos › Confiar en el desarrollador).
Se cuenta con 47 archivos de test que validan flujos completos, seguridad y cálculos:
# Correr todas las suites de prueba
npm run test
# Verificar linter de código
npm run lint
# Validar compilación de producción
npm run build
Pruebas unitarias de las funciones puras de Domain/, cálculo de 1RM, sincronización de temas y widgets:
xcodebuild test -project ios/SiezaGym.xcodeproj -scheme SiezaGym \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro'
Proyecto desarrollado en el marco de la carrera de Programación (UMAI) para la materia Programación 3.
Diseñado y construido por Tobías Arraiza y Valentín Sierra. Todos los derechos reservados.