📧 Sistema de Invitaciones por Email - Sin Envío Real
Fecha: 1 de enero, 2025
Estado: ✅ IMPLEMENTADO Y FUNCIONANDO
🎯 Cómo Funciona
Flujo Completo:
-
Participante crea equipo (
/hackathons/[slug]/teams/create)- Ingresa nombre del equipo
- (Opcional) Ingresa emails de compañeros en el campo "Invitar Participantes por Email"
- Puede agregar hasta 10 emails
-
Validación en el Cliente (Formulario)
- ✅ Valida formato de email (HTML5
type="email") - ✅ Filtra emails vacíos antes de enviar
- ✅ Valida formato de email (HTML5
-
Validación en el Servidor (Zod)
- ✅ Valida formato de email con
.email('Email inválido') - ✅ Valida que no sean más de 10 emails
- ✅ Valida formato de email con
-
Validación de Existencia y Disponibilidad
- ✅ Verifica que cada email exista en la DB (tabla
Profile) - ✅ Verifica que el usuario esté registrado en el hackathon
- ✅ Verifica que no tenga equipo en ese hackathon
- ✅ Verifica que no haya invitación pendiente ya
- ✅ Verifica que cada email exista en la DB (tabla
-
Creación de Notificación en DB
- ✅ Crea registro en
TeamInvitationcon:email: Email del invitadoteamId: ID del equiposenderId: ID del que envíareceiverId: ID del invitado (si existe en DB)status:PENDING
- ✅ Crea registro en
-
Consulta de Notificaciones
- ✅ Se puede consultar por email:
getPendingInvitationsByEmail(email) - ✅ Se puede consultar por profileId:
getPendingInvitationsByProfileId(profileId) - ✅ Se muestra en
/notificationscuando el usuario inicia sesión
- ✅ Se puede consultar por email:
✅ Lo que SÍ hace:
- ✅ Valida formato de email (Zod)
- ✅ Verifica existencia en DB (Profile)
- ✅ Verifica registro en hackathon
- ✅ Verifica disponibilidad (sin equipo)
- ✅ Crea notificación en DB (
TeamInvitation) - ✅ Consulta por email en DB
- ✅ Muestra en página de notificaciones
❌ Lo que NO hace:
- ❌ NO envía emails reales (no SMTP, no IMAP, no servicios de email)
- ❌ NO usa servicios externos de notificaciones por email
- ❌ NO requiere configuración de servidor de email
📋 Código Relevante
1. Formulario (create-team-form.tsx)
// Estado para emails
const [inviteEmails, setInviteEmails] = useState<string[]>(['']);
// Al enviar, filtra emails vacíos
const validEmails = inviteEmails.filter(email => email.trim() !== '');
const data: CreateTeamInput = {
name: formData.get('name') as string,
description: (formData.get('description') as string) || undefined,
inviteEmails: validEmails.length > 0 ? validEmails : undefined,
};
2. Validación (Zod) (validations.ts)
export const createTeamSchema = z.object({
name: z.string().min(3).max(100),
description: z.string().max(500).optional(),
inviteEmails: z
.array(z.string().email('Email inválido')) // ✅ Valida formato
.max(10, 'No puedes invitar más de 10 participantes')
.optional(),
});
3. Validación de Existencia (invitations/actions.ts)
// 12. Clasificar emails: existentes vs no existentes en BD
const existingProfiles = await db.profile.findMany({
where: {
email: { in: normalizedEmails }, // ✅ Busca en DB
},
});
// 13. Validar registro en hackathon
const participations = await db.hackathonParticipation.findMany({
where: {
hackathonId: team.hackathonId,
profileId: { in: existingProfileIds },
},
});
// 14. Validar que no tengan equipo
const hasTeamChecks = await Promise.all(
registeredProfileIdsList.map(profileId =>
hasTeamInHackathon(profileId, team.hackathonId)
)
);
4. Creación de Notificación (invitations/actions.ts)
// Crear invitación en DB
const invitation = await db.teamInvitation.create({
data: {
teamId: team.id,
email, // ✅ Email del invitado
senderId: currentUserProfile.id,
receiverId: profile.id, // ✅ ID del perfil (si existe)
status: TeamInvitationStatus.PENDING,
},
});
5. Consulta por Email (invitations/queries.ts)
export async function getPendingInvitationsByEmail(
email: string
): Promise<TeamInvitationWithRelations[]> {
return db.teamInvitation.findMany({
where: {
email, // ✅ Consulta por email
status: TeamInvitationStatus.PENDING,
},
include: {
team: { /* ... */ },
sender: { /* ... */ },
receiver: { /* ... */ },
},
});
}
🧪 Cómo Probar
1. Crear Equipo con Invitaciones
- Inicia sesión como
PARTICIPANT - Ve a un hackathon en estado
REGISTRATIONoRUNNING - Haz clic en "Crear Equipo"
- Ingresa nombre del equipo
- En "Invitar Participantes por Email", agrega emails:
test.participant2@example.comtest.participant3@example.com
- Haz clic en "Crear Equipo"
2. Verificar Notificaciones
- Inicia sesión como
test.participant2@example.com - Ve a
/notifications - Deberías ver la invitación pendiente
- Puedes aceptar o rechazar
3. Verificar en DB
-- Ver invitaciones pendientes
SELECT * FROM "TeamInvitation"
WHERE status = 'PENDING';
-- Ver invitaciones por email
SELECT * FROM "TeamInvitation"
WHERE email = 'test.participant2@example.com'
AND status = 'PENDING';
📊 Resultado de la Invitación
Cuando se invita por email, el sistema retorna:
{
success: true,
data: {
created: 2, // Invitaciones creadas exitosamente
skipped: 0, // Emails omitidos (ya tenían invitación pendiente)
errors: [ // Emails con problemas
{ email: 'noexiste@example.com', reason: 'No existe en la plataforma' },
{ email: 'notregistered@example.com', reason: 'No está registrado en este hackathon' },
{ email: 'hasteam@example.com', reason: 'Ya pertenece a un equipo' },
]
}
}
✅ Confirmación
El sistema funciona EXACTAMENTE como lo solicitaste:
- ✅ Solo valida formato y existencia en DB
- ✅ Crea notificaciones en DB asociadas al email
- ✅ Se puede consultar por email
- ✅ NO envía emails reales
- ✅ NO usa SMTP, IMAP ni servicios externos
Última Actualización: 1 de enero, 2025
Estado: ✅ FUNCIONANDO CORRECTAMENTE