Anúncios — Gestão pelo Admin (Web App)
Pilar: 02 — Funcionalidades Core / Web App
Status: 🟢 Implementado
Última Revisão Técnica: 2026-08-03
Módulos Conectados:gatein-web(src/screens/admin/Announcements),gatein-server(app/api/web/announcements.py,app/models.py),gatein-app(src/screens/AnnouncementsScreen, FCM Push Notifications)
1. Visão Geral e Integração com o App Mobile
O módulo de Gestão de Anúncios e Comunicados no Web App permite que Administradores de Terminais criem, editem, agendem e publiquem avisos operacionais, alertas de segurança em pátio e informativos institucionais direcionados aos motoristas de aplicativo.
Quando um anúncio é publicado ou atinge sua data de agendamento (start_at), o servidor FastAPI aceita a publicação e pode disparar automaticamente Notificações Push via Firebase Cloud Messaging (FCM) contendo um Deep Link (announcement_id) que abre o comunicado em tela cheia no aplicativo mobile.
1.1 Diagrama de Sequência de Publicação e Notificação FCM Batch
sequenceDiagram
autonumber
actor A as Admin do Terminal (Web App)
participant S as Gatein Server (FastAPI)
participant ST as Cloud Storage (S3/Firebase)
participant DB as PostgreSQL
participant FCM as Firebase Messaging
actor M as Motorista (App Mobile)
A->>S: POST /web/uploads (Upload do Banner de Imagem)
S->>ST: Envia imagem para o Bucket
ST-->>S: Retorna URL pública da imagem
A->>S: POST /web/announcements (title, description, image_url, start_at: now())
S->>DB: Insere registro na tabela announcements (is_active = True)
S->>FCM: Envia Push FCM em lote para motoristas elegíveis (payload: announcement_id)
S-->>A: HTTP 201 (Anúncio publicado com sucesso)
FCM-->>M: Notificação Push: "Novo Comunicado do Terminal"
M->>M: Toca na notificação -> Deep Link abre o Anúncio no App
2. Estruturas de Dados e Schemas Explícitos
2.1 Modelo Relacional no Banco de Dados (announcements)
| Coluna | Tipo SQL | Constraints | Descrição / Regra |
|---|---|---|---|
id | UUID | PRIMARY KEY, Default gen_random_uuid() | Identificador único interno |
company_id | UUID | FOREIGN KEY (companies.id), NOT NULL | Empresa criadora do comunicado |
title | VARCHAR(255) | NOT NULL | Título do anúncio |
subtitle | VARCHAR(255) | NULLABLE | Subtítulo ou resumo explicativo |
description | TEXT | NULLABLE | Corpo do texto completo em Markdown/HTML |
image_url | VARCHAR(512) | NULLABLE | URL da imagem do banner |
image_position | JSONB | DEFAULT '{"x": 50, "y": 50}' | Coordenadas de ajuste de corte da imagem na UI |
url | VARCHAR(512) | NULLABLE | Link externo para navegação ao clicar |
is_active | BOOLEAN | NOT NULL, Default True | Status de ativação |
start_at | TIMESTAMPTZ | NULLABLE | Data/hora programada de início da exibição |
end_at | TIMESTAMPTZ | NULLABLE | Data/hora de expiração e expulso |
2.2 Schemas de Requisição do Web App (CreateAnnouncementPayload)
{
"title": "Interdição do Gate 02 para Obras de Asfalto",
"subtitle": "Manutenção preventiva na pista interna de triagem",
"description": "Informamos a todos os motoristas que o Gate 02 estará fechado. Utilize exclusivamente o Gate 04.",
"image_url": "https://cdn.gatein.app/announcements/manutencao_gate2.jpg",
"image_position": { "x": 50, "y": 50 },
"url": "https://terminal-santos.com.br/comunicados/gate2",
"is_active": true,
"start_at": "2026-08-04T08:00:00Z",
"end_at": "2026-08-06T18:00:00Z"
}
3. Regras de Negócio Explícitas (RN-ANC-ADM-XXX)
RN-ANC-ADM-001: Anúncios sem Data de Expiração (end_at == NULL)
Se o Administrador deixar o campo end_at como nulo (NULL), o anúncio permanecerá ativo e elegível para exibição por tempo indeterminado, desde que respeitadas a flag is_active == True e a regra de concorrência da janela deslizante do app mobile (máximo de 3 anúncios simultâneos por empresa).
RN-ANC-ADM-002: Preservação Histórica e Soft-Delete
Anúncios que expirarem (end_at < now()) ou que forem desativados pelo Administrador não são deletados do banco de dados. O histórico é preservado na tabela announcements para fins de auditoria de comunicados e logs de visualização dos motoristas (announcement_logs).
RN-ANC-ADM-003: Agendamento Futuro (start_at > now())
Se a data start_at for configurada para um timestamp no futuro, o anúncio é gravado com status agendado. Ele não será retornado pela API mobile nem gerará notificações FCM até que a data/hora programada seja atingida.
RN-ANC-ADM-004: Disparo Único de Notificação Push FCM na Publicação
A notificação Push FCM em massa para os motoristas da empresa é disparada uma única vez no momento em que o anúncio é publicado ativamente (start_at <= now() e is_active == True). Edições subsequentes em textos ou títulos de um anúncio já publicado não disparam novas notificações em massa aos motoristas para evitar spam.
4. Detalhamento de Endpoints
4.1 GET /web/announcements
Retorna a listagem de todos os anúncios criados pela empresa do administrador, com filtros por status (active, scheduled, expired).
4.2 POST /web/announcements
Cria e publica/agenda um novo anúncio, efetuando o upload da imagem e disparando Push FCM em batch se ativo.
4.3 PUT /web/announcements/{id}
Atualiza os campos de texto, imagem, links e datas do anúncio.
4.4 DELETE /web/announcements/{id}
Marca o anúncio como desativado (is_active = False).
5. Regras de Segurança e Tabela de Erros
| Código HTTP | Código Interno | Causa Raiz | Ação no Web App |
|---|---|---|---|
400 Bad Request | INVALID_EXPIRATION_DATE | Data end_at é anterior à data start_at | Corrigir o intervalo de datas no formulário |
400 Bad Request | MISSING_BANNER_IMAGE | Tipo do anúncio exige imagem e a URL não foi fornecida | Realizar upload da imagem antes de salvar |
404 Not Found | ANNOUNCEMENT_NOT_FOUND | Anúncio informado não pertence à empresa do admin | Atualizar a lista de comunicados na UI |