Known gaps
-
Set
INSTALL_TOKENbefore the first deploy. Since the wizard fails closed in production, an unset value means/installreturns 404 and the browser has no route to the first administrator. Recoverable from a shell — see Recovering an instance — but the wizard is the pleasant path. -
On App Platform,
EXPORT_STORAGEcannot belocal. The web and worker containers have separate ephemeral filesystems, so the application default would have the worker write an archive the web container cannot see, and every download would 404.terraform/spaces.tftherefore creates a private Spaces bucket and a bucket-scoped access key, andmain.tfwires them intoEXPORT_STORAGE_BUCKET/_ENDPOINT/_REGION/_KEY/_SECRET.All you supply is
export_bucket_region— a Spaces datacenter slug liketor1, which is not the App Platform slug (tor) and cannot be derived from it. The bucket isprivate, is never destroyed while it holds objects, and has a 30-day lifecycle rule as a backstop against archives that outlive their database row. Download links expire after 48 hours and the app deletes the archive then, so that rule can never reach a live one.Bringing your own bucket instead: set
create_export_bucket = falseand fill in theexport_storage_*variables. -
No canned ACL works on every provider, so
EXPORT_STORAGE_ACLexists. The Flysystem S3 adapter always sends a canned ACL and offers no way to send none. Buckets created since 2023 on AWS default to “Bucket owner enforced”, which rejects everything exceptbucket-owner-full-controlwith a 400AccessControlListNotSupported, while MinIO and DigitalOcean Spaces accept only the app’s default,private. Get this wrong and every export upload fails inside the worker, where nobody is watching. -
Set
MERCURE_JWT_SECRETif you want site-review push. On App Platform, setting it runs a Mercure hub as a second service (module v1.6.0’senable_mercure) and routes/.well-known/mercureon the app’s own domain to it; the module injectsMERCURE_URL,MERCURE_PUBLIC_URLandMERCURE_JWT_SECRETitself. Leaving it empty keeps push off — review submissions still save, but never reach the bridge CLI, and the publish failure is only logged, so it degrades silently rather than erroring.The hub is in-memory: a restart drops undelivered updates. That is why submissions are recorded in the
site_review_eventsoutbox and the bridge resumes fromLast-Event-ID— delivery is best effort, replay is not. -
Nothing here has been applied against a live account.
terraform validatepasses andplanevaluates the full configuration up to the first API call, but no deploy has run. Specifically unobserved:- the Mercure component, reasoned from the
dunglas/mercureimage’s documented interface and the dev compose service; - the Spaces bucket and key, whose
readwritegrant is taken from DigitalOcean’s documentation rather than from a completed upload-download-delete cycle; - the S3 export path as a whole — it has never touched a real bucket;
- the single-host Compose stack, validated as configuration but never started;
- the production image itself, whose base is pinned by digest in
docker/prod/Dockerfile; no image built from that pin has been deployed.
- the Mercure component, reasoned from the