Skip to main content
Golden rule: secrets stay on the server. Fill the CHANGE-ME placeholders in the API’s env.prod there, never commit them, and never put a secret in a VITE_* / PUBLIC_* var (those are inlined into the shipped bundle).

Backend (shipwide_api)

  • Docker: the container boots migrate → seed → serve. Migrations + the idempotent seed run automatically. Provide a managed Postgres 17 + Redis 7 (or run them alongside).
  • Purge cron (required): run daily — node dist/jobs/purge.js (compiled path; tsx is dev-only). It’s the physical half of account deletion + support-ticket retention; idempotent.
  • Email: point SMTP_* at a transactional provider (e.g. Postmark). Set SPF, DKIM, DMARC on the sending domain — with passwordless auth, a code in spam means nobody can sign in.
  • CORS: CORS_ORIGINS = your exact web origin(s). Native schemes (capacitor://localhost, tauri://localhost) and the admin’s ADMIN_URL are always allowed.
  • Secrets to set: DATABASE_URL, REDIS_URL, JWT_SECRET (≥32), SMTP_*, ADMIN_*, and any GOOGLE_/APPLE_/REVENUECAT/ONESIGNAL integration you enable.

App (shipwide_app)

  • Web / PWA: npm run build → static output (keeps pre-compressed .gz/.br assets). Serve from any static host / CDN. Its origin must be in the API’s CORS_ORIGINS.
  • iOS / Android: npm run build:native (sets SHIPWIDE_NATIVE=1 so compressed assets aren’t bundled into the WebView), then open the committed ios/ / android/ projects in Xcode / Android Studio to archive and submit.
  • Desktop: Tauri bundles from src-tauri/ (Rust stable). Icons via npx tauri icon.

Admin (shipwide_admin)

Docker + nginx, built with --build-arg VITE_*:
nginx serves the SPA (fallback to index.html, hashed assets cached forever / index.html never, noindex + DENY). Outside the image: (1) point ADMIN_URL in the API env at this origin or CORS refuses it; (2) put a network gate in front (Cloudflare Access / IP allowlist) — it reads everyone’s data and needs no public reachability.

Website (shipwide_website)

npm run switch_to_prod (set your domain first), then npm run build (astro-i18next generate + astro check + astro build) → static output; serve from any static host / CDN. PUBLIC_* are inlined at build. If the support form posts to your API, set PUBLIC_SUPPORT_ENDPOINT and add the site origin to the API’s CORS_ORIGINS.