Documentos y Legajos Públicos¶
La visibilidad pública es la tercera pata del modelo de visibilidad del sistema. Junto con Interno y Reservado, permite abrir informacion a la ciudadania sin necesidad de login: cualquier persona en internet puede consultar los documentos oficiales y los legajos que el municipio decida publicar.
La idea en una frase
La publicidad se define por TIPO (no item por item), igual que la reserva. Un administrador marca un Tipo de Documento como Público o una Familia de Registro como Pública; a partir de ahi, todos los items de ese tipo quedan expuestos por una API publica de solo lectura, con reglas fijas y sin dar permisos a mano.
Las tres visibilidades¶
Cada Tipo de Documento tiene un campo visibility con uno de tres valores:
| Visibilidad | Quien lo ve | Donde se configura |
|---|---|---|
| Interno | Visibilidad estandar del municipio (conducta actual por defecto) | Tipos de Documento / Tipos de Expediente |
| Reservado | Solo firmantes, creador y responsables directos (ver Reservados) | Tipos de Documento / Tipos de Expediente |
| Público | Cualquiera en internet, sin login | Solo Tipos de Documento |
Los expedientes NUNCA son publicos
La opcion Público solo existe para Tipos de Documento. Los Tipos de Expediente admiten unicamente Interno o Reservado. El BackOffice rechaza con error cualquier intento de crear o editar un tipo de expediente como publico.
Los legajos (RLM) tienen su propio mecanismo de publicacion, a nivel de Familia de Registro (ver Familias públicas mas abajo).
Publicar un Tipo de Documento¶
Al crear un tipo de documento propio (boton Nuevo tipo propio en Tipos de Documentos), el modal incluye un selector obligatorio de Visibilidad con las tres opciones:
| Opcion | Descripcion que muestra el selector |
|---|---|
| Interno | Visibilidad estandar del municipio (conducta actual). |
| Reservado | Confidencial e irreversible. Solo firmantes/responsables directos podran verlo. |
| Público | Sin login, accesible por cualquiera en internet. Irreversible. |
Al elegir Público y presionar Crear tipo, el sistema pide una confirmacion explicita antes de dar de alta el tipo:
Dialogo de confirmacion — Crear tipo como Público
Este tipo de documento va a nacer como PUBLICO.
Esto es IRREVERSIBLE: no se va a poder volver a "Interno" despues de creado. Los PDFs firmados de este tipo van a quedar accesibles por cualquier persona en internet, SIN necesidad de login. Una vez publicado un PDF, aunque se borre despues puede seguir cacheado o indexado por buscadores. Asegurate de que este tipo de documento nunca vaya a contener datos sensibles (DNI, CBU, domicilios, etc.).
Botones: Cancelar / Si, crear como Público
Que se publica exactamente¶
Cuando un documento de un tipo publico se firma, su PDF oficial se copia automaticamente a un bucket publico y queda accesible por una URL estable. Solo se publican documentos oficiales firmados (signed_at presente): un borrador nunca sale a internet.
Irreversibilidad y prudencia
- La visibilidad de un tipo de documento se define una sola vez, al crearlo, y es irreversible: un tipo publico no se puede volver a interno.
- En el detalle del tipo la visibilidad aparece como una etiqueta de solo lectura ("La visibilidad se define al crear el tipo y no se puede cambiar.").
- Una vez que un PDF se publico, aunque despues se despublique o borre, puede seguir cacheado o indexado por buscadores. Nunca marques como publico un tipo que pueda contener datos personales o sensibles.
Solo tipos virgenes
Por debajo, el unico cambio de visibilidad que el sistema acepta por edicion es interno → publico (o interno → reservado) y solo si el tipo no tiene ningun documento creado todavia. En la practica esto se resuelve eligiendo la visibilidad en el momento del alta.
Familias de Registro públicas¶
Los legajos se publican a nivel de Familia de Registro. En el detalle de una familia (Familias de Registro) hay una tarjeta "Publicación Pública".
Publicación Pública
Expone los legajos de esta familia sin login, en internet. Reversible en cualquier momento.
A diferencia de los tipos de documento, publicar una familia es reversible: se puede prender y apagar cuando se quiera. Al apagarlo, la API publica deja de servir esos legajos de inmediato.
Configuracion de una familia publica¶
Al activar el toggle "Familia pública" el sistema pide confirmacion:
Dialogo — Publicar familia de legajos
Los legajos de esta familia van a ser visibles publicamente en internet, sin necesidad de login, mostrando solo los campos y estados que marques a continuacion.
Podes desactivarlo en cualquier momento (es reversible): al apagarlo, la API publica deja de servir estos legajos.
Botones: Cancelar / Sí, activar
Con la familia publica, se configura exactamente que se expone (public_config):
| Opcion | Que controla |
|---|---|
| Campos públicos | Subconjunto de los campos del esquema de datos de la familia que se muestran. Solo se publican los campos tildados; el resto nunca sale |
| Estados visibles | Solo los legajos que estan en alguno de estos estados salen por la API publica |
| Mostrar documentos vinculados | Expone los documentos publicos vinculados al legajo |
| Mostrar expedientes vinculados | Expone solo numero y caratula de los expedientes vinculados, sin acceso al contenido |
| Mostrar legajos relacionados | Expone los legajos relacionados que tambien pertenezcan a familias publicas |
Los estados filtran en vivo
Solo los legajos en los estados marcados salen por la API publica. Un legajo que cambia a un estado no marcado desaparece de lo publico automaticamente, sin ninguna accion manual. Es la forma natural de despublicar un legajo puntual: cambiarlo de estado.
Validaciones
- Los campos públicos deben ser un subconjunto de los campos definidos en el esquema de la familia.
- Los estados visibles deben ser un subconjunto de los estados de la familia.
- Si se borra un campo del esquema que estaba marcado como publico, el sistema lo saca de la configuracion publica automaticamente.
El acronimo queda congelado¶
Las URLs publicas dependen del acronimo del municipio (viaja en la ruta, ver API pública). Por eso, mientras el tenant tenga algun tipo de documento publico o alguna familia publica activa, no se puede cambiar el acronimo del municipio.
Error 409 al cambiar el acronimo
Si se intenta cambiar el acronimo de un municipio con publicaciones activas, el sistema responde:
No se puede cambiar el acronimo: el tenant tiene tipos de documento o familias de legajos publicos activos. Las URLs publicas dependen del acronimo.
Para cambiar el acronimo, primero hay que despublicar (apagar) las familias publicas. Los tipos de documento publicos, al ser irreversibles, hacen que esta decision sea de fondo: elegir bien el acronimo antes de publicar.
Publicacion de PDFs: viene lista de fabrica¶
El almacenamiento publico donde se sirven los PDFs viene habilitado de fabrica: toda instancia nace con su espacio de publicacion propio, creado automaticamente en el alta del municipio. El administrador no tiene que configurar ni pedir nada — alcanza con marcar un tipo de documento como publico para que sus PDFs firmados empiecen a publicarse.
- Cuando se firma un documento de un tipo publico, el PDF oficial se copia automaticamente al espacio publico y su
pdf_urlaparece en la API. - Si un documento vinculado no es de tipo publico, su
pdf_urlvienenull: es el comportamiento esperado, no una falla.
Auditoria
Todo cambio de visibilidad (crear un tipo publico, prender/apagar una familia, editar su public_config) queda registrado en la auditoria del sistema, en la misma transaccion que el cambio.
API pública¶
La informacion publicada se consume por un bloque de API de solo lectura pensado para portales de transparencia, integraciones y consultas de la ciudadania. Vive bajo el prefijo /api/v1/public/{muni}/..., donde {muni} es el acronimo del municipio (en minusculas).
Que necesita el equipo tecnico del municipio para integrar
- La URL base del ambiente (la entrega GDI en la puesta en marcha).
- La API Key del municipio (la entrega GDI por un canal seguro; nunca por mail junto con la URL).
- El acronimo del municipio, que va en la ruta.
- Un cliente server-to-server (backend propio, no un navegador).
Requiere API Key del municipio (no es anonima)
Aunque la informacion sea publica, la API no es anonima: cada pedido debe incluir el header X-API-Key con una clave de municipio. No lleva X-User-ID (la clave es del municipio, no de un usuario). La clave debe corresponder al {muni} de la URL; si no coincide, la respuesta es 403. Estas claves son server-to-server: no deben viajar a un navegador (por eso las respuestas se sirven como Cache-Control: private).
Endpoints¶
| Metodo y ruta | Que devuelve |
|---|---|
GET /api/v1/public/{muni}/search?q=... |
Busqueda combinada de documentos publicos + legajos publicos en un unico listado |
GET /api/v1/public/{muni}/registries |
Familias de registro publicas del municipio, con sus campos publicos |
GET /api/v1/public/{muni}/registries/{code}/records |
Legajos publicos de la familia code (paginado) |
GET /api/v1/public/{muni}/records/{record_number} |
Detalle de un legajo publico |
GET /api/v1/public/{muni}/documents/{document_id}/content |
Contenido (texto completo, en HTML) de un documento publico, identificado por su document_id (UUID) |
Parametros y notas:
search:qobligatorio (minimo 2 caracteres). Cada resultado es de tipodocument(conofficial_number,document_type,resume,snippet,pdf_url, ...) orecord(legajo, conrecord_number,display_name,registry_code,fields).registries/{code}/records: aceptapage(default 1),page_size(default 20, tope 25: valores mayores se ajustan a 25 sin error) ysearch(opcional, min 2 caracteres: con menos, el filtro se ignora y se devuelve el listado completo). Una familia inexistente o no publica devuelve 404 (no distingue "no existe" de "privada").records/{record_number}: devuelverecord_number,display_name,state,registryy losfieldspublicos; ademasdocuments,casesyrelated_recordssolo si la familia los habilito. Un legajo que no existe, cuya familia no es publica, o cuyo estado no esta envisible_states, devuelve 404.- Resumen de los vinculados: cada
documentsincluyeresumesolo si el documento es publico (mismo criterio quepdf_url); si no es publico,resumevienenull. Cadarelated_recordsincluyeresumesolo si el legajo destino es publico y navegable (mismo criterio quelinked); si no,resumevienenull. Loscases(expedientes) nunca incluyen resumen: siguen devolviendo solocase_numberyreference. document_idde los vinculados: cadadocumentsincluye ademas undocument_id(UUID) solo si el documento es publico; si no lo es, vienenull. Ese identificador es el que se usa en el endpoint de contenido (abajo). Es la unica forma de obtenerlo: la API nunca expone el UUID de un documento no publico.
- Resumen de los vinculados: cada
documents/{document_id}/content: devuelve el texto completo del documento en HTML, ademas deofficial_number,reference,document_typeysigned_at. Eldocument_ides el UUID que trae el detalle de legajo (documents[].document_id). Solo responde para documentos publicos y firmados; para cualquier otro caso —no existe, no es publico, no esta firmado, o eldocument_idno es un UUID valido— devuelve 404 con el mismo cuerpo ({"error": "Documento no encontrado"}), sin distinguir el motivo. El PDF de ese mismo documento se sigue descargando porpdf_url; el endpoint de contenido es el complemento en texto (para indexar, mostrar en HTML, etc.).
Ejemplos de uso¶
Listar las familias publicas del municipio:
{
"registries": [
{
"code": "NORMA",
"name": "Normativa HCD",
"description": "Registro de normativa emitida por el Honorable Concejo Deliberante",
"fields": ["materia", "tipo_norma", "numero_norma", "fecha_sancion"]
}
],
"total": 1
}
Listar los legajos de una familia, paginados:
curl -H "X-API-Key: $API_KEY" \
"https://URL-BASE/api/v1/public/muni/registries/NORMA/records?page=1&page_size=5"
{
"records": [
{
"record_number": "RLM-2026-00000036-MUNI-NORMA",
"display_name": "Ordenanza 5383 - Regula contrataciones municipales",
"state": "Vigente",
"registry_code": "NORMA",
"fields": {
"materia": {"value": "Presupuesto"},
"tipo_norma": {"value": "Ordenanza"},
"numero_norma": {"value": "5383"}
}
}
],
"total": 10,
"page": 1,
"page_size": 5,
"total_pages": 2
}
Detalle de un legajo, con sus documentos publicos:
curl -H "X-API-Key: $API_KEY" \
"https://URL-BASE/api/v1/public/muni/records/RLM-2026-00000036-MUNI-NORMA"
{
"record_number": "RLM-2026-00000036-MUNI-NORMA",
"display_name": "Ordenanza 5383 - Regula contrataciones municipales",
"state": "Vigente",
"registry": {"code": "NORMA", "name": "Normativa HCD"},
"fields": {
"materia": {"value": "Presupuesto"},
"tipo_norma": {"value": "Ordenanza"},
"numero_norma": {"value": "5383"}
},
"documents": [
{
"official_number": "NORPU-2026-00001234-MUNI-HCD",
"reference": "5383/26",
"document_id": "07669375-29d9-4446-b18c-239e8038d60c",
"pdf_url": "https://URL-PDF/NORPU-2026-00001234-MUNI-HCD.pdf",
"resume": "Resumen del contenido generado automaticamente..."
},
{
"official_number": "ANEXO-2026-00001235-MUNI-HCD",
"reference": "Anexo interno",
"document_id": null,
"pdf_url": null,
"resume": null
}
]
}
pdf_url: null NO es un error
Un documento vinculado al legajo que no sea de tipo publico aparece en la lista con pdf_url: null y resume: null. Es el comportamiento esperado: el legajo muestra que el documento existe, pero su contenido no es publico. El PDF de los documentos publicos se descarga directo de pdf_url, sin API Key (es un link publico).
Contenido (texto completo en HTML) de un documento publico. El document_id sale del detalle de legajo de arriba (documents[].document_id):
curl -H "X-API-Key: $API_KEY" \
"https://URL-BASE/api/v1/public/muni/documents/07669375-29d9-4446-b18c-239e8038d60c/content"
{
"document_id": "07669375-29d9-4446-b18c-239e8038d60c",
"official_number": "NORPU-2026-00001234-MUNI-HCD",
"reference": "5383/26",
"document_type": {"name": "Norma Publicada", "acronym": "NORPU"},
"content": {"html": "<div class=\"transcription\">...texto completo del documento...</div>", "format": "html"},
"signed_at": "2026-07-21T18:57:14+00:00"
}
PDF y contenido son complementarios
El detalle de legajo entrega, para cada documento publico, tanto el pdf_url (para descargar el PDF firmado) como el document_id (para pedir el texto en HTML por este endpoint). Sirven a fines distintos: el PDF es el documento oficial descargable; el contenido HTML es util para indexar, buscar o mostrar el texto embebido en un portal sin abrir el PDF.
Sanitizar el HTML antes de mostrarlo en un navegador
El content.html es el texto del documento tal como quedo en el sistema; la API lo devuelve sin sanitizar (es una API server-to-server, no pensada para render directo en un browser). Si el portal del municipio lo va a inyectar en una pagina, debe pasarlo antes por un sanitizador (por ejemplo DOMPurify) — nunca hacer dangerouslySetInnerHTML / innerHTML con el HTML crudo. Es la misma precaucion que con cualquier contenido de origen externo.
Flujo tipico de integracion
GET /registries-> familias publicas del municipio.GET /registries/{code}/records-> legajos de una familia.GET /records/{record_number}-> detalle del legajo; de aca sale, por cada documento publico, supdf_urly sudocument_id.GET /documents/{document_id}/content-> texto completo en HTML de ese documento.
Busqueda combinada:
Cada resultado trae type (record o document). Los resultados document incluyen ademas linked_records, con los legajos publicos a los que esta vinculado el documento.
Respuestas de error¶
| Caso | Codigo | Cuerpo |
|---|---|---|
Sin header X-API-Key |
401 | {"error": "X-API-Key requerido"} |
| Clave invalida, inactiva, vencida o revocada | 401 | {"error": "API Key invalida"} (mensaje generico a proposito) |
| Clave valida pero de otro municipio | 403 | {"error": "API Key no valida para este municipio"} |
| Familia inexistente o no publica | 404 | {"error": "Familia no encontrada"} |
| Legajo inexistente, no publico o en estado no visible | 404 | {"error": "Legajo no encontrado"} |
Documento inexistente, no publico, sin firmar, o document_id mal formado |
404 | {"error": "Documento no encontrado"} |
q de busqueda con menos de 2 caracteres |
400 | {"error": "q requerido (min 2 caracteres)"} |
| Exceso de consultas | 429 | {"error": "Rate limit exceeded. Retry after 60s"} |
Buenas practicas de integracion
- Cachear en el servidor las respuestas hasta 60 segundos (las respuestas ya lo indican con
Cache-Control: private, max-age=60). Un portal de transparencia no necesita pegarle a la API en cada visita. - Ante un 429, esperar 60 segundos y reintentar: es la proteccion contra abuso funcionando, no una falla.
- La API Key vive solo en el backend del municipio. Si aparece en el codigo del frontend, en un repositorio o en un navegador, hay que pedir a GDI que la rote (revocar y emitir una nueva).
- Al reportar un problema a GDI, enviar URL completa, fecha/hora, codigo HTTP y cuerpo de la respuesta. Nunca incluir la API Key en el reporte.
URLs de los PDFs¶
Los PDFs publicos se sirven con una URL plana y estable, cuyo nombre de archivo es el numero oficial del documento:
La URL base de publicacion depende del ambiente; el integrador no necesita construirla: siempre llega completa en el campo pdf_url de las respuestas. La URL se incluye solo para documentos de tipo publico; para el resto el campo pdf_url viene null. La descarga del PDF no requiere API Key.
Seguridad del bloque publico¶
El bloque publico se diseño con la seguridad como prioridad. Sin entrar en detalles de implementacion, estas son las garantias que ofrece:
| Garantia | Que significa |
|---|---|
| Acceso autenticado y aislado | Cada pedido se valida contra una clave de municipio y queda acotado a ese municipio: no hay forma de acceder a la informacion de otro (403 si la clave no corresponde) |
| Solo lectura y protegida contra abuso | La API no permite modificar nada y limita la cantidad de consultas por origen; los excesos se rechazan automaticamente |
| Solo se expone lo que marcas | Unicamente salen los campos que el administrador tilda explicitamente en la configuracion publica; el resto nunca se publica |
| Nunca expone reservados | Documentos y expedientes reservados jamas aparecen: se filtran en origen, antes de armar la respuesta |
| No revela la estructura interna | La respuesta nunca incluye datos internos del sistema ni de la base de datos |
Busqueda inteligente
La busqueda publica combina coincidencia por palabras con una busqueda que entiende el significado de la consulta, para devolver resultados relevantes aunque no coincidan exactamente los terminos. Si el servicio inteligente no esta disponible en un momento dado, la busqueda sigue funcionando de forma transparente por coincidencia de texto.