> ## Documentation Index
> Fetch the complete documentation index at: https://docs.patrimonion.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Upload

> Upload de mídias e documentos para MinIO. Dois buckets com políticas distintas: privado (documentos sensíveis) e público (fotos e vídeos).

## Arquitetura de storage

O módulo de upload usa **MinIO** (compatível com S3) com dois buckets de propósitos distintos:

| Bucket               | Visibilidade | Acesso                          | Usado para                                |
| -------------------- | ------------ | ------------------------------- | ----------------------------------------- |
| `MINIO_BUCKET`       | Privado      | Presigned URL (expira em 15min) | CPF, RG, comprovante, contratos assinados |
| `MINIO_BUCKET_FOTOS` | Público      | URL permanente                  | Fotos de imóveis, inspeções, inventário   |

<Warning>
  Nunca salve Presigned URLs no banco de dados — elas expiram em 15 minutos. Salve apenas a **key** e gere a URL sob demanda via `GET /upload/:recurso/:id/documento`.
</Warning>

## Limites

| Parâmetro      | Valor                                                                                      |
| -------------- | ------------------------------------------------------------------------------------------ |
| Tamanho máximo | 20MB por arquivo                                                                           |
| Tipos aceitos  | `image/jpeg`, `image/png`, `image/webp`, `application/pdf`, `video/mp4`, `video/quicktime` |
| Máx. arquivos  | 10 (imóvel, inventário) / 20 (inspeção)                                                    |

***

## Status do MinIO

Endpoint público — não requer autenticação. Útil para verificar se o storage está operacional antes de iniciar uploads.

```http theme={null}
GET /upload/status
```

```json Resposta 200 theme={null}
{
  "minioAtivo": true,
  "endpoint": "https://minio.seudominio.com",
  "bucketPrivado": {
    "nome": "patrimonion-docs",
    "tipo": "PRIVADO — documentos sensíveis (Presigned URLs, 15 min)",
    "uso": ["CPF", "RG", "comprovante de residência", "contratos assinados"]
  },
  "bucketPublico": {
    "nome": "patrimonion-fotos",
    "tipo": "PÚBLICO — fotos e mídias (URLs permanentes)",
    "uso": ["fotos de imóveis", "fotos de inspeções", "fotos de inventário"]
  }
}
```

***

## Documentos do locatário

### Upload

Aceita até 4 campos simultâneos via `multipart/form-data`. Todos vão para o bucket **privado**.

| Campo             | Descrição                          |
| ----------------- | ---------------------------------- |
| `doc_cpf`         | Foto ou scan do CPF (1 arquivo)    |
| `doc_rg`          | Foto ou scan do RG (1 arquivo)     |
| `doc_comprovante` | Comprovante de residência (1 arq.) |
| `doc_outros`      | Outros documentos (até 10)         |

```http theme={null}
POST /upload/locatario/:locatarioId
Cookie: imob_session=<session_cookie>
Content-Type: multipart/form-data

doc_cpf: <arquivo>
doc_rg: <arquivo>
```

```json Resposta 201 theme={null}
{
  "message": "2 tipo(s) de documento enviado(s) com sucesso.",
  "documentos": {
    "cpf": {
      "key": "uid123/locatarios/loc456-joao-da-silva/cpf/1706123456789.jpg",
      "nome": "cpf_joao.jpg",
      "enviadoEm": "2025-02-01T10:00:00.000Z"
    }
  }
}
```

### Gerar URL de visualização

```http theme={null}
GET /upload/locatario/:locatarioId/documento?tipo=cpf
Cookie: imob_session=<session_cookie>
```

<ParamField query="tipo" type="string" required>
  Tipo do documento: `cpf`, `rg`, `comprovante`, `outros`.
</ParamField>

<ParamField query="index" type="number" default="0">
  Índice do arquivo (somente para `tipo=outros`).
</ParamField>

```json Resposta 200 theme={null}
{
  "url": "https://minio.seudominio.com/...",
  "expiresInMinutes": 15,
  "aviso": "Esta URL expira em 15 minutos. Não salve — gere uma nova quando precisar."
}
```

***

## Contrato assinado

Aceita apenas **PDF**. Vai para o bucket privado e atualiza o campo `contratoAssinadoKey` no Firestore.

```http theme={null}
POST /upload/contrato/:contratoId
Cookie: imob_session=<session_cookie>
Content-Type: multipart/form-data

arquivo: <arquivo.pdf>
```

```json Resposta 201 theme={null}
{
  "message": "Contrato assinado enviado com sucesso.",
  "key": "uid123/contratos/con789/1706123456789.pdf"
}
```

### Gerar URL de visualização

```http theme={null}
GET /upload/contrato/:contratoId/documento
Cookie: imob_session=<session_cookie>
```

***

## Fotos do imóvel

Aceita até **10 arquivos** por requisição. URLs permanentes no bucket público.

```http theme={null}
POST /upload/imovel/:imovelId
Cookie: imob_session=<session_cookie>
Content-Type: multipart/form-data

arquivos: <arquivo1>, <arquivo2>, ...
```

```json Resposta 201 theme={null}
{
  "message": "3 foto(s) enviada(s).",
  "fotos": [
    {
      "key": "uid123/imoveis/abc123/1706123456789.jpg",
      "url": "https://minio.seudominio.com/patrimonion-fotos/uid123/imoveis/abc123/foto.jpg",
      "nome": "sala.jpg",
      "enviadoEm": "2025-02-01T10:00:00.000Z"
    }
  ]
}
```

### Listar fotos

```http theme={null}
GET /upload/imovel/:imovelId/fotos
Cookie: imob_session=<session_cookie>
```

***

## Mídias de inspeção

Aceita até **20 arquivos** (fotos e vídeos). A API separa automaticamente em `fotosKeys` e `videosKeys` com base no `mimetype`.

```http theme={null}
POST /upload/inspecao/:inspecaoId
Cookie: imob_session=<session_cookie>
Content-Type: multipart/form-data

arquivos: <arquivo1>, <arquivo2>, ...
```

### URL de vídeo

Valida o vínculo entre a key e a inspeção antes de retornar a URL.

```http theme={null}
GET /upload/inspecao/:inspecaoId/video?key=uid123/inspecoes/vis001/videos/video.mp4
Cookie: imob_session=<session_cookie>
```

***

## Fotos de inventário

Aceita até **10 arquivos** por item. O campo `fotosKeys` armazena tanto fotos quanto vídeos.

```http theme={null}
POST /upload/inventario/:itemId
Cookie: imob_session=<session_cookie>
Content-Type: multipart/form-data

arquivos: <arquivo1>, <arquivo2>, ...
```

***

## Deletar arquivo

Remove o arquivo do MinIO e limpa a referência no Firestore em uma única operação.

<ParamField query="key" type="string" required>
  Caminho completo do arquivo no MinIO (ex: `uid123/imoveis/abc123/foto.jpg`).
</ParamField>

<ParamField query="publico" type="string">
  `"true"` se o arquivo está no bucket público. Padrão: bucket privado.
</ParamField>

```http theme={null}
DELETE /upload/:colecao/:docId/arquivo?key=uid123/imoveis/abc123/foto.jpg&publico=true
Cookie: imob_session=<session_cookie>
```

### Coleções válidas

| Valor        | Firestore Collection |
| ------------ | -------------------- |
| `locatario`  | `locatarios`         |
| `imovel`     | `imoveis`            |
| `inspecao`   | `inspecoes`          |
| `inventario` | `inventario`         |
| `contrato`   | `contratos`          |

```json Resposta 200 theme={null}
{
  "message": "Arquivo e referência deletados com sucesso."
}
```

<Info>
  A key deve sempre começar com o `userId` do usuário autenticado. Tentativas de deletar arquivos de outros usuários retornam `403 Forbidden`.
</Info>
