BikeControl (SwiftControl)
使用 Zwift Click、Zwift Play、Shimano Di2,或任何藍牙控制器搭配 MyWhoosh、Rouvy、Zwift 等。可於 iOS、Android、Windows 與 macOS 免費試用。
AI 翻譯
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
App de entrenamiento adaptativo para Blue Horse Gym (Arroyo Seco, Santa Fe). Genera y ajusta planes usando solo el equipamiento que existe físicamente en el gimnasio. Contenido provisorio. Todos los valores de entrenamiento que hoy devuelve la app son marcadores de posición mientras se termina la investigación de contenido. No sirven como consejo para una persona real. Necesitás Node 22.12 o mayor (probado con 24 LTS) y, para la base local, Docker.檢視完整 README ↗
App de entrenamiento adaptativo para Blue Horse Gym (Arroyo Seco, Santa Fe). Genera y ajusta planes usando solo el equipamiento que existe físicamente en el gimnasio.
Contenido provisorio. Todos los valores de entrenamiento que hoy devuelve la app son marcadores de posición mientras se termina la investigación de contenido. No sirven como consejo para una persona real.
Necesitás Node 22.12 o mayor (probado con 24 LTS) y, para la base local, Docker.
npm install
cp .env.example .env # completá las variables (npm run db:start te las imprime)
npx supabase init # una sola vez: genera supabase/config.toml (ya versionado en el repo)
npm run db:start # levanta Postgres local e imprime las claves
npm run db:sync # genera y aplica la migración inicial desde supabase/schemas/
npm run db:reset # aplica migrations/ + seed.sql desde cero, para verificar
npm run dev # http://localhost:5173
supabase/config.toml ya tiene schema_paths = ["./schemas/*.sql"] configurado — no hace falta
tocarlo. Ese setting le dice a db:sync (no a db diff, que en CLI ≥ 2.116 dejó de leerlo) dónde
están los esquemas declarativos.
| Comando | Qué hace |
|---|---|
npm run dev | PWA en :5173 |
npm run check | lint + typecheck + tests |
npm run build | build de producción con service worker |
npm run db:reset | recrea la base local desde migrations/ + seed.sql |
npm run db:sync | genera y aplica una migración desde supabase/schemas/ |
npm run db:types | regenera los tipos de TypeScript desde la base |
npm run db:ruleset | sube el ruleset a la base y lo deja activo |
npm run admin | consultar los datos de los socios (ver abajo) |
# Las claves salen de `npx supabase status -o env` (local) o del panel de
# Supabase (nube). Nunca van en un archivo versionado.
export SUPABASE_URL=... SUPABASE_SERVICE_ROLE_KEY=...
npm run admin socios # quiénes hay y qué actividad tienen
npm run admin socio [email protected] # todo de una persona
npm run admin planes # todos los planes generados
npm run admin resumen # números del gimnasio
npm run admin tabla set_logs reps=10 # filas de cualquier tabla
npm run admin motor [email protected] # qué plan le armaría el motor, sin guardarlo
npm run admin socio [email protected] -- --json
La pregunta acá no es "qué hizo Fulano" sino "con esta entrada, ¿el motor prescribe bien?". No sale ningún nombre, ningún email ni ningún id de socio: la unidad de análisis es la ruta (objetivo · nivel · frecuencia · duración), no la persona. Tampoco toca cribado de salud ni molestias — no hacen falta para juzgar un plan.
npm run admin recetas # de qué entrada salió cada plan, agrupado por ruta
npm run admin receta 3 # qué prescribió esa ruta: ejercicios, volumen por músculo, avisos
npm run admin avisos # qué le viene avisando el motor a los planes
recetas muestra, por ruta: qué template eligió, cuántos planes salieron,
ejercicios y series por sesión, qué porcentaje de sesiones se completó y
cuántos planes salieron con avisos. El porcentaje completado es la señal más
dura de si un plan está bien calibrado: uno que nadie termina está mal armado
aunque los números cierren.
Esto es posible porque plans.goal_snapshot congela el objetivo tal como era
al generar el plan. Mirar user_goals hoy mostraría la entrada equivocada para
todo plan de alguien que después cambió de objetivo.
Y contra la base local únicamente, para trabajar sobre el proyecto:
npm run admin sql "select ..." # consulta libre de solo lectura (joins, agregados)
npm run admin sembrar "Juan" # socio de prueba listo para entrar a la app
npm run admin limpiar # borra los socios de prueba y todo lo suyo
Tres candados, porque la misma clave y el mismo comando pueden apuntar a
producción con cambiar una variable de entorno: sql/sembrar/limpiar se
niegan a correr si SUPABASE_URL no es 127.0.0.1; sql exige que la
consulta empiece con select o with y rechaza el ; (sin eso,
select 1; delete from plans pasaría); y limpiar borra por patrón de email
de prueba, nunca "todo lo que no reconozco".
motor corre el mismo generatePlan que la PWA contra el catálogo y el
ruleset reales, sin escribir nada. Sirve para ver una prescripción completa de
una persona concreta sin pasar por la interfaz. Necesita el Node 24 portátil
(importa .ts directo).
socio muestra lo que respondió en el onboarding (objetivo, frecuencia,
nivel), peso y altura, cribado de salud, restricciones, planes con su avance,
entrenamientos con sus series, récords, propuestas del motor y molestias
reportadas.
Por qué un script y no una pantalla. La RLS solo le abre profiles a un
admin: de otro socio, la app puede leer el nombre y poco más. Todo lo demás
está cerrado a user_id = auth.uid(), y pain_reports y health_screenings
lo están por decisión de producto, no por olvido — son datos de salud que no
se comparten con el gimnasio. Este script corre con la service_role en la
máquina de quien la tiene: salta la RLS por diseño, es solo lectura, y no
expone ninguna superficie nueva a internet. Abrirle esos datos al panel web
requiere ampliar las políticas primero, que es una decisión de privacidad.
packages/domain tipos, enums, zod, conversión de unidades. Sin dependencias del proyecto.
packages/engine contrato del motor de prescripción + implementación provisoria.
apps/web la PWA.
supabase/schemas fuente de verdad del esquema. Las migraciones se generan desde acá.
docs/ arquitectura, modelo de datos, glosario, roadmap y decisiones.
packages/ no importa React ni Supabase: el motor es una función pura, testeable y reemplazable.
Por qué, en docs/03-contrato-motor.md.
https://bluehorse-app.vercel.app — build de Vercel apuntando a main, con VITE_SUPABASE_URL
y VITE_SUPABASE_ANON_KEY configuradas contra un proyecto Supabase en la nube (no el local de
Docker). Sin esas variables la app tampoco rompe: cada pantalla lo indica en su lugar ("Supabase
no está configurado") en vez de tirar un error. El panel técnico de configuración
(import.meta.env.DEV) no sale en esta build — eso es solo para desarrollo local. La
configuración de build está en vercel.json — necesaria porque es un monorepo con npm
workspaces: instalar solo desde apps/web rompe la resolución de @bh/domain/@bh/engine. El
mismo archivo tiene el rewrite de SPA que hace falta para que rutas como /instalar o /progreso
no den 404 al navegarlas directo (por ejemplo, al escanear el QR del gimnasio).
Para verificar cambios mientras se desarrolla, usar npm run dev (local, con HMR) y reservar el
deploy de Vercel para compartir avances — cada push a main redeploya solo.
Fases 1, 2 y 3 completas (esqueleto y catálogo, motor y sesión, adaptación/progreso/offline) salvo
el relevamiento real del catálogo de Blue Horse, que es un paso manual del dueño del proyecto, no
de código. Fase 4 (contenido real de entrenamiento) espera esa investigación. Ver docs/06-roadmap.md
y docs/ESTADO.md para el detalle.