ModularReports
Companheiro do DRS
ModularReports: Inventário de Artefatos
| Campo | Valor |
|---|---|
| Produto | ModularReports |
| Documento | Inventário de Artefatos (companheiro do DRS) |
| Data de revisão | 2026-07-24 |
Documentos da família
- DRS (modularreports), o que o sistema faz.
- Roadmap de Implementação (modularreports-roadmap), em que ordem construir e como verificar.
- Jornadas dos Atores (modularreports-jornadas), como cada papel opera o sistema.
- Plano de Testes (modularreports-testes), o que validar antes de entregar.
- Questionário de Elicitação (modularreports-questionario), decisões de produto em aberto.
Este é o registro de completude: tudo que precisa existir para o sistema funcionar (tabelas, migration, permissões, infraestrutura, telas, configuração, analytics, mídia) e, para cada item, a ficha do que ele deve ser. Cada artefato aponta o RF e a tarefa do Roadmap que o cria; se a tarefa está pronta mas o artefato não bate com a ficha, algo falta. A ordem de construção está no Roadmap; aqui está a lista do que provisionar.
Como usar
Marque um artefato quando ele existir E bater com a Especificação. Cada cartão traz Para que serve, Relacionado com (RF e tarefa do Roadmap), Onde fica e Especificação (a ficha implementável no sub-formato do tipo). Fichas extensas referenciam os apêndices do DRS (Ap.1 a Ap.8) em vez de repetir a ficha.
Tipos de artefato
| Tipo | Contagem | Onde vivem |
|---|---|---|
| Entidade / tabela (ART-ENT) | 10 | Schema reports no banco da plataforma-mãe |
| Migração de dados (ART-MIG) | 2 | Migration de registro do módulo no Hub, conversão v2 para v3 (golden set) |
| Parâmetro de configuração (ART-CFG) | 1 (tabela com 8 parâmetros) | Painel do admin de agência |
| Papel / permissão (ART-ACS) | 1 | Catálogo de permissões reports.* em código do Hub |
| Serviço / container (ART-INFRA) | 4 | Bucket de storage, sandbox de parse isolado, leitor público, ingestor de eventos |
| Menu / navegação (ART-NAV) | 1 | Chrome do Reports |
| Tela / página (ART-SCR) | 1 (tabela com 10 superfícies) | Chrome do operador, leitor público, painéis |
| Dashboard / relatório (ART-DASH) | 1 | Painel de analytics por agência |
| Métrica / indicador (ART-KPI) | 1 (tabela com 4 métricas) | Painel de analytics |
| Auditoria / log (ART-AUD) | 1 | Log de auditoria do Hub, eventos reports.* |
| Notificação / alerta (ART-NOT) | 1 | Widget de comentário e Central do Hub |
| Documento / PDF gerado (ART-DOC) | 1 | Gerador de PDF da plataforma-mãe |
| Campo personalizado (ART-FLD) | 1 | Ficha account_identidade_visual do Hub |
| Asset (ART-MEDIA) | 1 | Bucket reports, criativos e logos |
Total: 27 artefatos.
Entidades e tabelas (schema reports)
Espelha o bloco 5 (E.1, E.2) do DRS. Migration que cria as tabelas de dados: {F1b-01} do Roadmap (antes das fatias que as consomem).report_jobeagency_domainnascem nas suas fatias (evolução e Fatia 14).
Para que serve: o relatório e sua identidade pública, incluindo o token do link e a duração de produção.
Relacionado com: RF-CMP-001, RF-PUB-001 a 004, RF-ADM-015; tarefas {F1b-01}, {F8-01}, {F9-02} a {F9-04} do Roadmap; entidade vizinha report_draft (1:1) e snapshot (1:1).
Onde fica: schema reports, banco da plataforma-mãe.
Especificação: Nome: report | Descrição: o relatório e sua identidade pública | Atributos: id (uuid, PK), company_id (uuid, FK companies, NOT NULL), account_id (uuid, FK accounts, NOT NULL), template_id (uuid, FK template, NULL), type (text), title (text), period (daterange ou text), public_token (text, único, mínimo 128 bits), password_hash (text, NULL), expires_at (timestamptz, NULL), status (enum: draft, published, revoked), created_at (timestamptz), published_at (timestamptz, NULL), production_minutes (int, NULL) | Chave primária: id | Chaves estrangeiras: company_id -> hub.companies (N:1), account_id -> hub.accounts (N:1), template_id -> reports.template (N:1, opcional) | Índices: public_token (único), (company_id, account_id), (account_id, period) para a pasta por ano (RF-ADM-013) | Regras de integridade: public_token gerado uma vez e mantido em republish (RN-001); status published exige snapshot associado; company_id igual ao company_id do Account referenciado, garantido por trigger (RN-009) | Escopo de acesso: RLS RESTRICTIVE por company_id (RNF-SEG-001).
Para que serve: o rascunho editável do relatório, 1:1 com report, onde o compositor lê e escreve.
Relacionado com: RF-CMP-002 a 004, RF-CUR-001 a 007; tarefas {F1b-01}, {F8-01} a {F8-12}; entidade report (pai).
Onde fica: schema reports.
Especificação: Nome: report_draft | Descrição: rascunho editável do relatório | Atributos: report_id (uuid, PK e FK report, 1:1), blocks (jsonb, contrato de bloco v3), data_points (jsonb, registro de proveniência dp:<id>), briefing (jsonb, KPI principal, intenção, destaques, identidade), updated_at (timestamptz) | Chave primária: report_id | Chaves estrangeiras: report_id -> reports.report (1:1) | Índices: nenhum além da PK | Regras de integridade: todo número em blocks referencia um dp: presente em data_points (RN-003) | Escopo de acesso: RLS RESTRICTIVE por company_id via join com report.
Para que serve: a foto imutável publicada do relatório, única por report, sem versionamento.
Relacionado com: RF-PUB-001, RF-REN-001 a 003; tarefas {F2-01} a {F2-04}, {F9-01}; entidade report (pai), comment (âncora nos blocos do payload).
Onde fica: schema reports.
Especificação: Nome: snapshot | Descrição: foto imutável publicada, única por report | Atributos: report_id (uuid, PK e FK report, 1:1), payload (jsonb: blocks, data_points, metas vigentes, branding, share_card, todos copiados no publish; sem data_points o leitor não resolve número), schema_version (int), published_at (timestamptz) | Chave primária: report_id | Chaves estrangeiras: report_id -> reports.report (1:1) | Índices: nenhum além da PK | Regras de integridade: payload nunca reescrito por edição do draft após publish, só por novo publish (RN-002); schema_version confere com o registro do tipo de bloco no momento do publish | Escopo de acesso: leitor público (RF-REN-006) via role só-SELECT; escrita só pelo fluxo de publish autenticado (RF-CUR-007).
Para que serve: o insumo cru (planilha, CSV, PDF, Markdown, JSON, imagem) que o operador sobe, descartável por TTL.
Relacionado com: RF-ING-001 a 006, RF-BND-002; tarefas {F4-01} a {F4-06}; entidade report (pai).
Onde fica: schema reports (metadado); arquivo cru no bucket reports do storage da plataforma-mãe.
Especificação: Nome: artifact | Descrição: insumo cru, descartável | Atributos: id (uuid, PK), report_id (uuid, FK report), sha256 (text), type (enum: planilha, csv, pdf, markdown, json, imagem), parse_status (enum: pendente, ok, erro), purge_after (timestamptz, TTL curto por LGPD) | Chave primária: id | Chaves estrangeiras: report_id -> reports.report (N:1) | Índices: report_id, purge_after (para o job de limpeza) | Regras de integridade: registro apagado (ou marcado apagado) quando purge_after expira, sem quebrar o report publicado (RN-004) | Escopo de acesso: RLS RESTRICTIVE por company_id via join com report; sem tela de listagem como acervo (RF-BND-002).
Para que serve: o comentário logado, ancorado a um bloco do snapshot.
Relacionado com: RF-COM-001 a 006; tarefas {F12-01} a {F12-06}; entidade report (pai), snapshot (referencia block_id do payload).
Onde fica: schema reports.
Especificação: Nome: comment | Descrição: comentário logado ancorado | Atributos: id (uuid, PK), report_id (uuid, FK report), block_id (text, id estável do bloco), excerpt (text, NOT NULL), author_contact_id (uuid, FK hub.contacts, NULL), body (text), orphaned (boolean, default false), resolved_at (timestamptz, NULL), created_at (timestamptz) | Chave primária: id | Chaves estrangeiras: report_id -> reports.report (N:1, ON DELETE CASCADE), author_contact_id -> hub.contacts (N:1, ON DELETE SET NULL) | Índices: report_id, (report_id, block_id), author_contact_id | Regras de integridade: excerpt sempre preenchido no create; orphaned vira true quando block_id some do snapshot numa republicação, sem apagar o comentário (RN-005); no offboarding LGPD (RF-ADM-011), apagar o Contact põe author_contact_id em NULL e o body é anonimizado, sem apagar o comentário (RN-007) | Escopo de acesso: leitura pública ligada ao snapshot; escrita só via endpoint autenticado separado do leitor (RF-COM-002).
Para que serve: o evento de audiência do link (visualização, referrer, sessão da agência).
Relacionado com: RF-ANL-001 a 005; tarefas {F13-01} a {F13-05}; entidade report (pai).
Onde fica: schema reports.
Especificação: Nome: link_event | Descrição: evento de audiência | Atributos: id (uuid, PK), report_id (uuid, FK report), event_type (enum: view, ...), referrer (text, NULL), opaque_visitor_id (text, identificador não pessoal), is_agency_session (boolean, para exclusão do painel), created_at (timestamptz) | Chave primária: id | Chaves estrangeiras: report_id -> reports.report (N:1) | Índices: report_id, created_at, (report_id, event_type, is_agency_session) para o KPI de visualizações (ART-KPI-01) | Regras de integridade: opaque_visitor_id nunca é o email ou identificador pessoal cru (RF-ANL-004); is_agency_session=true exclui o evento das métricas do painel (RF-ANL-003) | Escopo de acesso: escrita pelo pipeline de eventos separado do leitor (RF-ANL-001); leitura só pelo painel de analytics da própria agência (RF-ANL-006).
Para que serve: o tipo de relatório com os blocos padrão da agência, o gabarito que a IA preenche.
Relacionado com: RF-ADM-009, RF-ADM-010, RF-CMP-001; tarefas {F10-01}, {F10-02}, {F8-01}; entidade report (referenciado por template_id).
Onde fica: schema reports.
Especificação: Nome: template | Descrição: tipo de relatório com blocos padrão | Atributos: id (uuid, PK), company_id (uuid, FK companies, NULL quando template de fábrica), name (text), type (text), default_blocks (jsonb, contrato de bloco v3 sem dados do cliente), is_factory (boolean, default false; templates de fábrica têm company_id nulo e is_factory true, condicionado a {Q3}), created_at (timestamptz) | Chave primária: id | Chaves estrangeiras: company_id -> hub.companies (N:1, opcional) | Índices: company_id | Regras de integridade: default_blocks nunca contém números ou textos específicos de um cliente (RF-ADM-010); template de fábrica é visível a todas as agências para leitura e duplicável | Escopo de acesso: RLS RESTRICTIVE por company_id (templates de fábrica visíveis a todos para leitura); CRUD pelo admin e pelo operador (RF-ADM-009).
Para que serve: as metas e o planejamento por cliente, referência persistente de planejado versus realizado, sem TTL (não é artifact).
Relacionado com: RF-ING-007, RF-BND-003, RN-008; tarefas {F1b-01}, {F11-02} do Roadmap; bloco comparison (Ap.3) que lê daqui; snapshot (copia as metas no publish).
Onde fica: schema reports.
Especificação: Nome: report_goal | Descrição: metas e planejamento por cliente (referência, não tracking) | Atributos: id (uuid, PK), company_id (uuid, FK companies, NOT NULL), account_id (uuid, FK accounts, NOT NULL), metric (text), target_value (numeric), unit (text), period_label (text), source_artifact_id (uuid, NULL), created_at (timestamptz), updated_at (timestamptz) | Chave primária: id | Chaves estrangeiras: company_id -> hub.companies (N:1), account_id -> hub.accounts (N:1) | Índices: (company_id, account_id) | Regras de integridade: persistente por cliente, sem purge_after (não é artifact); o snapshot copia as metas vigentes no publish e alterá-las depois não muda o snapshot (RN-008); não gera tracking contínuo (RF-BND-003) | Escopo de acesso: RLS RESTRICTIVE por company_id.
Para que serve: o estado da composição quando ela deixar de ser síncrona (só existe quando a fila assíncrona entrar); no V1 a composição é síncrona in-process e custo/tempo gravam no report_draft.
Relacionado com: RF-CMP-012, RNF-PERF-002; tarefa de evolução (a fila não é V1); DRS E.2, RNF-PERF-002.
Onde fica: schema reports (só quando a fila for construída).
Especificação: Nome: report_job | Descrição: estado da composição assíncrona (evolução) | Atributos: id (uuid, PK), report_id (uuid, FK report), status (enum: queued, composing, done, failed), progress (int), tokens (int), duration_ms (int), error (text, NULL), created_at (timestamptz) | Chave primária: id | Chaves estrangeiras: report_id -> reports.report (N:1) | Índices: report_id, status | Regras de integridade: não existe no V1 (composição síncrona não persiste estado de job); entra com a fila assíncrona, disparada pelo primeiro request que estourar o tempo (RNF-PERF-002) | Escopo de acesso: RLS RESTRICTIVE por company_id via join com report.
Para que serve: o domínio custom da agência com validação de posse, para o link público sair sob o domínio da agência.
Relacionado com: RNF-SEG-006, ADR-015; tarefas {F14-01}, {F14-02} do Roadmap.
Onde fica: schema reports.
Especificação: Nome: agency_domain | Descrição: domínio custom da agência com validação de posse | Atributos: id (uuid, PK), company_id (uuid, FK companies, NOT NULL), domain (text, único), txt_token (text, para a validação TXT de posse), status (enum: pending, verified), created_at (timestamptz) | Chave primária: id | Chaves estrangeiras: company_id -> hub.companies (N:1) | Índices: domain (único), company_id | Regras de integridade: o CNAME só ativa com status verified após a posse por registro TXT (RNF-SEG-006); desvincular remove o CNAME | Escopo de acesso: RLS RESTRICTIVE por company_id.
Migração e permissões
Para que serve: cunha o module_key NOVO reports (não reusa results): adiciona o literal reports à restrição CHECK de módulos válidos da tabela de entitlements de módulo do Hub, e a entrada reports (rótulo "Relatórios", não core) ao catálogo de módulos em código. Depois disso o entitlement booleano por Company pode ser ligado (desligado por default).
Relacionado com: RF-ADM-001; tarefa {F6-01} do Roadmap; artefato vizinho ART-CFG-01 (o toggle por Company é admin-editável).
Onde fica: migration versionada do banco da plataforma-mãe (a CHECK de hub.module_entitlements) mais a lista de módulos em código (canonical-enums do Hub).
Especificação: Origem: catálogo de módulos do Hub em código | Destino: restrição CHECK de módulos válidos da tabela de entitlements de módulo, mais a lista de módulos em código | Entidades migradas e volume: 1 alteração de CHECK constraint mais 1 entrada de catálogo em código, sem dado de linha migrado | Mapeamento de campos: adiciona o literal 'reports' ao CHECK e a entrada {key:"reports", label:"Relatórios", core:false} ao catálogo | Transformações: nenhuma | Validação pós-migração: SELECT confirma que uma Company pode receber entitlement booleano 'reports'; nenhuma Company existente recebe o módulo ligado automaticamente; o catálogo em código lista 'reports' | Itens de revisão manual: nenhum | Reversibilidade: aditiva, reversível por migration de remoção do literal se nenhuma Company tiver o módulo ligado | Quando roda: one-shot, na {F6-01}, depois das tabelas de dados (F1b).
Para que serve: converter os relatórios reais do formato v2 para o contrato de bloco v3 e montar o conjunto de referência (golden set) da Fatia 1, insumo do juiz de rubrica e dos gates HARD.
Relacionado com: RF-CMP-006 (proveniência legada), DRS I.1, Ap.2, Ap.8; tarefa {F1-00} do Roadmap; contrato de bloco v3 ({F2-01}).
Onde fica: script determinístico de conversão mais o corpus resultante na pasta de fixtures do projeto (docs/golden-set/).
Especificação: Origem: relatórios reais em v2 (hero, kpis, sections) mais os artefatos crus quando existirem | Destino: documentos v3 (blocks[] com id estável, data_points com dp: e source) | Entidades migradas e volume: os relatórios reais já entregues, mais um export adversarial com número inflado (fail-loud), mais ao menos dois casos fora do nicho | Mapeamento de campos: hero/kpis/sections do v2 para blocks[] v3, cada bloco recebe id; para cada número v2 (já formatado) cria data_point com source {kind:"artifact", ...} quando o cru existe, ou marca provenance:"legacy" quando só há o formatado | Transformações: atribuição de id por bloco, extração de dp: por número | Validação pós-migração: cada documento v3 valida contra o contrato de bloco; todo número tem dp: ou provenance legacy; o caso adversarial é reconhecido como tal pela rubrica | Itens de revisão manual: os números sem cru disponível ficam marcados legacy e revisados a olho | Reversibilidade: os v2 originais são preservados; a conversão não os apaga | Quando roda: one-shot na {F1-00}, base da Fatia 1.
Para que serve: as capabilities do Reports por papel canônico do Hub, sem papel novo.
Relacionado com: RF-ADM-002, RF-ADM-003; tarefa {F6-03} do Roadmap; DRS B.1 (catálogo de atores).
Onde fica: catálogo de permissões em código do Hub (defaults por papel mais metadados de capability), prefixo reports., sem tabela nova; override por usuário reusa a concessão de capability existente.
Especificação: tabela Capability | super_admin | admin | team_manager/workforce | contact:
| Capability | super_admin | admin | operador | contact |
|---|---|---|---|---|
reports.entitlement.manage | Sim, escopo todos | Não | Não | Não |
reports.agency.manage_users | Sim, escopo todos | Sim, só a própria agência | Não | Não |
reports.identity.manage | Não | Sim, só a própria agência e seus clientes | Não | Não |
reports.template.manage | Não | Sim, só a própria agência | Sim, só a própria agência | Não |
reports.compose | Não | Não | Sim, só clientes da própria agência | Não |
reports.publish | Não | Não | Sim, só sessão humana | Não |
reports.analytics.view | Sim, escopo todos | Sim, só a própria agência | Não | Não |
reports.client.create | Não | Sim | Sim | Não |
reports.client.offboard | Não | Sim, só a própria agência | Não | Não |
reports.comment.create | Não | Não | Não | Sim, só se logado |
reports.comment.resolve | Não | Sim | Sim | Não |
Quem configura este papel: Super Admin (entitlement) e Admin de agência (usuários dentro da agência) | Plano(s) onde o papel existe: só no Hub (ModularReports não tem plano próprio) | Restrição de visibilidade de dados: por company_id (RNF-SEG-001) | Pode delegar: Admin de agência pode promover outro usuário da própria agência a admin; não pode criar Super Admin. Não repete a matriz completa de capabilities do Hub (essa vive no catálogo do Hub); traz só o recorte reports.* (REGRA-INV-2).
Infraestrutura
Para que serve: armazena o artefato cru (com TTL) e os assets (criativos, capas de compartilhamento) do módulo.
Relacionado com: RF-ING-004, RF-ING-005, ADR-009; tarefa {F4-04} do Roadmap; artefato ART-ENT-04 (artifact), ART-MEDIA-01.
Onde fica: storage da plataforma-mãe, bucket dedicado reports.
Especificação: Serviço: bucket de storage reports | Papel no sistema: artefato cru (TTL curto) e assets (persistentes até o processo LGPD) | Imagem/versão: o mesmo storage de arquivo do Hub, bucket novo (o Hub tem zero bucket hoje; o bucket reports é criação nova) | Recursos: dimensionado pelo volume de upload; limite por arquivo de 50 MB (o limite do storage de arquivo da plataforma-mãe), relevante para PDF e artefato grande | Portas/rede: acesso via API do storage da plataforma-mãe, sem exposição direta | Dependências: serviço de storage do Hub | Volumes/persistência: artefato cru com purge automático por purge_after; asset persistente até revogação LGPD | Health check: herda do storage da plataforma-mãe | Escalonamento: herda do storage da plataforma-mãe | Backup: herda a política de backup do storage da plataforma-mãe.
Para que serve: o único processo de fato isolado do pipeline: container efêmero sem rede que faz o parse dos artefatos e devolve JSON saneado. A composição de IA NÃO é um worker de fila separado no V1: roda in-process (síncrona), reusando o gateway de IA da plataforma-mãe.
Relacionado com: RF-ING-003, RF-CMP-009, ADR-004, ADR-011; tarefas {F1-02}, {F4-03} do Roadmap.
Onde fica: container efêmero no orquestrador de contêineres da plataforma-mãe (docker Compose), disparado por parse, com deploy independente da fila de release do Hub.
Especificação: Serviço: sandbox de parse isolado | Papel no sistema: recebe os bytes do artefato, parseia e devolve JSON estruturado saneado; a composição de IA roda in-process fora deste container | Imagem/versão: contêiner efêmero próprio, morto ao fim do parse | Recursos: limites de CPU, memória e tempo, com kill por timeout | Portas/rede: SEM rede de saída (é onde mora o risco de exploit de arquivo: XXE, zip bomb, SVG com script, PDF malicioso) | Dependências: nenhuma de rede; recebe bytes e devolve JSON | Volumes/persistência: nenhuma, efêmero | Health check: o processo vive só durante o parse; timeout mata | Escalonamento: horizontal por demanda de parse | Backup: não aplicável (efêmero). Nota: um worker de fila assíncrono para o render é evolução, disparado pelo primeiro arquivo que estourar o tempo de request (RNF-PERF-002), não V1.
Para que serve: serve o snapshot publicado sob role só-SELECT, sem alcance a outros schemas.
Relacionado com: RF-REN-006, RF-REN-010, ADR-003; tarefas {F5-01} a {F5-05} do Roadmap.
Onde fica: serviço isolado, deploy independente da fila de release do Hub.
Especificação: Serviço: leitor público | Papel no sistema: resolve o token do link para o snapshot e o renderiza via package renderizador | Imagem/versão: serviço SSR próprio | Recursos: dimensionado pelo tráfego público esperado dos links | Portas/rede: exposto publicamente na rota do link, sem outras rotas administrativas | Dependências: role reports_reader com GRANT de SELECT apenas em report, snapshot e comment (não no schema inteiro, RN-011), package renderizador | Volumes/persistência: nenhuma além do cache HTTP (asset imutável por snapshot_id, RNF-SEG-005) | Health check: endpoint de saúde próprio, monitorado independente do Hub | Escalonamento: horizontal, cacheável | Backup: não aplicável (leitura derivada do banco).
Para que serve: ingere os eventos de audiência do link e escreve em link_event, separado do leitor público (que é só-SELECT); a coleta não bloqueia o caminho de leitura.
Relacionado com: RF-ANL-001, RF-ANL-003, RF-ANL-004; tarefa {F13-08} do Roadmap; entidade ART-ENT-06 (link_event), ART-INFRA-03 (o leitor emite, o ingestor grava).
Onde fica: container próprio no orquestrador de contêineres da plataforma-mãe, separado do leitor.
Especificação: Serviço: ingestor de eventos de analytics | Papel no sistema: recebe os eventos que o leitor emite e grava em link_event (view, referrer, is_agency_session, opaque_visitor_id) | Imagem/versão: contêiner próprio | Recursos: dimensionado pelo volume de acessos aos links | Portas/rede: canal de escrita interno em link_event; o leitor público segue sem permissão de escrita (RF-REN-006) | Dependências: schema reports (escrita só em link_event) | Volumes/persistência: os eventos ficam em link_event | Health check: liveness do processo | Escalonamento: horizontal, desacoplado do leitor por fila leve | Backup: coberto pelo backup do banco.
Interface
Para que serve: a navegação própria do Reports, isolada do menu lateral do Hub.
Relacionado com: RF-ADM-014; tarefa {F7-01} do Roadmap.
Onde fica: grupo de rotas lazy do chrome do Reports.
Especificação: Item de menu: Relatórios (lista), Clientes, Templates, Analytics, Identidade da agência, Usuários; para o Super Admin: Painel do Super Admin (entitlement, agências, limites) | Destino: rota própria do Reports por item | Visível para: Operador e Admin (itens operacionais); Admin e Super Admin (itens de configuração); Super Admin (painel do Super Admin) | Ícone: conjunto de ícones do design system da plataforma-mãe | Ordem: Relatórios, Clientes, Templates, Analytics, Identidade, Usuários | Sub-itens: Clientes tem sub-item Pasta do cliente | Condição de exibição: entitlement reports ligado na Company (RF-ADM-001) e capability do papel (ART-ACS-01).
Para que serve: as telas e páginas do ModularReports, uma por linha da tabela F.1 do DRS.
Relacionado com: todos os RFs do sistema; tarefas {F7} a {F16} do Roadmap; DRS bloco 6 (F.1, F.3), mockup navegável aprovado (16 telas, {M-01}).
Onde fica: chrome do operador, leitor público, painéis.
Especificação: cada superfície segue, tela a tela, a página correspondente do mockup navegável aprovado (REGRA-INV-2, ficha extensa referencia o mockup em vez de repetir campo a campo o layout já aprovado):
| Superfície | Público | Natureza | RFs principais |
|---|---|---|---|
| Chrome do operador | Operador, Admin | Aplicativo isolado, entrada pelo Hub e endereço direto | RF-ADM-014 |
| Wizard de composição | Operador | 4 passos (Ap.1) | RF-CMP-001 a 004 |
| Compositor | Operador | Curadoria de blocos, três colunas | RF-CUR-001 a 007 |
| Modo apresentar | Operador | Tela cheia, rascunho ou publicado | RF-CUR-006 |
| Modal de publicação | Operador | Onde o link nasce (Ap.7) | RF-PUB-002 a 006 |
| Leitor público | Cliente final | Página estática isolada somente leitura | RF-REN-006, RF-REN-010 |
| Widget de comentário | Cliente final logado | Drawer lateral estilo documento colaborativo | RF-COM-001 a 006 |
| Painel de analytics | Admin | Agregado por agência | RF-ANL-006 |
| Painel do Super Admin | Super Admin | Entitlement, agências, limites, retenção | RF-ADM-001, RF-ADM-003 |
| Portal do cliente logado | Cliente final logado | Leitura agregada dos relatórios dos seus Accounts, opcional; tela cliente-painel | RF-REN-011 |
Rota, elementos, estados e responsivo de cada superfície: ver o mockup navegável aprovado (link em {M-01} do Roadmap) e a jornada do papel correspondente (documento Jornadas dos Atores). A gestão de domínio custom da agência ({F14-02}) já é uma seção da tela de identidade da agência no mockup; o que falta ali é o estado "pendente de validação TXT" antes do "propagado", a incluir numa próxima iteração do mockup (ADR-015).
Análise
Para que serve: o admin acompanha o desempenho agregado dos relatórios da própria agência.
Relacionado com: RF-ANL-006; tarefa {F13-06} do Roadmap; ART-KPI-01, ART-ENT-06 (link_event).
Onde fica: chrome do Reports, seção Analytics.
Especificação: Objetivo: quanto os relatórios da agência estão sendo vistos e comentados | Quem acessa: Admin da agência (RLS por company_id) | Métricas/colunas: ver ART-KPI-01 | Filtros disponíveis: por cliente, por período de publicação | Agrupamentos: por cliente | Período/granularidade: acumulado desde a publicação, sem série temporal contínua (RF-BND-001) | Fonte de dados: link_event, report (production_minutes), comment | Ações por linha: abrir o relatório, abrir os comentários não lidos | Exportação: diferida (não especificada nesta fatia) | Atualização: consulta direta, sem cache de longa duração.
Para que serve: as métricas exibidas no painel de analytics por agência.
Relacionado com: RF-ANL-002, RF-ANL-003, RF-ANL-005, RF-ADM-015; tarefas {F13-02}, {F13-03}, {F13-05}, {F13-07}.
Onde fica: painel de analytics por agência (ART-DASH-01).
Especificação:
| Nome | Definição | Fórmula | Unidade | Granularidade | Fonte |
|---|---|---|---|---|---|
| Visualizações | Acessos ao link excluindo sessões da própria agência e modo apresentar | Contagem de link_event com event_type=view e is_agency_session=false | Contagem | Por relatório | link_event |
| Último acesso | Data e hora do acesso mais recente ao link | MAX(created_at) de link_event filtrado como acima | Timestamp | Por relatório | link_event |
| Origem por referrer | Distribuição de acessos por referrer, ou "desconhecida" | Agrupamento de link_event.referrer | Contagem por origem | Por relatório | link_event |
| Duração de produção | Tempo entre início da composição e publicação | published_at - created_at (minutos) do report | Minutos | Por relatório | report.production_minutes |
Sem meta ou baseline formal nesta fatia; alimenta o critério de adoção (DRS A.7).
Governança
Para que serve: trilha imutável das ações relevantes do Reports (publicar, republicar, revogar, encerrar cliente).
Relacionado com: RF-ADM-012; tarefa {F6-05} do Roadmap; log de auditoria existente do Hub (hub.audit_log).
Onde fica: hub.audit_log, eventos com event_type prefixado reports..
Especificação: Eventos registrados: reports.report.published, reports.report.republished, reports.link.revoked, reports.client.offboarded (lista mínima, extensível) | Campos de cada evento: ator (user/contact id), ação (event_type), alvo (report_id ou account_id), valor anterior e valor novo (old_value/new_value, quando altera estado; a republicação usa isso para derivar o log humano de RF-PUB-010), timestamp | Imutabilidade: append-only POR RLS (as policies só permitem INSERT e SELECT; não há UPDATE nem DELETE por política; o service_role ainda alcança o storage, então é append-only por RLS, não imutável a nível físico) | Dado pessoal: NENHUM registro contém dado pessoal cru, só evento e identificadores (RN-007); a pseudonimização LGPD acontece nas tabelas de origem, nunca mutando o log | Retenção: herda a política de retenção do log do Hub, exceto onde a retenção específica do Reports (bloco 11) for mais curta | Quem consulta: Admin e Super Admin | Filtros disponíveis: por agência, por tipo de evento, por período | Onde fica armazenado: hub.audit_log, ponto único de escrita via o helper de auditoria do Hub (RF-ADM-012).
Para que serve: avisa o autor do comentário quando o operador marca como resolvido, fechando o loop.
Relacionado com: RF-COM-005; tarefa {F12-05} do Roadmap; ART-ENT-05 (comment).
Onde fica: canal de notificação existente do Hub (Central de Notificações), endereçado ao Contact autor.
Especificação: Evento que gera: comment.resolved_at preenchido | Destinatário: author_contact_id do comentário | Texto: "Seu comentário no relatório <título> foi resolvido" | Canal in-app: Central de Notificações do Hub | Ação ao clicar: abre o link público do relatório ancorado no bloco do comentário | Tempo real ou polling: herda o mecanismo de notificação do Hub | Quando marca como lida: ao abrir a notificação | Agrupamento: por relatório, se houver mais de um comentário resolvido no mesmo lote.
Documento e mídia
Para que serve: versão em PDF do relatório publicado, gerada sob demanda.
Relacionado com: RF-REN-008, RF-REN-009; tarefas {F15-01}, {F15-02} do Roadmap; ART-INFRA-03 (leitor), package renderizador ({F3-02}).
Onde fica: gerado sob demanda a partir do snapshot; não persiste como arquivo permanente além do cache de geração.
Especificação: Finalidade: levar o relatório para fora do link (anexo de email, impressão) | Gatilho de geração: ação "baixar PDF" no leitor público ou no chrome do operador | Dados/variáveis que preenche: o mesmo payload do snapshot, renderizado pelo package renderizador | Layout: mesma ordem de blocos do snapshot, tema claro, contraste AA | Idioma: o idioma do relatório publicado | Assinatura eletrônica: não | Onde fica armazenado: não persiste, gerado por requisição a partir do snapshot; se o gerador da plataforma-mãe estiver indisponível, a opção não é oferecida (RF-REN-008) | Versão/numeração: nenhuma, reflete sempre o snapshot vigente | Exigência regulatória: nenhuma.
Para que serve: fonte única de cores, logo, fontes e tom de voz do cliente, usada pela composição e pelo branding da página.
Relacionado com: RF-ADM-005, RF-ADM-006, RF-CMP-013; tarefas {F16-01}, {F16-02} do Roadmap; DRS Ap.6 (ficha completa).
Onde fica: tabela existente hub.account_identidade_visual; o Reports lê e popula, não cria tabela própria e não exige migration de ALTER (a tabela tem um campo de dados livre jsonb que já comporta logos, cores, fontes, tom de voz e restrições; a forma é validada na camada da rota).
Especificação: ficha extensa, referenciada no Apêndice 6 do DRS ("Ficha de identidade visual do cliente"), REGRA-INV-2. Resumo dos campos: Nome do campo: logos[] | Tipo: array de referência de asset (dentro do jsonb data) | Opções: N/A | Valor default: vazio, bloqueia ou usa default da agência (RF-ADM-006) | Obrigatório: não, com bloqueio condicional | Quem escreve: Admin, Operador | Quem lê: pipeline de composição, package renderizador | Regra associada: RF-ADM-006. Sem ALTER: o jsonb livre já comporta todos os campos. Campos completos (cores, fontes, tom_de_voz, restrições): Ap.6 do DRS.
Para que serve: as imagens de anúncio (criativos) inseridas como blocos de mídia no relatório, e a capa do card de compartilhamento.
Relacionado com: RF-ING-005, RF-CUR-003, RF-PUB-006; tarefas {F2-05}, {F8-07} do Roadmap; ART-INFRA-01 (bucket).
Onde fica: bucket reports do storage da plataforma-mãe.
Especificação: Tipo de asset: imagem (criativo de anúncio, logo do cliente, capa de compartilhamento) | Finalidade: bloco de mídia do relatório (RF-CUR-003), capa og:image do card (RF-PUB-006) | Dimensões/formato: conforme o uso (criativo na proporção original, capa em formato de card social) | Variações: nenhuma variação de tema exigida (a imagem é do cliente, não do chrome) | Fonte: enviada pelo operador como artefato ou selecionada da ficha de identidade do cliente | Onde fica armazenado: bucket reports, referenciado por asset_id e sha256, nunca por URL crua ou base64 no payload (RF-ING-005).
Parâmetros de configuração
Para que serve: todo valor operacional que o admin pode querer mudar sem migration ou deploy (DRS bloco 11).
Relacionado com: RF-ING-002, RF-ING-004, RF-ADM-011, RF-CMP-014, RF-ING-006, RF-ADM-006, RF-CMP-015, RF-ADM-009, RF-PUB-002; tarefas {F4-02}, {F4-04}, {F16-05}, {F1-10}, {F4-05}, {F16-02}, {F1-11}, {F10-01}, {F9-02}.
Onde fica: painel do admin de agência (e painel do Super Admin para os de escopo global).
Especificação:
| Nome do parâmetro | O que controla | Tipo | Valor default | Faixa/opções | Quem edita | Onde edita | Efeito ao mudar | Auditado | RN/RF |
|---|---|---|---|---|---|---|---|---|---|
| Quota de entrada | Nº de artefatos, MB totais, páginas de PDF por composição | Tabela (3 números) | A definir na Fatia 4 | Inteiro positivo | Admin | Painel de configuração da agência | Imediato, próxima composição | Sim | RF-ING-002 |
| TTL do artefato cru | Tempo até apagar o artefato cru após publish | Número (horas) | Curto (minimização LGPD) | Inteiro positivo | Admin | Painel de configuração da agência | Próximo ciclo de limpeza | Sim | RF-ING-004 |
| Retenção de snapshots, comentários e analytics | Tempo de guarda dos dados do cliente | Número (dias) | A declarar pelo admin | Inteiro positivo | Admin | Painel de configuração da agência | Próximo ciclo de limpeza/offboarding | Sim | RF-ADM-011 |
| Allowlist de fontes de benchmark e pesquisa de mercado | Quais fontes externas a IA pode citar | Lista de domínios/fontes | Vazia | Lista editável | Admin (por agência) e Super Admin (global) | Painel de configuração | Imediato, próxima composição | Sim | RF-CMP-014, RF-ING-006 |
| Identidade padrão da agência | Fallback quando a ficha do cliente está vazia | JSON (cores, tom de voz) | Nenhum até o admin declarar | Livre, validado como cor/tom | Admin | Painel de identidade da agência | Imediato, próximo publish sem ficha do cliente | Sim | RF-ADM-006 |
| Templates (tipos de relatório) | Blocos padrão por tipo de relatório | CRUD de entidade | Nenhum até o admin criar | Livre | Admin, Operador | Biblioteca de templates | Imediato, próximo relatório com esse template | Sim | RF-ADM-009 |
| Teto de verbosidade por bloco | Limite de caracteres por bloco de texto | Número (caracteres) | Definido no schema (ex.: 280 para insight) | Inteiro positivo | Super Admin (global) | Configuração do schema de blocos | Imediato, próxima composição | Sim | RF-CMP-015 |
| Rate-limit do link público | Requisições por janela ao caminho do link público | Número (requisições por janela) | A definir na Fatia 9, admin-editável | Inteiro positivo | Super Admin (global) e Admin (por agência) | Painel de configuração | Imediato, próximo acesso | Sim | RF-PUB-002 |