Operations
This chapter covers how the portal is deployed and how its Postgres schema is managed.Deploy the portal
The portal is distributed as a single Docker image that contains the Rust binary and the built frontend assets. The image entrypoint is/usr/local/bin/portal.
Required environment variables
See.env.example in the repository root. In production the following must be set:
APP_BASE_URL– the public URL customers use in their browser.DATABASE_URL– Postgres connection string.POCKET_ID_ISSUER,POCKET_ID_CLIENT_ID,POCKET_ID_CLIENT_SECRET– OIDC configuration.R2_ACCOUNT_ID,R2_ACCESS_KEY_ID,R2_SECRET_ACCESS_KEY,R2_BUCKET_NAME– object storage.STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET,STRIPE_PRICE_ID_*– billing integration.
DEV_MODE=true only for local development; in that mode OIDC, R2, and Stripe are stubbed. In production the portal refuses to start unless STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, and STRIPE_PRICE_ID_PRO are non-empty.
Database provisioning
The portal applies its full schema automatically at startup. The schema is embedded in the binary asportal/db/schema.sql and is applied idempotently using CREATE ... IF NOT EXISTS statements. This keeps deployment simple: any empty Postgres database pointed at by DATABASE_URL will be provisioned on first startup.
This approach trades granular rollback for operational simplicity. Because the schema is applied as a single script, downgrades are handled by deploying an older container image with an older schema file, not by reversing individual migrations.
Deploy order
- Build and push the new portal image.
- Roll out the new portal pods.
- The pods provision or update the schema automatically on startup.
- Run smoke tests:
/health, log in through OIDC, upload a small artifact.
Rolling back a schema change
To revert a bad schema change, redeploy the previous portal image. The older embedded schema will be applied idempotently on startup. Note that this does not delete columns or tables added by the newer schema; it only ensures the older schema’s expected objects exist. Data in columns or tables that the older binary does not reference is left untouched in Postgres. For destructive rollbacks, restore from a database backup taken before the deploy.Local development
Start an empty Postgres instance and run the portal withDEV_MODE=true. The embedded schema will be applied automatically on first startup.