🎯 Plan de Implementación Incremental - PuntoHack MVP
⚠️ Filosofía: Un Módulo a la Vez, 100% Completo
Regla de Oro: NO avanzar al siguiente módulo hasta que el actual esté:
- ✅ Implementado completamente
- ✅ Probado (tests >80% coverage)
- ✅ Verificado funcionando
- ✅ Documentado
Objetivo: Evitar el caos de múltiples módulos a medias. Cada módulo debe ser una base sólida para el siguiente.
📋 Orden de Implementación (Por Dependencias)
Core Layer
↓
Users Module
↓
Hackathons Module
↓
Teams Module ──┐
↓ │
Submissions ────┤
↓ │
Evaluation ────┤
↓ │
Sponsors ───────┘
🏗️ MÓDULO 0: Core Layer (Base de Todo)
Objetivo: Infraestructura fundamental que todos los módulos usarán.
Checklist de Completitud
1. Configuración Inicial
- Proyecto Next.js 16 creado con Turbopack
- TypeScript configurado (strict mode)
- Tailwind CSS 4 configurado
- ESLint + Prettier configurados
- Estructura de carpetas base creada
2. Database Setup
- Proyecto Supabase creado
- Connection string configurado en
.env - Prisma inicializado
- Schema básico (solo
Profilemodel por ahora) - Migración ejecutada (
pnpm prisma db push) - Prisma Studio funciona
3. Core Files (5 archivos)
src/core/db.ts
- Prisma Client singleton implementado
- Test de conexión funciona
src/core/auth.ts
- Clerk configurado
-
getCurrentUser()implementado - Middleware de autenticación configurado
- Test básico funciona
src/core/rbac.ts
-
hasRole()implementado -
requireRole()implementado - Type
Userdefinido - Tests de RBAC pasan
src/core/errors.ts
-
captureError()implementado - Sentry configurado (o mock para dev)
- Test básico funciona
src/core/validations.ts
-
validateHackathonDates()implementado -
validateDateExtension()implementado -
hackathonDatesSchema(Zod) creado - Tests de validaciones pasan
4. Testing Setup
- Vitest configurado
-
tests/setup.tscreado -
tests/test-utils.tsxcreado - Tests de Core Layer pasan (>80% coverage)
5. UI Mínima
- Landing page (
/) básica - Páginas de auth (
/sign-in,/sign-up) con Clerk - Layout principal con ClerkProvider
✅ Criterio de Completitud Módulo 0
DEBE funcionar:
- ✅
getCurrentUser()retorna usuario autenticado - ✅
requireRole()bloquea acceso no autorizado - ✅
validateHackathonDates()valida orden de fechas - ✅ Tests pasan con >80% coverage
- ✅ No hay errores de TypeScript
- ✅ Prisma se conecta a Supabase
NO avanzar hasta que TODO esto funcione.
👤 MÓDULO 1: Users Module
Dependencias: Core Layer ✅
Objetivo: Gestión completa de usuarios y perfiles.
Checklist de Completitud
1. Schema Prisma
- Model
Profilecompleto en schema - Enum
Roledefinido - Relaciones básicas definidas
- Migración ejecutada
2. Module Files (4 archivos)
src/modules/users/queries.ts
-
getUserByClerkId(userId: string) -
getProfileById(id: string) -
listProfiles(filters?: { role?: Role; limit?: number }) - Tests de queries pasan
src/modules/users/actions.ts
-
createProfile(formData: FormData)- Server Action- Valida RBAC (cualquiera puede crear su perfil)
- Valida con Zod
- Crea Profile en DB
- Revalida cache
-
updateUserRole(profileId: string, newRole: Role)- Server Action- Valida RBAC (solo ADMIN/ORGANIZER)
- Valida que ADMIN solo puede asignar ADMIN
- Actualiza role
- Revalida cache
- Tests de actions pasan
src/modules/users/validations.ts
-
createProfileSchema(Zod) -
updateUserRoleSchema(Zod) - Tests de validaciones pasan
src/modules/users/types.ts
- Types TypeScript exportados
- Types usados en queries/actions
3. Testing
- Tests de queries (100% coverage)
- Tests de actions (100% coverage)
- Tests de validations (100% coverage)
- Tests de RBAC (solo ADMIN puede cambiar roles)
- Coverage total >80%
4. UI Funcional
-
/onboarding- Formulario crear perfil- HTML nativo + Server Action
- Validación solo servidor
- Redirige a
/dashboarddespués
-
/dashboard- Panel básico (redirección por rol) -
/admin/users- Tabla de usuarios (solo ADMIN)- Lista usuarios
- Dropdown cambiar rol (Client Component mínimo)
- Server Action actualiza rol
✅ Criterio de Completitud Módulo 1
DEBE funcionar:
- ✅ Usuario puede crear perfil en onboarding
- ✅ Admin puede ver lista de usuarios
- ✅ Admin puede cambiar roles
- ✅ RBAC bloquea acciones no autorizadas
- ✅ Tests pasan con >80% coverage
- ✅ No hay errores de TypeScript
NO avanzar hasta que TODO esto funcione.
🎪 MÓDULO 2: Hackathons Module
Dependencias: Core Layer ✅, Users Module ✅
Objetivo: CRUD completo de hackathons con criterios y estados.
Checklist de Completitud
1. Schema Prisma
- Model
Hackathoncompleto - Model
Criterioncompleto - Model
HackathonParticipationcompleto - Enum
HackathonStatusdefinido - Relaciones definidas
- Migración ejecutada
2. Module Files (4 archivos)
src/modules/hackathons/queries.ts
-
getHackathon(slug: string) -
getHackathonById(id: string) -
listHackathons(filters?: { status?: HackathonStatus[] }) -
getOrganizerHackathons(userId: string) - Tests de queries pasan
src/modules/hackathons/actions.ts
-
createHackathon(formData: FormData)- RBAC: solo ORGANIZER/ADMIN
- Valida orden de fechas con
validateHackathonDates() - Crea Hackathon + Criteria en transaction
- Revalida cache
-
updateHackathon(id: string, formData: FormData)- RBAC: solo ORGANIZER/ADMIN (owner)
- Valida fechas
- Actualiza
-
deleteHackathon(id: string)- RBAC: solo ORGANIZER/ADMIN (owner)
- Soft delete o hard delete
-
registerForHackathon(hackathonId: string)- RBAC: solo PARTICIPANT
- Valida estado REGISTRATION
- Valida fechas de registro
- Crea HackathonParticipation
-
unregisterFromHackathon(hackathonId: string)- RBAC: solo PARTICIPANT
- Elimina participation
-
addCriterion(hackathonId: string, data: CriterionInput) -
updateCriterion(id: string, data: CriterionInput) -
deleteCriterion(id: string) - Tests de actions pasan
src/modules/hackathons/validations.ts
-
createHackathonSchema(Zod) -
criterionSchema(Zod) - Integración con
validateHackathonDates() - Tests de validaciones pasan
src/modules/hackathons/types.ts
- Types TypeScript exportados
3. Cron Job
-
src/app/api/cron/update-hackathon-states/route.tsimplementado -
vercel.jsonconfigurado -
CRON_SECRETen variables de entorno - Test manual del cron funciona
4. Testing
- Tests de queries (100% coverage)
- Tests de actions (100% coverage)
- Tests de validaciones (100% coverage)
- Tests de RBAC
- Tests de validación de fechas
- Coverage total >80%
5. UI Funcional
-
/hackathons- Lista pública- Filtro por status
- Server Component
-
/hackathons/[slug]- Detalle público- Muestra info del hackathon
- Botón "Registrarse" (si PARTICIPANT y REGISTRATION)
-
/admin/hackathons/create- Crear hackathon- Formulario HTML + Server Action
- Campos: name, slug, description, fechas, criterios
- Validación de fechas en servidor
-
/admin/hackathons/[slug]- Editar hackathon- Formulario pre-llenado
- Server Action actualiza
-
/admin/hackathons/[slug]/dashboard- Panel organizador- Stats básicas (participantes, equipos, submissions)
- Lista de participantes
✅ Criterio de Completitud Módulo 2
DEBE funcionar:
- ✅ ORGANIZER puede crear hackathon completo
- ✅ Participantes pueden registrarse
- ✅ Cron job cambia estados automáticamente
- ✅ Validación de fechas funciona
- ✅ Tests pasan con >80% coverage
- ✅ No hay errores de TypeScript
NO avanzar hasta que TODO esto funcione.
👥 MÓDULO 3: Teams Module
Dependencias: Core Layer ✅, Users Module ✅, Hackathons Module ✅
Objetivo: Sistema de equipos con códigos de invitación.
Checklist de Completitud
1. Schema Prisma
- Model
Teamcompleto - Model
TeamMembercompleto - Relaciones definidas
- Migración ejecutada
2. Module Files (4 archivos)
src/modules/teams/queries.ts
-
getTeamById(id: string) -
getTeamByCode(code: string) -
getUserTeam(hackathonId: string, userId: string) -
listTeamsByHackathon(hackathonId: string) - Tests de queries pasan
src/modules/teams/actions.ts
-
createTeam(hackathonId: string, data: CreateTeamInput)- RBAC: solo PARTICIPANT
- Valida que usuario está registrado en hackathon
- Valida que no tiene otro equipo
- Valida fechas (solo hasta
submissionDeadline) - Genera código único
- Crea Team + TeamMember
-
joinTeam(inviteCode: string)- RBAC: solo PARTICIPANT
- Valida código existe
- Valida cupo disponible
- Valida fechas
- Crea TeamMember
-
leaveTeam(teamId: string)- RBAC: solo PARTICIPANT (miembro del equipo)
- Valida fechas
- Si equipo queda vacío y sin submission → elimina Team
- Si equipo tiene submission → no permite salir al último miembro
- Elimina TeamMember
- Tests de actions pasan
src/modules/teams/validations.ts
-
createTeamSchema(Zod) -
joinTeamSchema(Zod) - Tests de validaciones pasan
src/modules/teams/types.ts
- Types TypeScript exportados
3. Testing
- Tests de queries (100% coverage)
- Tests de actions (100% coverage)
- Tests de validaciones (100% coverage)
- Tests de reglas de negocio (leave team, empty team)
- Coverage total >80%
4. UI Funcional
-
/hackathons/[slug]/teams- Gestión de equipos- Tab "Crear equipo" (formulario)
- Tab "Unirse a equipo" (input código)
- Muestra código de invitación
-
/hackathons/[slug]/my-team- Mi equipo- Lista miembros
- Botón "Salir del equipo" (hasta deadline)
✅ Criterio de Completitud Módulo 3
DEBE funcionar:
- ✅ Participantes pueden crear equipos
- ✅ Participantes pueden unirse con código
- ✅ Participantes pueden salir (con reglas de negocio)
- ✅ Códigos de invitación únicos
- ✅ Tests pasan con >80% coverage
- ✅ No hay errores de TypeScript
NO avanzar hasta que TODO esto funcione.
📝 MÓDULO 4: Submissions Module
Dependencias: Core Layer ✅, Users Module ✅, Hackathons Module ✅, Teams Module ✅
Objetivo: Sistema de envío y edición de proyectos.
Checklist de Completitud
1. Schema Prisma
- Model
Submissioncompleto - Relación con
Challenge(opcional) - Relaciones definidas
- Migración ejecutada
2. Module Files (4 archivos)
src/modules/submissions/queries.ts
-
getSubmissionById(id: string) -
getSubmissionByTeam(teamId: string) -
listSubmissionsByHackathon(hackathonId: string) - Tests de queries pasan
src/modules/submissions/actions.ts
-
createSubmission(hackathonId: string, data: CreateSubmissionInput)- RBAC: solo PARTICIPANT (miembro del equipo)
- Valida estado RUNNING
- Valida
now < submissionDeadline - Valida tamaño equipo >= minTeamSize
- Valida equipo no tiene submission previa
- Crea Submission
-
updateSubmission(id: string, data: UpdateSubmissionInput)- RBAC: solo PARTICIPANT (miembro del equipo)
- Valida
now < submissionDeadline - Valida estado != JUDGING/FINISHED
- Actualiza Submission
- Tests de actions pasan
src/modules/submissions/validations.ts
-
createSubmissionSchema(Zod) -
updateSubmissionSchema(Zod) - Tests de validaciones pasan
src/modules/submissions/types.ts
- Types TypeScript exportados
3. Testing
- Tests de queries (100% coverage)
- Tests de actions (100% coverage)
- Tests de validaciones (100% coverage)
- Tests de bloqueo después de deadline
- Coverage total >80%
4. UI Funcional
-
/hackathons/[slug]/submit- Enviar submission- Formulario HTML + Server Action
- Campos: title, description, repoUrl, demoUrl, challengeId (opcional)
- Countdown a deadline
- Botón "Editar" desaparece después de deadline
-
/hackathons/[slug]/submission- Ver/editar submission- Vista de solo lectura después de deadline
✅ Criterio de Completitud Módulo 4
DEBE funcionar:
- ✅ Equipos pueden enviar proyectos
- ✅ Equipos pueden editar hasta deadline
- ✅ Bloqueo después de deadline funciona
- ✅ Una submission por equipo (constraint DB)
- ✅ Tests pasan con >80% coverage
- ✅ No hay errores de TypeScript
NO avanzar hasta que TODO esto funcione.
⚖️ MÓDULO 5: Evaluation Module
Dependencias: Core Layer ✅, Users Module ✅, Hackathons Module ✅, Teams Module ✅, Submissions Module ✅
Objetivo: Sistema de evaluación con scoring ponderado y leaderboard.
Checklist de Completitud
1. Schema Prisma
- Model
HackathonJudgecompleto - Model
Scorecompleto - Relaciones definidas
- Migración ejecutada
2. Module Files (4 archivos)
src/modules/evaluation/queries.ts
-
getHackathonSubmissionsForJudge(hackathonId: string, judgeId: string) -
getScoresBySubmission(submissionId: string) -
getScoresByJudge(judgeId: string, submissionId: string) -
calculateLeaderboard(hackathonId: string)- Cálculo ponderado - Tests de queries pasan
src/modules/evaluation/actions.ts
-
assignJudge(hackathonId: string, judgeId: string)- RBAC: solo ORGANIZER/ADMIN
- Valida que judge no es participante del hackathon
- Crea HackathonJudge
-
submitScore(submissionId: string, criterionId: string, value: number, comment?: string)- RBAC: solo JUDGE
- Valida asignación existe
- Valida hackathon en estado JUDGING
- Valida value entre 0 y maxScore
- UPSERT Score (unique constraint)
- Tests de actions pasan
src/modules/evaluation/validations.ts
-
submitScoreSchema(Zod) - Tests de validaciones pasan
src/modules/evaluation/types.ts
- Types TypeScript exportados
- Type
LeaderboardEntry
3. Testing
- Tests de queries (100% coverage)
- Tests de actions (100% coverage)
- Tests de validaciones (100% coverage)
- Tests de cálculo de leaderboard (ponderado)
- Tests de aislamiento de scores (juez no ve otros)
- Coverage total >80%
4. UI Funcional
-
/admin/hackathons/[slug]/judges- Asignar jueces- Lista de profiles con role JUDGE
- Checkbox seleccionar jueces
- Server Action asigna
-
/judge/hackathons/[slug]- Panel de juez- Lista submissions del hackathon asignado
- Solo visible cuando estado JUDGING
-
/judge/hackathons/[slug]/evaluate/[submissionId]- Evaluar- Formulario por criterio
- Input numérico (0-maxScore)
- Textarea comentario opcional
- Server Action guarda scores
-
/hackathons/[slug]/leaderboard- Leaderboard público- Solo visible cuando estado FINISHED
- Muestra ranking con puntaje ponderado
✅ Criterio de Completitud Módulo 5
DEBE funcionar:
- ✅ ORGANIZER puede asignar jueces
- ✅ Jueces pueden evaluar submissions
- ✅ Leaderboard calcula correctamente (ponderado)
- ✅ Juez no ve scores ajenos durante JUDGING
- ✅ Tests pasan con >80% coverage
- ✅ No hay errores de TypeScript
NO avanzar hasta que TODO esto funcione.
🏆 MÓDULO 6: Sponsors Module
Dependencias: Core Layer ✅, Users Module ✅, Hackathons Module ✅, Teams Module ✅, Submissions Module ✅
Objetivo: Sistema de sponsors, challenges y shortlist.
Checklist de Completitud
1. Schema Prisma
- Model
Organizationcompleto - Model
OrganizationMembercompleto - Model
Sponsorshipcompleto - Model
Challengecompleto - Model
ShortlistItemcompleto - Enums definidos
- Relaciones definidas
- Migración ejecutada
2. Module Files (4 archivos)
src/modules/sponsors/queries.ts
-
getOrganizationById(id: string) -
getSponsorshipsByHackathon(hackathonId: string) -
getChallengesBySponsorship(sponsorshipId: string) -
getSubmissionsByChallenge(challengeId: string) -
getShortlistByOrganization(organizationId: string) - Tests de queries pasan
src/modules/sponsors/actions.ts
-
createOrganization(data: CreateOrgInput)- RBAC: solo SPONSOR/ADMIN
- Crea Organization + OrganizationMember (owner)
-
createSponsorship(hackathonId: string, data: CreateSponsorshipInput)- RBAC: solo SPONSOR (miembro de org)
- Crea Sponsorship
-
createChallenge(sponsorshipId: string, data: CreateChallengeInput)- RBAC: solo SPONSOR (miembro de org)
- Crea Challenge
-
shortlistSubmission(submissionId: string, organizationId: string, challengeId: string, notes?: string)- RBAC: solo SPONSOR (miembro de org)
- Valida submission eligió su challenge
- Crea ShortlistItem (unique constraint)
- Tests de actions pasan
src/modules/sponsors/validations.ts
-
createOrganizationSchema(Zod) -
createSponsorshipSchema(Zod) -
createChallengeSchema(Zod) - Tests de validaciones pasan
src/modules/sponsors/types.ts
- Types TypeScript exportados
3. Testing
- Tests de queries (100% coverage)
- Tests de actions (100% coverage)
- Tests de validaciones (100% coverage)
- Tests de RBAC
- Coverage total >80%
4. UI Funcional
-
/sponsor/organizations/create- Crear organización -
/sponsor/sponsorships/create- Crear sponsorship -
/sponsor/challenges/create- Crear challenge -
/sponsor/challenges/[id]/submissions- Ver submissions del challenge -
/sponsor/shortlist- Ver shortlist- Botón "Contactar equipo" (email vía Clerk)
✅ Criterio de Completitud Módulo 6
DEBE funcionar:
- ✅ Sponsors pueden crear organizaciones
- ✅ Sponsors pueden crear sponsorships y challenges
- ✅ Sponsors pueden shortlist proyectos
- ✅ Sponsors pueden contactar equipos
- ✅ Tests pasan con >80% coverage
- ✅ No hay errores de TypeScript
NO avanzar hasta que TODO esto funcione.
📊 Proceso de Verificación Después de Cada Módulo
Checklist de Verificación
Antes de marcar un módulo como "completo", verificar:
-
Código:
- Todos los archivos del módulo implementados
- No hay errores de TypeScript
- No hay errores de ESLint
- Código sigue convenciones del proyecto
-
Tests:
- Tests pasan (
pnpm test) - Coverage >80% (
pnpm test:coverage) - Tests de RBAC incluidos
- Tests de validaciones incluidos
- Tests pasan (
-
Funcionalidad:
- UI funciona (probar manualmente)
- Server Actions funcionan
- RBAC bloquea acciones no autorizadas
- Validaciones funcionan
-
Base de Datos:
- Schema actualizado
- Migración ejecutada
- No hay errores de Prisma
-
Documentación:
- Código comentado donde es necesario
- Funciones complejas documentadas
Comando de Verificación Rápida
# Ejecutar después de cada módulo
pnpm type-check # Verificar TypeScript
pnpm lint # Verificar ESLint
pnpm test # Ejecutar tests
pnpm test:coverage # Verificar coverage
pnpm build # Verificar que compila
🚨 Reglas Estrictas
❌ NO Hacer
- NO empezar un módulo nuevo si el anterior no está 100% completo
- NO implementar features de múltiples módulos a la vez
- NO saltar tests "por ahora"
- NO avanzar con errores de TypeScript
- NO implementar features no documentadas
✅ SÍ Hacer
- SÍ completar un módulo antes de pasar al siguiente
- SÍ escribir tests desde el inicio
- SÍ verificar que todo funciona antes de avanzar
- SÍ seguir el orden de dependencias
- SÍ pedir ayuda si hay dudas
📝 Notas de Implementación
Orden de Archivos Dentro de Cada Módulo
- Schema Prisma (si aplica)
- Types (
types.ts) - Validations (
validations.ts) - Queries (
queries.ts) - Actions (
actions.ts) - Tests (paralelo con implementación)
- UI (al final, cuando todo funciona)
Patrón de Server Action
Siempre seguir este patrón:
'use server';
export async function myAction(formData: FormData) {
try {
// 1. Auth
const user = await getCurrentUser();
if (!user) throw new Error('Unauthorized');
// 2. RBAC
requireRole(user, ['ORGANIZER']);
// 3. Validate
const validated = schema.parse(data);
// 4. Business Logic
const result = await db.model.create({ data: validated });
// 5. Revalidate
revalidatePath('/path');
return { success: true, data: result };
} catch (error) {
captureError(error, { context: 'myAction' });
return { success: false, error: error.message };
}
}
🎯 Resumen del Plan
Módulo 0: Core Layer → Base de todo
Módulo 1: Users → Depende de Core
Módulo 2: Hackathons → Depende de Core + Users
Módulo 3: Teams → Depende de Core + Users + Hackathons
Módulo 4: Submissions → Depende de Core + Users + Hackathons + Teams
Módulo 5: Evaluation → Depende de todos los anteriores
Módulo 6: Sponsors → Depende de Core + Users + Hackathons + Teams + Submissions
Total estimado: 4-5 semanas (siguiendo este orden estricto)
Última Actualización: 30 de diciembre, 2025
Versión: 1.0 - Plan de Implementación Incremental
Filosofía: Un módulo a la vez, 100% completo antes de avanzar