Saltar al contenido principal

👨‍💼 Flujo de Admin

Visión General

El flujo del ADMIN es el más simple conceptualmente pero el más poderoso: acceso completo a todo el sistema sin restricciones ("Dios mode").

Diagrama de Flujo Completo

Características Principales

1. Acceso Completo

ADMIN tiene acceso a TODO sin restricciones de RBAC:

// En cualquier Server Action
export async function adminAction() {
const user = await getCurrentUser();
requireRole(user, ['ADMIN']);

// No hay más validaciones - acceso completo
// Puede hacer cualquier operación
}

2. Cambiar Roles

ADMIN es el único que puede asignar el rol ADMIN:

export async function updateUserRole(profileId: string, newRole: Role) {
const user = await getCurrentUser();
requireRole(user, ['ADMIN']);

// Solo ADMIN puede asignar ADMIN
if (newRole === 'ADMIN' && user.profile.role !== 'ADMIN') {
throw new Error('Only admins can assign ADMIN role');
}

await db.profile.update({
where: { id: profileId },
data: { role: newRole },
});
}

3. Override de Validaciones

ADMIN puede forzar cambios que normalmente no están permitidos:

export async function forceHackathonStatus(
hackathonId: string,
newStatus: HackathonStatus,
skipValidations: boolean = false
) {
const user = await getCurrentUser();
requireRole(user, ['ADMIN']);

if (skipValidations) {
// ⚠️ PELIGRO: Puede romper reglas de negocio
await db.hackathon.update({
where: { id: hackathonId },
data: { status: newStatus },
});
} else {
// Validaciones normales
// ...
}
}

⚠️ Advertencia en UI: Siempre mostrar advertencia cuando ADMIN hace override.

4. Eliminación con Cascade

ADMIN puede eliminar usuarios y hackathons, lo que elimina en cascade:

export async function deleteUser(profileId: string) {
const user = await getCurrentUser();
requireRole(user, ['ADMIN']);

// ⚠️ CASCADE DELETE:
// - HackathonParticipation
// - TeamMember
// - Score
// - HackathonJudge
// - OrganizationMember
// - Notification
// - etc.

await db.profile.delete({
where: { id: profileId },
});
}

Casos de Uso Detallados

CU-1: Gestionar Usuarios

Actor: ADMIN
Precondiciones: Ninguna (acceso completo)

Flujo Principal:

  1. ADMIN va a /admin/users
  2. Ve tabla con todos los usuarios:
    • name, email
    • role
    • createdAt
  3. Puede:
    • Filtrar por rol
    • Buscar por name/email
    • Cambiar rol (dropdown)
    • Eliminar usuario
  4. Para cambiar rol:
    • Selecciona nuevo rol
    • Si es ADMIN, solo ADMIN puede asignarlo
    • Sistema actualiza Profile.role
  5. Para eliminar:
    • Muestra advertencia de cascade
    • Confirma eliminación
    • Sistema elimina usuario y todas sus relaciones

CU-2: Gestionar Hackathons

Actor: ADMIN
Precondiciones: Ninguna

Flujo Principal:

  1. ADMIN va a /admin/hackathons
  2. Ve TODOS los hackathons (incluido DRAFT)
  3. Puede:
    • Ver cualquier hackathon
    • Crear nuevo hackathon
    • Editar cualquier campo
    • Eliminar hackathon
    • Forzar cambio de estado
  4. Para editar:
    • Puede modificar cualquier campo
    • Puede override validaciones (con advertencia)
    • Sistema aplica cambios
  5. Para forzar estado:
    • Selecciona nuevo estado
    • Muestra advertencia
    • Confirma override
    • Sistema cambia estado sin validar fechas

CU-3: Ver Estadísticas Globales

Actor: ADMIN
Precondiciones: Ninguna

Flujo Principal:

  1. ADMIN va a /admin/dashboard
  2. Sistema muestra:
    • Usuarios por rol: Count de cada Role
    • Hackathons por estado: Count de cada HackathonStatus
    • Total equipos: Count de Team
    • Total submissions: Count de Submission
    • Gráficos básicos (opcional en MVP)
  3. Puede hacer clic en cualquier métrica para ver detalles

Query:

export async function getGlobalStats() {
const [usersByRole, hackathonsByStatus, totalTeams, totalSubmissions] =
await Promise.all([
db.profile.groupBy({
by: ['role'],
_count: true,
}),
db.hackathon.groupBy({
by: ['status'],
_count: true,
}),
db.team.count(),
db.submission.count(),
]);

return {
usersByRole: usersByRole.reduce(
(acc, item) => ({ ...acc, [item.role]: item._count }),
{}
),
hackathonsByStatus: hackathonsByStatus.reduce(
(acc, item) => ({ ...acc, [item.status]: item._count }),
{}
),
totalTeams,
totalSubmissions,
};
}

Restricciones en MVP

Lo que ADMIN NO puede hacer (por diseño)

  • Nada: ADMIN puede hacer TODO en el MVP

Advertencias Importantes

  1. Override de validaciones: Siempre mostrar advertencia
  2. Eliminación con cascade: Mostrar qué se eliminará
  3. Cambio de roles: Especialmente asignar ADMIN

Futuras Mejoras

Audit Logs

En futuras iteraciones, agregar:

model AuditLog {
id String @id @default(cuid())
adminId String
action String // "UPDATE_USER_ROLE", "DELETE_USER", etc.
resource String // "User", "Hackathon", etc.
resourceId String
oldValue Json?
newValue Json?
createdAt DateTime @default(now())
}

Reglas Específicas

Agregar reglas específicas para ciertas acciones:

  • No eliminar último ADMIN
  • No eliminar hackathons con submissions evaluadas
  • etc.

Diagrama de Permisos Admin

Próximos Pasos


Siguiente: Development Guide