Skip to main content

Overview

Satélite API follows a clean layered architecture pattern that separates concerns and promotes maintainability. The architecture consists of four primary layers:

Architectural Layers

1

GraphQL Schema Layer

Location: Schema/Query/ and Schema/Mutation/This layer handles GraphQL requests and responses. It defines the API contract and delegates business logic to services.
Schema/Query/Query.cs
public class Query
{
    private readonly UsuarioRepository _userRepository;
    
    public Query(UsuarioRepository userRepository)
    {
        _userRepository = userRepository;
    }

    [Authorize]
    public async Task<IEnumerable<UsuarioDTO>> GetUsuarios()
    {
        return await _userRepository.GetAll();
    }
}
2

Service Layer

Location: Services/Services contain business logic and orchestrate operations across multiple repositories. They handle complex workflows and business rules.Example services:
  • PlanComercialService
  • AuthenticationService
  • BitacoraCumplimientoService
  • DonacionService
3

Repository Layer

Location: Repository/ and inline with ServicesRepositories provide data access abstraction and encapsulate database operations.
public class UsuarioRepository
{
    private readonly IDbContextFactory<SateliteDBContext> _contextFactory;

    public async Task<IEnumerable<UsuarioDTO>> GetAll()
    {
        await using var context = await _contextFactory.CreateDbContextAsync();
        return await context.Usuarios.ToListAsync();
    }
}
4

Data Layer

Location: Services/*DBContext.csEntity Framework Core DbContexts manage database connections and entity mappings. See Database Contexts for details.

Dependency Injection

The application uses ASP.NET Core’s built-in dependency injection. All services and repositories are registered in Program.cs.

Repository Registration

Program.cs:521-677
// Repository registrations
builder.Services.AddScoped<UsuarioRepository>();
builder.Services.AddScoped<RolesRepository>();
builder.Services.AddScoped<PermisosRepository>();
builder.Services.AddScoped<ProductoRepository>();
builder.Services.AddScoped<ClientesRepository>();
builder.Services.AddScoped<PlanComercialRepository>();
builder.Services.AddScoped<BitCuResponsabilidadRepository>();
builder.Services.AddScoped<DonacionesRepository>();

// BitacoraCumplimiento Repositories
builder.Services.AddScoped<BitCuResponsabilidadRepository>();
builder.Services.AddScoped<BitCuProcesoRepository>();
builder.Services.AddScoped<BitCuLocalidadRepository>();
builder.Services.AddScoped<BitCuAuditoriaRepository>();

// Catalog repositories
builder.Services.AddScoped<SateliteAprobadoresRepository>();
builder.Services.AddScoped<CatalogoUnidadManejoRepository>();
builder.Services.AddScoped<CatalogoMaterialesHomologadosRepository>();

Service Registration

Program.cs:684-729
// Registro Consumo Services
builder.Services.AddScoped<TipoConsumoService>();
builder.Services.AddScoped<CategoriaConsumoService>();
builder.Services.AddScoped<UnidadConsumoService>();
builder.Services.AddScoped<RegistroConsumoService>();

// Donaciones Services
builder.Services.AddScoped<CatInstitucionService>();
builder.Services.AddScoped<CatContactoService>();
builder.Services.AddScoped<CatTransporteService>();
builder.Services.AddScoped<DonacionService>();

// Memoria de Sostenibilidad Services
builder.Services.AddScoped<CatMemoriaSostenibilidadProcesosService>();
builder.Services.AddScoped<MemoriaSostenibilidadService>();

// Databricks Services
builder.Services.AddScoped<ScadaHomologacionService>();
builder.Services.AddScoped<RutaDistanciaService>();

Extension Methods for Service Registration

The application uses extension methods to organize service registration:
Program.cs:729-742
builder.Services.AddPlanComercialServices();
builder.Services.AddNotaCreditoServices();
builder.Services.AddCatalogosServices();
builder.Services.AddServiceCollection(builder.Configuration);
builder.Services.AddSapServices(builder.Configuration);
builder.Services.AddUsuarioServiceCollection();
builder.Services.AddEquifaxServices(builder.Configuration);
builder.Services.AddCatalogoMaestroServices();
builder.Services.AddAprobacionServiceCollection();
builder.Services.AddNotaCreditoJobs();
Extension methods keep the Program.cs clean and organize related service registrations into logical groups.

Scheduled Jobs with Quartz

Satélite API uses Quartz.NET for scheduled background jobs. Jobs are configured in Program.cs:193-265.

Job Configuration

Program.cs:193-265
builder.Services.AddQuartz(q =>
{
    q.UseMicrosoftDependencyInjectionJobFactory();

    // Anticipo Job - Daily at 9:00 AM
    var anticipoKey = new JobKey("AnticipoJob");
    q.AddJob<TaskAnticipo>(opts => opts.WithIdentity(anticipoKey));
    q.AddTrigger(opts => opts
        .ForJob(anticipoKey)
        .WithIdentity("AnticipoJob-trigger")
        .WithCronSchedule("0 0 9 * * ?"));

    // Reembolso Job - Daily at 9:00 AM
    var reembolsoKey = new JobKey("ReembolsoJob");
    q.AddJob<TaskReembolso>(opts => opts.WithIdentity(reembolsoKey));
    q.AddTrigger(opts => opts
        .ForJob(reembolsoKey)
        .WithIdentity("ReembolsoJob-trigger")
        .WithCronSchedule("0 0 9 * * ?"));

    // Bitacora Caducidad Job - Daily at 8:00 AM
    var bitacoraCaducidadKey = new JobKey("BitacoraCaducidadJob");
    q.AddJob<TaskBitacoraCaducidad>(opts => 
        opts.WithIdentity(bitacoraCaducidadKey));
    q.AddTrigger(opts => opts
        .ForJob(bitacoraCaducidadKey)
        .WithIdentity("BitacoraCaducidadJob-trigger")
        .WithCronSchedule("0 0 8 * * ?"));

    // Activos Job - Daily at 9:00 AM
    var activosKey = new JobKey("ActivosJob");
    q.AddJob<TaskActivos>(opts => opts.WithIdentity(activosKey));
    q.AddTrigger(opts => opts
        .ForJob(activosKey)
        .WithIdentity("ActivosJob-trigger")
        .WithCronSchedule("0 0 9 * * ?"));

    // Procurement Job - Daily at 9:00 AM
    var procurmentKey = new JobKey("ProcurmentJob");
    q.AddJob<TaskProcurment>(opts => opts.WithIdentity(procurmentKey));
    q.AddTrigger(opts => opts
        .ForJob(procurmentKey)
        .WithIdentity("ProcurmentJob-trigger")
        .WithCronSchedule("0 0 9 * * ?"));

    // Tracking Job - Daily at 9:00 AM
    var trackingKey = new JobKey("TrackingJob");
    q.AddJob<TaskProcurmentSeguimiento>(opts => 
        opts.WithIdentity(trackingKey));
    q.AddTrigger(opts => opts
        .ForJob(trackingKey)
        .WithIdentity("TrackingJob-trigger")
        .WithCronSchedule("0 0 9 * * ?"));

    // Procurement Seguimiento Sin Correo - Every hour
    q.AddJob<TaskProcurmentSeguimientoSinCorreo>(opts => 
        opts.WithIdentity("TaskProcurmentSeguimientoSinCorreo"));
    q.AddTrigger(opts => opts
        .ForJob("TaskProcurmentSeguimientoSinCorreo")
        .WithIdentity("TaskProcurmentSeguimientoSinCorreo-trigger")
        .WithCronSchedule("0 0 * * * ?"));

    // Gestor Job - Daily at 6:00 AM
    var gestorKey = new JobKey("GestorJob");
    q.AddJob<TaskGestor>(opts => opts.WithIdentity(gestorKey));
    q.AddTrigger(opts => opts
        .ForJob(gestorKey)
        .WithIdentity("GestorJob-trigger")
        .WithCronSchedule("0 0 6 * * ?"));
});

builder.Services.AddQuartzHostedService(q => 
    q.WaitForJobsToComplete = true);

Scheduled Jobs Overview

TaskAnticipo

Schedule: Daily at 9:00 AMProcesses advance payment requests

TaskReembolso

Schedule: Daily at 9:00 AMProcesses reimbursement requests

TaskBitacoraCaducidad

Schedule: Daily at 8:00 AMChecks and updates expiration dates

TaskActivos

Schedule: Daily at 9:00 AMSynchronizes fixed assets data

TaskProcurment

Schedule: Daily at 9:00 AMProcesses procurement requests

TaskProcurmentSeguimiento

Schedule: Daily at 9:00 AMTracks procurement with email notifications

TaskProcurmentSeguimientoSinCorreo

Schedule: Every hourTracks procurement without emails

TaskGestor

Schedule: Daily at 6:00 AMDocument management tasks
All scheduled times use server timezone (UTC-5). Cron expressions follow standard Quartz syntax:
  • 0 0 9 * * ? = Daily at 9:00 AM
  • 0 0 * * * ? = Every hour

Data Flow Example

Here’s how a typical request flows through the architecture:

Configuration Management

Configuration is managed through appsettings.json and environment variables:
Program.cs:306-374
// Configure external API settings
builder.Services.Configure<ApiCofaseSettings>(
    builder.Configuration.GetSection("ApiCofase"));
builder.Services.Configure<ApiEquifaxSettings>(
    builder.Configuration.GetSection("ApiEquifax"));
builder.Services.Configure<DatabricksConfig>(
    builder.Configuration.GetSection("DatabricksConfig"));

Next Steps

Database Contexts

Explore the multiple database contexts

Error Handling

Learn error handling patterns