* feat: gates de qualidade da Fase 0 (auth, npm audit, cobertura, compose local) Implementa os itens pendentes de SPEC.md §18 mapeados pela mudança OpenSpec complete-foundation-parity (grupos 1, 2 e 3 de tasks.md): - MustVerifyEmail em User, com canAccessPanel exigindo is_active E hasVerifiedEmail(). Seeds de admin/assistant local passam a marcar email_verified_at. Verificação de e-mail permanece administrada apenas pelo admin (seed/edição) — não há rota de auto-verificação registrada (->emailVerification() não foi chamado) — decisão deliberada, já que usuários são criados pelo admin, não se autocadastram. - Reset de senha seguro: página customizada App\Filament\Pages\Auth\RequestPasswordReset substitui a página padrão do Filament, que vaza a existência de contas via notificação de erro distinguível em dois casos — Password::INVALID_USER (e-mail inexistente) e Password::RESET_THROTTLED (só ocorre para usuário existente, quando um token foi criado há pouco). Ambos os casos agora respondem com a mesma notificação de sucesso. - declare(strict_types=1) adicionado aos 15 arquivos de app/ que ainda não tinham: AdminPanelProvider, Controller e 13 páginas de Filament Resources. - npm audit adicionado ao script `quality` do composer e ao job `static` do CI, com --audit-level=high (documentado inline no workflow). O gate é hoje vazio na prática — package.json não tem `dependencies` de runtime — mas protege contra regressões futuras. - Gate de cobertura Domain/Application >= 80% no job `unit` do CI. Escopo via phpunit.coverage.xml dedicado (o phpunit.xml global continua cobrindo todo app/ para os demais usos). O job `unit` ganhou serviço de postgres e passou a rodar Unit+Architecture+Feature juntas, porque as classes de App\Application\Queries\Marketing só são exercitadas por testes Feature hoje — um gate baseado só em Unit ficaria bem abaixo de 80%. Medido localmente com pcov: 98,1% (nenhum teste novo foi necessário para atingir o limiar). - Serviço `app` (FrankenPHP) no docker-compose.yml para paridade local com staging/produção, dependente de postgres saudável, com DB_HOST/DB_PORT sobrescritos para resolver o serviço postgres pelo nome (o padrão 127.0.0.1 do .env só funciona para processos no host). Validado com um smoke isolado (projeto/portas dedicados via overlay `!override`, sem tocar o container amare-postgres compartilhado por outra worktree): depends_on/healthcheck funcionou, `php artisan migrate` rodou dentro do container via DB_HOST=postgres, e /up respondeu 200. README atualizado (PHP 8.4 canônico, composer.json mantém ^8.3 por design). Fora do escopo: deploy hello-world em staging (Dokploy com falha, item de infra não relacionado a este change) — L2353 e o critério de saída da Fase 0 continuam sem marcar. Também ficam pendentes, por dependerem de uma execução real de CI/PR (task 3.4, 6.1, 6.2 do OpenSpec): prova de que o CI falha com quebra intencional de audit/cobertura, e evidência de deploy/ rollback em staging. Co-Authored-By: Claude noreply@anthropic.com AI-Assisted: yes AI-Tool: claude-code * fix: fecha lockout de admin-criado e documenta pcov/compose no auth de usuários Correção de acompanhamento ao commit anterior (gates de qualidade da Fase 0), achada por revisão adicional após o primeiro commit: - CreateUser::handleRecordCreation agora define email_verified_at ao criar um usuário pelo painel. Sem isso, UserForm não expõe esse campo (nem está no #[Fillable] de User — de propósito, para nunca virar mass-assignable via formulário), então todo usuário criado pelo admin nascia com email_verified_at nulo e, com canAccessPanel() agora exigindo e-mail verificado, ficava trancado para sempre — sem rota de auto-verificação e sem recuperação via reset de senha (o callback do Filament pula o envio para quem falha canAccessPanel(), mas ainda reporta sucesso). Usa forceFill() (não atribuição direta, que o PHPStan rejeita pelo tipo Carbon/string do cast) para contornar o guard de mass assignment só nesse ponto. Regressão coberta por teste que cria um usuário via Livewire::test(CreateUser::class) — não pela factory, que não passa pelo mesmo caminho — e confirma login em seguida; teste falha sem a correção (verificado manualmente revertendo e rodando de novo). - Confirmado que DatabaseSeeder::run() (commit anterior) já funciona sem ajuste: User::query()->updateOrCreate() pareceria sofrer o mesmo guard de #[Fillable], mas `php artisan db:seed` executa dentro de Model::unguarded() (Illuminate\Database\Console\Seeds\SeedCommand), o que levanta o guard durante o seed inteiro. Adicionado teste de regressão que roda via $this->seed(DatabaseSeeder::class) (o mesmo caminho de `composer setup`) para travar esse comportamento — chamar a mesma lógica fora do comando db:seed reproduz o guard bloqueando o campo, confirmando que a dependência do unguard() é real, não coincidência. - README: nota de que `docker compose up -d postgres` agora exige o `.env` do passo 1, porque o serviço `app` referencia `.env` via `env_file` e o Compose valida o arquivo inteiro antes de subir qualquer serviço. - AGENTS.md: documentado `composer test:coverage` (usado pelo job `unit` do CI) e que `docker compose up -d` sem argumento também sobe o serviço `app` agora, não só o Postgres. Nota para quem for escrever o próximo teste de recurso Filament neste repo: Livewire::test(...)->fillForm([...]) é um no-op silencioso aqui — app()->runningUnitTests() retorna false no setup de testes deste projeto, então o guard de Filament\Schemas\Concerns\InteractsWithSchemas:: fillFormDataForTesting() nunca aplica o estado, e o teste falha depois com erros de validação "required" que parecem um bug no formulário, não no teste. Use ->set('data.campo', valor) (como os testes de Login já fazem) até isso ser investigado — fora do escopo deste change. Co-Authored-By: Claude noreply@anthropic.com AI-Assisted: yes AI-Tool: claude-code * fix(auth): verificar usuários existentes ao adotar MustVerifyEmail O `canAccessPanel` passou a exigir `hasVerifiedEmail()`, mas nenhuma migration preenchia `email_verified_at` para contas que já existem. Toda conta criada antes desta mudança tem o campo nulo e ficaria trancada fora do /admin no instante do deploy. E não haveria volta pelo aplicativo: nenhuma rota de verificação self-service é registrada, e o fluxo de reset de senha deliberadamente não notifica quem falha no `canAccessPanel` — ainda reportando sucesso. Recuperar exigiria shell no contêiner. Verificar essas contas é o padrão correto, não um atalho. Não existe cadastro público: toda conta existente foi criada por um admin, pelo painel ou pelo snippet de tinker do runbook de deploy. Esse ato é a verificação — exatamente o raciocínio que o CreateUser aplica às contas criadas de agora em diante. A verificação é datada pelo `created_at` da conta, não pelo momento em que a migration roda, para não inventar um histórico. O `down()` é um no-op documentado: anular as colunas recriaria justamente a falha que esta migration existe para evitar, e a divisão original entre nulos e não-nulos não está registrada em lugar nenhum. Co-Authored-By: Claude noreply@anthropic.com AI-Assisted: yes AI-Tool: claude-code --------- Co-authored-by: manoel.neto <manoel.neto@creditas.com>
6.0 KiB
Repository Guidelines
Project Structure & Module Organization
This is a Laravel 13 application for an event-planning consultancy. Application code lives in app/: domain rules belong in app/Domain, HTTP entry points in app/Http, and the internal Filament 5 panel in app/Filament. Blade views, JavaScript, and Tailwind CSS are under resources/; Vite publishes browser assets to public/. Database migrations, factories, and seeders live in database/. Tests are grouped into tests/Unit, tests/Architecture, tests/Feature, and tests/Browser. Treat SPEC.md as the product source of truth and use openspec/ for planned changes.
Build, Test, and Development Commands
composer setupinstalls PHP and npm dependencies, creates.env, migrates, and builds assets.docker compose up -d postgresstarts the local PostgreSQL service.docker compose up -d(no service name) also builds and starts theappservice — a local FrankenPHP container for parity with staging/production, see README.md.composer devruns Laravel, the queue listener, logs, and Vite together.npm run buildcreates the production frontend bundle.composer qualityruns formatting checks, PHPStan level 5, PHP + npm dependency audits, and every test suite.composer test:unit,composer test:feature, orcomposer test:browserrun focused suites.composer test:coverageruns the Domain/Application coverage gate (80% minimum, scoped viaphpunit.coverage.xml) used by CI'sunitjob. Requires a coverage driver (pcovorxdebug); fails with "No code coverage driver available" without one — that's an environment gap, not a broken repo.
Feature and browser tests require the amare_test PostgreSQL database configured in phpunit.xml.
Worktrees
Always work in a git worktree created from the main ref — never modify main directly and never commit from the primary working tree. Create a dedicated worktree per feature/branch with git worktree add -b <branch> <path> main. On finishing work, create a PR, watch CI until green, then merge it. Clean up the worktree with git worktree remove after merge.
Git Hooks (husky)
Hooks live in .husky/ and auto-install on any plain npm install via the prepare script. Note composer setup runs npm install --ignore-scripts, which skips hook installation — after setup, run npm install once (or npx husky) to activate hooks.
pre-commit: runscomposer pint:checkandcomposer phpstan.pre-push: gates on theamare_testdatabase (settings parsed fromphpunit.xml), blocks the push with adocker compose up -d postgreshint when Postgres is unreachable, then runscomposer test:unitandcomposer test:feature. Browser tests are CI-only (FrankenPHP container).
Coding Style & Naming Conventions
Follow PSR-4 and Laravel conventions: PascalCase classes, camelCase methods, and snake_case database columns. Use four spaces (two in YAML, except four in Compose files), LF endings, and UTF-8 as defined by .editorconfig. Every project-owned PHP file must place declare(strict_types=1); immediately after <?php. Keep domain code independent of Filament and Livewire. Run composer pint to format and composer phpstan before review.
Testing Guidelines
Tests use Pest 4; browser coverage uses Pest Browser/Playwright. Name files by behavior, ending in Test.php, and add tests in the suite matching the changed layer. Feature tests use RefreshDatabase. Add architecture coverage for dependency-boundary changes. No numeric coverage threshold is enforced, but changed behavior must have regression coverage.
Commit & Pull Request Guidelines
History follows Conventional Commit-style subjects, for example feat: Fase 0 — Fundação. Use <type>: <imperative summary> (feat, fix, docs, test, chore) and keep commits focused. Pull requests should explain scope, link the relevant issue or OpenSpec requirement, list verification commands, and include screenshots for UI changes. Ensure all CI jobs pass.
Security & Configuration
Copy .env.example; never commit secrets or production credentials. Development seed credentials are local-only. Validate uploads and authorization through Laravel policies, and run composer security-audit after dependency changes.
Design Context
Amare: refined, humane, precise — Heritage Editorial. Trust-first, both private + corporate audiences. Never generic wedding decor (hearts/gold/script) or AI-slop. Real proof only.
The design system lives in DESIGN.md (palette, typography, layout, do's and don'ts) and positioning in PRODUCT.md; tokens are implemented in resources/css/tokens.css and asserted by tests/Feature/PublicSite/HeritageEditorialTokensTest.php. Per-surface briefs live in .impeccable/surfaces/. The Impeccable skill itself is vendored at .github/skills/impeccable/SKILL.md — its setup step reads PRODUCT.md, DESIGN.md, and the matching surface brief.
Agent skills
Issue tracker
Issues live in Linear, driven through the Linear MCP tools. See docs/agents/issue-tracker.md for workspace, team, and tool conventions. The repo ships no .mcp.json, so the Linear MCP has to be enabled for the session before those tools exist — if it isn't, report that instead of silently falling back to another tracker.
Triage labels
Default vocabulary: needs-triage, needs-info, ready-for-agent, ready-for-human, wontfix. See docs/agents/triage-labels.md.
Domain docs
Single-context repo. There is no CONTEXT.md — the domain is documented in SPEC.md (§8 is the domain model and database schema) and PRODUCT.md, with current capabilities described per-capability under openspec/specs/. docs/adr/README.md is an index only: ADR-001 through ADR-010 are decided in SPEC.md §21, and there are no standalone ADR files. docs/agents/domain.md describes the generic CONTEXT.md/CONTEXT-MAP.md layout that the engineering skills look for and instructs them to proceed silently when it's absent, which is the case here.