# Armazenamento Seguro de Ficheiros + Auditoria

## 1. Ficheiros (secções 15, 16, 37, 38)

**Storage abstraction:** `Illuminate\Support\Facades\Storage`, driver
configurável (`local` em dev, `s3`/`minio`/`azure` em produção via
`.env` — zero código muda ao trocar de provider).

**`FileStorageService`** centraliza todo o upload:

```
1. Validar MIME real do ficheiro (não a extensão enviada) usando
   finfo_file() / Symfony Mime, contra uma whitelist por contexto
   (fotos: jpg/png/webp; documentos: pdf/docx; vídeos: mp4/mov)
2. Validar tamanho máximo (configurável por tipo)
3. Gerar nome novo com UUID — nunca usar o nome original no path
4. Guardar em disco PRIVADO (nunca disk 'public' para docs/facturas)
5. Registar em media_files (fileable polimórfico + organization_id)
6. Devolver apenas o ID do registo — nunca a URL directa
```

**Acesso a ficheiros:** rota dedicada `GET /api/v1/media/{mediaFile}` que:
1. Verifica autenticação
2. Verifica `MediaFilePolicy::view` (tenant + permissão sobre a entidade
   "pai" — ex: uma fatura só é vista por quem tem `invoices.view`)
3. Gera signed URL de curta duração (ex: 5 min, `Storage::temporaryUrl()`)
   ou faz streaming autenticado direto da app
4. Nunca expõe o path físico nem o disk

**Prevenção de execução de código:** uploads nunca ficam dentro de
`public/`; mesmo em `local`, ficam fora do document root. Extensões
executáveis (`.php`, `.phtml`, `.exe`, etc.) são rejeitadas mesmo que o
MIME reportado pareça válido.

## 2. Auditoria (secção 30)

Tabela `audit_logs` (ver ERD) alimentada por um **Listener genérico**
subscrito aos `Model Events` (`created`, `updated`, `deleted`) dos models
marcados com a interface `Auditable`, mais eventos de negócio explícitos
para acções sensíveis (aprovação de orçamento, mudança de estado de Work
Order, login de Super Admin).

```
Model::updated → AuditableObserver
    → grava organization_id, actor_id, action, entity_type, entity_id,
      old_values (diff), new_values (diff), ip, user_agent
```

- `audit_logs` **nunca** é editável ou apagável por utilizadores normais
  (sem rota de update/delete exposta; nem sequer Policy de update existe).
- Dados sensíveis (passwords, tokens) são explicitamente excluídos do diff
  via `$auditExclude` no model.
- Consulta de audit logs é uma permissão própria (`audit_logs.view`),
  tipicamente só Super Admin / Organization Owner.

## 3. O que nunca vai para logs (secção 41)

Passwords, tokens, API keys, session secrets e dados financeiros
desnecessários são explicitamente filtrados tanto do `audit_logs` como dos
`application logs` (Laravel `Log::channel()` — usar canais separados
`application`, `security`, `audit`, `queue` no `config/logging.php`).
