reports
Denúncias de conteúdo abusivo (user, post, comment, message, collection).
Sistema de denúncias do Geek Social. Implementado em 5 superfícies: usuários, posts, mensagens, coleções, conversas. O reporter informa o tipo (target_type) + ID do alvo + razão (enum) + descrição opcional.
Sem flow de moderação automatizado — admin vê dashboard de pendentes e marca como reviewed/dismissed manualmente. Pendência: integração com Linear/issue tracker.
Colunas
| Coluna | Tipo | Nullable | Default |
|---|---|---|---|
| id ● | uuid | NOT NULL | gen_random_uuid() |
| reporter_id | uuid | NOT NULL | — |
| target_type | enumcolumn | NOT NULL | — |
| target_id | uuid | NOT NULL | — |
| reason | enumcolumn | NOT NULL | — |
| description | text | NULL ok | — |
| status | enumcolumn | NOT NULL | pending |
| created_at | timestamp | NOT NULL | now() |
| updated_at | timestamp | NOT NULL | now() |
● primary key ◆ unique
Funcionalidade dos campos
id— UUID, PKreporter_id— quem denunciou (cascade)target_type— enum:user | message | post | collection | conversationtarget_id— UUID polimórfico (não é FK — referencia por type)reason— enum:spam | harassment | nsfw | hate | otherdescription— texto livre opcional, contexto do denunciantestatus—pending | reviewed | dismissed. Updated quando admin processa.created_at/updated_at— managed.
Foreign keys
| Coluna(s) | Referência | ON DELETE | ON UPDATE |
|---|---|---|---|
| reporter_id | users.id | cascade | no action |
target_id é polimórfico — sem FK explícita pra qualquer tabela. Backend valida na criação que o target existe.
Índices
| Nome | Único | Colunas | WHERE (parcial) |
|---|---|---|---|
| reports_reporter_target_unique | sim | reporter_id, target_type, target_id | — |
| reports_status_created_at_idx | não | status, created_at | — |
Detalhes:
reports_reporter_target_uniqueem(reporter_id, target_type, target_id)— impede o mesmo user denunciar o mesmo alvo 2xreports_status_created_at_idx— query de admin "pending mais antigos primeiro"
Constraints
PRIMARY KEY (id)
Polimorfismo do target
Dependendo de target_type, target_id aponta pra:
user→users.idmessage→messages.idpost→posts.idcollection→collections.idconversation→conversations.id
Se o alvo é deletado depois (cascade ou hard delete), a denúncia continua existindo com target_id apontando pra registro inexistente — admin precisa lidar com isso na UI ("conteúdo já removido").
Razões — semântica
spam— promoção indesejada, divulgação fora de contextoharassment— perseguição, ameaças, mensagens insistentes não-bem-vindasnsfw— conteúdo adulto/explícito sem flag adequadahate— discurso de ódio, discriminaçãoother— qualquer outra coisa; descrição obrigatória nesse caso? (Não enforced no schema; dependeria de validação no service.)
Padrões de uso
- Reportar —
POST /reports { targetType, targetId, reason, description? } - Listar pendentes (admin) —
GET /admin/reports?status=pending(endpoint admin não documentado aqui ainda) - Marcar reviewed —
PUT /admin/reports/:id { status: 'reviewed' }
Tabelas relacionadas
users— reporter (cascade)- Polimorfismo via
target_type/target_id:users,messages,posts,collections,conversations