Program.cs: wrap the boot-time MigrateAsync in try/catch (was an unhandled exception into a restart:unless-stopped crash-loop), log critical and exit(1) on failure, and add a --migrate-only flag that applies migrations then exits 0 without starting the web host. deploy.sh: run migrations as a preflight via the new --migrate-only image against the live novelly-data volume, before the running (old-image) stack is touched. A failing migration now aborts the deploy with the old containers still serving traffic, instead of swapping to a crash-looping new container first and finding out from the health-check timeout.