A cidade de atuação é São Paulo, garantida por teste em quatro lugares e exigida por openspec/specs/site-settings/spec.md. O identificador de timezone, porém, era America/Fortaleza. O identificador passa a acompanhar o negócio. A mudança não altera comportamento. America/Sao_Paulo e America/Fortaleza são UTC-3 o ano inteiro desde que o horário de verão brasileiro foi extinto — verificado para janeiro, março e dezembro de 2026, idênticos ao segundo. Nada renderizado muda, o relógio congelado dos testes visuais usa offset absoluto (-03:00) e os baselines seguem válidos. O motivo de mexer é outro: a divergência entre o timezone e a cidade custou tempo real. Uma sessão anterior a interpretou como drift e "corrigiu" a SPEC no sentido errado, mudando o documento normativo para Fortaleza em vez de olhar o que o negócio é. Com os dois valores dizendo São Paulo, não há mais o que interpretar. Escopo: config/app.php, .env.example, os dois pontos do ci.yml, SPEC.md (§0, §13.5, §15.4), README.md, docs/deployment/dokploy.md, CLAUDE.md, openspec/config.yaml, openspec/specs/visual-regression/spec.md e o withTimezone do VisualRegressionTest. Intocados de propósito: as asserções que garantem que Fortaleza não aparece como cidade de operação, em PublicPagesTest, SiteSettingsTest, ContentSeederProductionGatingTest e openspec/specs/site-settings. Essas tratam de cidade, não de fuso, e continuam corretas. Co-Authored-By: Claude noreply@anthropic.com AI-Assisted: yes AI-Tool: claude-code Co-authored-by: manoel.neto <manoel.neto@creditas.com>
70 KiB
SPEC.md — MVP da Plataforma de Assessoria de Eventos
Documento normativo para desenvolvimento orientado por especificação. Este arquivo é a fonte de verdade para agentes como Cursor, Claude Code e outros agentes de implementação.
0. Metadados
| Campo | Valor |
|---|---|
| Produto | Plataforma de Assessoria de Eventos |
| Tipo | Aplicação web single-tenant |
| Estágio | MVP |
| Status da especificação | Aprovada para implementação |
| Idioma da interface | Português do Brasil (pt-BR) |
| Timezone padrão | America/Sao_Paulo |
| Cidade de atuação | São Paulo (capital) |
| Moeda | BRL, sem conversão entre moedas |
| Princípio principal | YAGNI — implementar somente o necessário para validar o produto |
| Arquitetura | Monólito modular Laravel |
| Área interna | Filament |
| Área pública | Blade + JS vanilla progressivo (Livewire é dependência do Filament, não usada no site público — ver ADR-015) |
| Servidor de aplicação | FrankenPHP em modo regular |
| Banco de dados | PostgreSQL |
| Testes | Pest, Pest Browser/Playwright e testes visuais |
0.1 Vocabulário normativo
- MUST / DEVE: requisito obrigatório.
- MUST NOT / NÃO DEVE: comportamento proibido.
- SHOULD / DEVERIA: recomendação forte, dispensável apenas com justificativa registrada.
- MAY / PODE: opção permitida.
0.2 Ordem de precedência
Em caso de conflito, seguir esta ordem:
- Instrução explícita mais recente do responsável pelo produto.
- Este
SPEC.md. - ADRs aceitos no repositório.
- Testes automatizados existentes.
- Convenções já consolidadas no código.
- Preferência do agente ou da biblioteca.
O agente NÃO DEVE alterar silenciosamente uma decisão deste documento. Uma alteração de escopo ou arquitetura deve atualizar esta especificação ou criar uma ADR.
Mudanças incrementais são planejadas em openspec/changes/ e, após arquivadas, este documento DEVE ser revalidado para incorporar decisões ratificadas (back-sync). Este arquivo permanece a fonte de verdade do produto.
1. Contrato de operação para agentes
Antes de implementar qualquer mudança, o agente DEVE:
- Ler este arquivo integralmente.
- Inspecionar a estrutura atual do repositório.
- Identificar o requisito funcional pelo ID.
- Listar os arquivos que pretende criar ou alterar.
- Implementar uma fatia vertical pequena e funcional.
- Criar ou atualizar os testes correspondentes.
- Executar os gates de qualidade aplicáveis.
- Informar o que foi concluído, o que permanece pendente e qualquer desvio da especificação.
1.1 Regras de comportamento do agente
O agente:
- DEVE priorizar a solução mais simples que satisfaça os critérios de aceite.
- DEVE reutilizar recursos nativos de Laravel, Filament e Livewire antes de adicionar dependências.
- DEVE manter Filament Resources e componentes Livewire finos.
- DEVE colocar regras de negócio em classes testáveis de domínio ou aplicação.
- DEVE adicionar testes antes de marcar um requisito como concluído.
- DEVE preservar compatibilidade com PostgreSQL e com o contêiner de produção.
- DEVE trabalhar em uma fase do backlog por vez, salvo instrução explícita.
- NÃO DEVE criar funcionalidades listadas em “Fora do MVP”.
- NÃO DEVE introduzir microserviços, uma SPA separada, API pública, Redis ou mensageria externa.
- NÃO DEVE criar abstrações genéricas sem ao menos dois usos concretos.
- NÃO DEVE criar
RepositoryInterface,BaseService,BaseActionou “helpers” genéricos por antecipação. - NÃO DEVE colocar regras financeiras diretamente em views, Resources, Models observers ou callbacks de formulário.
- NÃO DEVE usar
floatpara dinheiro. - NÃO DEVE persistir status derivados que possam ser calculados corretamente a partir dos dados fonte.
- NÃO DEVE atualizar snapshots visuais apenas para fazer o CI passar sem revisar o diff.
1.2 Entrega incremental
Cada fatia vertical deve, quando aplicável, incluir:
- migration;
- enum ou regra de domínio;
- model e relacionamentos;
- Action/Query;
- Policy;
- interface Filament ou Livewire;
- factories e seed mínimo;
- testes unitários e/ou feature;
- teste browser quando a jornada for crítica;
- documentação curta de qualquer decisão não óbvia.
2. Visão do produto
O MVP é uma aplicação única para uma assessora de eventos ou uma equipe pequena. O produto possui duas superfícies integradas:
- Site público premium, usado para apresentar a marca, construir confiança e converter visitantes em leads.
- Área interna operacional, usada para gerenciar leads, eventos, tarefas, fornecedores, orçamento, pagamentos manuais, documentos e conteúdo do site.
2.1 Hipótese de produto
Uma assessora adotará o sistema quando ele:
- ajudar a vender melhor;
- reduzir planilhas e informações dispersas;
- mostrar claramente o que precisa de atenção;
- organizar o evento sem exigir uma mudança radical no fluxo de trabalho;
- transmitir profissionalismo aos possíveis clientes.
2.2 Resultados que o MVP precisa provar
- O site converte visitantes em leads qualificados.
- A assessora acompanha o pipeline sem planilhas externas.
- Um lead conquistado é convertido em evento sem redigitação.
- A assessora gerencia tarefas, fornecedores, orçamento e pagamentos manuais.
- O dashboard destaca pendências reais do dia.
- O site é visualmente forte, rápido, acessível e responsivo.
- A aplicação pode ser implantada e atualizada com segurança por pipeline automatizado.
2.3 Métricas iniciais
| Dimensão | Métrica | Meta inicial |
|---|---|---|
| Aquisição | Conclusão do formulário de briefing | Medir baseline e melhorar por iteração |
| Comercial | Leads ativos sem próxima ação | 0 ao fim de cada dia útil |
| Operação | Tarefas vencidas sem responsável | 0 |
| Financeiro | Itens de orçamento sem valor ou status | Menos de 5% por evento ativo |
| Qualidade | Jornadas E2E críticas passando | 100% antes de deploy |
| Visual | Snapshots aprovados | 100% |
| Confiabilidade | Erros não tratados | Alerta imediato e tendência decrescente |
3. Personas e acesso
3.1 Visitante
Objetivo: entender os serviços, confiar na assessora, ver eventos reais e solicitar contato.
Permissões:
- acessar apenas as rotas públicas;
- enviar o formulário de briefing;
- não possui conta nem área autenticada.
3.2 Assessora administradora
Objetivo: gerenciar toda a operação e o conteúdo do site.
Permissões:
- acesso integral ao Filament;
- gerenciar usuários internos;
- gerenciar configurações e conteúdos públicos;
- criar, atualizar e excluir entidades operacionais conforme Policies;
- visualizar auditoria.
3.3 Assistente
Objetivo: atualizar a rotina operacional dos eventos.
Permissões:
- acessar leads, eventos, tarefas, fornecedores, orçamento, pagamentos e documentos;
- não gerenciar usuários;
- não alterar configurações globais do site;
- não acessar ou apagar auditoria;
- não executar exclusões críticas sem autorização.
3.4 Papéis
Usar enum simples:
enum UserRole: string
{
case Admin = 'admin';
case Assistant = 'assistant';
}
Não instalar sistema de permissões granular no MVP.
4. Escopo
Recorte vigente do lançamento (ADR-016). O escopo aprovado para o lançamento de 31/08/2026 é o site institucional: Fases 0 e 1. As Fases 2 a 5 — CRM de leads, conversão de lead em evento, eventos, tarefas, fornecedores, orçamento, pagamentos manuais, documentos, dashboard orientado a exceções e auditoria — permanecem especificadas neste documento mas ficam adiadas, sem data.
A §4.1 abaixo descreve o produto completo, não o recorte do lançamento. Os itens marcados como adiados estão fora do que se constrói agora. Ver §18 para a divisão por fase e §23 para as condições de conclusão de cada recorte.
4.1 Incluído no MVP
No recorte do lançamento (Fases 0–1):
- site público;
- CMS interno do site;
- formulário de briefing;
- usuários internos e papéis simples;
- SEO básico;
- acessibilidade e testes visuais;
- CI/CD e deploy em contêiner com FrankenPHP.
Adiados para depois do lançamento (Fases 2–5, ver ADR-016):
- CRM de leads;
- conversão de lead em evento;
- cadastro e visão consolidada de eventos;
- checklist e tarefas;
- diretório e vínculo de fornecedores;
- orçamento por evento;
- pagamentos inseridos manualmente;
- documentos vinculados a leads e eventos;
- dashboard orientado a exceções;
- notificações internas e por e-mail para novos leads;
- auditoria de ações críticas.
Adiado não é o mesmo que fora do MVP: os itens acima seguem especificados neste documento e continuam sendo o produto pretendido. A §4.2 lista o que NÃO DEVE ser implementado em nenhum momento.
4.2 Fora do MVP
Os itens abaixo NÃO DEVEM ser implementados:
- portal ou login para cliente final;
- convites digitais;
- RSVP;
- gestão de convidados;
- check-in ou QR Code;
- mapa de mesas;
- pagamento online;
- Pix, boleto, cartão ou gateway de pagamento;
- conciliação bancária;
- emissão fiscal;
- assinatura eletrônica;
- geração jurídica de contratos;
- cobrança automática;
- integração oficial com WhatsApp;
- chat interno;
- comunicação omnichannel;
- multi-tenancy;
- SaaS para múltiplas assessorias;
- aplicativo nativo;
- PWA offline avançada;
- push notifications;
- marketplace de fornecedores;
- avaliações públicas de fornecedores;
- IA generativa;
- transcrição ou resumo automático de reuniões;
- leitura automática de contratos;
- microserviços;
- event sourcing;
- CQRS arquitetural;
- Kafka, RabbitMQ, SQS ou Redis obrigatório;
- mecanismo externo de busca;
- API pública;
- editor visual de páginas semelhante a page builder;
- Kanban com drag-and-drop para leads;
- editor de templates de checklist.
4.3 Regra de mudança de escopo
Uma funcionalidade fora do MVP só poderá entrar quando:
- desbloquear uma jornada já definida; ou
- resolver um problema observado em uso real; e
- tiver critério de aceite e impacto técnico documentados.
“Pode ser útil no futuro” não é justificativa suficiente.
5. Arquitetura de informação
5.1 Rotas públicas
| Método | Rota | Nome sugerido | Finalidade |
|---|---|---|---|
| GET | / |
home |
Home editorial |
| GET | /servicos |
services.index |
Lista de serviços publicados |
| GET | /portfolio |
portfolio.index |
Lista de casos publicados |
| GET | /portfolio/{slug} |
portfolio.show |
Detalhe de caso |
| GET | /sobre |
about |
História, método e credenciais |
| GET | /contato |
contact |
Briefing de contato |
| GET | /privacidade |
privacy |
Política de privacidade |
| GET | /sitemap.xml |
sitemap |
Sitemap público |
| GET | /robots.txt |
robots |
Política de crawling |
| GET | /up |
health |
Healthcheck sem autenticação |
5.2 Painel interno
Prefixo: /admin.
Navegação:
Dashboard
Comercial
├── Leads
└── Atividades
Eventos
├── Eventos
├── Tarefas
├── Fornecedores
├── Orçamento e pagamentos
└── Documentos
Conteúdo do site
├── Serviços
├── Portfólio
├── Depoimentos
└── Configurações
Administração
├── Usuários
└── Auditoria
5.3 Páginas customizadas obrigatórias
- Dashboard:
Filament Pagecustomizada com widgets orientados a exceção. - Detalhe do evento: página customizada do Resource com resumo operacional.
- Briefing público: Blade + Controller (
POST /contato), ver §11.2. - Home: Blade com componentes de design reutilizáveis.
5.4 Decisões de UX YAGNI
- Pipeline de leads será tabela com filtros e ações rápidas.
- Não criar Kanban no MVP.
- Conteúdo da home terá estrutura fixa; textos e itens serão editáveis.
- Não criar page builder genérico.
- Ações destrutivas precisam de confirmação.
- O dashboard deve priorizar pendências, não gráficos decorativos.
6. Design e experiência do site público
O site público é requisito funcional, não apenas acabamento visual.
6.1 Princípios visuais
- aparência editorial e premium;
- fotografia grande e bem tratada;
- tipografia com hierarquia clara;
- espaçamento generoso;
- poucos elementos simultâneos;
- transições sutis;
- contraste acessível;
- mobile-first;
- CTAs claros;
- sem aparência de template administrativo.
6.2 Estrutura da home
A home DEVE conter, nesta ordem aproximada:
- header e navegação;
- hero com proposta de valor e CTA;
- manifesto da marca;
- resumo dos serviços em destaque;
- casos selecionados do portfólio;
- método de trabalho (4 passos);
- depoimentos;
- posicionamento/perfil;
- CTA final para briefing;
- footer com contato, redes e links legais.
A ordem pode variar apenas se a revisão de UX justificar a mudança.
6.3 Design tokens mínimos
Centralizar tokens de:
- famílias tipográficas;
- escala de fonte;
- espaçamentos;
- raio de borda;
- largura de container;
- cores de fundo, texto, borda, destaque e estados;
- sombras;
- duração e easing de transições.
Não espalhar valores visuais arbitrários por componentes.
O MVP adota o sistema de design Heritage Editorial (ver DESIGN.md e ADR-013):
- tipografia serifada auto-hospedada (EB Garamond) com escala de display a label;
- paleta papel/oliva/sálvia/tinta com superfícies tonais; hierarquia sem sombras de card;
- raio de borda zero para superfícies interativas e de conteúdo;
- largura de container 1120px e ritmo de espaçamento de 8px;
prefers-reduced-motionrespeitado;- contraste WCAG AA (tinta sobre papel e oliva sobre papel).
6.4 Requisitos de mídia
- Imagens públicas DEVERÃO possuir texto alternativo.
- A aplicação DEVERÁ validar extensão, MIME e tamanho.
- A aplicação DEVERÁ gerar ou servir variantes responsivas.
- Imagens fora da primeira dobra DEVERÃO usar lazy loading.
- Dimensões DEVERÃO ser reservadas para evitar layout shift.
- Não armazenar blobs de imagem no PostgreSQL.
- Não depender do disco efêmero do contêiner em produção.
- O logotipo da marca DEVE possuir texto alternativo e variantes claro/escuro;
site_settings.logo_pathsobrescreve o asset padrão quando preenchido.
6.5 Acessibilidade
- navegação completa por teclado;
- foco visível;
- labels associados aos campos;
- mensagens de erro ligadas ao campo correspondente;
- landmarks semânticos;
- um único
h1por página; - ordem coerente de headings;
- contraste compatível com WCAG AA;
- suporte a
prefers-reduced-motion; - nenhuma issue automatizada crítica ou séria nas jornadas cobertas.
6.6 Performance e SEO
Metas:
| Métrica | Meta |
|---|---|
| LCP | ≤ 2,5 s nas páginas principais |
| CLS | ≤ 0,1 |
| INP | ≤ 200 ms |
| Erros JS no console | 0 nas jornadas críticas |
SEO obrigatório:
- title e meta description por página;
- canonical;
- Open Graph;
- sitemap;
- robots;
- slug legível;
- conteúdo publicado somente quando
published_atestiver preenchido; - dados estruturados básicos quando aplicáveis;
- páginas de portfólio indexáveis.
7. Requisitos funcionais
7.1 Site público e CMS
WEB-01 — Home editorial
Prioridade: P0
A home deve apresentar proposta, serviços, casos, método, depoimentos e CTA.
Aceite:
Given que existem serviços, casos e depoimentos publicados
When um visitante acessa a home
Then o conteúdo publicado é exibido na ordem configurada
And a página funciona em viewport desktop e mobile
And não existem erros JavaScript no console
And o CTA leva ao briefing
WEB-02 — Serviços
Prioridade: P0
Campos mínimos:
- título;
- slug;
- resumo;
- descrição;
- imagem de capa opcional;
- texto alternativo;
- ordem;
- destaque;
published_at.
Regras:
- slug deve ser único;
- serviço não publicado não aparece no site;
- exclusão deve exigir confirmação;
- admin pode gerenciar; assistant não pode.
WEB-03 — Portfólio
Prioridade: P0
Campos mínimos:
- título;
- slug;
- resumo;
- tipo de evento;
- cidade/local opcional;
- data do evento opcional;
- desafio;
- solução;
- resultado opcional;
- imagem de capa;
- galeria ordenada;
- destaque;
published_at;- metadados SEO opcionais.
Aceite:
Given um caso salvo como rascunho
When a assessora preenche os campos obrigatórios e publica o caso
Then a rota pública pelo slug passa a responder 200
And o caso aparece na listagem pública
And as imagens possuem dimensões reservadas e textos alternativos
WEB-04 — Depoimentos
Prioridade: P0
Campos:
- texto;
- nome da pessoa;
- contexto ou tipo de evento opcional;
- fotografia opcional;
- ordem;
- destaque;
published_at.
WEB-05 — Briefing de contato
Prioridade: P0
Campos públicos:
- nome completo;
- e-mail;
- telefone/WhatsApp;
- tipo de evento;
- data ou período desejado opcional;
- cidade;
- número estimado de convidados opcional;
- serviço de interesse opcional;
- mensagem/principal preocupação;
- origem de marketing capturada quando disponível;
- aceite do aviso de privacidade.
Regras:
- validar no servidor;
- usar honeypot e rate limiting;
- impedir duplo envio acidental;
- enviar e-mail de confirmação quando o serviço de e-mail estiver configurado;
- exibir sucesso sem revelar dados internos.
Estado atual (Fases 0–1): o formulário usa Blade + Controller e envia apenas e-mails informativos (para a assessoria e confirmação ao visitante), sem criar Lead. A criação de Lead (status
new, origemwebsite), a notificação aos administradores e o registro de aceite de privacidade entram na Fase 2, quando o formulário passa a criar o Lead viaCaptureWebsiteLead. A falha de e-mail não pode apagar dados já criados.
Aceite:
Given um visitante no formulário de briefing
When ele envia dados válidos uma única vez
Then um lead é criado com status Novo
And a tela mostra confirmação
And a assessora recebe notificação interna
And uma nova submissão causada por duplo clique não cria lead duplicado
WEB-06 — Configurações do site
Prioridade: P0
Singleton gerenciável apenas por admin:
- nome da marca;
- texto e CTA do hero;
- resumo institucional;
- e-mail;
- telefone;
- endereço/cidade opcional;
- links sociais;
- title padrão;
- description padrão;
- imagem Open Graph padrão;
- scripts de analytics opcionais, desabilitados por padrão.
Não criar sistema genérico de chave/valor se um singleton tipado resolver.
WEB-07 — Páginas institucionais
Prioridade: P1
- Sobre;
- Política de privacidade;
- página 404 com identidade visual;
- página 500 segura e sem stack trace em produção.
7.2 Leads e CRM
CRM-01 — Cadastro de lead
Prioridade: P0
Lead pode ser criado:
- automaticamente pelo briefing;
- manualmente no Filament.
Campos:
- nome;
- e-mail;
- telefone;
- tipo de evento;
- data estimada;
- cidade;
- convidados estimados;
- mensagem;
- origem;
- status;
- próxima ação em;
- tipo da próxima ação;
- observação da próxima ação;
- motivo da perda;
converted_event_idou relacionamento equivalente;- timestamps.
CRM-02 — Pipeline
Prioridade: P0
Estados permitidos:
enum LeadStatus: string
{
case New = 'new';
case Contacted = 'contacted';
case Meeting = 'meeting';
case Proposal = 'proposal';
case Negotiation = 'negotiation';
case Won = 'won';
case Lost = 'lost';
}
Transições permitidas no MVP:
- qualquer estado ativo pode avançar ou retroceder para outro estado ativo;
wonsomente por conversão bem-sucedida ou ação administrativa explícita;lostexige motivo;- lead convertido não pode voltar para estado ativo sem operação manual administrativa documentada;
- lead perdido pode ser reaberto por admin, limpando motivo de perda e criando auditoria.
CRM-03 — Próxima ação
Prioridade: P0
- lead ativo pode possuir data, tipo e observação;
- lead ativo sem próxima ação deve aparecer no dashboard;
- próxima ação passada deve aparecer como atrasada;
- lead
wonoulostnão precisa de próxima ação.
CRM-04 — Histórico
Prioridade: P0
Registrar atividades:
- nota manual;
- alteração de status;
- alteração de próxima ação;
- criação pelo site;
- conversão em evento;
- marcação como perdido ou reaberto.
O histórico deve ser cronológico e imutável pela interface comum. Admin pode remover somente em operação excepcional auditada.
CRM-05 — Busca e filtros
Prioridade: P0
Filtrar ou buscar por:
- nome;
- e-mail;
- telefone;
- status;
- origem;
- tipo de evento;
- data estimada;
- próxima ação;
- leads sem próxima ação.
CRM-06 — Conversão em evento
Prioridade: P0
A conversão:
- DEVE ser idempotente;
- DEVE executar em transação;
- DEVE criar somente um evento;
- DEVE copiar dados relevantes do lead;
- DEVE vincular lead e evento;
- DEVE criar checklist padrão;
- DEVE alterar lead para
won; - DEVE criar atividade e auditoria;
- DEVE rejeitar uma segunda conversão.
Aceite:
Given um lead ainda não convertido
When a assessora executa Converter em evento
Then um único evento é criado
And o checklist padrão é criado
And o lead é marcado como Conquistado
And uma segunda execução não cria outro evento
CRM-07 — Perda do lead
Prioridade: P0
- motivo é obrigatório;
- próxima ação deve ser removida;
- mudança deve aparecer no histórico;
- motivo não é visível em área pública.
7.3 Eventos
EVT-01 — Cadastro de evento
Prioridade: P0
Campos:
- título;
- tipo;
- lead de origem opcional;
- nome do cliente;
- e-mail do cliente;
- telefone do cliente;
- data e hora de início opcionais durante planejamento;
- data e hora de fim opcionais;
- local;
- cidade;
- status;
- orçamento-alvo em centavos opcional;
- resumo;
- observações internas;
- responsável interno opcional.
EVT-02 — Estados do evento
enum EventStatus: string
{
case Planning = 'planning';
case Confirmed = 'confirmed';
case InProgress = 'in_progress';
case Completed = 'completed';
case Cancelled = 'cancelled';
}
Regras:
- novo evento começa em
planning; confirmedexige data de início;in_progressexige data de início;completedregistracompleted_at;cancelledregistra motivo opcional e auditoria;- evento cancelado não aparece entre próximos eventos ativos;
- reabertura de evento concluído ou cancelado exige admin e auditoria.
EVT-03 — Visão consolidada
Prioridade: P0
A página do evento deve mostrar:
- resumo e status;
- cliente e contatos;
- dias restantes;
- próximas tarefas;
- tarefas vencidas;
- fornecedores vinculados;
- totais financeiros;
- próximos pagamentos;
- documentos recentes;
- atalhos para criar tarefa, vínculo de fornecedor, item de orçamento, pagamento e documento.
EVT-04 — Listagem e filtros
Prioridade: P0
Filtros:
- status;
- tipo;
- período;
- responsável;
- eventos nos próximos 7, 30 e 90 dias;
- eventos sem data;
- busca por título, cliente, cidade ou local.
7.4 Tarefas
TSK-01 — Checklist do evento
Prioridade: P0
Campos:
- evento;
- título;
- descrição opcional;
- responsável opcional;
- prazo opcional;
- prioridade;
- status;
- posição/ordem;
completed_at;completed_by.
Enums:
enum TaskPriority: string
{
case Low = 'low';
case Medium = 'medium';
case High = 'high';
case Critical = 'critical';
}
enum TaskStatus: string
{
case Pending = 'pending';
case InProgress = 'in_progress';
case Completed = 'completed';
}
TSK-02 — Regras de conclusão
- concluir tarefa preenche
completed_atecompleted_by; - reabrir tarefa limpa ambos;
- tarefa concluída não é considerada vencida;
- tarefa pendente com prazo anterior a hoje é vencida;
- tarefa sem responsável é explicitamente sinalizada;
- exclusão exige confirmação.
TSK-03 — Checklist padrão
Prioridade: P0
O MVP deve possuir um checklist padrão definido em seed ou configuração de código versionada.
- checklist deve ser criado na conversão de lead;
- tarefas podem possuir prazo relativo à data do evento quando esta existir;
- se a data do evento ainda não existir, tarefas relativas permanecem sem prazo;
- ao definir posteriormente a data do evento, a aplicação pode calcular prazos ausentes uma única vez;
- editor de templates fica fora do MVP.
Checklist inicial sugerido:
- confirmar briefing e escopo;
- definir data e local;
- definir orçamento-alvo;
- mapear fornecedores essenciais;
- confirmar fornecedores selecionados;
- revisar cronograma geral;
- realizar reunião final;
- confirmar contatos operacionais;
- revisar pagamentos pendentes;
- concluir evento e registrar aprendizados.
TSK-04 — Visão global de tarefas
Prioridade: P1
Listar tarefas de todos os eventos com filtros por:
- responsável;
- status;
- prioridade;
- evento;
- vencidas;
- hoje;
- próximos 7 dias;
- sem responsável.
7.5 Fornecedores
VEN-01 — Diretório
Prioridade: P0
Campos:
- nome;
- categoria;
- nome do contato opcional;
- e-mail opcional;
- telefone opcional;
- cidade/região;
- site ou rede social opcional;
- observações internas;
- ativo/inativo.
Categorias devem usar enum ou tabela fixa simples. Não criar CRUD de categorias no MVP.
Categorias iniciais:
- espaço;
- buffet;
- bebidas;
- decoração;
- fotografia;
- filmagem;
- música/DJ;
- som e iluminação;
- mobiliário;
- celebrante/cerimonial;
- segurança;
- limpeza;
- transporte;
- hospedagem;
- gráfica/comunicação;
- outros.
VEN-02 — Vínculo ao evento
Prioridade: P0
Campos:
- evento;
- fornecedor;
- status;
- contato específico opcional;
- observações;
- valor de referência opcional em centavos.
Status:
enum EventVendorStatus: string
{
case Quoted = 'quoted';
case Selected = 'selected';
case Contracted = 'contracted';
case Discarded = 'discarded';
}
Um fornecedor não deve ser vinculado duas vezes ao mesmo evento na mesma categoria sem justificativa explícita. Usar constraint adequada conforme o modelo final.
7.6 Orçamento e pagamentos manuais
FIN-01 — Item de orçamento
Prioridade: P0
Campos:
- evento;
- categoria;
- descrição;
- fornecedor opcional;
- valor planejado em centavos opcional;
- valor acordado em centavos opcional;
- status;
- observações;
- posição/ordem.
Status:
enum BudgetItemStatus: string
{
case Planned = 'planned';
case Quoted = 'quoted';
case Approved = 'approved';
case Contracted = 'contracted';
case Cancelled = 'cancelled';
}
FIN-02 — Dinheiro
Regras obrigatórias:
- todos os valores monetários são BRL;
- armazenar valores em centavos com
BIGINT; - nunca usar
floatem domínio, Action ou teste; - formatar na UI como moeda brasileira;
- entradas de formulário devem ser convertidas de string decimal para centavos;
- valores não podem ser negativos;
- não implementar conversão de moeda.
Criar Value Object pequeno somente se ele reduzir duplicação e bugs reais:
final readonly class Money
{
public function __construct(public int $cents) {}
}
FIN-03 — Pagamento manual
Prioridade: P0
Campos:
- evento;
- item de orçamento opcional;
- descrição;
- valor em centavos;
- vencimento;
- data de pagamento opcional;
- método opcional;
- comprovante opcional;
- observações;
- criado por;
- atualizado por.
Métodos permitidos:
- Pix;
- transferência;
- dinheiro;
- cartão;
- boleto;
- outro.
O método é apenas informativo. Nenhum pagamento é processado pelo sistema.
FIN-04 — Status derivado do pagamento
Não persistir status quando puder ser derivado:
paid_at != null => paid
paid_at == null e due_date < hoje => overdue
paid_at == null e due_date >= hoje => pending
“Vencendo em breve” é uma apresentação calculada para vencimentos entre hoje e hoje + 7 dias.
FIN-05 — Totais do evento
Calcular:
- planejado: soma de
planned_amount_centsnão cancelados; - acordado: soma de
agreed_amount_centsnão cancelados; - pago: soma de pagamentos com
paid_at; - pendente: soma de pagamentos sem
paid_at; - vencido: soma de pagamentos sem
paid_ate com vencimento passado; - saldo do acordado:
max(acordado - pago, 0).
Não criar tabela de totais materializados no MVP. Usar Query dedicada e índices adequados.
FIN-06 — Consistência financeira
- pagamento não pode ter valor zero ou negativo;
- data de pagamento pode ser anterior, igual ou posterior ao vencimento;
- comprovante é opcional;
- alteração e exclusão de pagamento geram auditoria;
- exclusão deve ser restrita a admin ou possuir confirmação reforçada;
- a soma de pagamentos pode superar o valor acordado; a UI deve sinalizar, não bloquear, pois ajustes reais podem existir;
- nenhum módulo contábil ou fiscal será criado.
Aceite:
Given um evento com item acordado de R$ 3.000,00
And dois pagamentos manuais de R$ 1.000,00 e R$ 2.000,00
When ambos possuem data de pagamento
Then o total pago é R$ 3.000,00
And o saldo acordado é R$ 0,00
And nenhum pagamento aparece como pendente ou vencido
7.7 Documentos
DOC-01 — Upload vinculado
Prioridade: P1
Documentos podem pertencer a:
- lead; ou
- evento.
Campos:
- nome exibido;
- path privado;
- MIME;
- tamanho;
- categoria;
- observação;
- usuário que enviou;
- timestamps.
Regras:
- arquivo deve ser privado por padrão;
- download requer autenticação e Policy;
- validar allowlist de tipos;
- limite inicial configurável, padrão 10 MB;
- nome original não deve determinar o path físico;
- não armazenar arquivos no banco;
- exclusão gera auditoria.
Categorias iniciais:
- briefing;
- proposta;
- contrato;
- orçamento;
- comprovante;
- referência visual;
- cronograma;
- outro.
7.8 Dashboard e notificações
DASH-01 — Dashboard orientado a atenção
Prioridade: P0
O dashboard deve responder: “O que precisa da minha atenção hoje?”
Widgets obrigatórios:
- leads novos;
- leads ativos sem próxima ação;
- próximas ações vencidas;
- eventos nos próximos 7, 30 e 90 dias;
- tarefas vencidas;
- tarefas de hoje;
- tarefas sem responsável;
- pagamentos vencidos;
- pagamentos vencendo em até 7 dias;
- atalhos para novo lead, evento, fornecedor e caso de portfólio.
Cada item deve ser acionável e levar ao registro correspondente.
DASH-02 — Notificação de novo lead
Prioridade: P0
- criar database notification para admins;
- enviar e-mail assíncrono quando configurado;
- usar database queue;
- falha de notificação não pode reverter a criação do lead;
- job deve ser idempotente quando possível.
DASH-03 — Lembrete diário
Prioridade: P1
Scheduler diário pode criar notificação resumida com:
- próximas ações vencidas;
- tarefas vencidas;
- pagamentos vencidos.
Não enviar resumo se não houver pendências.
7.9 Administração e auditoria
ADM-01 — Usuários internos
Prioridade: P0
- admin cria e desativa usuários;
- e-mail único;
- papel
adminouassistant; - usuário inativo não autentica;
- reset de senha seguro;
- acesso ao Filament restrito explicitamente.
ADM-02 — Auditoria
Prioridade: P0
Ações auditáveis:
- conversão de lead;
- marcação de lead perdido ou reaberto;
- mudança financeira;
- exclusão de pagamento;
- exclusão de documento;
- publicação ou despublicação de conteúdo;
- exclusão de entidade principal;
- mudança de papel ou ativação de usuário;
- reabertura de evento concluído/cancelado.
Campos mínimos:
- usuário opcional;
- ação;
- tipo da entidade;
- ID da entidade;
- metadados JSON sem dados sensíveis desnecessários;
- IP opcional;
- request ID;
- timestamp.
Auditoria não precisa ser um event sourcing. Registrar apenas operações críticas.
8. Modelo de domínio e banco de dados
8.1 Módulos
| Módulo | Responsabilidade |
|---|---|
| Marketing | Conteúdo público e conversão |
| CRM | Leads, atividades e conversão |
| Events | Eventos, tarefas e documentos |
| Vendors | Fornecedores e vínculos |
| Finance | Orçamento e pagamentos manuais |
| Identity | Usuários, acesso e auditoria |
8.2 Tabelas obrigatórias
users
idbigint PK;namevarchar;emailvarchar unique;email_verified_attimestamp nullable;passwordvarchar;rolevarchar indexed;is_activeboolean default true indexed;- remember token;
- timestamps.
site_settings
Singleton:
idbigint PK;brand_name;logo_pathnullable;logo_altnullable;hero_eyebrownullable;hero_title;hero_subtitle;hero_cta_label;hero_cta_secondary_labelnullable;hero_notenullable;manifesto_title;manifesto_lead;manifesto_body;method_stepsjsonb (4 passos tipados);principlesjsonb (lista tipada);about_summarynullable;email;phone;citynullable;social_linksjsonb;default_meta_title;default_meta_description;default_og_image_pathnullable;default_og_image_altnullable;analytics_enabledboolean default false;- timestamps.
services
id;title;slugunique;summary;descriptiontext;cover_image_pathnullable;cover_image_altnullable;sort_orderinteger indexed;is_featuredboolean indexed;published_attimestamp nullable indexed;- timestamps;
- soft delete opcional somente se recuperação for necessária.
portfolio_cases
id;title;slugunique;summary;event_type;citynullable;venuenullable;event_datedate nullable;challengetext;solutiontext;resulttext nullable;cover_image_path;cover_image_alt;is_featuredboolean indexed;sort_orderinteger indexed;published_attimestamp nullable indexed;meta_titlenullable;meta_descriptionnullable;- timestamps.
portfolio_images
id;portfolio_case_idFK cascade;path;alt_text;captionnullable;sort_orderinteger;- timestamps;
- index composto por
portfolio_case_id, sort_order.
testimonials
id;quotetext;author_name;contextnullable;photo_pathnullable;photo_altnullable;sort_orderinteger;is_featuredboolean indexed;published_attimestamp nullable indexed;- timestamps.
leads
id;name;emailnullable indexed;phonenullable indexed;event_type;estimated_event_datedate nullable indexed;citynullable;estimated_guestsinteger nullable;messagetext nullable;sourcevarchar indexed;statusvarchar indexed;next_action_attimestamp nullable indexed;next_action_typenullable;next_action_notestext nullable;lost_reasontext nullable;converted_event_idnullable unique;privacy_notice_accepted_attimestamp nullable;marketing_metadatajsonb nullable;- timestamps;
- soft deletes recomendados para recuperação operacional.
lead_activities
id;lead_idFK cascade;user_idFK nullable set null;typevarchar indexed;descriptiontext;metadatajsonb nullable;created_at;- sem
updated_atquando possível, pois atividade é append-only.
events
id;lead_idFK nullable unique;title;event_type;client_name;client_emailnullable;client_phonenullable;starts_attimestamp nullable indexed;ends_attimestamp nullable;venuenullable;citynullable;statusvarchar indexed;target_budget_centsbigint nullable;summarytext nullable;internal_notestext nullable;owner_user_idFK nullable indexed;completed_attimestamp nullable;- timestamps;
- soft deletes recomendados.
event_tasks
id;event_idFK cascade indexed;title;descriptiontext nullable;assigned_user_idFK nullable indexed;due_attimestamp nullable indexed;priorityvarchar indexed;statusvarchar indexed;sort_orderinteger;relative_due_daysinteger nullable;completed_attimestamp nullable;completed_by_user_idFK nullable;- timestamps;
- index composto por
event_id, status, due_at.
vendors
id;nameindexed;categoryvarchar indexed;contact_namenullable;emailnullable;phonenullable;city_regionnullable indexed;website_urlnullable;notestext nullable;is_activeboolean default true indexed;- timestamps;
- soft deletes opcionais.
event_vendors
id;event_idFK cascade indexed;vendor_idFK restrict indexed;categoryvarchar indexed;statusvarchar indexed;contact_overridenullable;reference_amount_centsbigint nullable;notestext nullable;- timestamps;
- índice composto por
event_id, category, status.
budget_items
id;event_idFK cascade indexed;vendor_idFK nullable set null;categoryvarchar indexed;description;planned_amount_centsbigint nullable;agreed_amount_centsbigint nullable;statusvarchar indexed;notestext nullable;sort_orderinteger;- timestamps;
- checks de valores não negativos quando suportado.
payments
id;event_idFK cascade indexed;budget_item_idFK nullable set null indexed;description;amount_centsbigint;due_datedate indexed;paid_attimestamp nullable indexed;methodvarchar nullable;proof_pathnullable;notestext nullable;created_by_user_idFK;updated_by_user_idFK;- timestamps;
- check
amount_cents > 0.
documents
id;lead_idFK nullable cascade;event_idFK nullable cascade;display_name;path;mime_type;size_bytesbigint;categoryvarchar indexed;notestext nullable;uploaded_by_user_idFK;- timestamps;
- constraint: exatamente um entre
lead_ideevent_iddeve ser preenchido.
audit_logs
id;user_idFK nullable set null indexed;actionvarchar indexed;auditable_typevarchar indexed;auditable_idbigint indexed;metadatajsonb nullable;ip_addressnullable;request_idnullable indexed;created_at.
Infraestrutura Laravel
Usar tabelas padrão conforme recursos habilitados:
- notifications;
- jobs;
- job_batches, somente se necessário;
- failed_jobs;
- password reset tokens;
- sessions, caso sessão em banco seja escolhida.
8.3 Integridade e transações
Usar transação em:
- conversão de lead em evento;
- criação de evento com checklist;
- alterações financeiras que gerem múltiplas gravações;
- exclusões críticas com auditoria;
- operações que atualizam estado e histórico juntos.
Constraints de banco devem proteger:
- e-mail único de usuário;
- slug único;
- lead convertido uma única vez;
- evento originado de um único lead;
- valores financeiros válidos;
- relacionamentos obrigatórios;
- documento pertencendo a um único owner lógico.
9. Arquitetura técnica
9.1 Stack
| Camada | Tecnologia |
|---|---|
| Runtime | PHP com versão minor fixada no Docker |
| Framework | Laravel 13 |
| Admin | Filament 5 |
| UI pública | Blade + Tailwind + JS vanilla progressivo (sem framework reativo; Livewire 4 confinado ao Filament — ver ADR-015 e §22) |
| Banco | PostgreSQL |
| Servidor | FrankenPHP + Caddy |
| Assets | Vite |
| Testes | Pest 4 + Pest Browser/Playwright |
| Arquivos | Laravel Filesystem + Cloudflare R2 (S3-compatible) em produção |
| Fila | Database queue |
| Scheduler | Laravel Scheduler em processo separado |
Caso o projeto seja criado com versões posteriores, o agente deve manter compatibilidade entre as versões instaladas e registrar a decisão. Não fazer upgrade de major version no meio da implementação sem ADR.
9.2 Estilo arquitetural
Monólito modular com dependências orientadas:
Interface (Filament / Livewire / HTTP)
↓
Application (Actions / Queries / Data)
↓
Domain (Enums / Value Objects / Rules)
↓
Infrastructure (Eloquent / Mail / Filesystem / Queue)
9.3 Regras arquiteturais
- Domain NÃO DEVE depender de Filament ou Livewire.
- Filament e Livewire chamam Actions e Queries.
- Eloquent Models podem existir em
app/Modelse ser usados por Actions/Queries. - Não criar repositórios genéricos.
- Queries de leitura podem usar Eloquent diretamente.
- Actions devem representar casos de uso, não CRUD trivial.
- Enums representam estados estáveis.
- Value Objects somente para conceitos com regra real, como dinheiro.
- Eventos Laravel somente para efeitos colaterais claros.
- Policies controlam autorização.
- Observers devem ser evitados para regras críticas por esconderem fluxo.
- Soft delete deve ser aplicado seletivamente.
- Todo arquivo PHP próprio deve usar
declare(strict_types=1);quando compatível.
9.4 Estrutura sugerida
app/
├── Application/
│ ├── Actions/
│ │ ├── CRM/
│ │ ├── Events/
│ │ ├── Finance/
│ │ ├── Marketing/
│ │ └── Vendors/
│ ├── Data/
│ └── Queries/
├── Domain/
│ ├── CRM/
│ ├── Events/
│ ├── Finance/
│ ├── Marketing/
│ ├── Vendors/
│ └── Identity/
├── Filament/
│ ├── Pages/
│ ├── Resources/
│ └── Widgets/
├── Livewire/
│ └── PublicSite/
├── Models/
├── Notifications/
├── Policies/
└── Support/
resources/views/
├── components/
├── layouts/
├── livewire/public-site/
└── pages/
tests/
├── Architecture/
├── Browser/
├── Feature/
└── Unit/
Não criar diretórios vazios antecipadamente. Criar quando o primeiro uso existir.
9.5 Actions mínimas esperadas
CaptureWebsiteLead;CreateManualLeadsomente se CRUD padrão não for suficiente;UpdateLeadStatus;ScheduleLeadNextAction;MarkLeadAsLost;ReopenLead;ConvertLeadToEvent;CreateDefaultEventChecklist;CompleteEventTask;ReopenEventTask;RecordManualPayment;UpdateManualPayment;DeleteManualPayment;PublishPortfolioCase;UnpublishPortfolioCase;StorePrivateDocument;WriteAuditLogou serviço equivalente, sem transformar auditoria em event sourcing.
Não criar Action para todo create/update se o Filament Resource puder salvar de forma segura sem regra adicional.
9.6 Queries mínimas esperadas
GetDashboardAttentionItemsou queries menores por widget;GetEventFinancialSummary;GetUpcomingEvents;GetOverdueTasks;GetLeadsWithoutNextAction;GetOverduePayments;GetDueSoonPayments.
9.7 Fluxos técnicos
Briefing
Livewire valida
→ CaptureWebsiteLead
→ Lead salvo em transação
→ LeadActivity criada
→ NewLeadCaptured disparado após commit
→ Database notification e e-mail em fila
→ confirmação exibida
Conversão
Filament Action autoriza
→ ConvertLeadToEvent
→ lock/checagem idempotente
→ cria Event
→ cria checklist
→ atualiza Lead
→ cria atividade e auditoria
→ commit
Pagamento
Filament form valida
→ RecordManualPayment
→ converte string monetária para centavos
→ salva Payment
→ cria auditoria
→ Query financeira recalcula leitura
Publicação de caso
Filament salva conteúdo
→ valida imagem e alt text
→ publica por published_at
→ rota pública passa a exibir
→ sitemap inclui slug
10. Interface Filament
10.1 Resources obrigatórios
LeadResource;EventResource;EventTaskResourceou relation manager + visão global;VendorResource;BudgetItemResourcepreferencialmente dentro do evento;PaymentResourcepreferencialmente dentro do evento + visão global;DocumentResourceou managers vinculados;ServiceResource;PortfolioCaseResource;TestimonialResource;SiteSettingResourceou página singleton;UserResource;AuditLogResourcesomente leitura.
10.2 Regras de Resource
- tabelas sempre paginadas;
- busca somente em campos úteis;
- filtros indexados;
- eager loading explícito para evitar N+1;
- ações de estado devem chamar Actions;
- labels e mensagens em pt-BR;
- valores monetários formatados em BRL;
- datas apresentadas no timezone do produto;
- ações destrutivas confirmadas;
- Policies aplicadas e testadas;
- campos internos nunca expostos em rotas públicas.
10.3 Dashboard
Widgets devem executar queries pequenas e independentes. Não fazer uma consulta gigante que carregue todos os registros.
10.4 Detalhe do evento
A página deve combinar, sem virar uma única classe monolítica:
- header do evento;
- cards de atenção;
- resumo financeiro;
- tarefas;
- fornecedores;
- documentos;
- ações rápidas.
Usar componentes/Widgets menores e testáveis.
11. Site público e interatividade
11.1 Estado atual e componentes candidatos
O site público não usa Livewire nem Alpine hoje. As páginas são Blade renderizado no servidor mais JavaScript vanilla progressivo (resources/js/app.js e resources/js/motion.js). O layouts.public carrega apenas @vite(['resources/css/app.css', 'resources/js/app.js']) — nenhum @livewireScripts. O pacote livewire/livewire existe no projeto apenas como dependência transitiva de filament/support e opera somente dentro do painel /admin.
Se surgir a necessidade de consulta dinâmica, os candidatos naturais a Livewire seriam FeaturedPortfolioCases e PublishedServices. Essa adoção está condicionada ao gatilho registrado em §22.
Não transformar seções estáticas em componentes Livewire. Usar Blade quando não houver estado ou interação.
11.2 Formulário de briefing
Estado atual: o formulário é implementado em Blade + Controller (
POST /contato,ContactBriefingRequest), conforme WEB-05, e essa é a abordagem aceita — não um estágio provisório. Os requisitos abaixo valem independentemente da tecnologia; a criação de Lead segue para a Fase 2.
O formulário deve:
- ter estado tipado ou Form Object quando útil;
- validar no servidor;
- possuir loading state;
- desabilitar botão durante submissão;
- preservar acessibilidade;
- limpar dados após sucesso;
- evitar exposição de exceção;
- suportar teste de submissão sem navegador (feature test);
- suportar jornada E2E em navegador real.
11.3 JavaScript
- manter o site público em JS vanilla progressivo;
- não introduzir framework SPA;
- não usar dependência JS quando CSS e HTML resolverem;
- toda interação crítica deve funcionar sem estado global complexo;
- Alpine só entra junto com Livewire, se o gatilho de §22 disparar.
12. Segurança e privacidade
12.1 Autenticação
- login interno;
- e-mail verificado;
- reset seguro;
- senhas tratadas pelo Laravel;
- cookie
secure,httpOnlyesameSiteem produção; - usuário inativo bloqueado;
- acesso Filament validado por
canAccessPanelou mecanismo equivalente.
2FA pode ser adicionado apenas se suportado de forma simples pelo stack escolhido. Não bloquear o MVP por isso.
12.2 Autorização
Policies obrigatórias para entidades internas.
Admin:
- acesso total.
Assistant:
- operação cotidiana;
- sem usuários, configurações globais e auditoria;
- exclusões críticas restritas.
12.3 Formulário público
- CSRF;
- rate limit;
- honeypot;
- validação server-side;
- limite de tamanho de campos;
- normalização de e-mail e telefone;
- proteção contra mass assignment;
- logs sem conteúdo integral da mensagem do visitante.
12.4 Uploads
- allowlist de MIME e extensão;
- limite de tamanho;
- path aleatório;
- arquivos privados por padrão;
- imagens públicas com validação e alt text;
- não confiar no nome original;
- download autorizado por Policy;
- proteção contra path traversal.
12.5 LGPD
- coletar apenas dados necessários;
- exibir aviso de privacidade no briefing;
- registrar aceite do aviso;
- não tratar consentimento como base universal;
- definir rotina administrativa para correção e exclusão quando cabível;
- evitar dados sensíveis no MVP;
- não registrar dados pessoais desnecessários em logs ou auditoria;
- documentar retenção de leads perdidos antes do lançamento.
12.6 Dependências
composer.locke lock de frontend versionados;composer auditno CI;npm auditconforme política definida no projeto;- nenhuma dependência abandonada ou sem uso;
- justificar dependências grandes em PR/ADR.
13. Estratégia de testes
13.1 Objetivo
A pirâmide deve possuir:
- muitos testes unitários rápidos;
- testes feature/integration suficientes para Laravel, PostgreSQL, Livewire e Filament;
- poucos testes E2E cobrindo jornadas críticas;
- testes visuais determinísticos nas telas mais importantes.
A distribuição é por intenção, não por percentual rígido.
13.2 Unit tests
Não inicializam Laravel nem banco quando possível.
Cobertura obrigatória:
- conversão e formatação de dinheiro;
- rejeição de valores negativos;
- status derivado de pagamento;
- cálculo de totais financeiros;
- transições de lead;
- invariantes de conversão;
- conclusão e reabertura de tarefa;
- cálculo de vencimento;
- regras de publicação quando extraídas para domínio.
Exemplo esperado:
it('marks an unpaid past-due payment as overdue', function () {
$payment = PaymentSchedule::from(
amount: new Money(150000),
dueDate: new DateTimeImmutable('2026-07-01'),
paidAt: null,
);
expect($payment->statusAt(new DateTimeImmutable('2026-07-27')))
->toBe(PaymentStatus::Overdue);
});
13.3 Feature e integration tests
Devem inicializar Laravel e usar PostgreSQL real no CI.
Cobertura obrigatória:
- migrations e constraints;
- Actions;
- Policies;
- conversão transacional e idempotente;
- criação de checklist;
- validação do briefing;
- notificações;
- upload e autorização de download;
- queries financeiras;
- filtros principais;
- Resources e Actions Filament;
- componentes Livewire;
- publicação e despublicação de conteúdo;
- autenticação e papéis.
Usar Mail::fake, Notification::fake, Storage::fake e Queue::fake quando o objetivo não for testar a integração externa.
13.4 E2E browser
Executar com Chromium headless contra a aplicação servida por FrankenPHP.
Jornadas obrigatórias:
| ID | Jornada | Resultado esperado |
|---|---|---|
| E2E-01 | Visitante envia briefing | Lead criado, sucesso visível, sem erro de console |
| E2E-02 | Assessora autentica e trata lead | Login, filtro, status e próxima ação funcionam |
| E2E-03 | Assessora converte lead | Evento e checklist criados uma única vez |
| E2E-04 | Assessora registra orçamento e pagamento | Totais atualizados e pagamento visível |
| E2E-05 | Assessora publica caso | Conteúdo aparece na rota pública |
Não duplicar todas as combinações no browser. Casos de borda ficam em unit/feature.
Em falha, CI deve publicar:
- screenshot;
- trace ou vídeo quando suportado;
- logs da aplicação;
- logs do browser;
- HTML report quando disponível.
13.5 Regressão visual
Usar assertScreenshotMatches() ou API equivalente do Pest Browser.
Snapshots obrigatórios:
| Tela | Desktop | Mobile |
|---|---|---|
| Home | 1440×1000 | 390×844 |
| Serviços | 1440×1000 | 390×844 |
| Portfólio | 1440×1000 | 390×844 |
| Detalhe do portfólio | 1440×1000 | 390×844 |
| Briefing vazio | 1280×900 | 390×844 |
| Briefing com erros | 1280×900 | 390×844 |
| Briefing sucesso | 1280×900 | 390×844 |
| Login | 1280×900 | Opcional |
| Dashboard | 1440×1000 | Não obrigatório |
| Detalhe do evento | 1440×1000 | Não obrigatório |
Determinismo obrigatório:
- Chromium e imagem Linux fixos;
- viewport fixo;
- timezone
America/Sao_Paulo; - locale
pt-BR; - fontes instaladas na imagem;
- relógio congelado;
- seed determinístico;
- animações e transições desabilitadas;
- dados dinâmicos mascarados quando necessário.
Atualização de baseline deve usar comando explícito e revisão humana do diff.
13.6 Testes de arquitetura
Criar regras Pest Architecture:
arch()
->expect('App\\Domain')
->toUseStrictTypes()
->not->toUse(['dd', 'dump', 'die']);
arch()
->expect('App\\Domain')
->not->toDependOn(['App\\Filament', 'App\\Livewire']);
Adicionar regras conforme a estrutura real, sem tornar a suíte excessivamente frágil.
13.7 Cobertura
- meta de 80% para
DomaineApplication; - não medir views, migrations, código gerado e framework;
- cobertura não substitui critérios de aceite;
- queda de cobertura em módulo crítico deve bloquear merge.
13.8 Acessibilidade automatizada
Smoke/browser tests devem verificar:
- ausência de issues críticas ou sérias;
- foco inicial coerente quando modal abrir;
- labels de formulário;
- landmarks e headings básicos;
- ausência de erro de console.
Revisão manual mínima antes do lançamento:
- navegação por teclado;
- foco visível;
- contraste;
- zoom a 200%;
- leitor de tela nos fluxos de briefing e login.
13.9 Comandos padronizados
O projeto deve expor scripts equivalentes:
composer test:unit
composer test:feature
composer test:browser
composer test
composer quality
composer visual:update
Composição esperada:
test:unit → Unit + Architecture
test:feature → Feature + Livewire + Filament
test:browser → E2E + visual + acessibilidade + smoke
quality → Pint check + PHPStan/Larastan + audits + testes
14. CI/CD
14.1 Gates de pull request
| Job | Responsabilidade | Bloqueia merge |
|---|---|---|
static |
Pint, PHPStan/Larastan, Composer validate, Composer e npm audit | Sim |
unit |
Unitários, arquitetura e cobertura | Sim |
feature |
PostgreSQL, migrations, Livewire, Filament e integração | Sim |
browser |
Vite, FrankenPHP, E2E, smoke, acessibilidade e visual | Sim |
container |
Build da imagem final e healthcheck | Sim |
14.2 Regras do pipeline
- todo PR executa todos os gates;
- usar cache de Composer, npm e browser de forma segura;
- banco de integração deve ser PostgreSQL;
- CI não deve usar SQLite como substituto;
- browser tests usam o mesmo artefato ou imagem próxima da produção;
- falhas devem publicar artefatos diagnósticos;
- migrations devem ser executadas em banco vazio;
- seed de demonstração deve ser executável;
- secrets nunca ficam no repositório ou na imagem.
14.3 Branches e ambientes
- PR: testes e preview opcional;
main: build imutável por SHA publicado no GHCR e deploy automático em staging via Dokploy;- staging: Dokploy Compose executa migração, healthcheck
/upe smoke pós-deploy (/up,/,/admin/login); - produção: promoção da mesma imagem aprovada, sem rebuild (retag do digest em
:production); - produção requer aprovação humana explícita no MVP (
workflow_dispatchcom confirmação); - rollback usa imagem anterior (SHA anterior, sem rebuild);
- migrations devem ser backward-compatible quando possível.
14.4 Definition of Done
Uma história só está concluída quando:
- critérios de aceite estão atendidos;
- código passa por Pint;
- PHPStan/Larastan está verde;
- unit e feature tests cobrem regras relevantes;
- E2E foi criado ou atualizado para fluxo crítico;
- snapshot foi criado ou revisado para UI coberta;
- acessibilidade automatizada não possui issues críticas/sérias;
- migration foi testada;
- autorização foi verificada;
- logs não expõem PII desnecessária;
- factories e seed foram atualizados;
- staging e smoke pós-deploy estão verdes;
- documentação afetada foi atualizada.
15. Deploy com FrankenPHP
15.1 Decisão
Usar FrankenPHP em modo regular no MVP.
NÃO ativar worker mode inicialmente.
Worker mode somente poderá ser ativado após:
- profiling demonstrar benefício relevante;
- testes de persistência de estado;
- testes de memória;
- suíte de regressão verde;
- ADR aprovada.
15.2 Processos
| Processo | Imagem | Comando/função |
|---|---|---|
| web | imagem da aplicação | FrankenPHP/Caddy servindo public/ |
| queue | mesma imagem | php artisan queue:work --sleep=2 --tries=3 |
| scheduler | mesma imagem | php artisan schedule:work ou cron schedule:run |
| database | serviço gerenciado | PostgreSQL com backup |
| files | serviço gerenciado | bucket S3-compatible |
15.3 Dockerfile
Usar multi-stage build:
- Composer dependencies;
- frontend assets;
- runtime FrankenPHP.
Requisitos:
- versão PHP fixada;
- extensões PHP explícitas;
composer install --no-dev --prefer-dist --no-interaction --classmap-authoritativeem produção;npm ci;- build Vite;
- usuário não-root quando suportado;
- nenhum secret em layer;
- healthcheck;
- imagem reproduzível;
- caches Laravel criados no entrypoint/deploy quando dependem do ambiente.
Não executar php artisan config:cache em uma stage que não possui as variáveis finais quando isso congelar configuração incorreta.
15.4 Variáveis de ambiente mínimas
APP_NAME
APP_ENV
APP_KEY
APP_DEBUG=false
APP_URL
APP_LOCALE=pt_BR
APP_FALLBACK_LOCALE=pt_BR
APP_TIMEZONE=America/Sao_Paulo
DB_CONNECTION=pgsql
DB_HOST
DB_PORT
DB_DATABASE
DB_USERNAME
DB_PASSWORD
CACHE_STORE=database ou file conforme ambiente
QUEUE_CONNECTION=database
SESSION_DRIVER=database ou cookie conforme decisão
FILESYSTEM_DISK=r2 em produção
R2_ACCESS_KEY_ID
R2_SECRET_ACCESS_KEY
R2_BUCKET
R2_ENDPOINT
R2_URL (domínio próprio opcional)
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION, AWS_BUCKET, AWS_ENDPOINT, AWS_USE_PATH_STYLE_ENDPOINT — opcionais, apenas se o disk s3 for usado
MAIL_MAILER=resend em produção (mailer nativo Laravel)
RESEND_API_KEY
MAIL_FROM_ADDRESS
MAIL_FROM_NAME
15.5 Healthcheck
GET /up deve:
- responder rapidamente;
- não exigir autenticação;
- não expor segredo;
- retornar falha quando a aplicação não inicializar;
- opcionalmente validar conexão simples com banco em check separado, sem tornar o endpoint caro.
16. Observabilidade, backup e operação
16.1 Logs
Logs estruturados devem incluir quando disponível:
- request ID;
- user ID;
- rota;
- ação;
- tipo e ID de entidade;
- duração;
- nível e exceção.
Não registrar:
- senha;
- token;
- conteúdo integral de comprovante;
- conteúdo integral de mensagem pessoal;
- dados pessoais sem necessidade.
16.2 Monitoramento mínimo
- disponibilidade da home;
- disponibilidade do briefing;
- disponibilidade do login;
- erros não tratados;
- falhas repetidas de queue;
- falha de backup;
- smoke pós-deploy.
Não construir stack própria de observabilidade distribuída no MVP.
16.3 Backup
| Item | Política inicial |
|---|---|
| PostgreSQL | backup diário automático |
| Retenção | mínimo 14 dias |
| Arquivos | versionamento ou lifecycle do bucket |
| RPO | até 24 horas |
| RTO | até 4 horas |
| Teste de restauração | trimestral |
O procedimento de restauração deve ser documentado antes da produção.
17. Seeds, factories e dados determinísticos
17.1 Factory obrigatória
Criar factories para:
- User;
- Lead;
- LeadActivity;
- Event;
- EventTask;
- Vendor;
- EventVendor;
- BudgetItem;
- Payment;
- Service;
- PortfolioCase;
- Testimonial;
- Document, quando viável sem arquivo real.
17.2 Seed de demonstração
O seed deve criar:
- um admin;
- um assistant;
- configurações do site;
- 3 serviços;
- 3 casos de portfólio;
- depoimentos reais: os 5 casais de
depoimentos.md(Jeniffer e Maick, Quesia e Jhonata, Milena e Weslley, Raquel e Pedro, Victoria e Pedro), preservando texto e datas; autores fictícios de demonstração removidos; em produção permanecem não publicados até autorização explícita de publicação; - leads em estados variados;
- 2 eventos futuros e 1 concluído;
- tarefas vencidas e futuras;
- fornecedores;
- itens de orçamento;
- pagamentos pagos, pendentes e vencidos.
As credenciais de desenvolvimento devem ser documentadas apenas em ambiente local e nunca usadas em produção.
17.3 Determinismo
Para visual e browser tests:
- usar datas fixas;
- usar imagens fixture versionadas ou placeholders estáveis;
- não depender de rede externa;
- não usar conteúdo randômico não seedado;
- congelar horário.
18. Backlog de implementação
Recorte vigente (ADR-016). Fases 0 e 1 são o escopo do lançamento e estão concluídas. Fases 2 a 5 estão adiadas, sem data. Não iniciar nenhuma delas sem uma decisão nova do responsável pelo produto — a §1.1 manda trabalhar uma fase por vez, e a fase corrente é o acabamento e a publicação do site.
O agente deve implementar na sequência, salvo instrução explícita.
Fase 0 — Fundação
Entregas:
- projeto Laravel;
- PostgreSQL local e CI;
- Filament instalado e autenticado;
- Livewire configurado;
- Tailwind/Vite;
- FrankenPHP e Docker Compose local;
- papéis admin/assistant;
- Pint;
- PHPStan/Larastan;
- Pest;
- Pest Browser;
- Architecture tests;
- pipeline CI inicial;
- design tokens mínimos;
- healthcheck;
- seed de admin local.
- verificação de e-mail e reset seguro (MustVerifyEmail);
- npm audit no
composer qualitye no jobstatic; - gate de cobertura
Domain/Application≥ 80%; - serviço de aplicação FrankenPHP no Compose local;
- hello-world implantado em staging (critério de saída) — run 31395107465 em
7e68c0e, comDokploy deployment succeedede smoke verde em/up,/e/admin/login.
Os itens pendentes acima são tratados pela mudança OpenSpec
complete-foundation-parity; o critério de saída da fase só é atingido com staging implantado.
Critério de saída: pipeline verde e hello-world implantado em staging.
Fase 1 — Site e CMS
site_settings;- serviços;
- portfólio e galeria;
- depoimentos;
- home;
- listagem e detalhe de serviços;
- listagem e detalhe de portfólio;
- sobre;
- privacidade;
- SEO;
- mídia otimizada;
- snapshots desktop/mobile;
- testes de acessibilidade.
Critério de saída: conteúdo gerenciável no Filament e site público aprovado visualmente (baselines em tests/.pest/snapshots/; aprovação humana do diff visual no PR).
Fase 2 — Leads — ADIADA (ADR-016)
- migration/model/factory de Lead;
- LeadActivity;
- briefing Livewire;
- proteção contra abuso;
- notificação de novo lead;
- LeadResource;
- filtros;
- próxima ação;
- histórico;
- perda e reabertura;
- testes unit/feature/browser;
- E2E-01 e E2E-02.
Critério de saída: jornada visitante → lead → tratamento interna totalmente verde.
Fase 3 — Eventos e tarefas — ADIADA (ADR-016)
- Event;
- EventTask;
- conversão idempotente;
- checklist padrão;
- EventResource;
- detalhe customizado;
- tarefas por evento;
- visão global de tarefas;
- dashboard operacional inicial;
- E2E-03.
Critério de saída: lead é convertido e evento pode ser administrado.
Fase 4 — Fornecedores e financeiro — ADIADA (ADR-016)
- Vendor;
- EventVendor;
- BudgetItem;
- Payment;
- Money/conversão para centavos;
- resumo financeiro;
- pagamentos pagos, pendentes e vencidos;
- comprovante opcional;
- auditoria financeira;
- widgets financeiros;
- E2E-04.
Critério de saída: assessora acompanha orçamento e pagamentos sem integração bancária.
Fase 5 — Documentos, hardening e lançamento — ADIADA (ADR-016)
- documentos privados;
- auditoria completa;
- scheduler de resumo;
- performance e índices;
- revisão N+1;
- revisão de Policies;
- revisão LGPD;
- backup e restore documentados;
- monitoramento;
- smoke pós-deploy;
- revisão manual de acessibilidade;
- E2E-05;
- seed de demonstração completo;
- documentação operacional.
Critério de saída: Definition of Done integral e produção aprovada.
19. Critérios de aceite transversais
Toda tela interna deve:
- exigir autenticação;
- aplicar Policy;
- estar em pt-BR;
- exibir estados vazios úteis;
- possuir validação server-side;
- indicar sucesso e falha;
- ser navegável por teclado;
- não executar N+1 conhecido;
- paginar listas de crescimento aberto;
- possuir teste proporcional ao risco.
Toda rota pública deve:
- funcionar sem autenticação;
- não expor conteúdo não publicado;
- possuir title e description;
- usar layout responsivo;
- não emitir erro de console;
- respeitar acessibilidade básica;
- ter comportamento de erro seguro.
Toda operação financeira deve:
- usar centavos inteiros;
- ser validada;
- ser autorizada;
- gerar auditoria quando crítica;
- possuir testes unitários e feature.
20. Riscos e mitigação
| Risco | Mitigação obrigatória |
|---|---|
| Filament concentrar domínio | Resources finos, Actions e Queries testáveis |
| Site parecer genérico | design tokens, conteúdo real, fotografia e visual tests |
| Snapshots instáveis | contêiner fixo, relógio/dados/fontes determinísticos |
| Escopo crescer | lista de não objetivos e mudança somente com hipótese real |
| Financeiro virar contabilidade | limitar a orçamento e pagamentos manuais |
| Worker mode vazar estado | manter modo regular até benchmark e ADR |
| Upload degradar performance | limites, variantes, storage externo |
| SQLite esconder diferenças | PostgreSQL em integração e CI |
| Regras escondidas em callbacks | Actions explícitas e testes de caso de uso |
| Dashboard ficar lento | queries independentes, índices e agregações pequenas |
21. ADRs iniciais
| ADR | Decisão | Status |
|---|---|---|
| ADR-001 | Monólito modular Laravel, sem microserviços | Aceita |
| ADR-002 | Filament para área interna (Livewire é dependência interna do Filament); site público em Blade — ver ADR-015 | Aceita |
| ADR-003 | PostgreSQL como único banco transacional | Aceita |
| ADR-004 | Pagamentos somente manuais | Aceita |
| ADR-005 | Pest unifica unit, feature, browser e visual | Aceita |
| ADR-006 | FrankenPHP regular mode; worker mode adiado | Aceita |
| ADR-007 | Single-tenant; SaaS e portal do cliente adiados | Aceita |
| ADR-008 | Database queue; Redis adiado | Aceita |
| ADR-009 | Dinheiro em BRL armazenado como centavos inteiros | Aceita |
| ADR-010 | Home com estrutura fixa e CMS tipado, sem page builder | Aceita |
| ADR-011 | Cloudflare R2 (S3-compatible) como storage de objetos em produção | Aceita |
| ADR-012 | E-mail transacional via Resend (mailer nativo Laravel) | Aceita |
| ADR-013 | Design system Heritage Editorial para o site público | Aceita |
| ADR-014 | Deploy via Dokploy Compose com imagem imutável por SHA no GHCR | Aceita |
| ADR-015 | Site público permanece Blade + JS vanilla; Livewire e Alpine ficam restritos ao Filament até o gatilho de §22. Emenda o texto da ADR-002 | Aceita |
| ADR-016 | Lançamento de 31/08/2026 entrega apenas o site institucional (Fases 0–1); Fases 2–5 seguem especificadas e adiadas, sem data | Aceita |
22. Gatilhos objetivos para evolução
| Evolução | Gatilho |
|---|---|
| Portal do cliente | clientes pedem repetidamente visibilidade e aprovação fora do WhatsApp |
| RSVP | volume relevante de eventos exige gestão de convidados |
| Pagamento online | cobrança manual causa esforço ou inadimplência mensurável |
| Multi-tenancy | uma segunda assessoria aceita pagar e usar o produto |
| Redis | database queue não atende volume ou confiabilidade |
| FrankenPHP worker | benchmark prova ganho e testes de estado/memória passam |
| API pública | existe consumidor real e contrato de integração |
| Kanban | tabela de leads demonstra limitação frequente observada |
| Editor de checklist | diferentes tipos de evento exigem manutenção frequente do seed |
| Livewire no site público | portfólio ou serviços exigem consulta ou filtro dinâmico que Blade + JS vanilla não resolvem de forma simples |
23. Condições de conclusão do MVP
O MVP está concluído somente quando:
A ADR-016 divide estas condições em dois recortes. Cada um se fecha por conta própria; o segundo não bloqueia o lançamento.
23.1 Lançamento do site (Fases 0–1)
O lançamento está concluído somente quando:
- site público está publicado e visualmente aprovado;
- assessora edita os conteúdos essenciais sem desenvolvedor;
- briefing envia o pedido de proposta de forma segura, com proteção contra abuso e aceite de privacidade registrado;
- usuários e Policies estão corretos;
- testes unit, feature, visuais e arquitetura estão verdes;
- CI bloqueia regressões;
- imagem FrankenPHP é reproduzível;
- staging e produção usam a mesma imagem promovida;
- backup, restauração e monitoramento estão documentados;
- nenhum item explicitamente fora do MVP (§4.2) foi introduzido.
Note a diferença em relação à versão anterior desta seção: o critério do briefing é enviar o pedido, não "criar leads". Criar Lead é Fase 2 e está adiado; o formulário atual envia e-mail e não persiste nada.
23.2 Produto completo (Fases 2–5, adiado)
Além de tudo em §23.1:
- pipeline e próxima ação funcionam;
- briefing cria leads de forma segura e persistente;
- lead é convertido uma única vez em evento;
- checklist é criado automaticamente;
- evento possui visão consolidada;
- fornecedores podem ser cadastrados e vinculados;
- orçamento e pagamentos manuais possuem totais consistentes;
- dashboard mostra pendências do dia;
- auditoria registra operações críticas;
- jornadas E2E das fases correspondentes estão verdes.
24. Formato esperado de reporte do agente
Ao finalizar uma tarefa, o agente deve responder no formato:
Requisito implementado: <ID e nome>
Alterações:
- <arquivo ou módulo>
- <arquivo ou módulo>
Testes adicionados/atualizados:
- <teste>
- <teste>
Comandos executados:
- <comando e resultado>
Critérios de aceite:
- [x] <critério>
- [x] <critério>
Pendências ou desvios:
- Nenhum
Caso exista desvio:
Desvio da SPEC:
- Decisão afetada:
- Motivo:
- Alternativa escolhida:
- Impacto:
- ADR criada/atualizada:
25. Primeira instrução recomendada ao agente
Leia integralmente o SPEC.md e inspecione o repositório. Implemente apenas a Fase 0 — Fundação. Antes de alterar arquivos, apresente um plano curto relacionando cada mudança aos requisitos da fase. Não avance para a Fase 1. Ao terminar, execute todos os gates disponíveis, reporte os resultados e marque somente os itens comprovadamente concluídos.