8.7 KiB
AN-002: Reglas de Negocio
Proyecto: Sistema de Registro de Estudiantes - Inter Rapidísimo Rol: Analista de Sistemas Fecha: 2026-01-07
1. Resumen
Este documento define las reglas de negocio que gobiernan el sistema de registro de estudiantes. Estas reglas son invariantes y deben ser validadas en la capa de dominio.
2. Reglas de Negocio
RN-001: Estructura del Catálogo de Materias
| Atributo | Valor |
|---|---|
| ID | RN-001 |
| Nombre | Catálogo Fijo de Materias |
| Descripción | El sistema contiene exactamente 10 materias académicas |
| Tipo | Restricción Estructural |
| Severidad | Crítica |
Datos Iniciales (Seed):
| ID | Materia | Profesor Asignado |
|---|---|---|
| 1 | Matemáticas I | Profesor A |
| 2 | Matemáticas II | Profesor A |
| 3 | Física I | Profesor B |
| 4 | Física II | Profesor B |
| 5 | Programación I | Profesor C |
| 6 | Programación II | Profesor C |
| 7 | Base de Datos I | Profesor D |
| 8 | Base de Datos II | Profesor D |
| 9 | Redes I | Profesor E |
| 10 | Redes II | Profesor E |
Validación: COUNT(Subjects) == 10
RN-002: Valor Uniforme de Créditos
| Atributo | Valor |
|---|---|
| ID | RN-002 |
| Nombre | Créditos por Materia |
| Descripción | Cada materia equivale exactamente a 3 créditos |
| Tipo | Restricción de Valor |
| Severidad | Crítica |
Fórmula:
Créditos_Materia = 3 (constante)
Créditos_Estudiante = COUNT(Inscripciones) × 3
Créditos_Máximos = 9 (3 materias × 3 créditos)
Validación: Subject.Credits == 3
RN-003: Límite de Inscripciones por Estudiante
| Atributo | Valor |
|---|---|
| ID | RN-003 |
| Nombre | Máximo 3 Materias |
| Descripción | Un estudiante solo puede inscribirse en máximo 3 materias |
| Tipo | Restricción de Cardinalidad |
| Severidad | Crítica |
Escenarios:
| Materias Actuales | Acción | Resultado |
|---|---|---|
| 0-2 | Inscribir | ✓ Permitido |
| 3 | Inscribir | ✗ Rechazado |
| 1-3 | Cancelar | ✓ Permitido |
Validación: Student.Enrollments.Count <= 3
Mensaje de Error: "El estudiante ya tiene el máximo de 3 materias inscritas"
RN-004: Asignación Profesores-Materias
| Atributo | Valor |
|---|---|
| ID | RN-004 |
| Nombre | Distribución de Profesores |
| Descripción | Existen 5 profesores, cada uno dicta exactamente 2 materias |
| Tipo | Restricción Estructural |
| Severidad | Crítica |
Invariantes:
COUNT(Professors) == 5∀ Professor: COUNT(Professor.Subjects) == 2∀ Subject: Subject.Professor != NULL
Validación:
professors.All(p => p.Subjects.Count == 2)
subjects.All(s => s.ProfessorId != null)
RN-005: Restricción de Profesor Único (CRÍTICA)
| Atributo | Valor |
|---|---|
| ID | RN-005 |
| Nombre | Prohibición de Mismo Profesor |
| Descripción | Un estudiante NO puede inscribirse en dos materias dictadas por el mismo profesor |
| Tipo | Restricción de Integridad |
| Severidad | CRÍTICA |
Lógica de Validación:
PARA inscribir(estudiante, nuevaMateria):
profesorNuevaMateria = nuevaMateria.Profesor
profesoresActuales = estudiante.Inscripciones.Select(i => i.Materia.Profesor)
SI profesorNuevaMateria EN profesoresActuales:
RECHAZAR "Ya tienes una materia con este profesor"
SINO:
PERMITIR inscripción
Casos de Prueba:
| Estudiante tiene | Intenta inscribir | Resultado |
|---|---|---|
| Matemáticas I (Prof A) | Matemáticas II (Prof A) | ✗ Rechazado |
| Matemáticas I (Prof A) | Física I (Prof B) | ✓ Permitido |
| Física I (Prof B), Programación I (Prof C) | Redes I (Prof E) | ✓ Permitido |
| Física I (Prof B), Programación I (Prof C) | Física II (Prof B) | ✗ Rechazado |
Mensaje de Error: "No puedes inscribir {materia} porque ya tienes una materia con {profesor}"
RN-006: Unicidad de Email
| Atributo | Valor |
|---|---|
| ID | RN-006 |
| Nombre | Email Único por Estudiante |
| Descripción | Cada estudiante debe tener un email único en el sistema |
| Tipo | Restricción de Unicidad |
| Severidad | Alta |
Validación: UNIQUE(Student.Email)
Mensaje de Error: "Ya existe un estudiante registrado con este email"
RN-007: Formato de Email Válido
| Atributo | Valor |
|---|---|
| ID | RN-007 |
| Nombre | Validación de Email |
| Descripción | El email debe cumplir formato estándar RFC 5322 |
| Tipo | Restricción de Formato |
| Severidad | Alta |
Patrón: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
Mensaje de Error: "El formato del email no es válido"
RN-008: Visibilidad de Compañeros
| Atributo | Valor |
|---|---|
| ID | RN-008 |
| Nombre | Privacidad de Datos |
| Descripción | Un estudiante solo puede ver el NOMBRE de sus compañeros de clase |
| Tipo | Restricción de Privacidad |
| Severidad | Media |
Datos Visibles:
- ✓ Nombre del compañero
- ✗ Email del compañero
- ✗ Otras materias del compañero
Condición: Solo aplica para materias donde ambos estudiantes están inscritos
3. Matriz de Validación por Capa
| Regla | Domain | Application | Adapter |
|---|---|---|---|
| RN-001 | ✗ | ✗ | Seed Data |
| RN-002 | ValueObject | ✗ | ✗ |
| RN-003 | DomainService | ✗ | ✗ |
| RN-004 | ✗ | ✗ | Seed Data |
| RN-005 | DomainService | ✗ | ✗ |
| RN-006 | ✗ | Validator | DB Constraint |
| RN-007 | ValueObject | Validator | ✗ |
| RN-008 | ✗ | Query Handler | ✗ |
4. Implementación en Código
RN-003 y RN-005 (Domain Service)
// Domain/Services/EnrollmentDomainService.cs
public class EnrollmentDomainService
{
public Result ValidateEnrollment(Student student, Subject newSubject)
{
// RN-003: Máximo 3 materias
if (student.Enrollments.Count >= 3)
return Result.Failure("MAX_ENROLLMENTS_EXCEEDED");
// RN-005: No repetir profesor
var existingProfessorIds = student.Enrollments
.Select(e => e.Subject.ProfessorId)
.ToHashSet();
if (existingProfessorIds.Contains(newSubject.ProfessorId))
return Result.Failure("SAME_PROFESSOR_CONSTRAINT");
return Result.Success();
}
}
RN-007 (Value Object)
// Domain/ValueObjects/Email.cs
public record Email
{
public string Value { get; }
private Email(string value) => Value = value;
public static Result<Email> Create(string email)
{
if (string.IsNullOrWhiteSpace(email))
return Result.Failure<Email>("EMAIL_REQUIRED");
if (!EmailRegex.IsMatch(email))
return Result.Failure<Email>("EMAIL_INVALID_FORMAT");
return Result.Success(new Email(email.ToLowerInvariant()));
}
private static readonly Regex EmailRegex = new(
@"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
RegexOptions.Compiled);
}
5. Diagrama de Restricciones
┌─────────────────────┐
│ ESTUDIANTE │
│ - Nombre │
│ - Email (único) │
└──────────┬──────────┘
│
│ máx 3 inscripciones
│ (RN-003)
▼
┌─────────────────────┐
│ INSCRIPCIÓN │
└──────────┬──────────┘
│
no puede repetir │ profesor (RN-005)
▼
┌─────────────┐ ┌─────────────────────┐ ┌─────────────┐
│ PROFESOR │──────│ MATERIA │──────│ 3 CRÉDITOS │
│ (5 total) │ 1:2 │ (10 total) │ │ (RN-002) │
└─────────────┘ └─────────────────────┘ └─────────────┘
6. Aprobación
| Rol | Nombre | Fecha | Firma |
|---|---|---|---|
| Analista | Sistema | 2026-01-07 | ✓ |
| Product Owner | Pendiente | - | - |
| Arquitecto | Pendiente | - | - |