# Anexo76 - Resumen de Arquitectura Tรฉcnica ## ๐Ÿ“‹ รndice 1. [Visiรณn General](#visiรณn-general) 2. [Stack Tecnolรณgico](#stack-tecnolรณgico) 3. [Arquitectura del Sistema](#arquitectura-del-sistema) 4. [Arquitectura de Schemas y Mรณdulos](#arquitectura-de-schemas-y-mรณdulos) 5. [Estructura del Proyecto](#estructura-del-proyecto) 6. [Flujos Principales](#flujos-principales) 7. [Seguridad](#seguridad) 8. [Base de Datos](#base-de-datos) 9. [API Reference](#api-reference) --- ## Visiรณn General Anexo76 es una aplicaciรณn SaaS multi-tenant para gestiรณn de comercio exterior en Mรฉxico, enfocada en cumplir con los Anexos 24, 31 y 22 del SAT. ### Objetivos de Negocio - Gestiรณn de inventarios para maquilas e IMMEX - Control de pedimentos aduanales - Manejo de facturas de importaciรณn/exportaciรณn - Cumplimiento normativo SAT - Licenciamiento flexible por planes --- ## Stack Tecnolรณgico ### Backend - **Framework**: FastAPI 0.110+ (Python 3.11+) - **ORM**: SQLAlchemy 2.0 - **Autenticaciรณn**: Keycloak (OpenID Connect) - **Base de Datos**: PostgreSQL 15+ - **Validaciรณn**: Pydantic 2.6+ - **Testing**: Pytest ### Frontend - **Framework**: SvelteKit 2.0+ (Svelte 5) - **Lenguaje**: TypeScript - **Auth Client**: keycloak-js - **Estilos**: TailwindCSS 4.1+ - **Build**: Vite 7+ ### Infraestructura - **Containerizaciรณn**: Docker / Docker Compose - **Orquestaciรณn**: Kubernetes (futuro) - **CI/CD**: GitHub Actions / GitLab CI - **Monitoreo**: Prometheus + Grafana --- ## Arquitectura del Sistema ### Patrรณn Arquitectรณnico: Modular Layered (estilo NestJS) ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ FRONTEND โ”‚ โ”‚ SvelteKit + Keycloak-js + TailwindCSS โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ HTTP/REST + JWT โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ API GATEWAY (FastAPI) โ”‚ โ”‚ Middleware: Tenant | License | Logging | CORS โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ MODULES โ”‚ โ”‚ CORE LAYER โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ€ข auth โ”‚ โ”‚ โ€ข config.py โ”‚ โ”‚ โ€ข tenants โ”‚ โ”‚ โ€ข database.py โ”‚ โ”‚ โ€ข licenses โ”‚ โ”‚ โ€ข security.py โ”‚ โ”‚ โ€ข ... โ”‚ โ”‚ โ€ข middleware โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ DATABASE LAYER (Multi-tenant) โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ Core DB โ”‚ โ”‚ Tenant 1 DB โ”‚ โ”‚ โ”‚ โ”‚ (shared) โ”‚ โ”‚ (dedicated) โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` ### Estructura Modular (por mรณdulo) Cada mรณdulo sigue el patrรณn: ``` modules/{module_name}/ โ”œโ”€โ”€ models.py # ORM Models (SQLAlchemy) โ”œโ”€โ”€ dto.py # Data Transfer Objects (Pydantic) โ”œโ”€โ”€ service.py # Business Logic Layer โ”œโ”€โ”€ routes.py # API Endpoints (FastAPI) โ””โ”€โ”€ __init__.py # Module exports ``` #### Responsabilidades por Capa 1. **models.py**: Representaciรณn de entidades en BD - Define tablas con SQLAlchemy - Relaciones entre entidades - Constraints y validaciones a nivel DB 2. **dto.py**: Contratos de entrada/salida de datos - DTOs de request (CreateDTO, UpdateDTO) - DTOs de response (ResponseDTO) - Validaciones de Pydantic 3. **service.py**: Lรณgica de negocio - Operaciones CRUD - Validaciones de negocio - Orquestaciรณn de operaciones complejas 4. **routes.py**: Exposiciรณn HTTP - Definiciรณn de endpoints - Documentaciรณn OpenAPI automรกtica - Manejo de dependencias (auth, db) --- ## Arquitectura de Schemas y Mรณdulos ### Estructura de Schemas en Base de Datos La aplicaciรณn utiliza una arquitectura de schemas para organizar lรณgicamente las tablas segรบn su funcionalidad y alcance: #### **Schema `a24` (Anexo 24)** Contiene todas las tablas relacionadas con el **Anexo 24 del SAT** (control de inventarios para empresas IMMEX): - Gestiรณn de inventarios - Control de entradas y salidas de mercancรญas - Reportes de existencias - Cumplimiento de obligaciones fiscales del Anexo 24 #### **Schema `a76` (Anexo 76)** Contiene todas las tablas relacionadas con el **Anexo 76 del SAT** (comercio exterior): - Pedimentos aduanales - Facturas de importaciรณn/exportaciรณn - Documentaciรณn de comercio exterior - Cumplimiento normativo de comercio exterior #### **Schema `public` (Catรกlogos Fijos)** Contiene **catรกlogos compartidos** y datos de referencia que no cambian frecuentemente: - Catรกlogos del SAT (tipos de material, unidades de medida, etc.) - Cรณdigos de paรญs - Catรกlogos de aduanas - Tipos de documento - Datos maestros compartidos entre mรณdulos ### Convenciรณn de Prefijos de Tablas Para mantener claridad y trazabilidad, las tablas utilizan prefijos que identifican su mรณdulo funcional: #### **Prefijo `inv_` (Inventarios)** Tablas relacionadas con el **control de inventarios**: - `inv_products`: Productos en inventario - `inv_movements`: Movimientos de entrada/salida - `inv_warehouses`: Almacenes - `inv_balances`: Saldos de inventario **Nota histรณrica**: Anteriormente se utilizaba el prefijo `s` (SCAII - Sistema de aduanas e Inventarios). #### **Prefijo `fa_` (Fixed Assets / Activos Fijos)** Tablas relacionadas con la **gestiรณn de activos fijos**: - `fa_assets`: Registro de activos fijos - `fa_depreciation`: Depreciaciรณn de activos - `fa_maintenance`: Mantenimiento de activos - `fa_transfers`: Transferencias de activos **Nota histรณrica**: Anteriormente se utilizaba el prefijo `q` (SCAF - Sistema de Control de Activos Fijos). ### Diagrama de Arquitectura de Schemas ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ DATABASE: anexo76_db โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ Schema: a24 โ”‚ โ”‚ Schema: a76 โ”‚ โ”‚Schema: public โ”‚ โ”‚ โ”‚ โ”‚ (Anexo 24) โ”‚ โ”‚ (Anexo 76) โ”‚ โ”‚ (Catรกlogos) โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ inv_products โ”‚ โ”‚ pedimentos โ”‚ โ”‚ material_typesโ”‚ โ”‚ โ”‚ โ”‚ inv_movements โ”‚ โ”‚ facturas โ”‚ โ”‚ uom_codes โ”‚ โ”‚ โ”‚ โ”‚ inv_warehouses โ”‚ โ”‚ customs_docs โ”‚ โ”‚ countries โ”‚ โ”‚ โ”‚ โ”‚ inv_balances โ”‚ โ”‚ export_ops โ”‚ โ”‚ customs_list โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ document_typesโ”‚ โ”‚ โ”‚ โ”‚ fa_assets โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ fa_depreciationโ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ fa_maintenance โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ fa_transfers โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` ### Ventajas de esta Arquitectura 1. **Separaciรณn Lรณgica**: Cada schema representa un dominio especรญfico del negocio 2. **Escalabilidad**: Facilita la adiciรณn de nuevos mรณdulos sin afectar los existentes 3. **Seguridad**: Permite aplicar permisos a nivel de schema 4. **Mantenibilidad**: Cรณdigo y migraciones organizados por dominio 5. **Claridad**: Los prefijos hacen evidente la funcionalidad de cada tabla 6. **Migraciรณn Gradual**: Permite actualizar sistemas legados (SCAII/SCAF) sin interrupciones ### Mapeo de Sistemas Legados | Sistema Legacy | Prefijo Antiguo | Sistema Nuevo | Prefijo Nuevo | Schema | |----------------------|-----------------|-------------------|---------------|----------| | SCAII (Inventarios) | `s` | Inventarios | `inv_` | `a24` | | SCAF (Activos Fijos) | `q` | Fixed Assets | `fa_` | `a24` | | Winsaii (Pedimentos) | `w` | - | - | `a22` | | - | `g` | Comercio Exterior | - | `a76` | | - | `g` | Catรกlogos SAT | - | `public` | --- ## Estructura del Proyecto ``` anexo76/ โ”œโ”€โ”€ backend/ โ”‚ โ”œโ”€โ”€ main.py # Aplicaciรณn FastAPI principal โ”‚ โ”œโ”€โ”€ requirements.txt # Dependencias โ”‚ โ”œโ”€โ”€ init_db.py # Script de inicializaciรณn โ”‚ โ”œโ”€โ”€ Dockerfile โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ core/ # Capa core (shared) โ”‚ โ”‚ โ”œโ”€โ”€ config.py # Configuraciรณn (Pydantic Settings) โ”‚ โ”‚ โ”œโ”€โ”€ database.py # Gestiรณn de BD multi-tenant โ”‚ โ”‚ โ”œโ”€โ”€ security.py # Auth Keycloak + JWT โ”‚ โ”‚ โ”œโ”€โ”€ middleware.py # Middlewares personalizados โ”‚ โ”‚ โ””โ”€โ”€ __init__.py โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ api/ โ”‚ โ””โ”€โ”€ v1/ โ”‚ โ”œโ”€โ”€ router.py # Router principal v1 โ”‚ โ”œโ”€โ”€ common/ # Utilidades compartidas โ”‚ โ”‚ โ”œโ”€โ”€ base_models.py โ”‚ โ”‚ โ”œโ”€โ”€ crud_routes.py โ”‚ โ”‚ โ”œโ”€โ”€ dto_mixins.py โ”‚ โ”‚ โ””โ”€โ”€ tenant_crud_routes.py โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ modules/ # Mรณdulos de negocio por schema โ”‚ โ”œโ”€โ”€ a24/ # Mรณdulo Anexo 24 (Inventarios) โ”‚ โ”‚ โ”œโ”€โ”€ inventarios/ โ”‚ โ”‚ โ””โ”€โ”€ activos_fijos/ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ a76/ # Mรณdulo Anexo 76 (Comercio Exterior) โ”‚ โ”‚ โ”œโ”€โ”€ pedimentos/ โ”‚ โ”‚ โ””โ”€โ”€ facturas/ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ public/ # Catรกlogos compartidos โ”‚ โ”œโ”€โ”€ material_types/ โ”‚ โ”œโ”€โ”€ uom_codes/ โ”‚ โ””โ”€โ”€ countries/ โ”‚ โ”œโ”€โ”€ frontend/ โ”‚ โ”œโ”€โ”€ src/ โ”‚ โ”‚ โ”œโ”€โ”€ routes/ # Pรกginas SvelteKit โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ +layout.svelte # Layout global con Keycloak โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ +page.svelte # Dashboard principal โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ callback/ # OAuth callback โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ lib/ โ”‚ โ”‚ โ”œโ”€โ”€ auth.ts # Servicio de autenticaciรณn โ”‚ โ”‚ โ””โ”€โ”€ api.ts # Cliente API โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ static/ โ”‚ โ”‚ โ””โ”€โ”€ silent-check-sso.html โ”‚ โ”œโ”€โ”€ package.json โ”‚ โ””โ”€โ”€ Dockerfile โ”‚ โ”œโ”€โ”€ docs/ โ”‚ โ”œโ”€โ”€ KEYCLOAK_SETUP.md # Guรญa de configuraciรณn โ”‚ โ””โ”€โ”€ ARCHITECTURE.md # Este documento โ”‚ โ”œโ”€โ”€ docker-compose.yml # Orquestaciรณn completa โ”œโ”€โ”€ start.sh # Script de inicio rรกpido โ”œโ”€โ”€ README.md # Documentaciรณn principal โ””โ”€โ”€ .gitignore ``` --- ## Flujos Principales ### 1. Flujo de Autenticaciรณn ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Frontend โ”‚ โ”‚ Keycloak โ”‚ โ”‚ Backend โ”‚ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ 1. Clic "Login" โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ 2. Formulario de login โ”‚ โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ 3. Credenciales โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ 4. Redirigir + auth code โ”‚ โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ 5. Intercambiar code x tokenโ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ 6. JWT (access + refresh) โ”‚ โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ 7. Request con Bearer token โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ 8. Validar token โ”‚ โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ 9. Public key โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ 10. Respuesta con datos โ”‚ โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ”‚ โ”‚ ``` ### 2. Flujo de Request Multi-tenant ``` Request con JWT โ†“ TenantMiddleware โ”œโ”€ Extrae tenant_id del token โ”œโ”€ Valida tenant existe y estรก activo โ””โ”€ Agrega tenant_id a request.state โ†“ LicenseValidationMiddleware โ”œโ”€ Consulta licencia del tenant โ”œโ”€ Valida estado (active/expired) โ”œโ”€ Valida fecha de vigencia โ””โ”€ Agrega license_info a request.state โ†“ Endpoint Handler โ”œโ”€ Obtiene tenant_id de request.state โ”œโ”€ Selecciona BD (shared o dedicated) โ””โ”€ Procesa request โ†“ Response ``` ### 3. Flujo de Selecciรณn de Base de Datos ```python # Pseudocรณdigo tenant_id = request.state.tenant_id tenant = db.query(Tenant).filter(Tenant.id == tenant_id).first() if tenant.type == "SHARED": # Usar BD compartida (core_db) db_session = CoreSessionLocal() # Queries incluyen tenant_id en WHERE elif tenant.type == "DEDICATED": # Usar BD dedicada del tenant db_config = json.loads(tenant.db_config) db_session = get_tenant_db(tenant_id, db_config) # No necesita filtrar por tenant_id ``` --- ## Seguridad ### Autenticaciรณn - **Keycloak** como Identity Provider - **OpenID Connect** (OIDC) - **JWT** con RS256 (firma asimรฉtrica) - **Refresh tokens** para renovaciรณn ### Autorizaciรณn - **RBAC** (Role-Based Access Control) - Roles: `admin`, `user`, `auditor`, `system` - Middleware `has_role()` para proteger endpoints ### Multi-tenancy - **Aislamiento por tenant_id** en JWT - **Row-level security** en BD compartida - **BD dedicada** para mayor aislamiento (enterprise) ### Row-Level Security (RLS) en BD compartida > Convenciรณn alineada al skill `aduanasoft-dev-standards` (secciรณn 10). > La capa API sigue siendo responsable del control fino (roles/permisos > con Keycloak + `PermissionService`); RLS aรฑade **defensa en profundidad** > a nivel de BD para que un bug en un `WHERE` no permita salirse del tenant. #### Variables de sesiรณn (`SET LOCAL`) | GUC | Origen | Comportamiento RLS | |-----|--------|--------------------| | `app.tenant_id` | JWT (`TenantMiddleware`) โ†’ `request.state.tenant_id` | Obligatoria. Si estรก vacรญa, `app.current_tenant_id()` retorna `NULL` y las polรญticas devuelven `0` filas (fail-closed). | | `app.company_id` | Header `X-Company-Id` o cookie `active_company_id` | Opcional. Si estรก vacรญa, el tenant ve **todas sus compaรฑรญas** (รบtil para selectores de compaรฑรญa y bootstrap). | Ambas se fijan con `SET LOCAL` al inicio de cada transacciรณn โ€” **nunca** con `SET` global, para no contaminar conexiones del pool. Helpers SQL definidos por la migraciรณn `d1a2b3c4e5f6_enable_rls_tenant_company`: ```sql CREATE FUNCTION app.current_tenant_id() RETURNS INTEGER LANGUAGE sql STABLE AS $$ SELECT NULLIF(current_setting('app.tenant_id', true), '')::INTEGER $$; CREATE FUNCTION app.current_company_id() RETURNS INTEGER LANGUAGE sql STABLE AS $$ SELECT NULLIF(current_setting('app.company_id', true), '')::INTEGER $$; ``` #### Tipos de polรญtica 1. **Solo `tenant_id`** (p.ej. `a76.company`, `core.licenses`): `tenant_id = app.current_tenant_id()`. 2. **`tenant_id` + `company_id`** (`TenantScopedMixin`, mayorรญa de tablas `a24/`a76/`core`): ademรกs exige `company_id = app.current_company_id()` cuando esa GUC estรก fijada. 3. **Solo `company_id`** (algunas tablas `a76.company_*`): valida el `tenant_id` indirectamente vรญa `EXISTS` contra `a76.company`. Todas las tablas usan `FORCE ROW LEVEL SECURITY` para que la polรญtica aplique tambiรฉn al owner. Las รบnicas tablas core **excluidas** son `core.tenants` y `core.user_tenants` โ€” necesarias para el bootstrap del selector de tenant antes de tener contexto fijado. #### Propagaciรณn del contexto | Camino | Cรณmo se fija el contexto | |--------|--------------------------| | HTTP request | `TenantMiddleware` rellena `request.state.tenant_id`/`company_id`; `get_core_db` / `get_async_core_db` leen esos valores y los guardan en `Session.info`. Un listener `after_begin` ejecuta `SET LOCAL` por transacciรณn. | | `LicenseValidationMiddleware` | Usa `scoped_core_db(tenant_id=...)` para que la consulta de licencia entre con contexto RLS vรกlido. | | Tareas Celery | `track_and_dispatch` inyecta `rls_tenant_id` / `rls_company_id` en los headers del task; los signals `task_prerun`/`task_postrun` los copian a `ContextVar`s del worker, que el listener `after_begin` consume como fallback. Tareas crรญticas (imports/exports de invoices, expediente) abren la sesiรณn con `scoped_core_db(tenant_id=..., company_id=...)`. | | Tests | Las suites de pytest pueden usar `scoped_core_db(...)` o emular el flujo con `set_config('app.tenant_id', ...)` antes del query. Hay un set de tests en `backend/tests/integration/test_rls_tenant_company.py` que valida aislamiento A vs B usando un rol sin `BYPASSRLS`. | #### Reparto de responsabilidades | Capa | Decide | |------|--------| | **API (FastAPI + Keycloak + `PermissionService`)** | Roles, permisos por compaรฑรญa, accesos a recursos concretos (`validate_access_to_resource`), reglas de negocio. | | **RLS (PostgreSQL)** | Lรญmite estructural duro: `tenant_id` y `company_id`. **No** modela roles/permisos para evitar duplicar lรณgica fina con la API. | #### Operaciรณn / DevOps - En **producciรณn** la API debe conectar con un rol **sin** `BYPASSRLS` (`postgres` superusuario lo bypassea por diseรฑo). El `docker-compose.yml` de desarrollo usa `postgres` deliberadamente para no romper migraciones; los tests crean un rol `anexo76_rls_test` para ejercitar las polรญticas. - Los jobs/ETL/migraciones que necesiten ver todos los tenants deben usar un rol tรฉcnico explรญcito con `BYPASSRLS` o fijar `app.tenant_id` por iteraciรณn โ€” nunca asumir que la sesiรณn global "ve todo". - La migraciรณn `d1a2b3c4e5f6_enable_rls_tenant_company` tiene `downgrade()` completo (drop policies + `DISABLE ROW LEVEL SECURITY`) para revertir. ### Validaciรณn de Licencias - Middleware verifica en cada request: - โœ“ Licencia activa - โœ“ No expirada - โœ“ Lรญmites no excedidos --- ## Base de Datos ### Modelo Hรญbrido Multi-tenant #### BD Core (Compartida) Tablas principales: - `tenants`: Informaciรณn de clientes - `licenses`: Control de licencias por tenant - `license_usage`: Mรฉtricas de uso - `users` (futuro): Usuarios por tenant Todas las tablas operacionales incluyen `tenant_id` para segmentaciรณn. #### BD Dedicadas (Enterprise) - Una BD PostgreSQL por tenant - Configuraciรณn almacenada en `tenants.db_config` - Migraciรณn automรกtica desde BD compartida ### Ejemplo de Tabla Multi-tenant ```sql CREATE TABLE inventories ( id SERIAL PRIMARY KEY, tenant_id INTEGER NOT NULL REFERENCES tenants(id), product_code VARCHAR(50) NOT NULL, quantity INTEGER NOT NULL, created_at TIMESTAMP DEFAULT NOW(), -- รndice compuesto para queries eficientes INDEX idx_tenant_product (tenant_id, product_code) ); ``` ### Migraciรณn y Upgrade ```python # Tenant en BD compartida โ†’ BD dedicada tenant_service.upgrade_to_dedicated( tenant_id=123, db_config={ "host": "dedicated-postgres.example.com", "port": 5432, "name": "tenant_123_db", "user": "tenant_123_user", "password": "secure_password" } ) ``` --- ## API Reference ### Mรณdulo: Authentication (`/v1/auth`) | Endpoint | Mรฉtodo | Descripciรณn | Auth | |----------|--------|-------------|------| | `/auth/login` | POST | Login con Keycloak | Pรบblico | | `/auth/refresh` | POST | Renovar access token | Pรบblico | | `/auth/me` | GET | Info del usuario actual | Bearer | | `/auth/logout` | POST | Cerrar sesiรณn | Bearer | | `/auth/health` | GET | Health check | Pรบblico | ### Mรณdulo: Tenants (`/v1/tenants`) | Endpoint | Mรฉtodo | Descripciรณn | Rol Requerido | |----------|--------|-------------|---------------| | `/tenants` | POST | Crear tenant | admin | | `/tenants` | GET | Listar tenants | admin | | `/tenants/{id}` | GET | Obtener tenant | user | | `/tenants/{id}` | PUT | Actualizar tenant | admin | | `/tenants/{id}` | DELETE | Eliminar tenant | admin | | `/tenants/slug/{slug}` | GET | Obtener por slug | user | ### Mรณdulo: Licenses (`/v1/licenses`) | Endpoint | Mรฉtodo | Descripciรณn | Rol Requerido | |----------|--------|-------------|---------------| | `/licenses` | POST | Crear licencia | admin | | `/licenses/tenant/{id}` | GET | Obtener licencia | user | | `/licenses/tenant/{id}` | PUT | Actualizar licencia | admin | | `/licenses/validate/{id}` | GET | Validar licencia | user | | `/licenses/usage/{id}` | GET | Uso de licencia | user | | `/licenses/my-license` | GET | Mi licencia | user | ### Planes de Licencia | Plan | Usuarios | Storage | Operaciones/mes | Features | |------|----------|---------|-----------------|----------| | Free | 5 | 10 GB | 1,000 | API bรกsica | | Basic | 20 | 50 GB | 10,000 | + Reportes | | Professional | 100 | 200 GB | 50,000 | + Integraciones | | Enterprise | โˆž | โˆž | โˆž | + Soporte + BD dedicada | --- ## Prรณximas Implementaciones ### Backend - [ ] Mรณdulo de inventarios - [ ] Mรณdulo de pedimentos - [ ] Mรณdulo de facturas - [ ] Webhooks para integraciones - [ ] Reportes avanzados - [ ] Export/Import de datos ### Frontend - [ ] Dashboard con grรกficas - [ ] Gestiรณn de inventarios UI - [ ] Formularios de pedimentos - [ ] Panel de administraciรณn - [ ] Reportes interactivos ### DevOps - [ ] CI/CD pipeline - [ ] Tests automatizados - [ ] Monitoreo con Prometheus - [ ] Dashboards de Grafana - [ ] Deploy a Kubernetes - [ ] Backup automatizado --- **รšltima actualizaciรณn**: Octubre 2025 **Versiรณn del documento**: 1.0