--- type: rule name: caminho-arquivos-minio description: Padronização obrigatória de caminhos de arquivos persistidos no MinIO em quatro segmentos ({inquilino}/{tabela_origem}/{codigo_origem}/{id}) scope: global trigger: model_decision updatedAt: "2026-10-14" --- # Regra: Padronização Obrigatória de Caminhos de Arquivos no MinIO ## Contexto Todos os arquivos persistidos e referenciados no MinIO dentro dos módulos do ecossistema (identificados via `modulo-id` em `memorias-ia/modulo.yml`) devem seguir uma estrutura canônica hierárquica e determinística composta por **exatamente quatro segmentos**: ``` {inquilino}/{tabela_origem}/{codigo_origem}/{id} ``` Essa padronização evita colisão de arquivos entre inquilinos ou entidades, permite identificação imediata da origem do arquivo e padroniza a gestão de permissões e storage. --- ## 1. Regra de Formato e Validação Canônica Todo caminho de arquivo enviado para o MinIO deve ser construído via função canônica `caminhoMinio` exportada pelo pacote `-comuns` (onde `` é extraído de `memorias-ia/modulo.yml`) e validado por `regexCamninhoMinio`: ```typescript /** Valida quatro segmentos e exige extensão no id. */ export const regexCamninhoMinio = /^[\w$.-]+\/\w+\/[\w.-]+\/[\w.%$-]+\.\w+$(?![\s\S])/ export type CaminhoMinioParams = { inquilino: string tabela_origem: string codigo_origem: string id: string } export const caminhoMinio = ({ inquilino, tabela_origem, codigo_origem, id, }: CaminhoMinioParams): string => { const partes = [inquilino, tabela_origem, codigo_origem, id] const caminho = partes.join("/") if (partes.some((parte) => parte.includes("/")) || !regexCamninhoMinio.test(caminho)) { throw new Error("Caminho MinIO inválido") } return caminho } ``` ### Regras dos Quatro Segmentos 1. **`inquilino`**: Identificador do município / cliente / tenant (ex.: `padrao-rs`). Não pode conter barras. 2. **`tabela_origem`**: Nome canônico da tabela no banco de dados (ex.: `tabelas.licenciamentos`, `tabelas.denuncias`, `tabelas.oficios`). 3. **`codigo_origem`**: UUID ou identificador único do registro na tabela de origem (ou identificador de escopo como `sistema` para brasões/ativos globais do tenant). 4. **`id`**: Identificador único do arquivo acompanhado obrigatoriamente de sua extensão (ex.: `01J...pdf`, `brasao.png`, `oficio_123.pdf`). --- ## 2. Persistência Obrigatória no Banco de Dados É **mandatório** que toda coluna do banco de dados que armazena referências a arquivos salve a **string completa retornada por `caminhoMinio`** (os 4 segmentos unidos por barras). Exemplos de colunas que armazenam o caminho completo: - `licencas.codigo_arquivo` - `anexos.codigo_arquivo` - `denuncias.codigo_pdf_documento` - `oficios.codigo_pdf_documento` - `documentos_registros.codigo_pdf_documento` - `auto_de_infracao.codigo_pdf_documento` - `fluxos_recebimentos.codigo_pdf_documento` - `entidades.prefeitura_brasao` > ⚠️ **Atenção:** Nunca salve apenas o último segmento (`id`) de arquivos gerados ou anexados. A string armazenada no banco deve ser a chave completa de 4 segmentos. --- ## 3. Upload e Integração com Plugins MinIO No backend (`-back`): - O plugin `enviarArquivoMiniO` valida o `codigoArquivo` recebido contra `regexCamninhoMinio`. - Caso `codigoArquivo` já contenha barras, o plugin reconhece que o inquilino já está incorporado no primeiro segmento e faz o upload direto para essa chave, sem duplicar o prefixo do inquilino. - No download ou cache temporário (`baixarArquivoMiniO`), caso a chave possua barras, o nome do arquivo temporário local em disco deve substituir as barras por underscores (`replace(/\//g, "_")`) para evitar erros de diretórios inexistentes em `/tmp`. --- ## 4. Miniaturas e Resoluções Gráficas No caso de imagens que possuem geração de miniaturas (thumbnails via Sharp): - A miniatura adiciona o sufixo `_y{tamanho}` **antes da extensão no 4º segmento**: `{inquilino}/{tabela_origem}/{codigo_origem}/{id_base}_y200.{ext}` - No frontend (`-front`), helpers como `urlArquivoBaixar` devem utilizar `lastIndexOf(".")` para formatar a URL da miniatura mantendo a hierarquia intacta. --- ## 5. Compatibilidade Legada O helper `bucket().caminho` em `-comuns` é retrocompatível: - Se `id` contém barras (`/`), ele já representa o caminho estruturado completo e é retornado sem alteração. - Se `id` não contém barras, ele trata como registro legado de 1 segmento e compõe `{inquilino}/{id}`. --- ## Referências - Identidade do Módulo: `memorias-ia/modulo.yml` - `-comuns/src/minio.ts` - `-back/src/plugins/MiniO/enviarArquivoMiniO.ts` - `-back/src/plugins/MiniO/baixarArquivoMiniO.ts` - `-front/src/api/recursos/arquivos.ts`