Solución de problemas
Los errores que puedes encontrar al instalar Kinora, qué causa cada uno y cómo solucionarlo.
Para el paquete Full Stack
Docker no se está ejecutando
failed to connect to the docker API at unix:///…/docker.sock; check if the path is correct and if the daemon is runningLas versiones antiguas de Docker muestran "Cannot connect to the Docker daemon" en su lugar. En ambos casos, el motor de Docker no está iniciado.
Abre Docker Desktop
Inicia Docker Desktop y espera a que indique que el motor está en ejecución. En Linux, inicia el servicio:
sudo systemctl start docker.Comprueba que Docker responde
Terminaldocker infoResultado esperado: Muestra una sección Server en lugar de un error.
Vuelve a ejecutar tu comando de inicio
docker compose up --buildpara el paquete Full Stack, o tus comandosdocker buildydocker runpara una sola aplicación.
Un puerto ya está en uso
ports are not available: exposing port TCP 0.0.0.0:3030 … bind: address already in use
Error: listen EADDRINUSE: address already in use :::3030La primera línea viene de Docker, la segunda de yarn dev. Otro programa ya escucha en 3030 o 8000: a menudo una ejecución anterior de Kinora, o el servidor de desarrollo de otro proyecto.
Averigua qué ocupa el puerto
En macOS o Linux:
Terminallsof -i :3030En Windows, en PowerShell:
Terminalnetstat -ano | findstr :3030Detenlo
Cierra ese programa o detén la ejecución anterior: Ctrl+C en su terminal,
docker compose downen su carpeta, odocker stoppara un contenedor que iniciaste condocker run. Después vuelve a iniciar Kinora.O ejecuta Kinora en otros puertos
Con el stack completo en Docker, crea un archivo llamado
.enven la carpetakinora-fitness-full-stack, junto adocker-compose.yml, con el puerto que necesites.DASHBOARD_PORTmueve el panel yAPI_PORTla API; las direcciones que usan las aplicaciones se ajustan solas.kinora-fitness-full-stack/.envDASHBOARD_PORT=3040Después ejecuta el mismo comando otra vez. Tras un arranque fallido, continúa donde se detuvo:
Terminalenkinora-fitness-full-stackdocker compose up --buildResultado esperado: El panel responde en su nuevo puerto, aquí localhost:3040Local.
Sin Docker, los puertos se configuran en los archivos .env. Para mover la API, cambia a la vez PORT en back-end/.env y las dos direcciones de la API en dashboard/.env. Para mover el panel, cambia PORT en dashboard/.env y CORS_ORIGIN en back-end/.env. Con Docker, usa API_PORT y DASHBOARD_PORT en su lugar. Para una sola aplicación iniciada con docker run, cambia el número a la izquierda de -p.
La construcción de Docker falla
La primera construcción descarga las imágenes base y todas las dependencias, y luego construye las imágenes. Si algo lo impide, se detiene con "failed to solve" y el paso que falló.
- Sin conexión o tiempo de espera agotado: la construcción necesita acceso a internet. Vuelve a ejecutar el comando cuando tengas conexión; los pasos terminados quedan en caché.
- No space left on device: libera espacio en Docker Desktop o revisa cuánto usa Docker con
docker system df. - Falla siempre en el mismo paso: vuelve a construir sin la caché y luego inicia.
kinora-fitness-full-stackdocker compose build --no-cache
docker compose upEn un paquete de una sola aplicación, añade --no-cache a tu comando docker build.
Un primer inicio que parece atascado suele estar todavía cargando los datos de demostración. El panel solo arranca cuando la API indica que está sana.
Yarn dice que su versión es 1.22
This project's package.json defines "packageManager": "yarn@4.8.1…". However the current global version of Yarn is 1.22…Cada aplicación fija Yarn 4 a través de Corepack. Este mensaje significa que Corepack aún no está habilitado, así que respondió en su lugar el Yarn global antiguo.
corepack enableDespués vuelve a ejecutar yarn install. Si tu Node.js no trae Corepack, instálalo antes con npm install -g corepack.
La API se detiene antes de iniciarse
✖ The API cannot start: JWT_SECRET is not set. Set it in back-end/.env to the output of: …
✖ The API cannot start: JWT_SECRET is still the example value from .env.example, …
✖ The API cannot start: CORS_ORIGIN is not set. List the dashboard origin (comma separated if there are several), …La API revisa sus ajustes antes de iniciarse y muestra una línea por cada problema. Las causas:
- No hay archivo `.env`, o `JWT_SECRET` está vacío. Crea el archivo en
back-end/concp .env.example .env. - `JWT_SECRET` sigue siendo el valor de ejemplo con `NODE_ENV=production`. Cualquiera podría firmar un token con el ejemplo público, así que un inicio en producción lo rechaza. Genera tu propio secreto.
- `CORS_ORIGIN` está vacío con `NODE_ENV=production`. Ponle la dirección del panel, separadas por comas si hay varias.
Genera un secreto con:
node -e "console.log(require('crypto').randomBytes(48).toString('hex'))"Con Docker no necesitas uno: un contenedor sin un JWT_SECRET propio, o con el de ejemplo, genera un secreto y lo guarda en el volumen de datos.
La comprobación de estado responde 503
{"status":"unavailable"}
The database has no tables yet. Run `yarn seed` in back-end/, then restart the API./api/health responde 503 hasta que la base de datos responde y contiene sus tablas. La segunda línea es lo que dice el registro de la API al arrancar cuando faltan las tablas.
- Sin Docker, en desarrollo: ejecuta
yarn seedenback-end/(tablas y datos de demostración), oyarn db:sync(solo tablas), y luego reinicia la API. - Con `NODE_ENV=production`: la API no crea las tablas por sí misma. Ejecuta
yarn db:sync:prod(tablas vacías) oyarn seed:prod(con los datos de demostración) una vez, después deyarn build. - Con Docker sobre SQLite: el contenedor crea las tablas por sí mismo en el primer inicio. Con MySQL no lo hace: su registro te indica que ejecutes tú mismo una vez
node dist/database/sync-schema.js(tablas) onode dist/database/seeder.js(tablas y datos de demostración). - "The database has no accounts, so nobody can sign in" significa que las tablas existen pero nunca se añadió ninguna cuenta: ejecuta
yarn seedenback-end/.
MySQL no arranca o no carga los datos
La API crea sus tablas en una base de datos que ya existe; no crea la base de datos por sí misma. Crea primero una base de datos vacía, pon su nombre en DB_DATABASE en back-end/.env y luego ejecuta yarn seed (o yarn db:sync para las tablas sin datos de demostración).
- Revisa los cinco valores de conexión
DB_*y queDB_TYPE=mysql. - Con
NODE_ENV=productionla API en marcha nunca crea tablas, así que uno de esos comandos se ejecuta antes del primer inicio:yarn db:sync:prodoyarn seed:proddespués deyarn build.
El inicio de sesión falla
- Comprueba la cuenta. Todos inician sesión en el mismo formulario en el puerto
3030: el Head Coach esheadcoach@example.comconCoach@123, y el miembromember@example.comconMember@123. - Revisa el registro de la API. "The database has no accounts, so nobody can sign in" significa que nunca se añadieron los datos de demostración. Sin Docker, ejecuta
yarn seedenback-end/. Con Docker, el volumen se creó conSEED_DEMO_DATA=false. - "The database has no tables yet" significa que el esquema nunca se creó: ejecuta
yarn seedenback-end/y reinicia la API. - Cambiaste la contraseña del Head Coach y ya no la tienes: empieza de cero con datos de demostración nuevos, más abajo.
- "That email and password combination didn't work. Please try again." es la misma respuesta para un correo sin cuenta y para una contraseña incorrecta, así que revisa ambos.
- "Too many attempts. Wait a minute and try again." significa que una dirección hizo más de 10 intentos en la ruta de inicio de sesión, registro o eliminación de cuenta en un minuto. Espera un minuto y vuelve a intentarlo.
El inicio de sesión falla
- Revisa el registro de la API. "The database has no accounts, so nobody can sign in" significa que nunca se añadieron los datos de demostración: ejecuta
yarn seed, o inicia el contenedor de Docker con-e SEED_DEMO_DATA=trueen un volumen nuevo. - "The database has no tables yet" significa que el esquema nunca se creó: ejecuta
yarn seedy reinicia la API. - Comprueba la cuenta. Todos inician sesión en
POST /api/auth/login: el Head Coach esheadcoach@example.comconCoach@123, y el miembromember@example.comconMember@123. Un inicio de sesión fallido responde401con el mismo mensaje tanto si el correo como si la contraseña es incorrecta. - Una respuesta `429` significa que una dirección hizo más de 10 intentos en la ruta de inicio de sesión, registro o eliminación de cuenta en un minuto. La cabecera
Retry-Afterindica cuántos segundos esperar.
El inicio de sesión falla
Con los datos de ejemplo no se comprueba la contraseña, pero el formulario sigue pidiendo al menos 6 caracteres. Un correo que pertenece a una cuenta de ejemplo inicia sesión como esa cuenta, y cualquier otro correo inicia sesión como el Head Coach. Cuando conectes una API, inicia sesión con una cuenta que exista en ella: el Head Coach de demostración es headcoach@example.com con Coach@123, y el miembro de demostración member@example.com con Member@123.
Todos los visitantes reciben "Too many attempts" detrás de un proxy
El inicio de sesión, el registro y la eliminación de cuenta permiten 10 peticiones por minuto por dirección y ruta, y después responden 429. La API busca la dirección del visitante en X-Forwarded-For solo cuando la petición viene de un proxy en una dirección privada, de loopback o de la plataforma, como en Docker, en Railway o detrás de un proxy inverso en la misma máquina.
Cuando tu proxy llega a la API desde una dirección pública, todos los visitantes parecen ese único proxy y comparten un solo cupo. Indica a la API cuántos proxies hay delante de ella:
TRUST_PROXY=1TRUST_PROXY=false nunca lee la cabecera. Déjalo sin configurar cuando se accede a la API directamente o a través de un proxy con una dirección privada. Los recuentos se guardan en la memoria de la API, así que un reinicio los borra.
Aparece un aviso "Sample data"
No API is connected (NEXT_PUBLIC_API_BASE_URL is empty), so the dashboard is running on built-in sample data: …El panel se inició o se construyó sin NEXT_PUBLIC_API_BASE_URL, así que responde a cada petición con datos de ejemplo en el navegador. Lo que cambies se guarda entonces en el navegador, no en la base de datos.
Dale al panel la dirección de la API
Crea
dashboard/.enva partir de.env.examplesi no lo tiene.NEXT_PUBLIC_API_BASE_URLdebe ser la dirección de la API con/apiincluido, por ejemplohttp://localhost:8000/api, yNEXT_PUBLIC_WEBSOCKET_BASE_URLel mismo servidor sin él.Comprueba que la API responde
Abre localhost:8000/api/healthLocal. Debería responder
{"status":"ok"}. Si la dirección está configurada pero la API no responde, las páginas no pueden cargar sus datos: los datos de ejemplo no la sustituyen.Reinicia o vuelve a construir el panel
La dirección se compila dentro. Reinicia
yarn devdespués de cambiarla, vuelve a ejecutaryarn buildantes deyarn start, o con Docker vuelve a ejecutardocker compose up --build.
Un cambio en el .env del panel no tiene efecto
Cada valor NEXT_PUBLIC_* se compila en el JavaScript que carga el navegador cuando se construye la aplicación. Cambiar el archivo no cambia nada hasta que la aplicación se vuelve a construir.
| Cómo lo ejecutas | Después de cambiar un valor |
|---|---|
yarn dev | Detenlo y vuelve a ejecutar yarn dev. |
yarn build y yarn start | Vuelve a ejecutar yarn build y luego yarn start. |
| Docker Compose | Ejecuta docker compose up --build. Configura API_URL, DASHBOARD_URL o MEDIA_HOSTNAME en el .env junto a docker-compose.yml, no en la carpeta del panel. |
docker build para el panel | Vuelve a construir la imagen con el valor como --build-arg. |
Una función indica que no está configurada
Las subidas y el asistente de IA solo se activan cuando sus claves están en back-end/.env. Una clave que aún tiene exactamente su valor de .env.example cuenta como no configurada, así que un .env.example copiado arranca sin problemas y cada una de esas funciones indica que está desactivada en lugar de fallar en su primera llamada.
- Pega tu clave real encima del valor de ejemplo, no a su lado.
- Reinicia la API después de cambiar
back-end/.env. Con Docker Compose la API también lee ese archivo, así que basta con volver a ejecutardocker compose up; un contenedor de API independiente necesita--env-file .enven sudocker run.
Se rechazan las subidas
File storage is not configured on this server. Set the R2 variables in .env to enable uploads.Las fotos de perfil, las fotos de progreso y los adjuntos de mensajes van a un bucket de Cloudflare R2 u otro compatible con S3, y una subida responde 400 con este mensaje hasta que las cinco variables R2_* estén configuradas en back-end/.env. Los datos de demostración no necesitan bucket: sus imágenes son rutas /assets/images/… que el panel sirve desde su propia carpeta public/.
Las solicitudes se bloquean en tus propios dominios
Access to XMLHttpRequest at 'https://api.your-domain.com/api/…' from origin 'https://app.your-domain.com' has been blocked by CORS policyLa API solo responde a navegadores desde las direcciones de CORS_ORIGIN, y a sus sockets en vivo solo desde FRONTEND_URL cuando está configurado (si no, desde la misma lista). Los dos apuntan por defecto al panel local en el puerto 3030, así que en tu propio dominio deben indicarlo.
CORS_ORIGIN=https://app.your-domain.com
FRONTEND_URL=https://app.your-domain.comEscribe cada dirección exactamente como la muestra el navegador, con https:// y sin barra final, y luego reinicia la API. Con Docker Compose, configura en su lugar DASHBOARD_URL y API_URL en el .env junto a docker-compose.yml y ejecuta docker compose up --build: el archivo compose construye los dos valores a partir de ellos.
"Forgot password" no envía nada
Las páginas de contraseña olvidada y de restablecer contraseña del panel son solo las pantallas: no se envía ningún restablecimiento y ninguna contraseña cambia a través de ellas. Llaman a POST /api/auth/forgot-password y POST /api/auth/reset-password, que la API de la plantilla no tiene, así que con la API el formulario muestra un error. Con los datos de ejemplo el formulario muestra su confirmación, pero tampoco se envía nada. Para dar a un miembro una contraseña nueva, una cuenta de personal con members.update la establece en la página del miembro, en Gimnasio. Un restablecimiento por cuenta propia necesita las dos rutas y un proveedor de correo propio.
El contenedor de la API no encuentra su entrypoint
exec /usr/local/bin/docker-entrypoint.sh: no such file or directoryEl script tiene finales de línea de Windows, que un editor o Git en Windows pueden añadir. El back-end/Dockerfile incluido los elimina durante la construcción, así que esto solo aparece con una imagen construida a partir de un Dockerfile modificado. Conserva su línea sed -i 's/\r$//', o guarda el script con finales de línea LF, y luego reconstruye sin la caché.
kinora-fitness-full-stackdocker compose build --no-cache api
docker compose upLa carpeta se ve diferente
Ejecuta los comandos dentro de la carpeta en la que se extrae el ZIP. Si no tienes el comando unzip, extráelo con tu gestor de archivos; algunas herramientas añaden una carpeta extra con el nombre del ZIP, así que entra en la carpeta interior.
| Paquete | Carpeta | Contiene |
|---|---|---|
| Full Stack | kinora-fitness-full-stack | back-end, dashboard, docker-compose.yml |
| Panel | kinora-fitness-dashboard | Dockerfile, package.json, .env.example |
| Backend | kinora-fitness-backend | Dockerfile, package.json, .env.example |
Empieza de cero con datos de demostración nuevos
Esto elimina tus datos
Se elimina todo lo que creaste en local y se vuelven a cargar los datos de demostración.
Con Docker Compose, desde la carpeta kinora-fitness-full-stack:
kinora-fitness-full-stackdocker compose down -v
docker compose upCon un contenedor de API independiente, elimina primero el contenedor (docker ps -a lo muestra, docker rm -f con su id lo elimina), luego borra el volumen y vuelve a ejecutarlo:
kinora-fitness-backenddocker volume rm kinora-data
docker run -p 8000:8000 -v kinora-data:/data -e SEED_DEMO_DATA=true kinora-apiSin Docker, detén la API y luego, en su carpeta:
rm -f database.sqlite* && yarn seedEn PowerShell:
Remove-Item database.sqlite*; yarn seedVolver a ejecutar yarn seed en una base de datos que conservas no es un reinicio: solo añade lo que falta y nunca cambia una fila que editaste. yarn db:reset elimina todas las tablas, tanto en SQLite como en MySQL, antes de yarn seed.
Empieza de cero con los datos de ejemplo
Sin una API, tus cambios se guardan en el navegador. Para recuperar los datos de ejemplo, ejecuta esto en la consola del navegador en la página del panel:
localStorage.removeItem("mock_db_v1"); location.reload();