Cómo separar adjuntos pesados con MinIO y PostgreSQL
Un flujo simple evita que facturas, fotos y contratos inflen la base. MinIO guarda objetos; PostgreSQL conserva dueño, estado y auditoría; el backup prueba ambos lados.
Un objeto S3 guarda el archivo; PostgreSQL guarda la fila que lo vuelve encontrable. Esa división evita que facturas, fotos de obra o contratos escaneados agranden la base hasta volver lentas las copias. En una escuela técnica del este mendocino, el enemigo era la carpeta compartida que aceptaba todo y no probaba nada. Esta guía muestra cómo separar adjuntos con MinIO, permisos, backup y restauración. ## Dónde la base se vuelve depósito PostgreSQL tiene el tipo bytea para guardar cadenas binarias, según su documentación oficial. Esa opción sirve para casos pequeños; cuando los adjuntos pesan cientos de megas, la base empieza a cargar bytes que el usuario solo quiere descargar. El síntoma aparece en backups lentos, restauraciones largas y consultas que arrastran columnas que nadie necesita abrir. La regla práctica se escribe antes de instalar: la base conserva datos qué se buscan, se filtran y se auditan; el almacén de objetos conserva archivos qué se descargan. Esa frase corta evita discusiones largas cuando aparece el primer contrato de 180 MB. La cuenta que ordena la decisión es concreta. Backblaze publica almacenamiento B2 desde USD 5 por TB por mes, mientras un disco de servidor con snapshots, copia externa y restauración probada cuesta bastante más que su precio de compra. A la vez, la encuesta de Stack Overflow 2024 muestra PostgreSQL en 49% de uso, un dato que explica por qué muchas pymes ya tienen equipo o proveedor capaz de sostener la base de metadatos. El tornillo visible del caso era una etiqueta blanca pegada sobre un disco USB de 2 TB, guardado en un armario de netbooks. La directora sabía qué cursos habían subido fotos de prácticas; nadie podía probar quién había borrado una carpeta.
Cómo funciona por dentro
El flujo técnico tiene siete pasos. Primero, el usuario sube una factura, foto, acta o contrato desde la aplicación. Segundo, la aplicación calcula nombre, hash, tamaño, tipo de archivo y dueño. Tercero, MinIO recibe el objeto, lo guarda en un bucket y conserva metadatos; si se activa versionado, retiene versiones anteriores del mismo objeto. Cuarto, PostgreSQL guarda la fila: ID del objeto, estado, usuario, permiso, fecha, trámite y hash. Quinto, Keycloak entrega grupos y roles para leer, cargar, aprobar o borrar según perfil. Sexto, el tablero o búsqueda muestra el trámite sin descargar el archivo hasta que alguien lo pide. Séptimo, el backup copia PostgreSQL y MinIO, y una prueba restaura una operación real con archivo y metadatos. MinIO toma objetos grandes y entrega una URL o una descarga controlada. PostgreSQL toma datos estructurados y entrega consultas repetibles. El monitoreo revisa espacio, latencia, errores de subida y fallas de backup. La restauración confirma que el objeto y su fila vuelven juntos.
Qué se instala o configura primero
La pila mínima usa una aplicación web, PostgreSQL 17, MinIO, Keycloak, backup con pgBackRest o Restic, y una copia externa S3 compatible. Para una pyme con 2 TB útiles, el costo mensual puede quedar entre USD 90 y USD 180 si se incluye servidor, almacenamiento, copia externa y monitoreo. A ARS 1.450 por dólar, equivale a ARS 130.500 a ARS 261.000 por mes. El tiempo razonable de implementación va de 30 a 50 horas. El primer entregable verificable es chico: un bucket con versionado, tres roles, diez archivos de prueba, una tabla de metadatos, una búsqueda por trámite y una restauración documentada. Si el archivo restaurado no conserva hash, dueño y fecha, el entregable todavía está incompleto. UMSA suele resolver este tipo de separación en dos capas: infraestructura para almacenamiento y base, y una guía operativa para que gerencia sepa qué se puede borrar, qué se conserva y quién autoriza excepciones. El área IT conserva acceso administrativo; las áreas usuarias trabajan con permisos de aplicación.
Dónde se rompe y cómo probarlo
El primer riesgo es el objeto huérfano. La señal aparece cuando MinIO tiene archivos sin fila en PostgreSQL o filas que apuntan a objetos ausentes. La prueba recorre ambos lados, compara IDs y rechaza cierres si hay diferencias. El segundo riesgo es la URL firmada con vida demasiado larga. La señal aparece cuando un enlace sigue abriendo fuera del plazo previsto. La prueba crea una URL de cinco minutos, espera el vencimiento y exige error de acceso. El tercer riesgo es el backup de una sola capa. La señal aparece cuando la base restaura bien y los archivos quedan vacíos, o cuando los objetos vuelven sin metadatos. La prueba levanta un entorno limpio, restaura base y bucket, abre diez trámites y compara hash. El cuarto riesgo es una regla de retención mal puesta. La señal aparece cuando un archivo que debía conservarse se borra, o cuando un archivo vencido queda retenido para siempre. La prueba aplica dos etiquetas, una de conservación y otra de vencimiento, y revisa el comportamiento con usuarios distintos. Separar archivos y datos reduce el peso técnico; probar la vuelta decide si el sistema sirve.