ADR-016 · Artefactos compartidos de ecosistema (core/py-common, core/ts-common, service-template, ECOSYSTEM.md)¶
Fecha: 2026-04-22 Source:
/srv/projects/cis/cis-plan/DECISIONS.md(do not edit here — re-split desde la fuente)
Mergeado 2026-04-29 desde
ADRs-borrador-013-015-016.md(P0.3). Numeración renumerada 2026-04-27 (era ADR-012 en el borrador; ese número fue tomado por S2S auth shared-key header).
Contexto
Hoy existen shared libs parciales:
- core/core-style — tokens CSS, shell JS, brand logos, graphs (FS/CDN). Consumido por 15+ frontends. 🟢.
- core/core-auth-lib — Python OIDC dep injection (illanes-auth). Consumido por backends Python. 🟢.
- cis-core — infra REST / MCP. Consumido por admin/Claudia. 🟢.
Problema observado: cada servicio nuevo reimplementa:
- Error handling (mapping exception → HTTP + logging)
- Structured logging (structlog setup)
- Vault client con cache (cada repo se escribe su propio vault_client.py: cis-sign, cis-core, cis-admin, etc.)
- Retry decorators (tenacity wrapper)
- Prometheus helpers (cis-sii-gateway tiene 9 metrics; cis-platform tiene otras 8; no comparten setup)
15+ frontends copipastean:
- Auth hooks (useAuthUser, useAuthGate)
- API fetch client con credentials: 'include' + error mapping
- Setup del custom element <cis-shell> (navbar/footer)
- Error display (toast/modal)
El plan maestro (§1.3 RBAC, §cross-cutting core) ya apunta a consolidar, pero nadie agendó el trabajo.
Propuesta
Crear 4 artefactos:
core/py-common(/srv/projects/core/py-common/, pip editable)- Módulos:
oidc.py(depends onillanes-auth),errors.py(TypedException → HTTPException map),logging.py(structlog JSON config),vault.py(httpx client con TTL cache),retry.py(tenacity wrapper con settings),metrics.py(Prometheus helpers). -
Consumidor: todo backend Python nuevo + migración gradual de existentes.
-
core/ts-common(/srv/projects/core/ts-common/, npm workspace package@cis/common) - Módulos:
useAuthUser.ts,useAuthGate.tsx,apiClient.ts(fetch wrapper con credentials + error mapping),shell.ts(wrappers del custom element),toast.ts. -
Consumidor: todo frontend Next/Vite nuevo.
-
@cis/service-template(cookiecutter en/srv/projects/core/service-template/) - Un comando:
cis-create-service <nombre> <tipo=fastapi|next|express>. -
Deja listo: estructura backend o frontend,
CLAUDE.mdstub,AGENT-CONTEXT.mdstub con campos pre-llenados, systemd unit adaptado al puerto reservado, Caddy block,.env.example, pre-commit hooks, secrets manifest (lista de keys vault que el servicio necesitará). -
/srv/projects/ECOSYSTEM.md(auto-generado) - Script
/srv/projects/bin/regenerate-ecosystem.shlee:CONTRACTS.md(matriz productor/consumer)systemctl list-units '*.service'del hostAGENT-CONTEXT.mdde cada repo
- Regenera
/srv/projects/ECOSYSTEM.mdcon:- Inventory tabulado de servicios + puertos + units + owners
- Mapa visual (Mermaid graph o Graphviz DOT) de dependencias
- Se corre en CI y en hook post-deploy.
Alternativas consideradas
- No hacer nada: seguir copipasteando. Funciona pero duplica trabajo indefinidamente, los bugs se arreglan en un lugar y no en los otros.
- Un único mega-repo monorepo: forzar toda la organización. Demasiado disruptivo ahora; ADR-007 explícitamente mantiene divisiones.
- Adoptar un framework existente (ej. https://github.com/tiangolo/full-stack-fastapi-template): perdemos control y el stack del ecosistema es opinionated (structlog, illanes-auth, vault propio, cis-shell).
Decisión propuesta
Implementar los 4 artefactos en ese orden: py-common → ts-common → service-template → ECOSYSTEM.md auto-gen.
Justificación:
py-commonpaga por sí solo: cada vault_client reimplementado es un bug esperando. Con TTL cache central, ahorramos N requests/min alcore-server.ts-commonpaga con los frontends pendientes (cis-portal, cis-librospa backend-connected, indieweb v2, cis-inbox extensions).service-templateacelera el onboarding — hoy un servicio nuevo toma ~2 días de boilerplate; con template <2 horas.ECOSYSTEM.mdresuelve el problema que este ADR surge: visibilidad del mapa completo en un solo lugar.
Consecuencias
- Positivo: 3-4 semanas bootstrap; después cada servicio nuevo se hace en horas, no días. Bugs de infra se arreglan en 1 sitio. Los AGENT-CONTEXT.md se mantienen coherentes porque el template los prescribe.
- Negativo: versionado de libs compartidas (semver estricto, ADR nuevo para cambios mayores — convenciones ya establecidas en CONTRACTS.md §"Convenciones de versionado"). Coordinación de PRs que afectan múltiples repos.
- Migración gradual: los servicios existentes (cis-sign, cis-core, cis-admin, etc.) no se obligan a migrar de una. Regla: servicios nuevos usan
py-common/ts-commonpor default; servicios existentes migran cuando toquen el archivo relevante. - Riesgo de lock-in: si una lib compartida tiene bug, afecta a todos los consumers. Mitigación: tests extensivos + release canaria (un servicio primero, el resto después).
- Dependencia de autoridad:
ECOSYSTEM.mdauto-generado requiere que todos losAGENT-CONTEXT.mdestén presentes y consistentes. Este ADR se apoya en el trabajo previo de crear AGENT-CONTEXT.md en todos los repos (hecho 2026-04-22). - Naming:
core/hoy alberga 2 items (core-style, core-auth-lib). Agregar 3 items más (py-common,ts-common,service-template) lo convierte en un contenedor estándar. Considerar si renombrar acore/libs/en el futuro.