Reviewed-on: ADUANASOFT/anexo76#470
Anexo76
Aplicación SaaS para gestión de comercio exterior conforme a Anexos 24, 30 y 22 del SAT
Anexo76 es una plataforma multi-tenant diseñada para maquilas, empresas IMMEX y agentes aduanales, que permite gestionar inventarios, pedimentos y facturas de importación/exportación con control de licencias y cumplimiento normativo.
🏗️ Arquitectura
Backend
- Framework: FastAPI 0.110+
- Autenticación: Keycloak (OpenID Connect)
- Base de Datos: PostgreSQL con SQLAlchemy
- Modelo Multi-tenant: Híbrido
- BD compartida para tenants pequeños/medianos
- BD dedicadas para clientes enterprise
- Estructura Modular: Patrón similar a NestJS
models.py: Modelos ORM (SQLAlchemy)dto.py: Data Transfer Objects (Pydantic)service.py: Lógica de negocioroutes.py: Endpoints API
Frontend
- Framework: SvelteKit
- Autenticación: keycloak-js
- UI: Dashboard moderno y responsivo
Infraestructura
- Containerización: Docker / Docker Compose
- Orquestación: Kubernetes (futuro)
- Monitoreo: Prometheus + Grafana
📁 Estructura del Proyecto
anexo76/
├── backend/
│ ├── main.py # Aplicación FastAPI principal
│ ├── requirements.txt # Dependencias Python
│ ├── .env.example # Variables de entorno de ejemplo
│ ├── core/ # Módulos core
│ │ ├── config.py # Configuración centralizada
│ │ ├── paths.py # Rutas base y layout_path() para importación CSV
│ │ ├── database.py # Configuración de BD multi-tenant
│ │ ├── security.py # Autenticación y autorización
│ │ └── middleware.py # Middlewares personalizados
│ ├── layouts/ # Directorio de datos: temp y errors de importación CSV (creado al arranque)
│ └── api/
│ └── v1/
│ ├── router.py # Router principal API v1
│ └── modules/ # Módulos de negocio
│ └── a76/
│ ├── layouts_csv/ # Lógica centralizada de cargas por CSV (routes, tasks, validaciones por proceso)
│ │ ├── facturas/
│ │ ├── customs_brokers/
│ │ ├── clients_and_providers/
│ │ └── ... # Una carpeta por proceso de importación
│ ├── csv_templates/
│ └── ...
│ ├── auth/
│ ├── tenants/ # Gestión de tenants
│ ├── licenses/ # Control de licencias
│ └── ...
├── frontend/
│ ├── src/
│ │ ├── routes/
│ │ ├── lib/
│ │ └── app.html
│ ├── package.json
│ └── svelte.config.js
├── docker-compose.yml
└── README.md
🚀 Inicio Rápido
Requisitos Previos
- Docker y Docker Compose
- Python 3.11+ (para desarrollo local)
- Node.js 18+ (para desarrollo frontend)
1. Clonar el repositorio
git clone <repository-url>
cd anexo76
2. Configurar variables de entorno
cp backend/.env.example backend/.env
# Editar backend/.env con tus configuraciones
3. Iniciar con Docker Compose
docker-compose up -d
Esto iniciará:
- PostgreSQL en
localhost:5432 - Keycloak en
localhost:8080 - Backend API en
localhost:8000 - Frontend en
localhost:5173
4. Configurar Keycloak
- Acceder a Keycloak: http://localhost:8080
- Login:
admin/admin - Crear un nuevo realm o usar el realm
master - Crear cliente para backend:
- Client ID:
anexo76-backend - Client Protocol:
openid-connect - Access Type:
confidential - Copiar el Secret y agregarlo a
.env
- Client ID:
- Crear cliente para frontend:
- Client ID:
anexo76-frontend - Client Protocol:
openid-connect - Access Type:
public - Valid Redirect URIs:
http://localhost:5173/*
- Client ID:
5. Inicializar base de datos
# Con Docker
docker-compose exec backend python -c "from core.database import init_db; init_db()"
# O localmente
cd backend
python -c "from core.database import init_db; init_db()"
6. Acceder a la aplicación
- API Documentation: http://localhost:8000/docs
- Frontend: http://localhost:5173
- Keycloak Admin: http://localhost:8080
🛠️ Produccion
docker build -t dev.aduanasoft.com/anexo76/backend:latest -f ./backend/Dockerfile ./backend
Importación CSV y workers Celery: La lógica de cargas por CSV está en api/v1/modules/a76/layouts_csv/ (una carpeta por proceso). Los workers Celery deben cargar los módulos api.v1.modules.a76.layouts_csv.<proceso>.tasks. El directorio de trabajo del worker debe ser la raíz del backend para que layout_path("imports", "temp") y layout_path("imports", "errors") apunten a los mismos directorios que la API. Si API y worker comparten volumen, los archivos temporales y de errores se escriben en backend/layouts/imports/temp y backend/layouts/imports/errors.
docker build -t dev.aduanasoft.com/anexo76/backend:latest -f ./backend/Dockerfile ./backend
docker build \
--build-arg VITE_API_URL=https://anexo76-dev.aduanasoft.com/api/ \
--build-arg VITE_KEYCLOAK_URL=https://anexo76-dev.aduanasoft.com/kcauth/ \
--build-arg INTERNAL_API_URL=http://backend:3467/api/ \
-t dev.aduanasoft.com/anexo76/frontend:latest \
-f ./frontend/Dockerfile.prod \
./frontend
Publica en el registro (ajusta el registry si corresponde):
docker login dev.aduanasoft.com
docker push dev.aduanasoft.com/anexo76/backend:latest
docker push dev.aduanasoft.com/anexo76/frontend:latest
🛠️ Desarrollo Local
Backend
cd backend
python -m venv .venv
source .venv/bin/activate # En Windows: .venv\Scripts\activate
pip install -r requirements.txt
uvicorn main:app --reload
Los directorios backend/layouts/imports/temp y backend/layouts/imports/errors se crean automáticamente al arrancar el backend para la importación CSV.
Frontend
cd frontend
npm install
npm run dev
📦 Módulos Principales
1. Auth (/v1/auth)
- Login con Keycloak
- Refresh token
- Logout
- Información de usuario
2. Tenants (/v1/tenants)
- Creación y gestión de tenants
- Upgrade de BD compartida a dedicada
- Gestión de realms de Keycloak
3. Licenses (/v1/licenses)
- Control de planes (Free, Basic, Professional, Enterprise)
- Validación de licencias activas
- Tracking de uso (usuarios, storage, operaciones)
- Límites por plan
🔐 Autenticación y Autorización
Flujo de Autenticación
- Usuario ingresa credenciales + tenant_slug
- Backend valida contra Keycloak del realm del tenant
- Keycloak retorna JWT con tenant_id y roles
- Middleware valida tenant y licencia en cada request
- Request procesado si todo es válido
Roles Disponibles
admin: Administrador con acceso totaluser: Usuario estándarauditor: Solo lectura con acceso a reportessystem: Para integraciones y servicios
🎯 Multi-Tenancy
Modelo Híbrido
BD Compartida (tenants pequeños/medianos):
- Tabla única con
tenant_idcomo foreign key - Row-level security
- Más económico para clientes con bajo volumen
BD Dedicada (tenants enterprise):
- Base de datos PostgreSQL independiente
- Máximo aislamiento y performance
- Configuración almacenada en
tenants.db_config
Migración de Shared a Dedicated
# Ejemplo de upgrade
from api.v1.modules.tenants.service import TenantService
db_config = {
"host": "dedicated-db-host.example.com",
"port": 5432,
"name": "tenant_123_db",
"user": "tenant_123_user",
"password": "secure_password"
}
service = TenantService(db)
service.upgrade_to_dedicated(tenant_id=123, db_config=db_config)
📊 Control de Licencias
Planes Disponibles
| 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 | Ilimitado | Ilimitado | Ilimitado | + Soporte dedicado + BD dedicada |
Middleware de Validación
El LicenseValidationMiddleware verifica en cada request:
- ✅ Licencia activa
- ✅ No expirada
- ✅ Límites no excedidos
- ✅ Features habilitadas
🧪 Testing
# Backend
cd backend
pytest
# Con cobertura
pytest --cov=. --cov-report=html
# Frontend
cd frontend
npm test
📈 Monitoreo
Prometheus Metrics
El backend expone métricas en /metrics:
- Request duration
- Request count por endpoint
- Error rate
- Active connections
Logging
Logs estructurados con nivel configurable:
- INFO: Operaciones normales
- WARNING: Validaciones fallidas
- ERROR: Errores de sistema
- DEBUG: Información detallada (solo desarrollo)
🤝 Contribución
- Fork el proyecto
- Crear rama feature (
git checkout -b feature/AmazingFeature) - Commit cambios (
git commit -m 'Add some AmazingFeature') - Push a la rama (
git push origin feature/AmazingFeature) - Abrir Pull Request
📝 Licencia
Este proyecto es privado y propietario.
📞 Soporte
Para soporte técnico o consultas:
- Email: soporte@anexo76.com
- Documentación: https://docs.anexo76.com
Desarrollado con ❤️ para la industria de comercio exterior mexicana