Files
gw-svelte/DEPLOYMENT.md
T

5.5 KiB

Deployment

Server layout confirmed

The production server currently runs multiple separate Docker Compose projects:

  • Main public site WordPress stack:
    • project: goodwalkconz
    • path: /docker/wordpress/goodwalk.co.nz
  • Onboarding WordPress stack:
    • project: onboardinggoodwalkconz
    • path: /docker/wordpress/onboarding.goodwalk.co.nz
  • Shared nginx:
    • project: nginx
    • path: /docker/nginx
  • Shared mysql:
    • project: mysql
    • path: /docker/mysql

The deployment scripts in this repo are set up to deploy the new Svelte site as a separate stack at:

  • remote path: /docker/goodwalk-svelte
  • compose file: docker-compose.prod.yml
  • docker project: goodwalk-svelte

This leaves the onboarding site, shared nginx, shared mysql, and other unrelated containers untouched.

Files involved

  • deploy.ps1
    • Windows entrypoint for packaging the repo, uploading it, and running the remote deployment helper over SSH.
  • scripts/deploy-remote.sh
    • Server-side helper that updates only the goodwalk-svelte compose project.
  • docker-compose.prod.yml
    • Production compose file for the new Svelte app, mail API, and Postgres.
  • scripts/export-homepage-content.mjs
    • Local helper that exports the current src/lib/content/homepage.ts into a deployable JSON payload before each deployment.
  • scripts/sync-homepage-content.mjs
    • Runtime helper that upserts the exported homepage content into PostgreSQL after deploys that affect the app/database.
  • ssh-config
    • Repo-local SSH config used by the deployment script.
  • nginx/goodwalk.co.nz.svelte.conf.example
    • Example shared-nginx config for routing the main public site to the new Svelte app and mail API.

First-time server preparation

  1. Fill in ssh-config with the real host details.

  2. Create the deployment directory on the server:

mkdir -p /docker/goodwalk-svelte
  1. The first deployment will auto-create the production env file on the server at:
/docker/goodwalk-svelte/.env

It is created from deploy.env.template. Current template contents:

APP_VERSION=4.0.1
TZ=Pacific/Auckland

POSTGRES_DB=goodwalk
POSTGRES_USER=goodwalk
POSTGRES_PASSWORD=gw_Pg_7Jm9!Qx4#Ld2@Vr8
POSTGRES_PASSWORD_URLENCODED=gw_Pg_7Jm9%21Qx4%23Ld2%40Vr8

RESEND_API_KEY=replace-me
OWNER_EMAIL=replace-me
FROM_EMAIL=GoodWalk <bookings@goodwalk.co.nz>
REPLY_TO=aless@goodwalk.co.nz

FORM_MIN_SECONDS=4
FORM_MAX_SECONDS=7200
RATE_LIMIT_WINDOW_SECONDS=900
RATE_LIMIT_MAX_PER_IP=5
RATE_LIMIT_MAX_PER_EMAIL=3
RATE_LIMIT_MIN_INTERVAL_SECONDS=20

After the first deploy, edit /docker/goodwalk-svelte/.env on the server and replace:

  • RESEND_API_KEY=replace-me
  • OWNER_EMAIL=replace-me
  1. Confirm the shared Docker network already exists:
docker network ls | grep webnet

Your server already uses webnet, so this should already be present.

First deploy

From Windows PowerShell in the repo root:

powershell -ExecutionPolicy Bypass -File .\deploy.ps1

Or skip the confirmation prompt:

powershell -ExecutionPolicy Bypass -File .\deploy.ps1 -Force

To rebuild and restart only one service, for example the mail API:

powershell -ExecutionPolicy Bypass -File .\deploy.ps1 -Force -Service mail-api

Homepage content sync

Local development can feel fresher than production because production reads the homepage/shared content from PostgreSQL whenever DATABASE_URL is set.

The deployment flow now handles that automatically:

  1. deploy.ps1 exports the current src/lib/content/homepage.ts into deploy-data/homepage-content.json.
  2. The deploy archive uploads that JSON payload with the app source.
  3. After the Goodwalk stack is updated, the remote helper runs a content sync inside the app container.
  4. That sync upserts the homepage row in site_content.

This means future deploys will carry your latest file-based homepage/navigation/ shared content changes into production PostgreSQL automatically.

Cutover nginx

After the new Svelte stack is up and healthy, update the shared nginx config on the server for the main site.

Current live file:

/docker/nginx/conf.d/goodwalk.co.nz.conf

Use the repo example as the new target config:

nginx/goodwalk.co.nz.svelte.conf.example

Important:

  • deploy.ps1 now copies the repo nginx config to /docker/nginx/conf.d/goodwalk.co.nz.conf and reloads the shared nginx container as part of deployment.
  • The repo nginx config uses Docker's internal resolver so future app/mail container rebuilds will not leave nginx pinned to stale upstream IPs.

Manual nginx commands, if you ever need them:

docker compose -p nginx -f /docker/nginx/docker-compose.yml exec nginx nginx -t
docker compose -p nginx -f /docker/nginx/docker-compose.yml exec nginx nginx -s reload

Important notes

  • Do not deploy the top-level docker-compose.yml to this server for production. It includes its own nginx service and does not match the shared nginx setup on the host.
  • The deployment scripts do not stop or remove the onboarding WordPress stack.
  • The deployment scripts do not touch the shared mysql compose project.
  • The deployment scripts preserve the remote .env file.
  • The site check in deploy.ps1 targets https://www.goodwalk.co.nz/api/health. Before nginx cutover, use -SkipSiteCheck or expect that check to fail.