diff --git a/README.md b/README.md index 929189d5..d300d730 100644 --- a/README.md +++ b/README.md @@ -1,344 +1,156 @@ -# Anexo76 +# Plantilla Workspace — Aduanasoft -**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 negocio - - `routes.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 - -```bash -git clone -cd anexo76 -``` - -### 2. Configurar variables de entorno - -```bash -cp backend/.env.example backend/.env -# Editar backend/.env con tus configuraciones -``` - -### 3. Iniciar con Docker Compose - -```bash -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 - -1. Acceder a Keycloak: http://localhost:8080 -2. Login: `admin` / `admin` -3. Crear un nuevo realm o usar el realm `master` -4. Crear cliente para backend: - - Client ID: `anexo76-backend` - - Client Protocol: `openid-connect` - - Access Type: `confidential` - - Copiar el Secret y agregarlo a `.env` -5. Crear cliente para frontend: - - Client ID: `anexo76-frontend` - - Client Protocol: `openid-connect` - - Access Type: `public` - - Valid Redirect URIs: `http://localhost:5173/*` - -### 5. Inicializar base de datos - -```bash -# 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..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 - -```bash -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 - -```bash -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 - -1. Usuario ingresa credenciales + tenant_slug -2. Backend valida contra Keycloak del realm del tenant -3. Keycloak retorna JWT con tenant_id y roles -4. Middleware valida tenant y licencia en cada request -5. Request procesado si todo es válido - -### Roles Disponibles - -- `admin`: Administrador con acceso total -- `user`: Usuario estándar -- `auditor`: Solo lectura con acceso a reportes -- `system`: Para integraciones y servicios - -## 🎯 Multi-Tenancy - -### Modelo Híbrido - -**BD Compartida** (tenants pequeños/medianos): - -- Tabla única con `tenant_id` como 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 - -```python -# 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 - -```bash -# 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 - -1. Fork el proyecto -2. Crear rama feature (`git checkout -b feature/AmazingFeature`) -3. Commit cambios (`git commit -m 'Add some AmazingFeature'`) -4. Push a la rama (`git push origin feature/AmazingFeature`) -5. 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 +Plantilla base para nuevos proyectos del ecosistema **Workspace de Aduanasoft**. +Incluye autenticación SSO con Keycloak/Hub, arquitectura multi-tenant, y un dashboard +funcional listo para extender. --- -**Desarrollado con ❤️ para la industria de comercio exterior mexicana** +## Stack + +| Capa | Tecnología | +|---|---| +| Frontend | SvelteKit 5 + Tailwind CSS | +| Backend | FastAPI + SQLAlchemy + PostgreSQL | +| Auth | Keycloak (OpenID Connect) vía Workspace Hub | +| Cache / Queue | Valkey (Redis) + Celery | +| Storage | MinIO (S3-compatible) | +| Contenedores | Docker Compose | + +--- + +## Estructura del proyecto + +``` +├── backend/ +│ ├── api/v1/modules/ +│ │ ├── core/ # Auth, usuarios, tenants, permisos, licencias +│ │ └── example/ # Módulo de referencia — copia y renombra +│ ├── core/ # Config, seguridad, DB, middleware +│ └── alembic/ # Migraciones (solo esquema core) +│ +├── frontend/ +│ ├── src/routes/ +│ │ ├── auth/ # Callback OAuth2, SSO, logout +│ │ ├── login/ # Login local (dev) o redirect al workspace +│ │ └── dashboard/ # Shell + rutas stub +│ └── src/lib/ +│ ├── server/ # workspace-auth, workspace-apps, api SSR +│ └── stores/ # company, system, workspace-apps +│ +└── scripts/ + └── auth-mode.sh # Alterna entre modo local y workspace +``` + +--- + +## Inicio rápido + +### 1. Clonar y configurar + +```bash +git clone https://git.aduanasoft.com/ADUANASOFT/plantillas-proyectos.git mi-proyecto +cd mi-proyecto +``` + +Renombrar el proyecto en `.env` y `docker-compose.yml`: +- `CORE_DB_NAME=app_core` → `mi_proyecto_core` +- `name: app` en `docker-compose.yml` → `mi-proyecto` + +### 2. Levantar en modo local (sin workspace) + +```bash +./scripts/auth-mode.sh local +docker compose up -d +``` + +Abre `http://localhost:5173` → click **"Entrar como dev"**. + +### 3. Conectar al workspace + +```bash +./scripts/auth-mode.sh workspace +# Pregunta: +# URL del workspace → https://workspace.aduanasoft.com +# Keycloak Realm → master +# Keycloak Client ID → nombre-del-client +``` + +> El equipo del Hub debe registrar la app y agregar el redirect URI: +> `http://localhost:5173/auth/callback` + +--- + +## Variables de entorno + +El `.env` usa una sola URL base para derivar toda la configuración del workspace: + +```env +# Una variable, todo se deriva de aquí +WORKSPACE_URL=https://workspace.aduanasoft.com +KEYCLOAK_REALM=master +KEYCLOAK_CLIENT_ID=mi-app-frontend + +# Auth local (desarrollo sin workspace) +DEV_LOCAL_AUTH=False # True = botón "Entrar como dev" +SECRET_KEY=... # Se genera automáticamente con auth-mode.sh local +``` + +El `docker-compose.yml` construye automáticamente: +- `HUB_URL` = `${WORKSPACE_URL}` +- `VITE_KEYCLOAK_URL` = `${WORKSPACE_URL}/kcauth` + +--- + +## Agregar un módulo nuevo + +### Backend + +Copia `backend/api/v1/modules/example/` y renombra: + +``` +my_module/ +├── __init__.py +├── models.py # SQLAlchemy — hereda TenantScopedMixin + TimestampMixin +├── dto.py # Pydantic v2 — Request / Response separados +├── service.py # Lógica de negocio, recibe db + tenant_id + company_id +└── routes.py # FastAPI router, usa Depends(get_current_user) +``` + +Registrar en `backend/api/v1/router.py`: + +```python +from .modules.my_module.routes import router as my_router +router.include_router(my_router, prefix="/my-module", tags=["my-module"]) +``` + +### Frontend + +Crear `frontend/src/routes/dashboard/my-module/+page.svelte` y agregar al sidebar en +`frontend/src/lib/components/sidebar/modules.ts`: + +```typescript +{ title: 'Mi módulo', url: '/dashboard/my-module', icon: MyIcon } +``` + +--- + +## Script auth-mode + +```bash +./scripts/auth-mode.sh status # Ver modo actual +./scripts/auth-mode.sh local # Activar login local (dev sin workspace) +./scripts/auth-mode.sh workspace # Configurar y conectar al workspace +``` + +Al cambiar de modo el script pregunta si reiniciar los contenedores automáticamente. + +--- + +## Convenciones + +- **Commits**: Conventional Commits (`feat:`, `fix:`, `refactor:`, `chore:`) +- **Branches**: `feature/DESC`, `fix/DESC` +- **Nombres en código**: inglés; comentarios de lógica de negocio en español +- **Backend**: Pydantic v2, async por default, routers por dominio +- **Frontend**: SvelteKit 5 runes (`$state`, `$derived`, `$effect`), Tailwind utility-first