Futbol Veritabanı
8대 리그 클럽·선수·통계—Transfermarkt 데이터
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
📖 Caso de estudio : el problema, las decisiones técnicas y lo que aprendí construyéndola 🎾 Demo con datos ficticios (jugadores de Los Simpson): pide las cuentas de prueba Inicio · Mixing · Sorteo · Publicar partido (demo con datos ficticios) ▶ Recorrido en vídeo (67 s) · starpoint es una PWA para un grupo de pádel: mixings semanales con sorteo de parejas, partidos publicados para buscar jugadores, ranking ELO y validación de resultados. Construida con Next.js 16, Supabase y Emotion, pensada solo para móvil.README 전문 보기 ↗
starpoint es una PWA para un grupo de pádel: mixings semanales con sorteo de parejas, partidos publicados para buscar jugadores, ranking ELO y validación de resultados. Construida con Next.js 16, Supabase y Emotion, pensada solo para móvil.
pg_cron llama cada 15 minutos a /api/cron/generate-draws, que sortea y publica los mixing abiertos y completos (se queda con el mejor de 10 intentos, con las primeras pistas del club) y avisa a jugadores y admins. Si faltan jugadores no genera nada, avisa a los admins y reintenta hasta el inicio. El admin puede sortear a mano antes, y tras un Rehacer el automático no vuelve a actuar. Se apaga con AUTO_DRAW=false.Cualquier jugador puede publicar un partido (club, fecha, hora y cuántas palas busca, de 1 a 3) para completar sus 4 jugadores y 90 minutos, con un comentario opcional ("necesitamos una chica", "buscamos un revés"…). Se avisa al grupo por notificación push, aparece en "Lo que viene" y los demás se apuntan o se borran. Sin sorteo ni resultados.
La pantalla del partido muestra siempre los 4 puestos: el organizador, los jugadores que ya tiene cerrados fuera de la app (con el nombre que él les ponga), los que se apuntan y las plazas libres. El organizador puede añadir jugadores de fuera del grupo, renombrarlos o quitarlos, editar el partido o cancelarlo; desaparece al terminar.
Publicar escribiéndolo o dictándolo, con IA (solo en la demo). Encima del formulario hay una caja donde se describe el partido con palabras ("busco 2 para el jueves a las 19:00 en Padel Indoor, mejor un revés") o se dicta con el micrófono, y Claude Haiku 4.5 rellena el formulario. Nunca publica: el jugador revisa y publica.
ai_requests.src/lib/config.ts). El cálculo y la actualización de los 4 perfiles, el historial y el estado del partido ocurren en una única transacción de PostgreSQL (confirm_match_atomic).| Rol | Capacidades |
|---|---|
| Jugador | Inscribirse a mixings y partidos, publicar partidos, introducir y confirmar resultados, ver su historial |
| Admin | Todo lo anterior, más: crear y editar eventos, gestionar participantes e invitados, sorteo, partidos pendientes de todo el grupo, exclusiones y jugadores |
Un admin empieza en la vista de jugador y cambia a la de administración desde el menú del avatar (solo los admins tienen ese menú; el resto usa la pestaña Perfil). El registro de usuarios está cerrado: solo existen cuentas creadas por un admin.
Supabase Realtime en eventos, partidos e inscripciones; notificaciones push; instalable en pantalla de inicio. Al abrir la app desde cero se ve una splash animada (una vez por sesión) y los enlaces compartidos llevan una imagen de marca.
| Capa | Tecnología |
|---|---|
| Frontend | Next.js 16 (App Router), React 19 |
| Estilos | Emotion (tema claro y oscuro, con escalas cerradas de espaciado y tipografía, en src/theme.ts) |
| Backend / BD | Supabase (PostgreSQL, Auth, Realtime, RLS) |
| Despliegue | Vercel (cron semanal); pg_cron de Supabase para el cierre y el sorteo automáticos |
| Formularios | React Hook Form + Zod v4 |
| Iconos | Lucide React |
| IA | Claude Haiku 4.5 con el SDK de Anthropic (salidas estructuradas), Web Speech API para el dictado |
src/
├── app/ # Rutas: / · /mixing · /partido · /events/[id] · /history · /profile · /admin/*
│ ├── actions/ # Server Actions (events, matches, mixing-generator, admin-*, users…)
│ └── api/cron/ # create-weekly-event, close-pending-matches, generate-draws
├── components/
│ ├── atoms/ # Button, Input, Avatar, Select, Switch…
│ ├── molecules/ # Header, TabBar, Dialog, PlayerList, CourtCard…
│ └── organisms/ # EventOpenView, EventDrawView, EventGenerator, MatchEventView…
├── lib/ # rating-logic, mixing-algorithm, auto-draw, draw-publish, confirm-match, match-parser…
└── theme.ts # Tokens de diseño
supabase/ # Esquema completo, migraciones y jobs de pg_cron (se aplican a mano)
docs/ # Caso de estudio (es/en) y capturas
Más contexto técnico (reglas de privacidad, base de datos, convenciones y flujo de trabajo) en AGENT.md.
# 1. Clonar
git clone https://github.com/amat3/star-point.git
cd star-point
# 2. Instalar dependencias
npm install
# 3. Variables de entorno: crea .env.local con las claves de abajo
# 4. Desarrollo
npm run dev
NEXT_PUBLIC_SUPABASE_URL=https://xxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
SUPABASE_SERVICE_ROLE_KEY=eyJ... # solo servidor: operaciones de admin y cron
CRON_SECRET=... # protege /api/cron/*
NEXT_PUBLIC_VAPID_PUBLIC_KEY=... # notificaciones push
VAPID_PRIVATE_KEY=...
VAPID_SUBJECT=mailto:...
TEST_PUSH_USER_IDS=id1,id2 # opcional: quién recibe los avisos de los eventos de prueba
WEEKLY_EVENT_CREATED_BY=id # opcional: autor del evento semanal (por defecto, el primer admin)
PUSH_DISABLED=true # opcional, solo en local: no se envía ninguna notificación
AUTO_DRAW=false # opcional: apaga el sorteo automático sin redesplegar
NEXT_PUBLIC_DEMO=true # solo en el despliegue de demo: muestra el aviso, no crea eventos ni sortea solo y activa el relleno con IA
ANTHROPIC_API_KEY=sk-ant-... # solo en la demo: el relleno del partido con IA
AI_MATCH_PARSER=false # opcional: apaga el relleno con IA (mock, solo en local: respuestas de ejemplo sin llamar a la API)
El esquema completo está en supabase/supabase_schema_full.sql. Las migraciones y los jobs de pg_cron (cierre automático y sorteo automático) están en la misma carpeta, y se aplican a mano en Supabase. Los jobs llevan el marcador <CRON_SECRET>: el valor real se pone al ejecutarlos y nunca se sube al repositorio. Más detalles en AGENT.md.
La demo (datos ficticios de Los Simpson) es otro proyecto de Supabase y otro despliegue de Vercel con el mismo código y NEXT_PUBLIC_DEMO=true. Se reconstruye desde cero con npx tsx src/scripts/seed-demo.ts --apply --reset: solo lee .env.demo.local y se niega a ejecutarse contra cualquier otro proyecto.
rating-logic.test.ts), algoritmo de sorteo (mixing-algorithm.test.ts), sorteo automático (ventana de 3 horas y elección del mejor sorteo, auto-draw.test.ts), textos de la inscripción (event-capacity.test.ts), validación de lo que devuelve la IA (match-parser.test.ts) y utilidades de fechas y rondas (utils.test.ts).npx -y tsx src/scripts/eval-match-parser.ts (16 frases con los campos esperados, unos 5 céntimos por pasada).npm run test (una vez) / npm run test:watch (modo watch)..github/workflows/ci.yml) ejecuta en cada push a main y en cada PR: tsc --noEmit → eslint → vitest run → next build.e2e/, npm run test:e2e): 33 tests, 18 de ellos de accesibilidad (axe-core, WCAG 2.2 AA, en tema claro y oscuro, sin ningún problema de contraste ni de etiquetas; tutorial de cómo funciona axe), más los flujos reales: portada pública y redirección al login, acceso, la splash, publicar un partido, apuntarse y desapuntarse con otro usuario y cancelarlo. Corren solo contra la demo (una comprobación se niega a ejecutarse contra cualquier otra base de datos), usan selectores por rol y por etiqueta, y borran los partidos que crean aunque un test falle. Se ejecutan a mano en GitHub Actions (e2e.yml), contra la demo (la ejecución semanal está preparada y desactivada hasta que se den de alta sus secretos), y no en cada push para que una respuesta lenta de la base de datos no ponga el repositorio en rojo.Los parámetros del ELO se centralizan en src/lib/config.ts:
K_PROVISIONAL: 0.40 // K para jugadores con < 10 partidos
K_ESTABLISHED: 0.15 // K para jugadores establecidos
PROVISIONAL_LIMIT: 10 // Partidos para considerarse establecido
DISPARITY_FULL: 1.0 // Gap ≤ 1.0 → partido vale 100%
DISPARITY_ZERO: 2.5 // Gap ≥ 2.5 → partido vale 0%
DAMPENING_START: 4.5 // Desde aquí se reduce la volatilidad
DAMPENING_END: 6.5 // Aquí K queda al 60%
MATCH_WEIGHT: 0.70 // Peso del margen del resultado (subido desde 0.40 en jul-2026)
MIN_RATING: 0
MAX_RATING: 7
INITIAL_RATING: 3.5
Un cambio de parámetros puede recalcularse con carácter retroactivo sobre todo el historial con src/scripts/retroactive-match-weight.ts (dry-run por defecto).
Código publicado solo para consulta, como muestra de portfolio. Todos los derechos reservados: no se permite copiarlo, modificarlo ni reutilizarlo sin autorización por escrito. Ver LICENSE.
Creado con ❤️ para la comunidad de pádel.