academia/docs/architecture/diagrams/03-sequence-enrollment.puml

112 lines
3.1 KiB
Plaintext
Raw Permalink Normal View History

@startuml sequence-enrollment
!theme plain
skinparam sequenceMessageAlign center
skinparam responseMessageBelowArrow true
skinparam sequenceParticipantBackgroundColor #F8F9FA
skinparam sequenceParticipantBorderColor #495057
title Secuencia: Inscripción de Estudiante en Materia (con JWT)
actor "Estudiante" as user
participant "Frontend\n(Angular)" as frontend
participant "API GraphQL\n(HotChocolate)" as api
participant "JWT Middleware" as jwt
participant "EnrollStudentHandler" as handler
participant "EnrollmentDomainService" as domainService
participant "StudentRepository" as studentRepo
participant "SubjectRepository" as subjectRepo
participant "EnrollmentRepository" as enrollRepo
database "SQL Server" as db
== Autenticación (previo) ==
note over user, frontend
El estudiante ya inició sesión
y tiene un JWT válido almacenado
end note
== Solicitud de Inscripción ==
user -> frontend : Selecciona materia\ny hace clic en "Inscribir"
activate frontend
frontend -> api : mutation enrollStudent(\n studentId, subjectId)\n[Authorization: Bearer <JWT>]
activate api
api -> jwt : Validate JWT
activate jwt
jwt -> jwt : Verify signature\n& expiration
jwt --> api : ClaimsPrincipal
deactivate jwt
api -> handler : Handle(EnrollStudentCommand)
activate handler
== Obtención de Datos ==
handler -> studentRepo : GetByIdWithEnrollmentsAsync(studentId)
activate studentRepo
studentRepo -> db : SELECT Student + Enrollments
db --> studentRepo : Student data
studentRepo --> handler : Student
deactivate studentRepo
alt Cuenta no activada
handler --> api : Error: "Cuenta no activada"
api --> frontend : { errors: [...] }
frontend --> user : Muestra mensaje:\n"Activa tu cuenta primero"
end
handler -> subjectRepo : GetByIdAsync(subjectId)
activate subjectRepo
subjectRepo -> db : SELECT Subject
db --> subjectRepo : Subject data
subjectRepo --> handler : Subject
deactivate subjectRepo
== Validación de Reglas de Negocio ==
handler -> domainService : ValidateEnrollment(student, subject)
activate domainService
domainService -> domainService : CheckMaxEnrollments()\n[máx 3 materias]
alt Estudiante tiene 3 materias
domainService --> handler : throw MaxEnrollmentsExceededException
handler --> api : Error: "Límite de materias alcanzado"
api --> frontend : { errors: [...] }
frontend --> user : Muestra mensaje de error
end
domainService -> domainService : CheckProfessorConstraint()\n[no repetir profesor]
alt Ya tiene materia con el profesor
domainService --> handler : throw SameProfessorConstraintException
handler --> api : Error: "Ya tienes materia con este profesor"
api --> frontend : { errors: [...] }
frontend --> user : Muestra mensaje de error
end
domainService --> handler : Validación OK
deactivate domainService
== Persistencia ==
handler -> enrollRepo : AddAsync(enrollment)
activate enrollRepo
enrollRepo -> db : INSERT Enrollment
db --> enrollRepo : OK
enrollRepo --> handler : Enrollment
deactivate enrollRepo
handler --> api : EnrollmentPayload
deactivate handler
api --> frontend : { enrollment: {...} }
deactivate api
frontend --> user : Muestra confirmación:\n"Inscrito en [materia]"
deactivate frontend
@enduml