Esta é a causa real da queda do deploy de staging, reportada pelo erro
`sh: 2: Syntax error: "&&" unexpected`.
O `command` do serviço `migrate` estava escrito como block scalar
dobrado (`command: >`). Em YAML, o dobramento junta linhas com espaço
apenas quando elas têm a mesma indentação da primeira; toda linha mais
indentada preserva a quebra. As linhas `&& ...` estavam um espaço mais à
direita, então o valor final era:
sh -c "php artisan migrate --force --no-interaction
&& php artisan db:seed --class=ContentSeeder --force --no-interaction
&& php artisan media:generate-variants"
O `sh` recebe isso como duas linhas e aborta na segunda, antes de rodar
qualquer comando — daí o `sh: 2:` no erro. Como todos os outros serviços
dependem do migrate por `condition: service_completed_successfully`, a
stack inteira nunca sobe, e o Dokploy reporta `status=error` com
`errorMessage: null` porque nada da aplicação chegou a executar.
O formato exec-array de uma linha não tem essa ambiguidade. Ele já havia
sido adotado em 5949fad exatamente por isso, e o squash de reconciliação
58f24a6 o reverteu para o formato dobrado — o mesmo commit que também
apagou os oito baselines visuais restaurados no PR #29.
O `--force` inválido em `media:generate-variants`, corrigido no PR #32,
era um segundo defeito real na mesma linha, mas não era o que derrubava o
deploy: o `sh` morria antes de chegar lá.
Acrescenta guarda de regressão: nenhum `command` do compose de deploy
pode ser block scalar. Verificada nos dois sentidos — passa com o formato
atual e falha com a mensagem certa se o formato dobrado voltar.
Co-Authored-By: Claude noreply@anthropic.com
AI-Assisted: yes
AI-Tool: claude-code
Co-authored-by: manoel.neto <manoel.neto@creditas.com>
O serviço `migrate` do docker-compose.deploy.yml encadeia três comandos
artisan com `&&`, e o último é `php artisan media:generate-variants
--force`. Esse comando não declara nenhuma opção — sua assinatura é
apenas `media:generate-variants`. O artisan responde `The "--force"
option does not exist.` e sai com código 1.
Como todos os outros serviços dependem do migrate por
`condition: service_completed_successfully`, o one-shot falhando impede
`web`, `queue` e `scheduler` de subirem. A stack inteira fica fora do ar
e o Dokploy reporta `status=error` com `errorMessage: null`, sem nada no
log do CI que aponte a causa.
O deploy de staging falhou assim em quatro commits seguidos: 58f24a6,
949f6ae, e9b4534 e fc3d5c4. A opção entrou em 10a1f0d.
Reproduzido dentro da própria imagem de produção:
docker run --rm --entrypoint sh amare-app:ci \
-c 'php artisan media:generate-variants --force; echo "EXIT=$?"'
The "--force" option does not exist.
EXIT=1
Além de remover a opção, adiciona um teste que percorre todas as chamadas
`php artisan` do compose de deploy e verifica que cada comando existe e
que cada opção passada está definida — considerando também as opções
globais do console, como `--no-interaction`. O teste falha se `--force`
voltar.
Co-Authored-By: Claude noreply@anthropic.com
AI-Assisted: yes
AI-Tool: claude-code
Co-authored-by: manoel.neto <manoel.neto@creditas.com>
Seed+media step made non-fatal so a transient R2 write issue
doesn't block web/queue/scheduler from starting. Seed output
preserved in dokploy deployment logs for diagnosis.
staging R2 was empty — migrate ran but no seeder, so ContentSeeder
never placed fixtures on the configured disk (r2) and media:generate-variants
had nothing for image paths. Staging deploy now seeds content.
Migrate could not resolve the database internal hostname because the
Compose stack used an isolated project network. Attach services to the
external dokploy-network used by Dokploy Postgres.
Co-authored-by: Cursor <cursoragent@cursor.com>
Publish immutable FrankenPHP images to GHCR, auto-deploy staging after CI,
and promote the same digest to production with smoke, backup, and rollback docs.
Co-authored-by: Cursor <cursoragent@cursor.com>