# 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/Fortaleza` | | 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 | Livewire + Blade | | 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: 1. Instrução explícita mais recente do responsável pelo produto. 2. Este `SPEC.md`. 3. ADRs aceitos no repositório. 4. Testes automatizados existentes. 5. Convenções já consolidadas no código. 6. 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. --- ## 1. Contrato de operação para agentes Antes de implementar qualquer mudança, o agente DEVE: 1. Ler este arquivo integralmente. 2. Inspecionar a estrutura atual do repositório. 3. Identificar o requisito funcional pelo ID. 4. Listar os arquivos que pretende criar ou alterar. 5. Implementar uma fatia vertical pequena e funcional. 6. Criar ou atualizar os testes correspondentes. 7. Executar os gates de qualidade aplicáveis. 8. 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`, `BaseAction` ou “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 `float` para 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: 1. **Site público premium**, usado para apresentar a marca, construir confiança e converter visitantes em leads. 2. **Á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: ```php enum UserRole: string { case Admin = 'admin'; case Assistant = 'assistant'; } ``` Não instalar sistema de permissões granular no MVP. --- ## 4. Escopo ### 4.1 Incluído no MVP - site público; - CMS interno do site; - formulário de briefing; - 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; - usuários internos e papéis simples; - notificações internas e por e-mail para novos leads; - auditoria de ações críticas; - SEO básico; - acessibilidade e testes visuais; - CI/CD e deploy em contêiner com FrankenPHP. ### 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: 1. desbloquear uma jornada já definida; ou 2. resolver um problema observado em uso real; e 3. 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: ```text 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 Page` customizada com widgets orientados a exceção. - Detalhe do evento: página customizada do Resource com resumo operacional. - Briefing público: componente Livewire próprio. - Home: Blade/Livewire 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: 1. header e navegação; 2. hero com proposta de valor e CTA; 3. prova visual por eventos em destaque; 4. resumo dos serviços; 5. método de trabalho; 6. casos selecionados; 7. depoimentos; 8. CTA final para briefing; 9. 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. ### 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. ### 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 `h1` por 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_at` estiver 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:** ```gherkin 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:** ```gherkin 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; - criar Lead com status `new`; - registrar origem `website`; - notificar administradores; - exibir sucesso sem revelar dados internos; - enviar e-mail de confirmação quando o serviço de e-mail estiver configurado; - falha no e-mail não pode apagar o lead já criado. **Aceite:** ```gherkin 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_id` ou relacionamento equivalente; - timestamps. #### CRM-02 — Pipeline **Prioridade:** P0 Estados permitidos: ```php 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; - `won` somente por conversão bem-sucedida ou ação administrativa explícita; - `lost` exige 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 `won` ou `lost` nã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:** ```gherkin 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 ```php 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`; - `confirmed` exige data de início; - `in_progress` exige data de início; - `completed` registra `completed_at`; - `cancelled` registra 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: ```php 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_at` e `completed_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: 1. confirmar briefing e escopo; 2. definir data e local; 3. definir orçamento-alvo; 4. mapear fornecedores essenciais; 5. confirmar fornecedores selecionados; 6. revisar cronograma geral; 7. realizar reunião final; 8. confirmar contatos operacionais; 9. revisar pagamentos pendentes; 10. 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: ```php 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: ```php 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 `float` em 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: ```php 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: ```text 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_cents` não cancelados; - acordado: soma de `agreed_amount_cents` não cancelados; - pago: soma de pagamentos com `paid_at`; - pendente: soma de pagamentos sem `paid_at`; - vencido: soma de pagamentos sem `paid_at` e 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:** ```gherkin 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 `admin` ou `assistant`; - 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` - `id` bigint PK; - `name` varchar; - `email` varchar unique; - `email_verified_at` timestamp nullable; - `password` varchar; - `role` varchar indexed; - `is_active` boolean default true indexed; - remember token; - timestamps. #### `site_settings` Singleton: - `id` bigint PK; - `brand_name`; - `hero_eyebrow` nullable; - `hero_title`; - `hero_subtitle`; - `hero_cta_label`; - `about_summary` nullable; - `email`; - `phone`; - `city` nullable; - `social_links` jsonb; - `default_meta_title`; - `default_meta_description`; - `default_og_image_path` nullable; - analytics fields nullable; - timestamps. #### `services` - `id`; - `title`; - `slug` unique; - `summary`; - `description` text; - `cover_image_path` nullable; - `cover_image_alt` nullable; - `sort_order` integer indexed; - `is_featured` boolean indexed; - `published_at` timestamp nullable indexed; - timestamps; - soft delete opcional somente se recuperação for necessária. #### `portfolio_cases` - `id`; - `title`; - `slug` unique; - `summary`; - `event_type`; - `city` nullable; - `venue` nullable; - `event_date` date nullable; - `challenge` text; - `solution` text; - `result` text nullable; - `cover_image_path`; - `cover_image_alt`; - `is_featured` boolean indexed; - `sort_order` integer indexed; - `published_at` timestamp nullable indexed; - `meta_title` nullable; - `meta_description` nullable; - timestamps. #### `portfolio_images` - `id`; - `portfolio_case_id` FK cascade; - `path`; - `alt_text`; - `caption` nullable; - `sort_order` integer; - timestamps; - index composto por `portfolio_case_id, sort_order`. #### `testimonials` - `id`; - `quote` text; - `author_name`; - `context` nullable; - `photo_path` nullable; - `photo_alt` nullable; - `sort_order` integer; - `is_featured` boolean indexed; - `published_at` timestamp nullable indexed; - timestamps. #### `leads` - `id`; - `name`; - `email` nullable indexed; - `phone` nullable indexed; - `event_type`; - `estimated_event_date` date nullable indexed; - `city` nullable; - `estimated_guests` integer nullable; - `message` text nullable; - `source` varchar indexed; - `status` varchar indexed; - `next_action_at` timestamp nullable indexed; - `next_action_type` nullable; - `next_action_notes` text nullable; - `lost_reason` text nullable; - `converted_event_id` nullable unique; - `privacy_notice_accepted_at` timestamp nullable; - `marketing_metadata` jsonb nullable; - timestamps; - soft deletes recomendados para recuperação operacional. #### `lead_activities` - `id`; - `lead_id` FK cascade; - `user_id` FK nullable set null; - `type` varchar indexed; - `description` text; - `metadata` jsonb nullable; - `created_at`; - sem `updated_at` quando possível, pois atividade é append-only. #### `events` - `id`; - `lead_id` FK nullable unique; - `title`; - `event_type`; - `client_name`; - `client_email` nullable; - `client_phone` nullable; - `starts_at` timestamp nullable indexed; - `ends_at` timestamp nullable; - `venue` nullable; - `city` nullable; - `status` varchar indexed; - `target_budget_cents` bigint nullable; - `summary` text nullable; - `internal_notes` text nullable; - `owner_user_id` FK nullable indexed; - `completed_at` timestamp nullable; - timestamps; - soft deletes recomendados. #### `event_tasks` - `id`; - `event_id` FK cascade indexed; - `title`; - `description` text nullable; - `assigned_user_id` FK nullable indexed; - `due_at` timestamp nullable indexed; - `priority` varchar indexed; - `status` varchar indexed; - `sort_order` integer; - `relative_due_days` integer nullable; - `completed_at` timestamp nullable; - `completed_by_user_id` FK nullable; - timestamps; - index composto por `event_id, status, due_at`. #### `vendors` - `id`; - `name` indexed; - `category` varchar indexed; - `contact_name` nullable; - `email` nullable; - `phone` nullable; - `city_region` nullable indexed; - `website_url` nullable; - `notes` text nullable; - `is_active` boolean default true indexed; - timestamps; - soft deletes opcionais. #### `event_vendors` - `id`; - `event_id` FK cascade indexed; - `vendor_id` FK restrict indexed; - `category` varchar indexed; - `status` varchar indexed; - `contact_override` nullable; - `reference_amount_cents` bigint nullable; - `notes` text nullable; - timestamps; - índice composto por `event_id, category, status`. #### `budget_items` - `id`; - `event_id` FK cascade indexed; - `vendor_id` FK nullable set null; - `category` varchar indexed; - `description`; - `planned_amount_cents` bigint nullable; - `agreed_amount_cents` bigint nullable; - `status` varchar indexed; - `notes` text nullable; - `sort_order` integer; - timestamps; - checks de valores não negativos quando suportado. #### `payments` - `id`; - `event_id` FK cascade indexed; - `budget_item_id` FK nullable set null indexed; - `description`; - `amount_cents` bigint; - `due_date` date indexed; - `paid_at` timestamp nullable indexed; - `method` varchar nullable; - `proof_path` nullable; - `notes` text nullable; - `created_by_user_id` FK; - `updated_by_user_id` FK; - timestamps; - check `amount_cents > 0`. #### `documents` - `id`; - `lead_id` FK nullable cascade; - `event_id` FK nullable cascade; - `display_name`; - `path`; - `mime_type`; - `size_bytes` bigint; - `category` varchar indexed; - `notes` text nullable; - `uploaded_by_user_id` FK; - timestamps; - constraint: exatamente um entre `lead_id` e `event_id` deve ser preenchido. #### `audit_logs` - `id`; - `user_id` FK nullable set null indexed; - `action` varchar indexed; - `auditable_type` varchar indexed; - `auditable_id` bigint indexed; - `metadata` jsonb nullable; - `ip_address` nullable; - `request_id` nullable 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 | Livewire 4 + Blade + Alpine + Tailwind | | Banco | PostgreSQL | | Servidor | FrankenPHP + Caddy | | Assets | Vite | | Testes | Pest 4 + Pest Browser/Playwright | | Arquivos | Laravel Filesystem + storage 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: ```text 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/Models` e 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 ```text 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`; - `CreateManualLead` somente se CRUD padrão não for suficiente; - `UpdateLeadStatus`; - `ScheduleLeadNextAction`; - `MarkLeadAsLost`; - `ReopenLead`; - `ConvertLeadToEvent`; - `CreateDefaultEventChecklist`; - `CompleteEventTask`; - `ReopenEventTask`; - `RecordManualPayment`; - `UpdateManualPayment`; - `DeleteManualPayment`; - `PublishPortfolioCase`; - `UnpublishPortfolioCase`; - `StorePrivateDocument`; - `WriteAuditLog` ou 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 - `GetDashboardAttentionItems` ou queries menores por widget; - `GetEventFinancialSummary`; - `GetUpcomingEvents`; - `GetOverdueTasks`; - `GetLeadsWithoutNextAction`; - `GetOverduePayments`; - `GetDueSoonPayments`. ### 9.7 Fluxos técnicos #### Briefing ```text 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 ```text Filament Action autoriza → ConvertLeadToEvent → lock/checagem idempotente → cria Event → cria checklist → atualiza Lead → cria atividade e auditoria → commit ``` #### Pagamento ```text Filament form valida → RecordManualPayment → converte string monetária para centavos → salva Payment → cria auditoria → Query financeira recalcula leitura ``` #### Publicação de caso ```text 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`; - `EventTaskResource` ou relation manager + visão global; - `VendorResource`; - `BudgetItemResource` preferencialmente dentro do evento; - `PaymentResource` preferencialmente dentro do evento + visão global; - `DocumentResource` ou managers vinculados; - `ServiceResource`; - `PortfolioCaseResource`; - `TestimonialResource`; - `SiteSettingResource` ou página singleton; - `UserResource`; - `AuditLogResource` somente 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. Livewire e site público ### 11.1 Componentes sugeridos - `ContactBriefingForm`; - `FeaturedPortfolioCases` se houver necessidade de consulta dinâmica; - `PublishedServices` se houver necessidade de consulta dinâmica. Não transformar todas as seções estáticas em componentes Livewire. Usar Blade quando não houver estado ou interação. ### 11.2 Formulário de briefing O componente 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 Livewire sem browser; - suportar jornada E2E em navegador real. ### 11.3 JavaScript - usar Alpine apenas para interações pequenas; - não introduzir framework SPA; - não usar dependência JS quando CSS/HTML/Livewire resolverem; - toda interação crítica deve funcionar sem estado global complexo. --- ## 12. Segurança e privacidade ### 12.1 Autenticação - login interno; - e-mail verificado; - reset seguro; - senhas tratadas pelo Laravel; - cookie `secure`, `httpOnly` e `sameSite` em produção; - usuário inativo bloqueado; - acesso Filament validado por `canAccessPanel` ou 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.lock` e lock de frontend versionados; - `composer audit` no CI; - `npm audit` conforme 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: 1. muitos testes unitários rápidos; 2. testes feature/integration suficientes para Laravel, PostgreSQL, Livewire e Filament; 3. poucos testes E2E cobrindo jornadas críticas; 4. 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: ```php 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/Fortaleza`; - 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: ```php 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 `Domain` e `Application`; - 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: ```bash composer test:unit composer test:feature composer test:browser composer test composer quality composer visual:update ``` Composição esperada: ```text 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 e audits | 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 e deploy automático em staging; - staging: migration, cache warmup e smoke pós-deploy; - produção: promoção da mesma imagem aprovada, sem rebuild; - produção requer aprovação humana explícita no MVP; - rollback usa imagem anterior; - 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: 1. Composer dependencies; 2. frontend assets; 3. runtime FrankenPHP. Requisitos: - versão PHP fixada; - extensões PHP explícitas; - `composer install --no-dev --prefer-dist --no-interaction --classmap-authoritative` em 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 ```text APP_NAME APP_ENV APP_KEY APP_DEBUG=false APP_URL APP_LOCALE=pt_BR APP_FALLBACK_LOCALE=pt_BR APP_TIMEZONE=America/Fortaleza 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=s3 em produção AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_DEFAULT_REGION AWS_BUCKET AWS_ENDPOINT opcional AWS_USE_PATH_STYLE_ENDPOINT opcional MAIL_MAILER MAIL_HOST MAIL_PORT MAIL_USERNAME MAIL_PASSWORD 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; - 3 depoimentos; - 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 O agente deve implementar na sequência, salvo instrução explícita. ### Fase 0 — Fundação **Entregas:** - [x] projeto Laravel; - [x] PostgreSQL local e CI; - [x] Filament instalado e autenticado; - [x] Livewire configurado; - [x] Tailwind/Vite; - [x] FrankenPHP e Docker Compose local; - [x] papéis admin/assistant; - [x] Pint; - [x] PHPStan/Larastan; - [x] Pest; - [x] Pest Browser; - [x] Architecture tests; - [x] pipeline CI inicial; - [x] design tokens mínimos; - [x] healthcheck; - [x] seed de admin local. **Critério de saída:** pipeline verde e hello-world implantado em staging. ### Fase 1 — Site e CMS - [x] `site_settings`; - [x] serviços; - [x] portfólio e galeria; - [x] depoimentos; - [x] home; - [x] listagem e detalhe de serviços; - [x] listagem e detalhe de portfólio; - [x] sobre; - [x] privacidade; - [x] SEO; - [x] mídia otimizada; - [x] snapshots desktop/mobile; - [x] 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 - [ ] 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 - [ ] 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 - [ ] 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 - [ ] 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 e Livewire/Blade para área pública | 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 | --- ## 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 | --- ## 23. Condições de conclusão do MVP O MVP está concluído somente quando: - site público está publicado e visualmente aprovado; - assessora edita os conteúdos essenciais sem desenvolvedor; - briefing cria leads de forma segura; - pipeline e próxima ação funcionam; - 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; - usuários e Policies estão corretos; - auditoria registra operações críticas; - testes unit, feature, E2E, 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 foi introduzido. --- ## 24. Formato esperado de reporte do agente Ao finalizar uma tarefa, o agente deve responder no formato: ```text Requisito implementado: Alterações: - - Testes adicionados/atualizados: - - Comandos executados: - Critérios de aceite: - [x] - [x] Pendências ou desvios: - Nenhum ``` Caso exista desvio: ```text Desvio da SPEC: - Decisão afetada: - Motivo: - Alternativa escolhida: - Impacto: - ADR criada/atualizada: ``` --- ## 25. Primeira instrução recomendada ao agente ```text 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. ```