* 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>
52 lines
1.6 KiB
YAML
52 lines
1.6 KiB
YAML
services:
|
|
postgres:
|
|
image: postgres:17
|
|
container_name: amare-postgres
|
|
restart: unless-stopped
|
|
ports:
|
|
- "${DB_PORT:-5432}:5432"
|
|
environment:
|
|
POSTGRES_DB: ${DB_DATABASE:-amare}
|
|
POSTGRES_USER: ${DB_USERNAME:-amare}
|
|
POSTGRES_PASSWORD: ${DB_PASSWORD:-secret}
|
|
volumes:
|
|
- amare_postgres_data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME:-amare} -d ${DB_DATABASE:-amare}"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 10
|
|
start_period: 10s
|
|
|
|
# Local parity with the FrankenPHP image used on staging/production.
|
|
# Manual smoke test (not run in CI — the `container` job already builds and
|
|
# health-checks the same Dockerfile-based image):
|
|
# docker compose up -d
|
|
# curl localhost:8000/up
|
|
app:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
container_name: amare-app
|
|
restart: unless-stopped
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
env_file:
|
|
- .env
|
|
environment:
|
|
# Override host-side .env defaults: DB_HOST=127.0.0.1 only resolves for
|
|
# processes running on the host, not for this container reaching the
|
|
# `postgres` service by its Compose service name. DB_PORT is also
|
|
# forced back to Postgres's internal container port (5432) — .env may
|
|
# have DB_PORT remapped for host-side tooling (e.g. to avoid a local
|
|
# port clash), but that remapping only applies to the published host
|
|
# port, never to container-to-container traffic.
|
|
DB_HOST: postgres
|
|
DB_PORT: "5432"
|
|
ports:
|
|
- "8000:8000"
|
|
|
|
volumes:
|
|
amare_postgres_data:
|