Skip to content

Environment Variables

API Configuration

These variables are set in api/local.settings.json for local development or in Azure Function App → Configuration for production.

VariableRequiredDescriptionDefault
COSMOS_ENDPOINTCosmos DB endpoint URLhttps://localhost:8081 (emulator)
COSMOS_KEYCosmos DB primary keyEmulator key
COSMOS_DATABASEDatabase namechoirtickets
JWT_SECRETSecret for signing session tokens
FRONTEND_URLFrontend URL for magic link callbackshttp://localhost:5173
RESEND_API_KEYResend API key for sending emails
FROM_EMAILSender email addressonboarding@resend.dev
E2E_TEST_MODEEnable test-mode endpoints (dangerous)false
NODE_ENVEnvironment: development or productiondevelopment
REFRESH_TOKEN_TTL_DAYSPositive integer lifetime for refresh tokens, in days90
COSMOS_REQUEST_TIMEOUT_MSNumeric Cosmos request timeout in milliseconds for key-based clientsCosmos SDK default
SHARED_EVENTS_ENABLEDExact true or false switch for Shared Event creation and mutationfalse
SHARED_EVENTS_ORGANIZATION_ALLOWLISTComma-separated organization IDs allowed to mutate Shared EventsEmpty, no organization restriction
GITHUB_FEEDBACK_TOKENToken with issue-write access for optional GitHub issue creation from beta feedbackNone
DELEGATED_MEMBER_CATALOG_ENABLEDRollout switch that shows a partner organization's delegated concerts in that partner's own member catalog (Home, Bestill billetter)false
DELEGATED_MEMBER_ORDERING_ENABLEDRollout switch that allows a partner organization's members to create new self-service orders for a delegated concertfalse

Frontend Configuration

These variables control the frontend application behavior. Set them in a .env file in the frontend/ directory:

VariableRequiredDescriptionDefault
VITE_API_URLBase URL for API calls/api (proxy)
VITE_BETA_FEEDBACKSet to 'true' to enable the beta feedback UI (floating button + menu item). Disabled if not set.false
VITE_DELEGATED_MEMBER_CATALOG_ENABLEDSet to the literal string 'true' to show delegated concerts in a partner organization's own Home and Bestill billetter screens. Any other value, including unset, keeps them hidden.false

Test mode and development

E2E_TEST_MODE enables dangerous test-only endpoints (like /api/management/cleanup) for E2E testing. It requires three conditions to be active:

  1. E2E_TEST_MODE=true
  2. NODE_ENV is NOT production
  3. FRONTEND_URL contains localhost

DANGER

Do NOT enable this in production. Test mode endpoints can delete all data.

NODE_ENV controls the build and runtime environment:

  • development — enables debug logging and verbose errors
  • production — optimized build, hides debug info

In production, this must be set to production to prevent test endpoints from running, regardless of E2E_TEST_MODE.

Shared Event configuration

SHARED_EVENTS_ENABLED accepts only the lowercase strings true and false. If it is unset, Shared Event creation and mutation are disabled. Invalid values are rejected as configuration errors. Read and maintenance paths use their own safe behavior so existing records and recovery work are not deleted when mutation is disabled.

SHARED_EVENTS_ORGANIZATION_ALLOWLIST is optional. Separate organization IDs with commas. The API trims and lowercases each ID, accepts up to 128 characters, and allows lowercase letters, digits, ., _, :, and -. Empty means no additional organization restriction. Malformed or duplicate normalized entries are configuration errors. Super Admin mutation paths can bypass the allowlist where the handler explicitly permits it, but not the global disabled switch.

Delegated member ordering configuration

These two switches control the rollout of delegated normal-event sales for partner organization members (v1.2.0). Both are exposure/availability controls, never authorization: every live delegation, membership, and role check runs exactly as before regardless of these settings. Both default to off, and both are read fresh on every call, so a rollback takes effect without a restart.

  • DELEGATED_MEMBER_CATALOG_ENABLED (server) and VITE_DELEGATED_MEMBER_CATALOG_ENABLED (frontend build-time) decide whether a delegated concert is shown at all in a partner organization's own member catalog. Accepted truthy values on the server are 1, true, yes, on (case-insensitive); the frontend flag accepts only the exact string 'true'. This is exposure only — it does not close the ordering endpoint.
  • DELEGATED_MEMBER_ORDERING_ENABLED (server) is the real availability switch. It gates only the creation of new delegated member self-orders. While it is off, the API returns a stable 503 with error code DELEGATED_MEMBER_ORDERING_UNAVAILABLE for a new order attempt, and the member's ticket selection stays in the cart so they can try again later. Orders already in the system are unaffected: cancel, approve, deliver, report sold, and report returned all keep working, so an emergency stop never strands tickets mid-lifecycle.

Rollout order matters. Enable DELEGATED_MEMBER_ORDERING_ENABLED before DELEGATED_MEMBER_CATALOG_ENABLED / VITE_DELEGATED_MEMBER_CATALOG_ENABLED. Turning the catalog on first would show members a delegated concert whose orders are refused. Enabling the catalog switch does not by itself grant any new capability; it only makes an already-authorized concert visible.

Enabling the switches in an Azure Static Web Apps pull request preview

Azure Static Web Apps application settings are scoped per environment, so a fresh preview environment can have these switches configured independently of any other environment, following the same ordering-first-then-catalog sequence documented above. az staticwebapp appsettings set targets one environment with --environment-name, and it merges into that environment's existing settings instead of replacing them, so inherited database settings stay intact. The preview environment has to exist first, so run the commands after the pull request deployment has finished.

bash
# 1. availability first
az staticwebapp appsettings set -n <SWA_NAME> -g <RESOURCE_GROUP> \
  --environment-name <PR_NUMBER> \
  --setting-names DELEGATED_MEMBER_ORDERING_ENABLED=true

# 2. exposure second
az staticwebapp appsettings set -n <SWA_NAME> -g <RESOURCE_GROUP> \
  --environment-name <PR_NUMBER> \
  --setting-names DELEGATED_MEMBER_CATALOG_ENABLED=true

# verify, without printing any other setting value
az staticwebapp appsettings list -n <SWA_NAME> -g <RESOURCE_GROUP> \
  --environment-name <PR_NUMBER> \
  --query "properties.{ordering:DELEGATED_MEMBER_ORDERING_ENABLED,catalog:DELEGATED_MEMBER_CATALOG_ENABLED}"

Never run az staticwebapp appsettings list without the --query filter in a shared terminal or a CI log: it prints every setting value, including database keys. set redacts its own output.

A settings change restarts the environment's managed functions. Allow up to about two minutes and retry the verification query before concluding that something failed. No redeployment is required, because both switches are read from process.env on every call.

VITE_DELEGATED_MEMBER_CATALOG_ENABLED needs no manual step for a pull request preview. As part of the v1.2.0 production release gate, the deployment workflow now builds this flag as true for both pull request builds and pushes to main. A fresh preview or other non-production environment still shows nothing until DELEGATED_MEMBER_CATALOG_ENABLED is also set on that same environment, so the ordering-first-then-catalog sequence documented above still applies to any environment where these switches default to off. Closing the pull request deletes the preview environment and its settings with it.

Existing data compatibility. No migration is required to enable these switches. Delegations created before this rollout do not store the newer approval permission explicitly; an active delegation is treated as carrying it, so existing partner delegations work immediately once the switches are turned on.

Token and database timeouts

REFRESH_TOKEN_TTL_DAYS accepts a positive integer number of days. Unset, non-integer, non-finite, and values below 1 use the 90-day default.

COSMOS_REQUEST_TIMEOUT_MS is converted to a number and passed to the Cosmos SDK only when COSMOS_KEY selects the key-based client, such as the local emulator. If it is unset or does not produce a usable nonzero number, the application leaves the SDK timeout unchanged. Managed Identity clients do not use this application setting.

Magic link emails are sent via Resend. The provider currently offers a free transactional-email allowance for low-volume use. Check Resend pricing for current monthly and daily limits before planning production volume.

VariableDescription
RESEND_API_KEYYour Resend API key
FROM_EMAILSender address, preferably a verified production sender. The code falls back to onboarding@resend.dev
FRONTEND_URLFrontend URL for magic link callback

Development without Resend

  • If RESEND_API_KEY is not set, email delivery is skipped. Development logs contain only a masked summary of the recipient, subject, and sender; they do not contain the login link, verification code, or email body.
  • The normal API response remains generic and does not expose a login link.
  • The API returns devLink and devCode only in guarded E2E test mode. This requires E2E_TEST_MODE=true, a localhost FRONTEND_URL, and a non-production NODE_ENV; the mode skips email delivery and must not be used as production behavior.

Switching email providers

Email logic is isolated in api/src/shared/email.ts. To switch providers, replace the Resend SDK with SendGrid, Azure Communication Services, etc.

Feedback configuration

  • Set VITE_BETA_FEEDBACK=true at frontend build time to show the feedback button and menu item. Any other value, including an unset value, leaves the UI disabled.
  • GITHUB_FEEDBACK_TOKEN is optional. When it is present, the API makes a best-effort attempt to create a GitHub issue after storing feedback in Cosmos DB. Feedback storage remains the primary operation if GitHub issue creation fails.

Database Setup

Run the setup script to create all containers with proper TTL settings:

bash
cd api
npx ts-node scripts/setup-database.ts

This creates:

  • rateLimits container with TTL enabled for auto-cleanup
  • authTokens container with TTL for expired token cleanup
  • All other application containers

Sample local.settings.json

json
{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "COSMOS_ENDPOINT": "https://localhost:8081",
    "COSMOS_KEY": "<your-emulator-key>",
    "COSMOS_DATABASE": "choirtickets",
    "JWT_SECRET": "dev-secret-change-in-production",
    "FRONTEND_URL": "http://localhost:5173"
  }
}

Production

In production, set JWT_SECRET to a strong random value and configure RESEND_API_KEY and FROM_EMAIL for email delivery.


Next: Azure Deployment · See also: Local Development

Built with VitePress