Saltar a contenido

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_url aparece en la API.
  • Si un documento vinculado no es de tipo publico, su pdf_url viene null: 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

  1. La URL base del ambiente (la entrega GDI en la puesta en marcha).
  2. La API Key del municipio (la entrega GDI por un canal seguro; nunca por mail junto con la URL).
  3. El acronimo del municipio, que va en la ruta.
  4. 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: q obligatorio (minimo 2 caracteres). Cada resultado es de tipo document (con official_number, document_type, resume, snippet, pdf_url, ...) o record (legajo, con record_number, display_name, registry_code, fields).
  • registries/{code}/records: acepta page (default 1), page_size (default 20, tope 25: valores mayores se ajustan a 25 sin error) y search (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}: devuelve record_number, display_name, state, registry y los fields publicos; ademas documents, cases y related_records solo si la familia los habilito. Un legajo que no existe, cuya familia no es publica, o cuyo estado no esta en visible_states, devuelve 404.
    • Resumen de los vinculados: cada documents incluye resume solo si el documento es publico (mismo criterio que pdf_url); si no es publico, resume viene null. Cada related_records incluye resume solo si el legajo destino es publico y navegable (mismo criterio que linked); si no, resume viene null. Los cases (expedientes) nunca incluyen resumen: siguen devolviendo solo case_number y reference.
    • document_id de los vinculados: cada documents incluye ademas un document_id (UUID) solo si el documento es publico; si no lo es, viene null. 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.
  • documents/{document_id}/content: devuelve el texto completo del documento en HTML, ademas de official_number, reference, document_type y signed_at. El document_id es 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 el document_id no 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 por pdf_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:

curl -H "X-API-Key: $API_KEY" \
  "https://URL-BASE/api/v1/public/muni/registries"
{
  "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

  1. GET /registries -> familias publicas del municipio.
  2. GET /registries/{code}/records -> legajos de una familia.
  3. GET /records/{record_number} -> detalle del legajo; de aca sale, por cada documento publico, su pdf_url y su document_id.
  4. GET /documents/{document_id}/content -> texto completo en HTML de ese documento.

Busqueda combinada:

curl -H "X-API-Key: $API_KEY" \
  "https://URL-BASE/api/v1/public/muni/search?q=ordenanza%205383"

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:

{url-base-de-publicacion}/{numero_oficial}.pdf

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.