Arquitectura
This content is not available in your language yet.
ERP DLM es un ERP completo construido con Python FastAPI + Vue 3 + PrimeVue 4 + PostgreSQL 16, containerizado con Docker Compose.
Stack tecnológico
Sección titulada «Stack tecnológico»| Capa | Tecnología |
|---|---|
| Backend | Python 3.13, FastAPI, SQLAlchemy 2.0 async, asyncpg, Alembic, Pydantic v2 |
| Frontend | Vue 3 Composition API, TypeScript, PrimeVue 4, Pinia, vue-i18n, Vite |
| Base de datos | PostgreSQL 16 (UUID PKs, soft deletes, timestamps, JSONB) |
| Infraestructura | Docker Compose (postgres, redis, backend, frontend), Caddy reverse proxy |
Estructura del repositorio
Sección titulada «Estructura del repositorio»erp-dlm/├── backend/│ └── app/│ ├── core/ # Auth, DB, module_loader, servicios core│ └── modules/ # ~50 módulos funcionales├── frontend/│ └── src/│ ├── core/ # Layouts, componentes reutilizables, API client, tours│ ├── modules/ # Vistas por módulo│ ├── locales/ # es.json, en.json│ └── router/ # Vue Router con lazy loading├── docs/ # Documentación técnica adicional└── docs-site/ # Este sitio de documentación (Astro + Starlight)Módulos del backend
Sección titulada «Módulos del backend»Cada módulo funcional vive en backend/app/modules/<nombre>/ y contiene típicamente:
__init__.py— puede estar vacío.api.py— variablerouter = APIRouter(prefix="", ...).models.py— tablas SQLAlchemy.schemas.py— modelos Pydantic.service.py— lógica de negocio.
Module loader
Sección titulada «Module loader»backend/app/core/module_loader.py escanea backend/app/modules/ en el arranque y registra automáticamente cada módulo con el prefijo /api/{nombre-del-modulo}.
Reglas importantes:
- El
routerde cadaapi.pydebe tenerprefix="". - El loader convierte guiones bajos en guiones:
sales_invoicesse monta como/api/sales-invoices. - Algunos módulos se excluyen del auto-descubrimiento y se registran manualmente en
main.py:bank_reconciliation→/api/bank-reconciliationmcp_server→/api/mcpclient_portal→/api/portalaccounting/reports_api.py→/apisaas_manager→/api/saas
Multi-tenant por subdominio
Sección titulada «Multi-tenant por subdominio»El sistema soporta multi-tenant a través del header Host.
erp.ovlicuo.com→ instancia por defecto.acme-sl.erp.ovlicuo.com→ tenantacme-sl.
El middleware (backend/app/core/tenant_middleware.py) extrae el subdominio, consulta la base de datos del gestor SaaS (saas_manager) y crea un engine SQLAlchemy cacheado para la base de datos del tenant. La variable request.state.tenant_subdomain se propaga a get_db().
Servicios core
Sección titulada «Servicios core»| Servicio | Fichero | Responsabilidad |
|---|---|---|
accounting_service |
backend/app/core/accounting_service.py |
Genera asientos contables automáticos desde facturas y define mapeo de subcuentas de IVA/RE |
numbering |
backend/app/core/numbering.py |
Numeración automática de documentos: {SERIE}-{AÑO}-{SECUENCIA:05d} |
pdf_service |
backend/app/core/pdf_service.py |
Generación de PDFs con ReportLab |
stock_service |
backend/app/core/stock_service.py |
Gestión de stock por almacén, reservas e-commerce y transferencias |
tax_reports |
backend/app/core/tax_reports.py |
Modelos fiscales españoles: 303, 347, 349, 111, 115, 390, 190, 130 |
document_workflow |
backend/app/core/document_workflow.py |
Conversión entre documentos de ventas/compras |
Autenticación y permisos
Sección titulada «Autenticación y permisos»El backend usa JWT:
- Login:
POST /api/auth/logindevuelveaccess_tokenyrefresh_token. - Refresh:
POST /api/auth/refresh. - Perfil:
GET /api/auth/me. - Permisos:
GET /api/auth/me/permissions.
Para integraciones externas existe el módulo api_tokens, que permite crear tokens con ámbitos (api_access) y filtrar por company_id en entornos multi-tenant.
Convenciones de frontend
Sección titulada «Convenciones de frontend»- Views orquestan páginas, Components reciben props y emiten eventos, Composables contienen la lógica.
apiClienttienebaseURL: '/api': las llamadas usan rutas sin duplicar el prefijo (apiClient.get('/agents')).- PrimeVue 4: usa
Select(noDropdown),ToggleSwitch(noInputSwitch) yTabs/TabList/Tab(noTabView). - Cada nueva vista del router bajo
MainLayoutrequiere tour (core/tours/<routeName>.ts), registro encore/tours/registry.ts, guía encore/guide/guide-content.tsy claves i18n enes.jsonyen.json.