Banco de dadosTables
message_attachments
Anexos de mensagens (imagem, áudio, vídeo, arquivo) com metadata.
Mídia anexada a mensagens de chat. Suporta:
- Imagens —
mime_type: image/*,thumbnail_urlgerado por sharp - Áudio —
mime_type: audio/*,duration_ms+waveform_peaks(array de amplitudes pra desenhar onda) - Vídeo —
mime_type: video/*,thumbnail_url(frame extraído via ffmpeg) +duration_ms - Arquivo — qualquer
mime_type,filenamepreserva nome original
message_id é opcional (nullable). Permite cenários onde o upload acontece antes da mensagem (ex: tela de envio com preview); a mensagem é criada depois e o attachment vinculado.
Colunas
| Coluna | Tipo | Nullable | Default |
|---|---|---|---|
| id ● | uuid | NOT NULL | gen_random_uuid() |
| message_id | uuid | NULL ok | — |
| uploaded_by | uuid | NOT NULL | — |
| url | text | NOT NULL | — |
| filename | text | NOT NULL | — |
| mime_type | text | NOT NULL | — |
| size_bytes | integer | NOT NULL | — |
| display_order | integer | NOT NULL | 0 |
| duration_ms | integer | NULL ok | — |
| waveform_peaks | jsonb | NULL ok | — |
| thumbnail_url | text | NULL ok | — |
● primary key ◆ unique
Funcionalidade dos campos
id— UUID, PKmessage_id— FK pramessages. Nullable + cascade delete.uploaded_by— quem uploadou. Cascade delete.url— URL S3/MinIO (path-style)filename— nome original do arquivo (informativo, sem normalização)mime_type— Content-Type detectadosize_bytes— tamanho em bytesdisplay_order— pra galerias com múltiplos anexosduration_ms— pra áudio/vídeo. NULL pra imagem/arquivo.waveform_peaks— JSONB array de números 0-100. Apenas pra áudio. Frontend desenha onda visual.thumbnail_url— versão reduzida pra grid (imagem/vídeo)
Foreign keys
| Coluna(s) | Referência | ON DELETE | ON UPDATE |
|---|---|---|---|
| message_id | messages.id | cascade | no action |
| uploaded_by | users.id | cascade | no action |
Índices
Esta tabela não tem índices customizados.
Sem índice secundário; lookups são por message_id (poucos anexos por msg) ou uploaded_by (admin/auditoria, raro).
Constraints
PRIMARY KEY (id)
Pipeline de upload
[Cliente envia multipart]
↓
multer/fastify-multipart parser
↓
Validate mime + size (limite 5MB por file no env atual)
↓
Se imagem: sharp gera thumbnail
Se áudio: ffmpeg extrai duração + computa peaks
Se vídeo: ffmpeg extrai duração + frame thumbnail
↓
S3Adapter.put(file) + S3Adapter.put(thumbnail)
↓
INSERT message_attachments com URLs e metadataLimpeza de S3
Mesmo problema dos post_media: cascade delete remove DB row, mas arquivos S3 ficam órfãos. Pendência: deletar via S3Adapter no service de delete.
Padrões de uso
- Upload + send — multipart
POST /chat/messagescria msg + attachments numa transação - Upload preview — multipart
POST /chat/attachments(sem message_id ainda) e mensagem criada depois comattachmentIds - Download — endpoint signed URL
GET /chat/messages/:id/download