Files
amare/AGENTS.md
Manoel Freitas 7e68c0e37f chore: fechar portões de qualidade da Fase 0 (MAN-120) (#39)
* 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>
2026-08-10 10:48:04 -03:00

65 lines
6.0 KiB
Markdown

# 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 setup` installs PHP and npm dependencies, creates `.env`, migrates, and builds assets.
- `docker compose up -d postgres` starts the local PostgreSQL service. `docker compose up -d` (no service name) also builds and starts the `app` service — a local FrankenPHP container for parity with staging/production, see README.md.
- `composer dev` runs Laravel, the queue listener, logs, and Vite together.
- `npm run build` creates the production frontend bundle.
- `composer quality` runs formatting checks, PHPStan level 5, PHP + npm dependency audits, and every test suite.
- `composer test:unit`, `composer test:feature`, or `composer test:browser` run focused suites.
- `composer test:coverage` runs the Domain/Application coverage gate (80% minimum, scoped via `phpunit.coverage.xml`) used by CI's `unit` job. Requires a coverage driver (`pcov` or `xdebug`); 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`: runs `composer pint:check` and `composer phpstan`.
- `pre-push`: gates on the `amare_test` database (settings parsed from `phpunit.xml`), blocks the push with a `docker compose up -d postgres` hint when Postgres is unreachable, then runs `composer test:unit` and `composer 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.