project-deploylisted
Install: claude install-skill ubermuda/loupe
# Deploying
Production is a DigitalOcean App Platform app pulling `ghcr.io/ubermuda/loupe:prod`.
Infrastructure lives in `terraform/`, and `terraform/terraform.tfvars` is
gitignored, so it holds the real values.
## The two halves, and why they are not the same event
A deploy is two independent things, and confusing them is the failure this skill
exists to prevent.
1. **The image.** `just build-prod` builds it, `just push-prod` pushes it to the
`prod` tag. Nothing about this changes production.
2. **The app spec.** `terraform apply` changes environment variables, instance
sizes and routes. It creates a deployment.
**A `terraform apply` deployment does not re-pull the image.** The tag is fixed
at `prod`, so App Platform sees the same tag it already has and reuses the layers
it holds. The spec change goes live and the code does not.
That is not a bug in the platform. `variable "image_tag"` says so: "A fixed tag
means App Platform's deployment history is the only record of what ran."
## Ship code
```bash
just deploy # build-prod, push-prod, then create-deployment --wait
```
Or, when the image is already pushed:
```bash
doctl apps create-deployment "$(cd terraform && terraform output -raw app_id)" --force-rebuild --wait
```
`--force-rebuild` is what makes the platform fetch the tag again. Without it a
deployment can complete, report `ACTIVE`, and run the previous image.
The working tree must be clean. `APP_VERSION` comes from `git describe --tags
--alway