Skip to content

Lineamientos de Arquitectura — Plataforma Imagy

Principios Fundamentales

  1. JWT Propagation: El JWT se propaga completo entre servicios. Cada servicio valida independientemente. Nunca headers custom para identidad.
  2. Database-per-Domain: Cada dominio de negocio tiene su propia base de datos. Nunca acceder a la BD de otro servicio.
  3. Event-Driven Communication: Comunicación asíncrona via RabbitMQ (MassTransit) entre dominios. Síncrona solo cuando se necesita respuesta inmediata.
  4. Multi-Tenancy por RLS: Todas las tablas con tenant_id. PostgreSQL Row Level Security activo. Nunca queries sin filtro de tenant.
  5. Maker-Checker: Cambios críticos (productos, roles, configuraciones) requieren aprobación configurable por tenant.
  6. Trazabilidad Total: Todo evento se publica. Cada acción deja rastro. Subject 360 consolida la vista del cliente.
  7. FTR-Compliant: Toda decisión de infraestructura debe cumplir requisitos de AWS Foundational Technical Review.

Stack Tecnológico (NO negociable)

ComponenteTecnologíaVersión mínima
Backend.NET 1010.0
Base de datosPostgreSQL16
ORM (escritura)Entity Framework Core10.0
Queries (lectura)Dapper2.x
CacheValkey (Redis-compatible)8.x
MensajeríaRabbitMQ (MassTransit)8.x
AuthKeycloak24.x
API GatewayYARP2.x
FrontendReact 19 + Vite 8 + TypeScript 6
State Management (FE)Zustand5.x
Forms (FE)React Hook Form + Zod7.x / 3.x
Testing (BE)xUnit + FluentAssertions
Testing (FE)Vitest + Testing Library
IaCAWS CDK (TypeScript)2.x
ContainersDocker (multi-stage builds)
Orchestration (AWS)ECS Fargate
Orchestration (local)Docker Compose

Patrón CQRS: EF Core (escritura) + Dapper (lectura)

  • Escritura (Commands): Entity Framework Core contra la instancia primaria de PostgreSQL
  • Lectura (Queries): Dapper contra la instancia read replica de PostgreSQL
csharp
// Dos connection strings por servicio
public class DatabaseSettings
{
    public string WriteConnectionString { get; set; } // → RDS Primary
    public string ReadConnectionString { get; set; }  // → RDS Read Replica
}
OperaciónHerramientaInstancia DB
INSERT, UPDATE, DELETEEF CorePrimary
SELECT (listados, filtros, reportes)DapperRead Replica
SELECT post-escritura (read-your-writes)EF CorePrimary

Estructura de Proyecto por Servicio

src/
├── Imagy.{Domain}.Api/              # Controllers, middleware, DI config
├── Imagy.{Domain}.Application/      # Use cases, commands, queries (MediatR)
├── Imagy.{Domain}.Domain/           # Entidades, value objects, interfaces
├── Imagy.{Domain}.Infrastructure/   # EF Core, Dapper, RabbitMQ, HTTP clients
│   ├── Persistence/                 # EF Core DbContext (Primary)
│   ├── ReadModel/                   # Dapper repositories (Read Replica)
│   ├── Messaging/                   # MassTransit consumers/publishers
│   └── ExternalServices/            # HTTP clients a otros servicios
├── Imagy.{Domain}.Migrations/       # DbUp - scripts SQL versionados
│   ├── Scripts/                     # V001__, V002__, etc.
│   ├── Seed/                        # S001__, S002__, etc.
│   └── Program.cs                   # Runner
└── Imagy.{Domain}.Tests/            # Unit + Integration tests

Multi-Tenancy

  • El tenant_id se extrae del JWT (claim tenant_id) validado por middleware .NET
  • Cada servicio usa IIdentityContext para acceder al tenant/user actual
  • EF Core interceptor ejecuta SET app.current_tenant_id en cada conexión
  • Dapper repositories ejecutan el mismo SET antes de cada query
  • En llamadas servicio-a-servicio, el JWT se propaga automáticamente
  • En consumers de eventos, el TenantId viene del payload del mensaje
  • NUNCA hacer queries sin tenant context (excepto platform_admin endpoints)
  • NUNCA usar headers custom (X-Tenant-Id) — siempre JWT firmado

Comunicación entre Servicios

TipoCuándoMecanismo
Evento asyncNotificaciones, actualización de Subject 360, auditoríaRabbitMQ (MassTransit)
Query síncronaServicio necesita datos de otro para decidirHTTP + JWT propagado
Command síncronoServicio dispara acción en otroHTTP + JWT propagado

Reglas de Integración

  1. No acceder a la DB de otro servicio directamente — siempre via API o evento
  2. No duplicar lógica de negocio — si necesitas algo de otro servicio, consúmelo
  3. Eventos son contratos — cambiar la estructura requiere coordinación
  4. Backward compatibility — agregar campos OK, eliminar/renombrar NUNCA
  5. Idempotencia — todos los consumers deben ser idempotentes

Convenciones de Código

Naming

  • Tablas: snake_case plural (flow_versions, credit_products)
  • Columnas: snake_case (tenant_id, created_at)
  • Primary Keys: UUID v4, columna id
  • Foreign Keys: {entity}_id
  • Timestamps: timestamp with time zone (UTC siempre)
  • Soft Delete: is_active boolean (nunca DELETE físico en datos de negocio)
  • JSON: jsonb para datos semi-estructurados
  • Namespaces .NET: Imagy.{Domain}.{Layer} (ej: Imagy.Lending.Application)
  • Interfaces: Prefijo I (ej: IIdentityContext, ICreditProductRepository)

Endpoints API

  • Prefijo: /api/v{version}/{resource}
  • Versionamiento: URL path segment usando Asp.Versioning.Mvc
  • Respuestas: envelope { data, errors, metadata }
  • Paginación: ?page=1&page_size=20{ total, page, page_size }
  • Filtros: query params

Eventos RabbitMQ

  • Exchange: imagy.events (topic)
  • Routing key: {domain}.{entity}.{action} (ej: lending.credit.disbursed)
  • Payload: estructura base obligatoria (ver event-contracts.md)

Dominios de Negocio

DominioServicioBase de DatosResponsabilidad
IdentityImagy Identity (Gateway + Management)imagy_identityAuth, tenants, orgs, sesiones, RBAC
FlowImagFlow Engineimagy_flowDiseño y ejecución de flujos, proveedores, reglas
LendingImagLendimagy_lendingProductos de crédito, originación, cartera
SignImagSignimagy_signFirma digital/electrónica, documentos
SubjectImagID (Subject 360)imagy_subjectPerfil unificado, dispositivos, listas, scoring
ComplianceImagGuard (futuro)imagy_complianceKYC, AML, PEP

Reimagine Tech LLC — Documentacion Interna