305 lines
8.7 KiB
Markdown
305 lines
8.7 KiB
Markdown
|
|
# 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:**
|
|||
|
|
```csharp
|
|||
|
|
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)
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
// 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)
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
// 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 | - | - |
|