# Relatórios - Pendências pós Sprint 1

> Sprint 1 entregou: config por projeto (blocos/seções liga-desliga + ciclos com dia/horário),
> preview com dado real (todos os blocos ativáveis renderizam), assembler único
> (preview = snapshot), geração + persistência (`report_runs`/`report_snapshots`), lista de
> gerados + visualizador de snapshot.
>
> Este arquivo lista o que ficou em aberto, para não perder contexto.

## 1. RESOLVIDO - Imagens da Meta / Envio por e-mail (ver docs/relatorios-envio-email-deploy.md)

Decisão tomada: formato de entrega = **resumo HTML no corpo + PDF anexo**. As thumbnails da Meta
vivem **dentro do PDF** (bytes baixados no render, embutidos como data URI - **Opção C**), com
placeholder em falha. O PDF pronto é o artefato imutável, guardado no **Google Cloud Storage**
(bucket privado; download via signed URL). base64 no JSONB foi descartado.

Implementado nesta fase: `ReportPdfService` (Browsershot), `ReportMail` + `ReportDeliveryService`,
jobs `GenerateReportPdfJob` (fila `reports`) e `ReportDeliveryJob`, tabela `report_deliveries`,
colunas de PDF/entrega em `report_runs`, modo de envio por projeto (auto/aprovação manual) e
envio/reenvio pela lista. Passos de infra (swap, node/Chromium, supervisor, GCS) em
`docs/relatorios-envio-email-deploy.md`.

## 2. Fase 2 - Coleta de dados que falta (sync novo)

Blocos já cadastrados com `requiresSync: true`, desabilitados na config até o dado existir:
- **GA4 Dispositivos** - coluna `fact_marketing_daily.device_type` existe mas está 100% NULL;
  exige estender o `Ga4Provider` com a dimensão `deviceCategory`.
- **GA4 Cidades** - idem, dimensão `city` (coluna `country` existe e está vazia).

Quando o sync for estendido, os blocos "acendem" sozinhos (renderizador é trivial, mesmo padrão de tabela).

## 3. Pré-requisito de produção - Reconciliação de schema (Fase 0 do plano)

O banco de homologação está **à frente das migrations** (ex.: `fact_marketing_daily` tem 32 colunas
no banco vs ~15 na migration). **Antes de subir o módulo para produção**, reconciliar migrations ↔ banco,
senão o `DashboardDataController`/assembler quebram em prod. Ver `docs/plano-modulo-relatorios.md` §5.

## 4. Agendador + Envio por e-mail

- **Agendador (cron/scheduler)**: FEITO. Comando `reports:dispatch-due` agendado `*/15 min` (SP),
  gera os ciclos devidos (weekday/dia + horário passou), idempotente 1×/dia via `trigger=scheduled`.
  Geração é **enfileirada** (`GenerateReportRunJob`, fila `database`). Observações:
  - **Latência ≤15 min**: relatório às 09:00 sai no 1º tick ≥09:00. Edge: horários perto da
    meia-noite podem escorregar de dia (a maioria é matinal - aceitável no MVP).
  - **Depende do cron** `schedule:run` a cada minuto + worker de fila ativo (supervisor). Após editar
    Jobs, rodar `php artisan queue:restart`.
- **Envio por e-mail** (PRÓXIMO): `report_recipients` + `report_deliveries`, montagem do PDF/HTML,
  disparo. Depende da decisão do item 1 (imagens Meta).

## 5. Permissões (revisar antes de prod)

Config e geração de relatórios estão sob `project.access` (mesma da tela) para não travar a
iteração. Como é configuração interna, avaliar restringir a **Exent** (padrão de
`projetos.dashboard-config.*`, que é `auth+exent`). Alinhar junto com quem pode ver a lista de
gerados (cliente vê? só time?).

## 6. Itens menores / técnicos

- **Breakdowns sem comparativo período-a-período** no MVP (só os KPI-rows têm trend, vindos de
  `base.trends`). Se quiser trend em tabelas (ex.: campanhas vs período anterior), é evolução.
- **Google Ads sem criativo**: não há thumbnail/asset de anúncio Google (só Meta). Bloco
  `gads_anuncios` mostra nome/tipo, sem imagem - limitação da fonte.
- **Landing pages GA4**: hoje o bloco `ga4_paginas` usa `fact_ga4_page_daily` (páginas mais
  acessadas). "Página de destino" (entrada) de verdade exigiria a métrica `entrances`, que existe
  como coluna mas nunca é populada.
- **`fact_leads_daily`**: tabela morta (0 linhas, sem writer) - candidata a limpeza.
- **Ativação de ciclo vs geração manual**: "Gerar agora" usa a **config salva** (não os toggles não
  salvos). Fluxo é Salvar → Gerar. Documentado; reavaliar se confunde o usuário.
- **`report_runs.generated_by`**: hoje é `varchar` nullable (auditoria, sem FK). `public.users.id`
  desta app é **inteiro** (não uuid - `auth.users` do Supabase é que é uuid). Se um dia amarrar FK
  real para `users`, usar `unsignedBigInteger`, nunca uuid. (Corrigido no Sprint 1 - a coluna nascera
  uuid e causava 500 ao gerar logado.)
