Skip to content

ShinjiMC/Enrollment-Management-System-UNSA

Repository files navigation

Enrollment Management System UNSA (By Dexo Corp)

Typing SVG

.Net C# MySQL MongoDB RabbitMQ Docker Postman Swagger React TypeScript

Build Status Microservices Commits Version License

1. Descripción

Equipo de Desarrollo

  • Nombre del Equipo: Dexo Corp
  • Integrantes:
    • Mogollon Caceres Sergio Daniel
    • Davis Coropuna Leon Felipe
    • Apaza Apaza Nelzon Jorge
    • Lupo Condori Avelino
    • Maldonado Casilla Braulio Nayap
    • Parizaca Mozo Paul Antony
    • Huaman Coaquira Luciana Julissa

Cliente

  • Organización: Universidad Nacional de San Agustín (UNSA)

Propósito del Proyecto

El propósito de este proyecto es desarrollar un Sistema de Gestión de Matrículas (SGM) que optimice los procesos de inscripción y gestión de matrículas de los estudiantes de la Universidad Nacional de San Agustín (UNSA). Este sistema tiene como objetivo ser escalable, seguro y fácil de usar, basado en una arquitectura moderna de microservicios.

2. Requisitos y Features

2.1. Requisitos Funcionales y No Funcionales

Requisitos Funcionales:

  • RF1: Gestionar Autenticación
  • RF2: Gestionar Usuarios
  • RF3: Gestionar Cursos
  • RF4: Gestionar Horarios
  • RF5: Realizar Matrícula
  • RF6: Generar Reportes de Matrícula
  • RF7: Gestionar Escuelas
  • RF8: Gestionar Notificaciones
  • RF9: Gestionar Pagos
  • RF10: Gestionar Cupos

Requisitos No Funcionales:

  • RNF1: Usabilidad
  • RNF2: Rendimiento
  • RNF3: Seguridad
  • RNF4: Escalabilidad
  • RNF5: Disponibilidad
  • RNF6: Mantenibilidad
  • RNF7: Compatibilidad

2.2. Features

Gestionar Autenticación
  • Feature 1.1: Autenticación de Usuarios
  • Feature 1.2: Recuperación de Contraseña
Gestionar Usuarios
  • Feature 2.1: Creación de Usuarios
  • Feature 2.2: Actualización de Usuarios
  • Feature 2.3: Eliminación de Usuarios
Gestionar Cursos
  • Feature 3.1: Creación de Cursos
  • Feature 3.2: Actualización de Cursos
  • Feature 3.3: Eliminación de Cursos
Gestionar Horarios
  • Feature 4.1: Creación de Horarios
  • Feature 4.2: Actualización de Horarios
  • Feature 4.3: Eliminación de Horarios
Realizar Matrícula
  • Feature 5.1: Inscripción de Estudiantes
  • Feature 5.2: Actualización de Matrícula
  • Feature 5.3: Cancelación de Matrícula
Generar Reportes de Matrícula
  • Feature 6.1: Reporte de Inscripciones
  • Feature 6.2: Reporte de Pagos
Gestionar Escuelas
  • Feature 7.1: Creación de Escuelas
  • Feature 7.2: Actualización de Escuelas
  • Feature 7.3: Eliminación de Escuelas
Gestionar Notificaciones
  • Feature 8.1: Envío de Notificaciones
  • Feature 8.2: Gestión de Plantillas
Gestionar Pagos
  • Feature 9.1: Procesamiento de Pagos
  • Feature 9.2: Verificación de Pagos
Gestionar Cupos
  • Feature 10.1: Asignación de Cupos
  • Feature 10.2: Actualización de Cupos
  • Feature 10.3: Cancelación de Cupos

3. Arquitectura del Sistema

Descripción general de la arquitectura de microservicios.

3.1. Diagrama General

Arquitectura

3.2. Lista de Microservicios

4. Implementación

4.1. Tecnologías Utilizadas

  • Backend:
    • .NET: Framework de desarrollo para la implementación de los microservicios backend.
    • C#: Lenguaje de programación para el desarrollo de los microservicios backend.
    • Entity Framework Core: ORM para el mapeo de objetos a relaciones.
    • NUnit: Framework de pruebas unitarias para las pruebas del backend.
  • Frontend:
    • React: Biblioteca de JavaScript para la creación de interfaces de usuario declarativas.
    • Redux: Librería para la gestión del estado de la aplicación.
    • TypeScript: Lenguaje de programación superconjunto de JavaScript con tipado estático.
    • SASS: Preprocesador de CSS para la creación de estilos CSS más organizados y mantenibles.
  • Mensajería:
    • RabbitMQ: Sistema de mensajería asíncrona para la comunicación entre microservicios.
  • Base de Datos:
    • Mysql: Sistema de gestión de bases de datos relacionales.
    • Mongodb: Base de datos NoSQL de código abierto.

4.2. Clean Code

El código ha sido desarrollado siguiendo las mejores prácticas de clean code para asegurar su mantenibilidad, legibilidad y escalabilidad. Algunos de los principios aplicados incluyen:

  • Nombres significativos: Uso de nombres claros y descriptivos para variables, funciones y clases.
  • Funciones pequeñas: Funciones que realizan una única tarea específica.
  • Comentarios útiles: Comentarios que explican el "por qué" detrás de una decisión de código.
  • Manejo de errores: Manejo adecuado de excepciones y errores para prevenir fallos inesperados.

4.3. Principios SOLID

El diseño del sistema sigue los principios SOLID para garantizar una arquitectura robusta y flexible:

  • S - Principio de Responsabilidad Única (Single Responsibility Principle): Cada clase debe tener una única responsabilidad. Por ejemplo, una clase UserService se encarga únicamente de la lógica relacionada con los usuarios.

    public class UserService
    {
        private readonly IUserRepository _userRepository;
    
        public UserService(IUserRepository userRepository)
        {
            _userRepository = userRepository;
        }
    
        public void AddUser(User user)
        {
            // ...
        }
    }
  • O - Principio de Abierto/Cerrado (Open/Closed Principle): Las clases deben estar abiertas para extensión, pero cerradas para modificación. Utilizamos la herencia y la interfaz para extender el comportamiento sin modificar el código existente.

    public interface IPaymentProcessor
    {
        void ProcessPayment(Payment payment);
    }
    
    public class CreditCardPaymentProcessor : IPaymentProcessor
    {
        public void ProcessPayment(Payment payment)
        {
            // ...
        }
    }
  • L - Principio de Sustitución de Liskov (Liskov Substitution Principle): Las clases derivadas deben ser sustituibles por sus clases base. Las clases hijas deben implementar completamente la funcionalidad esperada por la clase padre.

    namespace users_microservice.Domain.ValueObjects
    {
        public class StudentInfo
        {
            // Details related to student information
        }
    
        public class AcademicPerformance
        {
            // Details related to academic performance
        }
    
        public class CourseModel
        {
            // Details related to course model
        }
    }
    
    namespace users_microservice.Domain.Entities
    {
        public class UserModel
        {
            public string? Username { get; set; }
            public string? Email { get; set; }
    
            public virtual void DisplayInfo()
            {
                Console.WriteLine($"Username: {Username}, Email: {Email}");
            }
        }
    
        public class StudentModel : UserModel
        {
            public StudentInfo? StudentData { get; set; }
            public int? Credit { get; set; }
            public AcademicPerformance? AcademicPerformance { get; set; }
            public List<CourseModel>? StudentCourses { get; set; }
    
            public StudentModel() { }
    
            public override void DisplayInfo()
            {
                base.DisplayInfo();
                Console.WriteLine("Student Data and additional information.");
            }
        }
    
        public class AdminModel : UserModel
        {
            public string? PhoneNumber { get; set; }
    
            public AdminModel() { }
    
            public override void DisplayInfo()
            {
                base.DisplayInfo();
                Console.WriteLine($"Phone Number: {PhoneNumber}");
            }
        }
    }
    
    namespace users_microservice.Application.Services
    {
        public interface IUserService
        {
            void AddUser(UserModel user);
            UserModel GetUser(string username);
            List<UserModel> GetAllUsers();
        }
    
        public class UserService : IUserService
        {
            private readonly List<UserModel> _users = new List<UserModel>();
    
            public void AddUser(UserModel user)
            {
                _users.Add(user);
            }
    
            public UserModel GetUser(string username)
            {
                return _users.FirstOrDefault(user => user.Username == username);
            }
    
            public List<UserModel> GetAllUsers()
            {
                return _users;
            }
        }
    }
    • Ejemplo de uso:
    IUserService userService = new UserService();
    
    // Crear instancias de StudentModel y AdminModel
    UserModel student = new StudentModel
    {
        Username = "john_doe",
        Email = "john@example.com",
        StudentData = new StudentInfo(),
        Credit = 30,
        AcademicPerformance = new AcademicPerformance(),
        StudentCourses = new List<CourseModel>()
    };
    
    UserModel admin = new AdminModel
    {
        Username = "admin_user",
        Email = "admin@example.com",
        PhoneNumber = "123-456-7890"
    };
    
    // Agregar usuarios al servicio
    userService.AddUser(student);
    userService.AddUser(admin);
  • I - Principio de Segregación de Interfaces (Interface Segregation Principle): Una clase no debería estar forzada a implementar interfaces que no usa. Dividimos las interfaces grandes en otras más pequeñas y específicas.

    // Interfaces Segregadas
    public interface IStudentService
    {
        void AddStudent(StudentModel student);
        StudentModel GetStudent(string username);
        List<StudentModel> GetAllStudents();
    }
    
    public interface IAdminService
    {
        void AddAdmin(AdminModel admin);
        AdminModel GetAdmin(string username);
        List<AdminModel> GetAllAdmins();
    }
    
    // StudentService
    public class StudentService : IStudentService
    {
        private readonly List<StudentModel> _students = new List<StudentModel>();
    
        public void AddStudent(StudentModel student)
        {
            _students.Add(student);
        }
    
        public StudentModel GetStudent(string username)
        {
            return _students.FirstOrDefault(student => student.Username == username);
        }
    
        public List<StudentModel> GetAllStudents()
        {
            return _students;
        }
    }
    
    // AdminService
    public class AdminService : IAdminService
    {
        private readonly List<AdminModel> _admins = new List<AdminModel>();
    
        public void AddAdmin(AdminModel admin)
        {
            _admins.Add(admin);
        }
    
        public AdminModel GetAdmin(string username)
        {
            return _admins.FirstOrDefault(admin => admin.Username == username);
        }
    
        public List<AdminModel> GetAllAdmins()
        {
            return _admins;
        }
    }
  • D - Principio de Inversión de Dependencia (Dependency Inversion Principle): Las dependencias deben ir desde los módulos de alto nivel hacia los módulos de bajo nivel. Utilizamos la inyección de dependencias para implementar este principio.

    • Inyeccion de dependencias desde Program.cs:
    // Builder
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddControllers();
    builder.Services.AddEndpointsApiExplorer();
    
    // Register database context
    builder.Services.AddSingleton<MongoDbContext>();
    
    // Register application services
    builder.Services.AddScoped<IElectronicBillService, ElectronicBillService>();
    builder.Services.AddScoped<IPaymentCodeService, PaymentCodeService>();
    builder.Services.AddScoped<IPaymentService, PaymentService>();
    builder.Services.AddScoped<IPayerService, PayerService>();
    
    // Register domain services
    builder.Services.AddScoped<IElectronicBillDomainService, ElectronicBillDomainService>();
    builder.Services.AddScoped<IPaymentCodeDomainService, PaymentCodeDomainService>();
    builder.Services.AddScoped<IPaymentDomainService, PaymentDomainService>();
    
    // Register repositories
    builder.Services.AddScoped<IPaymentRepository, PaymentRepository>();
    builder.Services.AddScoped<IElectronicBillRepository, ElectronicBillRepository>();
    builder.Services.AddScoped<IPaymentCodeRepository, PaymentCodeRepository>();
    builder.Services.AddScoped<IPayerRepository, PayerRepository>();
    • Uso en controladores:
    public interface IAdminController
    {
        Task<IActionResult> GetAllStudents();
    }
    
    
    [Route("api/[controller]")]
    [ApiController]
    public class AdminController : ControllerBase, IAdminController
    {
        private readonly IAdminService _adminService; // inyeccion de dependencia
    
        public AdminController(IAdminService adminService)
        {
            _adminService = adminService;
        }
    
        [HttpPost("register/student")]
        public async Task<IActionResult> RegisterStudent([FromBody] StudentDto student)
        {
            var createdStudent = await _adminService.CreateStudentAsync(student);
            return StatusCode(createdStudent.StatusCode, createdStudent);
        }
        
        [HttpPost("register/admin")]
        public async Task<IActionResult> RegisterAdmin([FromBody] AdminDto userDTO)
        {
            var response = await _adminService.CreateAdminAccountAsync(userDTO);
            return StatusCode(response.StatusCode, response);
        }
    }

5. Instalación y Configuración

5.1. Requisitos Previos

  • Requisitos del sistema:

    • Sistema operativo compatible (Windows, macOS, Linux).
    • .NET 8 SDK instalado.
    • Docker y Docker Compose instalados (para despliegue en contenedores).
    • MySQL (Base de datos relacional disponible de manera local o en la nube)
    • MongoDB (Base de datos no relacional disponible de manera local o en la nube)
  • Software necesario:

    • Git para el control de versiones.
    • Visual Studio Code y C# Dev Kit (extensiones para trabajar en el entorno de .NET).
    • Herramientas de línea de comandos (bash, PowerShell, etc.).

5.2. Instrucciones

1. Crear Solución

mkdir users-microservice && cd users-microservice
dotnet new sln

Esta sección crea una nueva solución .NET en un directorio específico.

2. Crear Proyecto Fuente

mkdir src && cd src && dotnet new web

Esta sección crea un nuevo proyecto web dentro de la carpeta src.

3. Crear Proyecto de Pruebas

mkdir test && cd test && dotnet new nunit

Esta sección crea un nuevo proyecto de pruebas usando NUnit dentro de la carpeta test.

  • Vincular el Proyecto de Pruebas con el Proyecto Fuente:
    dotnet add reference ../src/src.csproj

4. Vincular Subproyectos al Proyecto Base

  • Navegar a la raíz del proyecto base.
  • Vincular Proyecto Fuente con el Proyecto Base:
    dotnet sln add src/src.csproj
  • Vincular Proyecto de Pruebas con el Proyecto Base:
    cd ..
    dotnet sln add test/test.csproj

5. Instalar Dependencias

En src/:

  • EntityFramework Core para ejecutar comandos de dotnet ef en CLI:
    dotnet tool install --global dotnet-ef
  • EntityFrameworkCore.Design para migraciones:
    dotnet add package Microsoft.EntityFrameworkCore.Design --version 9.0.0-preview.1.24081.2
  • Dependencia Pomelo.EntityFrameworkCore.MySql para MySQL:
    dotnet add package Pomelo.EntityFrameworkCore.MySql --version 9.0.0-preview.1
  • Dependencia MongoDB.Driver para MongoDB:
    dotnet add package MongoDB.Driver --version 2.28.0
  • Dependencia Microsoft.AspNetCore.Authentication.JwtBearer para tokenización JWT:
    dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version 8.0.5

En test/:

  • coverlet.collector para reportes de cobertura:
    dotnet add package coverlet.collector --version 6.0.2
  • Dependencia Moq para mocking:
    dotnet add package Moq --version 4.20.70

6. Añadir Migraciones

Navegar a la carpeta src/:

cd src/

Añadir una nueva migración:

dotnet ef migrations add NameMigrate

Actualizar la base de datos con la nueva migración:

dotnet ef database update

7. Ejecutar la Aplicación

dotnet run --project src/src.csproj

8. Ejecutar Pruebas

dotnet test

9. Construir la Aplicación

dotnet build src/src.csproj --configuration Release

10. Cobertura

dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput=../../coverage # no funciona
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover --output coverage # funciona pero con advertencias

6. Configuración de Pruebas

Descripción de las Pruebas Implementadas

Las pruebas han sido diseñadas para asegurar la calidad del código y la funcionalidad del microservicio de gestión de matrículas. Se incluyen pruebas unitarias, pruebas de integración y pruebas funcionales. Las pruebas cubren escenarios de autenticación, manejo de usuarios, gestión de cursos, y más.

Cómo Ejecutar las Pruebas

1. Crear Proyecto de Pruebas

mkdir test && cd test && dotnet new nunit

2. Vincular el Proyecto de Pruebas con el Proyecto Fuente

dotnet add reference ../src/src.csproj

3. Instalar Dependencias de Pruebas

  • coverlet.collector para reportes de cobertura:
    dotnet add package coverlet.collector --version 6.0.2
  • Dependencia Moq para mocking:
    dotnet add package Moq --version 4.20.70

4. Ejecutar las Pruebas

dotnet test

5. Cobertura de Código

Para obtener reportes de cobertura de código, ejecutar:

dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover --output coverage

7. Despliegue

A. Dockerizacion

  1. Crear el Dockerfile: Asegúrate de que el Dockerfile se encuentra en la raíz del proyecto.

    # Utilizar la imagen oficial de .NET como imagen base
    FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
    WORKDIR /app
    EXPOSE 80
    
    # Utilizar la imagen oficial de .NET SDK como imagen base para compilación
    FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
    WORKDIR /src
    COPY ["src/YourProject.csproj", "src/"]
    RUN dotnet restore "src/YourProject.csproj"
    COPY . .
    WORKDIR "/src/src"
    RUN dotnet build "YourProject.csproj" -c Release -o /app/build
    
    FROM build AS publish
    RUN dotnet publish "YourProject.csproj" -c Release -o /app/publish
    
    FROM base AS final
    WORKDIR /app
    COPY --from=publish /app/publish .
    ENTRYPOINT ["dotnet", "YourProject.dll"]
  2. Construir la imagen de Docker: Ejecuta el siguiente comando en la terminal desde la raíz del proyecto donde se encuentra el Dockerfile.

    docker build -t yourproject-image .
  3. Crear y ejecutar un contenedor: Usa el siguiente comando para crear y ejecutar un contenedor a partir de la imagen recién creada.

    docker run -d -p 8080:80 --name yourproject-container yourproject-image

B. Entornos de despliegue

a) Desarrollo

Para el entorno de desarrollo, puedes utilizar Docker Compose para gestionar múltiples contenedores. Crea un archivo docker-compose.yml con el siguiente contenido:

version: '3.4'

services:
  yourproject:
    image: yourproject-image
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:80"
    environment:
      - ASPNETCORE_ENVIRONMENT=Development

Luego, ejecuta:

docker-compose up

b) Pruebas

Para el entorno de pruebas, puedes modificar el archivo docker-compose.yml para incluir servicios adicionales como bases de datos o servicios de prueba.

version: '3.4'

services:
  yourproject:
    image: yourproject-image
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:80"
    environment:
      - ASPNETCORE_ENVIRONMENT=Testing
  db:
    image: mysql:latest
    environment:
      MYSQL_ROOT_PASSWORD: yourpassword
      MYSQL_DATABASE: yourdatabase
    ports:
      - "3306:3306"

Ejecuta:

docker-compose -f docker-compose.yml up --build

c) Producción

Para el entorno de producción, asegúrate de que todas las configuraciones y secretos están correctamente configurados. Puedes usar servicios de orquestación como Kubernetes para gestionar el despliegue a escala.

version: '3.4'

services:
  yourproject:
    image: yourproject-image
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "80:80"
    environment:
      - ASPNETCORE_ENVIRONMENT=Production

Ejecuta:

docker-compose -f docker-compose.prod.yml up --build -d

8. Integración Continua

La integración continua se gestiona a través de Jenkins, automatizando la construcción, pruebas y análisis del código. El pipeline está configurado para ejecutar las siguientes etapas de manera paralela para cada microservicio:

a) Construcción Automática con .NET

  • Compilación: Se utiliza dotnet build para compilar el código de cada microservicio.
  • Publicación: dotnet publish genera los artefactos necesarios para el despliegue.

b) Análisis de Código con SonarCloud

  • Análisis Estático: Realiza un análisis de calidad del código, cobertura, y detecta vulnerabilidades mediante SonarCloud.

c) Pruebas de API con Postman

  • Ejecución de Pruebas: Las colecciones de Postman se ejecutan con Newman CLI para validar los endpoints de cada microservicio.

d) Pruebas de Rendimiento con JMeter

  • Evaluación de Carga: Ejecuta planes de prueba de JMeter para medir el rendimiento y detectar cuellos de botella.

e) Pruebas de Seguridad con OWASP ZAP

  • Escaneo de Vulnerabilidades: Utiliza OWASP ZAP para identificar problemas de seguridad en las aplicaciones.

f) Dockerización

  • Construcción y Despliegue: Se crean imágenes Docker para cada microservicio y se gestionan los contenedores para desarrollo, pruebas y producción.

Cada etapa del pipeline se ejecuta en paralelo para los diferentes microservicios, asegurando un proceso de integración continua eficiente.

Arquitectura

9. Licencia

This project is licensed under Creative Commons Atribución-NoComercial-CompartirIgual 4.0 Internacional:

Licencia Creative Commons

10. Referencias

[1] W. by Iamprovidence, “Backend side architecture evolution (N-layered, DDD, Hexagon, Onion, Clean Architecture)”, Medium, 27-jun-2023. [En línea]. Disponible en: https://medium.com/@iamprovidence/backend-side-architecture-evolution-n-layered-ddd-hexagon-onion-clean-architecture-643d72444ce4.

[2] C. Ramalingam, “Building domain driven microservices - Walmart global tech blog - medium”, Walmart Global Tech Blog, 01-jul-2020. [En línea]. Disponible en: https://medium.com/walmartglobaltech/building-domain-driven-microservices-af688aa1b1b8.

[3] J. Loscalzo, “Domain Driven Design: principios, beneficios y elementos — Segunda Parte”, Medium, 18-jun-2018. [En línea]. Disponible en: https://medium.com/@jonathanloscalzo/domain-driven-design-principios-beneficios-y-elementos-segunda-parte-337d77dc8566.

[4] P. Martinez, “Domain-Driven Design: Everything you always wanted to know”, SSENSE-TECH, 15-may-2020. [En línea]. Disponible en: https://medium.com/ssense-tech/domain-driven-design-everything-you-always-wanted-to-know-about-it-but-were-afraid-to-ask-a85e7b74497a.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published