This service is an Express application that loads configuration from environment variables using dotenv. When you run the server locally it automatically looks for a .env file at the project root (/workspace/innerpeace-api/.env).
- Copy the example file and fill in the values that apply to your deployment:
You can also start from the production defaults if you prefer:
cp .env.example .env
cp .env.prod .env
- Edit
.envand populate the required secrets. The Google Drive private key must keep the literal\nnewlines when stored in a single-line.enventry. You can create an additional.env.localto override any values for your machine; it is loaded automatically in development. - Start the API (
npm run devornpm run start). Environment files are loaded automatically byserver/config/loadEnv.tswhen the process boots.
Note If you deploy to Cloud Run or another managed environment, set the same variables in the service configuration instead of using a
.envfile.
The backend now talks to Google APIs exclusively through a dedicated Service Account. Configure the following variables for both local development and Cloud Run:
| Variable | Description |
|---|---|
GOOGLE_PROJECT_ID |
Google Cloud project ID that owns the Service Account. |
GOOGLE_SA_EMAIL |
Service Account email with access to Calendar and Drive. |
GOOGLE_SA_KEY |
Private key for the Service Account. Accepts the raw PEM (with \n) or a base64-encoded blob. |
DRIVE_MEDIA_FOLDER_ID |
Default Drive folder ID to use when clients omit ?folderId=. |
MEDIA_ALLOWED_MIME |
Optional. Comma-separated MIME allowlist (defaults to video/*,audio/*). |
MEDIA_CACHE_MAX_AGE |
Optional. Value for the Cache-Control header when streaming media. |
API requests are authenticated with Supabase access tokens. Configure the Supabase project reference so both the gateway and backend validate the same issuer and audience:
| Variable | Description |
|---|---|
SUPABASE_PROJECT_REF |
Supabase project ref (e.g. abcd1234). Used to build the issuer https://<ref>.supabase.co/auth/v1. |
SUPABASE_AUD |
Optional override for the expected audience (defaults to authenticated). |
All protected requests must send a single header: Authorization: Bearer <supabase_access_token>.
Protected endpoints are fronted by Google Cloud API Gateway. The OpenAPI definition in infra/gateway/openapi-google.yaml configures ESPv2 to validate Supabase JWTs from the Authorization header.
To roll out changes, update the API config and redeploy the gateway:
CONFIG_ID=innerpeace-config-$(date +%Y%m%d%H%M)
gcloud api-gateway api-configs create "$CONFIG_ID" \
--api=innerpeace-api \
--openapi-spec=infra/gateway/openapi-google.yaml \
--project=$PROJECT_ID
gcloud api-gateway gateways update innerpeace-gateway \
--api=innerpeace-api \
--api-config="$CONFIG_ID" \
--location=europe-west2 \
--project=$PROJECT_IDAfter deploying the new config, confirm requests succeed with a Supabase access token:
curl -i "$GATEWAY_HOST/api/bookings?uid=<SUPABASE_UID>" \
-H "Authorization: Bearer $SUPABASE_ACCESS_TOKEN"The response should be a 200 (or an application error), not a 401. A jwt_authn_access_denied{Jwt_is_missing} error indicates the gateway config still needs to be updated.