Skip to main content

Infrastructure

Place each process only after the deployment checklist is confirmed against the ScalaHosting plan. Until then, the production URL and the machine layout stay undecided. The logical separation does not.

Processes​

ProcessPublicState
Next.jsYes, HTTPSNo payment secrets and no database role.
ExpressWebhooks only, plus private calls from Next.jsBusiness data and provider secrets.
WorkerNoJobs, mail, thumbnails, refund calls.
PostgreSQLNoSystem of record. TLS from the API and worker.
Object storageNo public objectsOriginals and thumbnails.
DocusaurusYes, static HTTPSDocumentation only.

Database​

  • PostgreSQL 15 or newer.
  • The API, the worker, and Prisma migrations connect with DATABASE_URL only. There is no second connection string.
  • The database user in that URL is not a superuser. Append-only tables reject update and delete in the database.
  • Daily logical backup plus the host's volume snapshots if they exist. See recovery.

Storage​

The bucket policy denies public reads. The API signs GetObject for 300 seconds after the gallery check. The worker's credential can write thumbnails and read originals. It is not embedded in Next.js.

Email and payments​

The Stripe account is USD. The webhook endpoint is the public Express route, with the signing secret from the environment. Mail is sent by the worker. A failed delivery stays on notification_deliveries and is retried.

Monitoring​

Track at least:

  • Webhook signature failures and unique-constraint conflicts on payment_webhook_events.
  • Orders remaining in PENDING_PAYMENT after a provider payment exists.
  • Jobs in FAILED, and the age of the oldest pending job.
  • Download responses refused because access is not approved. A spike is a signal to inspect, not by itself a defect.
  • Backup success and the time of the last restore drill.

Logs omit passwords, access tokens, refresh tokens, setup tokens, card data, and storage secrets. Audit metadata follows the same rule.

Documentation host​

Publish kstudeo-doc as a static site. Set url in the Docusaurus config to that host before the production build so canonical links are correct.