diff --git a/rules/caminho-arquivos-minio.md b/rules/caminho-arquivos-minio.md new file mode 100644 index 0000000..af3d9b2 --- /dev/null +++ b/rules/caminho-arquivos-minio.md @@ -0,0 +1,105 @@ +# Regra: Padronização Obrigatória de Caminhos de Arquivos no MinIO + +## Contexto + +Todos os arquivos persistidos e referenciados no MinIO dentro do ecossistema GOV/Quipo 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 por `quipo-comuns` 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 / 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 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 (`QUIPO-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, helpers como `urlArquivoBaixar` devem utilizar `lastIndexOf(".")` para formatar a URL da miniatura mantendo a hierarquia intacta. + +--- + +## 5. Compatibilidade Legada + +O helper `bucket().caminho` em `quipo-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 + +- `QUIPO-COMUNS/src/minio.ts` +- `QUIPO-BACK/src/plugins/MiniO/enviarArquivoMiniO.ts` +- `QUIPO-BACK/src/plugins/MiniO/baixarArquivoMiniO.ts` +- `QUIPO-FRONT/src/api/recursos/arquivos.ts` +- `QUIPO-PORTAL3/src/utilitarios/arquivos.ts`