Arquitectura Backend y Hono RPC
⚙️ Arquitectura Backend y Hono RPC
Sección titulada «⚙️ Arquitectura Backend y Hono RPC»El backend de Criptofolio (apps/backend) es un servicio centralizado, ligero y ultrarrápido construido sobre Hono.js.
Actúa como la única fuente de verdad para:
- Las rutas de la API REST consumidas por la aplicación frontend en Vue 3.
- La seguridad de tipos extremo a extremo mediante Hono RPC sin generadores de código intermedios.
- El almacenamiento seguro de credenciales cifradas (Bóveda).
- La coordinación analítica entre SQLite y el motor DuckDB.
🏛️ Estructura del Servidor y Separación de Responsabilidades
Sección titulada «🏛️ Estructura del Servidor y Separación de Responsabilidades»El backend se divide en dos puntos de entrada bien diferenciados:
apps/backend/src/├── app.ts # Aplicación pura Hono: middlewares, enrutado y exportación de AppType├── index.ts # Bootstrapper: pool de bases de datos, tareas programadas, puerto HTTP├── core/│ ├── domain/ # Modelos e interfaces del dominio│ ├── application/ # Casos de Uso (ej. UnlockVaultUseCase, IngestTransactionsUseCase)│ └── infrastructure/│ ├── di/container.ts# Contenedor central de Inyección de Dependencias (Composition Root)│ ├── adapters/ # Adaptadores para los motores SQLite y DuckDB│ ├── routes/ # Definiciones modulares de rutas Hono│ └── jobs/ # Tareas en segundo plano (ej. ExchangeRateSyncJob)app.ts(Aplicación Pura): Configura middlewares de logging, cabeceras CORS, registra las rutas y exporta el tipoAppType. No incluye escucha activa en sockets, lo que facilita enormemente los tests conapp.request().index.ts(Arrancador en Runtime): Abre los archivos de base de datos, ejecuta migraciones pendientes, valida variables de entorno y vincula el servidor HTTP de Node.js al puerto configurado.
🔗 Seguridad de Tipos Extremo a Extremo (Hono RPC)
Sección titulada «🔗 Seguridad de Tipos Extremo a Extremo (Hono RPC)»Las arquitecturas habituales requieren generadores pesados de código cliente basados en OpenAPI/Swagger o GraphQL cada vez que cambia un endpoint.
Criptofolio utiliza Hono RPC, compartiendo los tipos de TypeScript directamente entre los paquetes del monorepo sin pasos previos de compilación:
1. Definición y Exportación de Rutas (apps/backend/src/app.ts)
Sección titulada «1. Definición y Exportación de Rutas (apps/backend/src/app.ts)»import { Hono } from 'hono';import { metricsRoutes } from './core/infrastructure/routes/metrics';import { taxRoutes } from './core/infrastructure/routes/tax';import { vaultRoutes } from './core/infrastructure/routes/vault';
const routes = new Hono() .route('/api/metrics', metricsRoutes) .route('/api/tax', taxRoutes) .route('/api/credentials', vaultRoutes);
export const app = new Hono().route('/', routes);export type AppType = typeof routes;2. Consumo en el Frontend (apps/frontend/.../BffClient.ts)
Sección titulada «2. Consumo en el Frontend (apps/frontend/.../BffClient.ts)»El frontend inicializa el cliente RPC importando exclusivamente la definición de tipo AppType:
import { hc } from 'hono/client';import type { AppType } from '@criptofolio/backend';
export const bffClient = hc<AppType>(import.meta.env.VITE_API_URL || 'http://localhost:3001');
// Autocompletado completo, verificación de argumentos y tipo de retorno estricto:const response = await bffClient.api.metrics.kpis.$get();if (response.ok) { const data = await response.json(); // ¡Datos 100% tipados! console.log(data.total_equity);}🔌 Inyección de Dependencias Centralizada (container.ts)
Sección titulada «🔌 Inyección de Dependencias Centralizada (container.ts)»Los controladores de ruta de Hono no instancian servicios directamente. Un contenedor DI resuelve adaptadores concretos y los inyecta en los Casos de Uso:
export interface Container { sqliteLedgerAdapter: SqliteLedgerAdapter; duckDbAdapter: DuckDbAdapter; fifoMaterializerService: FifoMaterializerService; vaultCredentialsPort: IVaultCredentialsPort; ingestAndMaterializeUseCase: IngestAndMaterializeUseCase;}Esto garantiza:
- Testabilidad: En suites de pruebas, el contenedor intercambia bases de datos en archivo por instancias
:memory:. - Gestión Eficiente del Pool: DuckDB y SQLite mantienen un único pool de conexiones compartido sin fugas de descriptores.
📡 Resumen de Endpoints Principales
Sección titulada «📡 Resumen de Endpoints Principales»| Prefijo de Ruta | Método | Función |
|---|---|---|
/api/metrics/kpis |
GET |
Resumen patrimonial (equity, coste base, PnL realizado/no realizado, ratio de acierto). |
/api/metrics/risk |
GET |
Métricas de riesgo (Sharpe, volatilidad 30d, caída ATH, Alpha y Beta). |
/api/metrics/performance |
GET |
Serie temporal de valoración diaria del portfolio en la currency solicitada (por defecto EUR), convertida en cada punto con la tasa de su fecha; los puntos sin tasa son null. |
/api/tax/import |
POST |
Procesamiento del pipeline de ingesta con perfil de formato de origen. |
/api/tax/lots |
GET |
Consulta de lotes fiscales calculados con desglose de custodia. |
/api/settings/accounts |
GET |
Lista las cuentas visibles al usuario (id como value, nombre como label); ListAccountsUseCase excluye las contrapartes sintéticas de custodia. |
/api/tax/transactions/spot |
GET |
Transacciones spot de la vista efectiva (editada), con filtro opcional por accountId, mediante SearchSpotTransactionsUseCase. Orden del libro, la más antigua primero. |
/api/credentials/vault/* |
Varios | Gestión de claves API cifradas y estado de desbloqueo de la bóveda. |
/api/advisor/* |
Varios | Asesor de Cartera con IA de solo lectura: chat con streaming y configuración de cadena de modelos y perfiles de ejecución. Ver Asesor de IA. |