Plataforma técnica · Orchestrator
Manual de Cuentas (Admin)
Orchestrator Command Manual Cuentas
ManualCuentasService administra el catálogo canónico de documentación contable: para cada código de cuenta, qué se carga al debe, qué al haber, asientos tipo, normas NIC/IFRS aplicables, ejemplos y referencias cruzadas. A diferencia del plan de cuentas (estructura jerárquica, vive en PostgreSQL), el manual es prosa estructurada por cuenta y vive en MongoDB.
Por qué MongoDB
Section titled “Por qué MongoDB”Cada documento de manual tiene un schema flexible: arrays de asientos tipo de longitud variable, prosa con markdown, tags, ver-tambien, metadata de versión. El acceso es siempre findByCodigo o $text search, no joins ni transacciones — un caso de uso clásico de documento.
Modelo del Documento
Section titled “Modelo del Documento”ManualCuenta:
| Campo | Tipo | Notas |
|---|---|---|
codigo | string | Código de cuenta (e.g. 1101030). Único. |
es_grupo | boolean | Derivado del plan: la cuenta tiene hijos. |
debe | string (markdown) | Qué se carga al debe. |
haber | string (markdown) | Qué se carga al haber. |
nic_ifrs | { norma?, tratamiento?, referencia? } | Norma aplicable (e.g. NIIF 15). |
ejemplos | Array<{ titulo, descripcion_md }> | Casos prácticos. |
asientos_tipo | Array<{ titulo, debe[], haber[] }> | Plantillas de asiento. |
ver_tambien | string[] | Códigos relacionados. |
tags | string[] | Para búsqueda. |
meta | { autor?, created_at, updated_at, version } | Versioning incremental. |
Índices MongoDB
Section titled “Índices MongoDB”ManualCuentasRepository.ensureIndexes crea (una sola vez, memoizado):
| Índice | Tipo | Para |
|---|---|---|
{ codigo: 1 } | UNIQUE | Lookup por código (findByCodigo). |
{ debe, haber, nic_ifrs.tratamiento, tags } | TEXT | Búsqueda full-text de cuenta. |
Arquitectura
Section titled “Arquitectura”flowchart LR
R["routes/command/manual-cuentas/"]
S["ManualCuentasService"]
REP["ManualCuentasRepository<br/>(estático)"]
M[("MongoDB · nostromo_manual<br/>collection: cuentas")]
PL["lib/plan-cuentas-source.ts"]
TPL[("PostgreSQL · accounting_template<br/>plan_contable")]
R --> S
S --> REP --> M
S -. valida código existe .-> PL --> TPL El servicio cruza dos motores de datos. Antes de un upsert, valida que el codigo exista en el plan template de PostgreSQL — no permite documentar cuentas inexistentes en el plan oficial. Y deriva es_grupo consultando si el código tiene hijos (planCuentaHasChildren).
Operaciones del Service
Section titled “Operaciones del Service”| Método | Validación | Efecto |
|---|---|---|
getByCodigo(codigo) | — | Lookup directo en Mongo. |
list(opts) | limit clamp a [1, 100], skip ≥ 0. | Paginación + búsqueda $text opcional. |
save(dto) | codigo requerido y existente en accounting_template.plan_contable. | Upsert + bumpea meta.version. |
remove(codigo) | — | deleteOne({ codigo }). |
Versionado de meta
Section titled “Versionado de meta”En cada save:
| Campo | Comportamiento |
|---|---|
meta.created_at | Preservado si ya existía; nuevo now() si es creación. |
meta.updated_at | Siempre now(). |
meta.version | (actual ?? 0) + 1. Incrementa monotónico, sin saltos. |
meta.autor | Preservado del documento previo (no se sobrescribe). |
No hay histórico de versiones anteriores — replaceOne sobreescribe. Si se necesita auditoría granular, usar el audit log con tableName: 'manual_cuentas' desde el handler.
Endpoints
Section titled “Endpoints”Los endpoints viven en routes/command/manual-cuentas/index.ts bajo /api/command/manual-cuentas y están detallados en Command Center API.
Resumen:
| Método | Ruta | Uso |
|---|---|---|
GET | /api/command/manual-cuentas | Lista con paginación / search. |
GET | /api/command/manual-cuentas/:codigo | Detalle de cuenta. |
PUT | /api/command/manual-cuentas/:codigo | Upsert. |
DELETE | /api/command/manual-cuentas/:codigo | Eliminar. |
Export read-only para Jean d’Arc
Section titled “Export read-only para Jean d’Arc”routes/internal/manual-cuentas.ts expone un endpoint GET /api/internal/manual-cuentas protegido por token interno que retorna el dump completo (ManualCuentasRepository.listAllForExport) ordenado por código. Es consumido durante el pnpm build de este sitio para materializar las páginas estáticas del Manual de Cuentas.
Búsqueda Full-Text
Section titled “Búsqueda Full-Text”Cuando opts.search está presente, la query usa $text con score:
const filter = { $text: { $search: search } };const projection = { _id: 0, score: { $meta: 'textScore' } };const sort = { score: { $meta: 'textScore' }, codigo: 1 };El índice TEXT cubre debe, haber, nic_ifrs.tratamiento y tags. Los resultados se ordenan por relevancia y, en empate, por código ascendente. El campo score se elimina antes de retornar al cliente.
Errores Conocidos
Section titled “Errores Conocidos”| Error | Causa |
|---|---|
BadRequestError("codigo cuenta requerido") | DTO sin codigo o vacío. |
BadRequestError("codigo cuenta inexistente") | El código no está en accounting_template.plan_contable. |
Error("manual_cuenta_upsert_failed") | El findByCodigo post-upsert no devolvió documento (caso casi imposible — indica corrupción). |
Por qué no hay borrado en cascada
Section titled “Por qué no hay borrado en cascada”Borrar un código del manual no elimina la cuenta del plan: son catálogos separados. La doctrina es: el plan es la verdad operacional (rige los movimientos contables); el manual es documentación. Una cuenta puede existir sin manual; un manual no puede existir sin plan.