BikeControl (SwiftControl)
使用 Zwift Click、Zwift Play、Shimano Di2,或任何藍牙控制器搭配 MyWhoosh、Rouvy、Zwift 等。可於 iOS、Android、Windows 與 macOS 免費試用。
AI 翻譯
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
⚽ Club 90 Minutos — Polla Liga BetPlay Club 90 Minutos es una aplicación web de pronósticos deportivos (quiniela/polla) para la Liga BetPlay colombiana. Los participantes pronostican resultados de partidos, goleadores, campeón, finalistas y clasificados a cuadrangulares, y acumulan puntos según la precisión de sus predicciones. • Node.js ≥ 18 • npm ≥ 9 • PostgreSQL (o cuenta en Neon para BD en la nube) La app estará disponible en http://localhost:3001. Crear un archivo .env basado en .env.example:檢視完整 README ↗
Club 90 Minutos es una aplicación web de pronósticos deportivos (quiniela/polla) para la Liga BetPlay colombiana. Los participantes pronostican resultados de partidos, goleadores, campeón, finalistas y clasificados a cuadrangulares, y acumulan puntos según la precisión de sus predicciones.
🌐 Producción: club90minutos.com
| Capa | Tecnología |
|---|---|
| Framework | Next.js 15 (App Router) |
| UI | React 19 |
| Lenguaje | TypeScript 5 |
| Base de Datos | PostgreSQL (Neon) |
| ORM | Prisma 6 |
| IA | Google Gemini (trivia, oráculo, crónicas) |
| Resend | |
| Gráficos | Recharts |
| Iconos | Lucide React |
| Datos en vivo | ESPN API (pública, sin autenticación) |
| Hosting | Hostinger (Node.js hosting) |
# 1. Clonar el repositorio
git clone https://github.com/tu-usuario/Club90minutos.git
cd Club90minutos
# 2. Instalar dependencias
npm install
# 3. Configurar variables de entorno
cp .env.example .env
# Editar .env con tus credenciales (ver sección siguiente)
# 4. Generar el cliente de Prisma
npx prisma generate
# 5. Aplicar el esquema a la base de datos (primera vez)
npx prisma db push
# 6. Levantar en modo desarrollo
npm run dev
La app estará disponible en http://localhost:3001.
Crear un archivo .env basado en .env.example:
| Variable | Descripción | Ejemplo |
|---|---|---|
DATABASE_URL | URL de conexión a PostgreSQL (pooled/connection pooler) | postgresql://user:pass@host:5432/dbname?sslmode=require |
DIRECT_URL | URL directa a PostgreSQL (para migraciones Prisma) | postgresql://user:pass@host:5432/dbname?sslmode=require |
NEXT_PUBLIC_APP_URL | URL pública de la app (para links en emails) | https://club90minutos.com |
RESEND_API_KEY | API Key de Resend para envío de emails | re_xxxxxxx |
SYNC_LIVE_SECRET | Secreto para proteger el endpoint /api/sync-live | Generar con: node -e "console.log(require('crypto').randomBytes(24).toString('hex'))" |
Club90minutos/
├── prisma/
│ └── schema.prisma # Esquema de base de datos (14 modelos)
├── public/
│ ├── images/ # Imágenes generales
│ ├── marca/ # Logos y branding
│ └── robots.txt
├── docs/
│ ├── api/ # Documentación de endpoints
│ ├── guias/ # Guías operativas (pgAdmin, etc.)
│ ├── internal/ # Notas técnicas de desarrollo
│ └── reglas-puntuacion.md # Reglas del juego documentadas
├── scripts/
│ ├── mantenimiento/ # Scripts recurrentes (sync maestro, reliquidar)
│ └── hotfixes/ # Correcciones puntuales ya ejecutadas
├── src/
│ ├── middleware.ts # Basic Auth para Vercel (staging)
│ ├── lib/
│ │ ├── db.ts # Singleton de Prisma Client
│ │ ├── calculadorPuntos.ts # ⭐ Motor de cálculo de puntos
│ │ ├── syncLive.ts # Sincronización en vivo con ESPN
│ │ └── tablaFija.ts # Datos fijos de tabla de posiciones
│ └── app/
│ ├── globals.css # Estilos globales
│ ├── layout.tsx # Layout raíz (metadata, fuentes, Toaster)
│ ├── page.tsx # Landing pública (/)
│ ├── error.tsx # Error boundary de ruta
│ ├── global-error.tsx # Error boundary global
│ ├── not-found.tsx # Página 404
│ ├── dashboard/
│ │ └── page.tsx # ⭐ App principal (login + dashboard completo)
│ ├── components/
│ │ ├── TablaPosicionesAfiche.tsx
│ │ ├── PronosticosPartidoAfiche.tsx
│ │ ├── PronosticosTorneoAfiche.tsx
│ │ ├── CentralDatosView.tsx
│ │ ├── TriviaModal.tsx
│ │ └── TerminosCompletos.tsx
│ ├── api/ # 24 endpoints (ver docs/api/)
│ │ ├── admin/ # Cargar/quitar resultados, reliquidar
│ │ ├── auth/ # Registro, login, reset password
│ │ ├── ai/ # Trivia, oráculo, crónica, noticias
│ │ ├── consolidados/ # Datos consolidados + export Excel
│ │ ├── cron/ # Sincronización automática ESPN
│ │ ├── datos-maestros/ # Equipos, partidos, jugadores
│ │ ├── guardar-pronosticos/
│ │ ├── sync-live/ # Marcadores en tiempo real
│ │ └── validar-usuario/ # Autenticación por sesión
│ ├── construccion/ # Página "en construcción"
│ ├── recuperar-password/
│ ├── restablecer-password/
│ └── terminos/ # Términos y condiciones
├── .env.example
├── .gitignore
├── next.config.mjs
├── package.json
└── tsconfig.json
erDiagram
Rol ||--o{ Usuario : tiene
Usuario ||--o| PrediccionInicial : crea
Usuario ||--o{ PrediccionPartido : envía
Usuario ||--o{ Puntaje : acumula
Usuario ||--o{ ResultadoOficial : ingresa
Equipo ||--o{ Jugador : tiene
Equipo ||--o{ Partido : "juega como local"
Equipo ||--o{ Partido : "juega como visitante"
Partido ||--o| ResultadoOficial : tiene
Partido ||--o{ PrediccionPartido : recibe
Partido ||--o{ Puntaje : genera
ResultadoOficial ||--o{ ResultadoGoleador : registra
Jugador ||--o{ ResultadoGoleador : anotó
PrediccionInicial ||--o{ PrediccionClasificado : incluye
| Modelo | Descripción |
|---|---|
Usuario | Participantes y administradores (con sesión por token) |
Equipo | 20 equipos de la Liga BetPlay |
Jugador | Jugadores por equipo (para predicción de goleador) |
Partido | Calendario completo con estados (programado → puntaje_calculado) |
PrediccionInicial | Predicciones de torneo (campeón, finalistas, clasificados, goleador) |
PrediccionPartido | Marcador predicho + goleador por partido |
ResultadoOficial | Marcador real + goleadores reales |
Puntaje | Puntos otorgados por categoría por partido |
| Categoría | Puntos | Condición |
|---|---|---|
| Ganador / Empate | 3 | Acertar quién gana (o empate) |
| Marcador Exacto | 5 | Acertar el marcador exacto (adicional al ganador) |
| Goleador | 2 | Acertar a uno de los goleadores del partido |
| Clasificados a Cuadrangulares | 3 c/u | Por cada equipo acertado de los 8 clasificados |
| Finalistas | 5 c/u | Acertar los 2 finalistas |
| Campeón | 10 | Acertar el campeón del torneo |
| Goleador del Torneo | 5 | Acertar al máximo goleador |
ℹ️ Ver documentación detallada en
docs/reglas-puntuacion.md.
| Comando | Descripción |
|---|---|
npm run dev | Servidor de desarrollo (puerto 3001) |
npm run build | Build de producción (prisma generate + next build) |
npm run start | Servidor de producción (puerto 3001) |
npm run db:generate | Regenerar Prisma Client |
npm run db:studio | Abrir Prisma Studio (GUI de BD) |
El repositorio está conectado a Hostinger con deploy automático vía GitHub:
npm run build automáticamente⚠️ Importante: El build de Hostinger puede fallar silenciosamente. Después de cada push, verificar que el sitio cargue correctamente en club90minutos.com.
Configurar las mismas variables del .env en el panel de hPanel → Node.js → Variables de entorno.
La app se conecta a la API pública de ESPN para:
/api/sync-live): Actualiza los marcadores de partidos en curso automáticamente.STATUS_FULL_TIME, el sistema calcula los puntos de todos los participantes automáticamente./api/cron/espn): Endpoint diseñado para ser llamado por un cron job externo cada N minutos durante la jornada.localStorage (sin JWT).next.config.mjs.bcryptjs.participante y administrador — el panel de admin solo es visible para rol administrador.Proyecto privado. Todos los derechos reservados.