@startuml domain-model
!theme plain
skinparam classAttributeIconSize 0
skinparam classFontStyle bold
skinparam classBackgroundColor #F8F9FA
skinparam classBorderColor #495057

title Sistema de Registro de Estudiantes - Modelo de Dominio

package "Domain" {

    class User <<Entity>> {
        - id: int
        - username: string
        - passwordHash: string
        - recoveryCodeHash: string
        - role: string
        - studentId: int?
        - createdAt: DateTime
        - lastLoginAt: DateTime?
        --
        + {static} Create(username, passwordHash, ...): User
        + UpdatePassword(newHash): void
        + UpdateLastLogin(): void
        + IsAdmin: bool
        + IsStudent: bool
    }

    class Student <<Entity>> {
        - id: int
        - name: string
        - email: Email
        - activationCodeHash: string?
        - activationExpiresAt: DateTime?
        - enrollments: List<Enrollment>
        --
        + getTotalCredits(): int
        + canEnroll(): bool
        + hasProfessor(professorId): bool
        + addEnrollment(enrollment): void
        + removeEnrollment(enrollment): void
        + setActivationCode(hash, expiresIn): void
        + clearActivationCode(): void
        + isActivated: bool
        + isActivationExpired(): bool
    }

    class Subject <<Entity>> {
        - id: int
        - name: string
        - credits: int {= 3}
        - professorId: int
        --
        + getProfessor(): Professor
    }

    class Professor <<Entity>> {
        - id: int
        - name: string
        - subjects: List<Subject>
        --
        + getSubjects(): List<Subject>
    }

    class Enrollment <<Entity>> {
        - id: int
        - studentId: int
        - subjectId: int
        - enrolledAt: DateTime
        --
        + getStudent(): Student
        + getSubject(): Subject
    }

    class Email <<Value Object>> {
        - value: string
        --
        + {static} create(value: string): Email
        - validate(value: string): void
    }

    class EnrollmentDomainService <<Domain Service>> {
        --
        + validateEnrollment(student: Student, subject: Subject): void
        - checkMaxEnrollments(student: Student): void
        - checkProfessorConstraint(student: Student, subject: Subject): void
    }

    enum UserRoles <<Enumeration>> {
        Admin
        Student
    }

    ' Relaciones
    User "0..1" -- "0..1" Student : vinculado a
    User --> UserRoles : tiene
    Student "1" *-- "0..3" Enrollment : tiene
    Subject "1" *-- "0..*" Enrollment : inscripciones
    Professor "1" *-- "2" Subject : imparte
    Student *-- Email : email

    EnrollmentDomainService ..> Student : valida
    EnrollmentDomainService ..> Subject : valida
}

note bottom of User
  <b>Autenticación:</b>
  - PBKDF2-SHA256 (100k iter)
  - JWT para sesiones
  - Recovery code para reset
end note

note bottom of Student
  <b>Invariantes:</b>
  - Máximo 3 inscripciones
  - Email válido y único
  - No repetir profesor
  - Requiere activación
end note

note bottom of Subject
  <b>Invariantes:</b>
  - Créditos = 3 (fijo)
  - Pertenece a un profesor
end note

note right of Professor
  Cada profesor
  imparte exactamente
  2 materias
end note

@enduml
