← Infografía SubseBot · Documentación técnica Informe detallado

Informe Técnico: Arquitectura de SubseBot con MCP, Multi-Rol y OAuth

Proyecto: SubseBot — Piloto de Cursos Obligatorios, Gobierno de la Ciudad de Buenos Aires Fecha: 25 de agosto de 2026 Preparado por: Jota (con asistencia de Claude) Fuente primaria: Especificación de Requerimientos EARS - SubseBot (documento completo, leído el 2026-08-25) Limitación declarada: el prototipo actual en Google Apps Script + Sheets (link provisto) está protegido por login de Google del usuario propietario; no fue accesible para este análisis. Todo lo que sigue sobre el prototipo actual es inferencia razonable a partir del nombre "Apps Script + Sheets", no una auditoría del código real.


1. Resumen ejecutivo

SubseBot es un asistente conversacional que responde, para el piloto de Cursos Obligatorios de GCBA, dos tipos de consulta: (a) un colaborador pregunta qué cursos le faltan y recibe los enlaces a ICBA; (b) RRHH consulta estados por equipo/curso y exporta reportes en Excel. La especificación EARS ya vigente exige dos cosas que son, en el fondo, requisitos de arquitectura: que el sistema trabaje solo sobre una copia anonimizada de los datos (nunca el original), y que exista una distinción de comportamiento por rol (colaborador vs. RRHH) atada a un identificador único (el legajo).

Este informe traduce esa spec funcional a una arquitectura técnica, usando el patrón MCP (Model Context Protocol) para separar la orquestación conversacional (a cargo de un LLM) de la ejecución de la lógica de negocio y el acceso a datos (a cargo de código determinístico). Se presentan dos propuestas —A, evolución liviana del prototipo actual, y B, arquitectura desacoplada con base de datos— pensadas como una decisión Now/Next: A para el piloto, B como horizonte si el proyecto escala a más áreas de GCBA.


2. Contexto y alcance del piloto

2.1 Qué existe hoy

2.2 Actores del sistema

Actor Qué necesita Dato sensible que toca
Colaborador Saber qué cursos obligatorios tiene pendientes y cómo hacerlos Su propio legajo y estado de cursos — nada de otros
RRHH (lector/operador) Filtrar pendientes por equipo o curso, exportar a Excel Legajos y estados de todo un equipo o de toda la organización
RRHH (administrador de datos) Ejecutar/supervisar el proceso de anonimización y sync Acceso transitorio a la fuente original para generar la copia anonimizada
Administrador del sistema (implícito, no está en la spec) Mantener el servicio, revisar logs de error Metadatos de sistema, no debería necesitar ver datos personales

2.3 Fuera de alcance del piloto (según REQ-UNW-02)

Explícitamente fuera: saldo de días de vacaciones y "cualquier información sensible" no relacionada a cursos obligatorios. Esto importa para el diseño: el sistema no debe convertirse en un punto de acceso genérico a RRHH, sino mantenerse acotado a un dominio de datos (cursos + legajo + equipo).


3. Mapeo de la especificación EARS a decisiones de arquitectura

Esta tabla es el corazón del informe: conecta cada bloque de requerimientos con la decisión técnica que le corresponde.

Requerimiento EARS Qué exige Decisión de arquitectura
REQ-UBI-01 — solo copia anonimizada Nunca tocar el original Pipeline de anonimización/ETL separado del servicio de consulta; el servicio de consulta ni siquiera tiene credenciales hacia el original
REQ-UBI-02 — legajo como ID único Cruce determinístico El legajo nunca se toma de texto libre del usuario final; se resuelve server-side a partir de la identidad autenticada (OAuth)
REQ-EVD-01/02 — consulta individual + links Respuesta personalizada con enlaces Tool MCP consultar_estado(legajo) — determinístico; el LLM solo decide cuándo llamarlo
REQ-EVD-03/04 — filtros y exportación RRHH Acceso agregado, solo para RRHH Tools separadas (listar_por_equipo, exportar_excel) con scope de autorización distinto al de colaborador
REQ-UNW-01/02/03 — errores Legajo no encontrado, fuera de alcance, falla de origen Manejo de excepciones explícito en el servidor MCP, no delegado al LLM
REQ-STD-01 — 100% cumplido No mostrar links si ya está todo aprobado Lógica condicional determinística en la tool, no en el prompt
REQ-STD-02 — bloqueo durante sync No servir datos a mitad de actualización Un flag de estado ("sincronizando") que el servidor chequea antes de responder cualquier tool
REQ-OPT-01/02 — roadmap futuro Carga de certificados, FAQ de RRHH Diseñado como tools adicionales, sin tocar el core — el MCP server es extensible por diseño
REQ-CPX-01 — reporte para líderes bajo permiso admin Combinación de rol + evento Autorización de grano fino: no alcanza con "es RRHH", hace falta un scope específico (rrhh_admin vs rrhh_lector)

4. Por qué MCP y no "un LLM con acceso a la planilla"

Un enfoque ingenuo sería darle al LLM acceso directo a la Google Sheet y dejar que arme las queries. Esto es exactamente lo que la spec pide evitar, por dos motivos concretos:

  1. REQ-UBI-01 se rompe en la práctica. Si el modelo tiene la Sheet completa en contexto o puede leerla libremente, no hay forma de garantizar que un colaborador nunca vea el legajo de otro — la restricción dependería de que el modelo "decida bien" en cada respuesta, y eso no es un control de seguridad, es una esperanza.
  2. No hay auditoría posible. Si la lógica de acceso vive en el prompt, no hay un punto de código donde loguear "el usuario X consultó el legajo Y" — algo que un organismo público probablemente va a necesitar poder mostrar ante una auditoría.

MCP resuelve esto poniendo una frontera dura entre el modelo (que interpreta lenguaje y decide qué herramienta llamar) y el servidor (que ejecuta funciones puras, con su propia autenticación, autorización y logging, independientes del prompt). El modelo nunca ve el dataset completo — solo ve lo que la tool decide devolverle, ya filtrado por el rol de quien preguntó.


5. Propuesta A — Evolución liviana sobre Google Workspace

5.1 Diagrama

flowchart TB
    subgraph Usuarios
        COL[Colaborador]
        RRHH[RRHH]
    end
    subgraph Canal
        BOT[Canal de chat: WhatsApp / Google Chat / Web]
    end
    subgraph Identidad
        OAUTH[Google OAuth 2.0 - Workspace GCBA]
    end
    subgraph MCPLayer[Servidor MCP]
        RBAC[Middleware: valida token, resuelve rol y legajo]
        T1[tool: consultar_estado]
        T2[tool: listar_por_equipo]
        T3[tool: exportar_excel]
    end
    subgraph Datos
        SHEET[(Google Sheet anonimizada)]
        SYNC[Apps Script: job de sync + anonimización]
        ORIG[(Base RRHH original)]
    end

    COL --> BOT
    RRHH --> BOT
    BOT --> OAUTH
    OAUTH -->|id_token con email| RBAC
    RBAC --> T1
    RBAC --> T2
    RBAC --> T3
    T1 --> SHEET
    T2 --> SHEET
    T3 --> SHEET
    ORIG -->|solo lectura, ventana programada| SYNC
    SYNC -->|escribe copia anonimizada| SHEET

5.2 Flujo paso a paso

  1. El colaborador o usuario de RRHH inicia sesión en el canal (WhatsApp Business, Google Chat, o un webchat) — el canal delega la identidad a Google OAuth 2.0 sobre el Workspace de GCBA.
  2. El id_token de Google llega al servidor MCP. El middleware RBAC extrae el email verificado y lo cruza contra una tabla chica (Sheet o archivo de config) de mapeo email → legajo y email → rol.
  3. El LLM orquestador recibe el mensaje del usuario ya con el contexto de identidad resuelto (rol + legajo), interpreta la intención, y decide qué tool MCP invocar.
  4. La tool ejecuta la consulta contra la Sheet anonimizada — nunca contra el original — y devuelve datos ya filtrados por el legajo o equipo autorizado.
  5. Un job separado (Apps Script existente) sigue corriendo en una ventana programada, leyendo el original en modo solo-lectura y regenerando la copia anonimizada. Mientras corre, marca un flag de "sincronizando" que el servidor MCP respeta (REQ-STD-02).

5.3 Seguridad y privacidad

5.4 Ventajas y límites

A favor: tiempo de entrega corto (días), reutiliza el prototipo existente casi entero, costo de infraestructura mínimo, encaja con el marco temporal de un piloto.

En contra: Google Sheets como fuente de verdad tiene límites de cuota de API, no ofrece row-level security nativo (todo el control de acceso vive en el código del servidor, no en el almacenamiento), y la auditoría de accesos requiere instrumentarse a mano (no viene gratis).


6. Propuesta B — Arquitectura desacoplada con base de datos dedicada

6.1 Diagrama

flowchart TB
    subgraph Usuarios
        COL2[Colaborador]
        RRHHL[RRHH lector]
        RRHHA[RRHH admin]
    end
    subgraph Canales
        WA[WhatsApp]
        WEBP[Portal web]
        SLK[Chat interno]
    end
    subgraph IdP[Identity Provider OIDC]
        OAUTH2[Google Workspace / IdP GCBA]
    end
    subgraph MCP[Servidor MCP - stateless]
        GATE[Middleware: valida JWT + scope]
        TOOLA[tool: consultar_estado]
        TOOLB[tool: reporte_equipo]
        TOOLC[tool: exportar_excel]
        TOOLD[tool: resumen_lideres]
    end
    subgraph DB[Datastore]
        ANON[(Vista anonimizada - Postgres, RLS por rol)]
        AUDIT[(Log de auditoría: acceso por legajo)]
    end
    JOB[Job ETL determinístico: extrae + pseudonimiza]
    ORIGDB[(Base RRHH original - sistema de origen)]

    COL2 --> WA
    RRHHL --> WEBP
    RRHHA --> SLK
    WA --> OAUTH2
    WEBP --> OAUTH2
    SLK --> OAUTH2
    OAUTH2 -->|JWT con rol y sub| GATE
    GATE --> TOOLA
    GATE --> TOOLB
    GATE --> TOOLC
    GATE --> TOOLD
    GATE --> AUDIT
    TOOLA --> ANON
    TOOLB --> ANON
    TOOLC --> ANON
    TOOLD --> ANON
    ORIGDB -->|solo lectura, ventana programada| JOB
    JOB -->|escribe| ANON

6.2 Qué cambia respecto de A

6.3 Ventajas y límites

A favor: escala a más secretarías/cursos, auditoría real desde el día uno, los permisos no dependen de que cada nueva tool "se acuerde" de chequear el rol — la base los impone estructuralmente.

En contra: más superficie para construir y operar (base de datos, ETL, hosting del servidor) — desproporcionado para un piloto de una sola área, salvo que ya exista experiencia de DevOps disponible en el equipo.


7. Comparación A vs B

Dimensión A — Sheets + MCP liviano B — Postgres + MCP desacoplado
Tiempo estimado a producción Días Semanas
Fuente de datos Google Sheet anonimizada Postgres con RLS
Dónde se impone el permiso Código del servidor MCP Base de datos (RLS) + servidor MCP
Auditoría de accesos Requiere instrumentación manual Tabla de auditoría nativa
Costo de infraestructura Casi nulo Bajo-medio
Reutiliza el prototipo actual Sí, casi entero Solo el criterio de anonimización
Mejor para El piloto tal como está planteado Adopción en más áreas de GCBA

Recomendación: arrancar con A para la demo del Idiatón. B queda documentado como el paso siguiente natural si RRHH decide extender SubseBot más allá del piloto — no se justifica construir RLS en Postgres para validar un flujo con una sola área.


8. Determinismo vs no determinismo

Principio guía: separar "decisión de negocio y acceso a datos" (determinístico, en código) de "comprensión del lenguaje y redacción de la respuesta" (no determinístico, en el LLM). Confianza alta en el principio general; confianza media en el mapeo específico a cada requerimiento, porque depende de decisiones de implementación que el equipo todavía no tomó.

8.1 Debe ser determinístico (código, nunca generado por el LLM)

8.2 Puede ser no determinístico (terreno del LLM)

8.3 Regla práctica para la reunión de equipo

Si un error en un punto del flujo implica mostrarle a alguien un dato que no le corresponde, ese punto tiene que ser código determinístico, sin excepción. Si el error implica, en el peor caso, una respuesta mal redactada o con un tono poco claro, puede quedar del lado del LLM.


9. Stack recomendado (propuesta, no hecho verificado)

Nivel de certeza: especulación fundamentada — depende de qué stack ya tiene instalado o preferido el equipo de GCBA, información que no forma parte de la spec revisada.

Componente Recomendación Motivo
Servidor MCP Node.js + TypeScript (SDK oficial de MCP) o Python Ninguno de los dos tiene ventaja técnica clara acá; conviene el que el equipo ya domine
Identidad Google OAuth 2.0 / OIDC contra el Workspace de GCBA El prototipo ya vive en Google Apps Script — es la integración más barata para empezar
Identidad (a futuro) IdP intermedio (Keycloak / Auth0) si hay que federar con otros organismos Solo se justifica si aparece un segundo organismo o sistema externo
Datos — Propuesta A Google Sheets Continuidad con el prototipo actual
Datos — Propuesta B Postgres (Supabase como opción rápida de levantar con RLS nativo) RLS de fábrica, sin reinventar control de acceso a mano
Canal de chat El que ya esté acordado con RRHH (WhatsApp Business API, Google Chat, webchat) Es independiente de la arquitectura de datos — no condiciona A ni B
Generación de Excel Librería determinística del lado del servidor (openpyxl, exceljs) Nunca generado por el LLM

10. Riesgos y mitigaciones

Riesgo Impacto Mitigación propuesta
El LLM interpreta mal una intención y llama la tool equivocada Bajo si las tools están bien acotadas — en el peor caso, una respuesta irrelevante, no una fuga de datos Diseñar tools con alcance estrecho y validación de parámetros en el servidor
Falla o demora en el job de anonimización Servicio sirve datos desactualizados o inconsistentes REQ-STD-02 ya contempla esto: bloquear consultas mientras el flag de sync esté activo
Suplantación de rol (alguien se hace pasar por RRHH) Alto — expone legajos de terceros El rol nunca se autodeclara por el usuario; se resuelve desde el token OAuth y una tabla de permisos controlada por el administrador del sistema
Cuota de la API de Google Sheets se agota con uso alto (Propuesta A) Servicio degradado en momentos de pico Cachear resultados de lectura con TTL corto, o migrar a Propuesta B si el volumen lo justifica
Falta de auditoría en A ante un pedido de organismo de control Dificultad para demostrar cumplimiento de protección de datos Igual en A conviene loguear accesos a un archivo/hoja separada desde el día uno, aunque sea manual

11. Plan de implementación sugerido (Now / Next / Later)

Now (piloto, Propuesta A):

  1. Definir la tabla de mapeo email → legajo → rol.
  2. Envolver el job de anonimización existente en Apps Script con un flag de estado (sincronizando / listo).
  3. Construir el servidor MCP con las tres tools mínimas: consultar_estado, listar_por_equipo, exportar_excel.
  4. Integrar OAuth de Google Workspace en el canal elegido.
  5. Probar los tres casos de error de la spec (REQ-UNW-01/02/03) antes de la demo.

Next (si RRHH pide extender el piloto): 6. Sumar logging de auditoría básico sobre la Propuesta A (sin migrar aún de almacenamiento). 7. Sumar la tool resumen_lideres (REQ-CPX-01) con su scope de permiso específico.

Later (si se adopta en más áreas — Propuesta B): 8. Migrar el almacenamiento a Postgres con RLS. 9. Formalizar el ETL como job versionado y monitoreado. 10. Evaluar si hace falta un IdP intermedio para federar con otros organismos.


12. Glosario breve


13. Preguntas abiertas para acordar con el equipo

Estas preguntas no están respondidas por la spec EARS ni por este informe — son decisiones que le corresponden al equipo, no a la arquitectura. Agruparlas ayuda a no perder ninguna en la reunión.

Identidad y roles

  1. ¿Google Workspace es la única fuente de identidad del organismo, o existe (o va a existir) un IdP corporativo distinto que debería ser el que emita el token?
  2. ¿"RRHH" es un rol único desde el día uno del piloto, o ya hay que distinguir lector/administrador para poder cumplir REQ-CPX-01 (reporte para líderes bajo permisos administrativos)?
  3. Cuando alguien cambia de equipo o deja de trabajar en GCBA, ¿quién actualiza su legajo/rol en la tabla de mapeo, y con qué demora aceptable?

Datos y privacidad

  1. ¿Qué campos concretos quedan excluidos de la copia anonimizada (DNI, sueldo, domicilio, etc.), y quién los define y valida — RRHH, legal, o sistemas?
  2. ¿Existe una obligación normativa de GCBA de auditar accesos a datos de RRHH, aunque sea un piloto? Esto decide si el logging manual de la Propuesta A alcanza o si hace falta la tabla de auditoría de la Propuesta B desde el inicio.
  3. ¿Agus y Laureano (o el equipo de RRHH mencionado en el mail modelo del documento original) ya validaron el criterio de anonimización, o sigue pendiente esa aprobación?

Operación

  1. ¿Quién es responsable de que el job de sincronización/anonimización corra y de resolver una falla (REQ-UNW-03) — hay alguien de guardia o es best-effort?
  2. Ante una consulta fuera de alcance (REQ-UNW-02), ¿qué mensaje institucional exacto hay que devolver? ¿Existe un canal de derivación a una persona de RRHH?
  3. Si el piloto migra a la Propuesta B, ¿quién operaría la infraestructura nueva (Postgres, ETL) — el equipo de sistemas de GCBA o un proveedor externo?

Timeline y volumen

  1. ¿Cuál es la fecha del Idiatón mencionado en el documento original, y qué es lo mínimo indispensable para mostrar ese día?
  2. ¿Cuántos colaboradores y consultas por día se esperan durante el piloto? Es el dato que más rápido justificaría saltar directo a la Propuesta B en vez de empezar por A.
  3. ¿Cuál es el canal de chat definitivo (WhatsApp Business API, Google Chat, webchat propio) y ya está aprobado por el área de sistemas?

14. Fuentes y trazabilidad