Skip to content

Environment Variables

These are build-time variables injected by GitHub Actions. They are embedded into the compiled JavaScript bundle by Vite — they are not secret from end users. Do not put secrets in VITE_* variables.

VariableRequiredDescription
VITE_API_BASE_URLYesBase URL of the Main API for this environment (e.g. https://staging-arc.semalink.africa)
VITE_CF_ACCESS_CLIENT_IDYesCloudflare Access service token Client ID. Attached as CF-Access-Client-Id header on every API request
VITE_CF_ACCESS_CLIENT_SECRETYesCloudflare Access service token Client Secret. Attached as CF-Access-Client-Secret header on every API request
VITE_ENVYesEnvironment name: staging, test, or production

Per-environment values

VariableStagingTestProduction
VITE_API_BASE_URLhttps://staging-arc.semalink.africahttps://test-arc.semalink.africahttps://arc.semalink.africa
VITE_ENVstagingtestproduction
VITE_CF_ACCESS_CLIENT_IDStaging service tokenTest service tokenProd service token

Build-time variables injected by GitHub Actions. Same rules as the customer app — these are embedded in the JS bundle and visible to users. Do not put secrets here.

VariableRequiredDescription
VITE_API_BASE_URLYesBase URL of the Main API (e.g. https://staging-arc.semalink.africa)
VITE_ENVYesEnvironment name: staging or production

Per-environment values

VariableStagingProduction
VITE_API_BASE_URLhttps://staging-arc.semalink.africahttps://arc.semalink.africa
VITE_ENVstagingproduction

The admin portal does not use Cloudflare Zero Trust service tokens in the build — Zero Trust is enforced at the network level (CF Access policy on the domain), not via request headers from the app.


Runtime variables loaded by the server process. Validated on startup via Zod — the server will not start if required variables are missing or malformed.

Core

VariableRequiredDefaultDescription
PORTNo3000HTTP port to listen on
NODE_ENVNodevelopmentdevelopment, test, or production
API_VERSIONNov1API path prefix (e.g. /api/v1)

Database

VariableRequiredDescription
DATABASE_URLYesPostgreSQL connection string (postgresql://user:pass@host:port/db)

Cache

VariableRequiredDescription
REDIS_URLYesRedis connection string (redis://host:6379)

Message Queue

VariableRequiredDescription
RABBITMQ_URLYesRabbitMQ AMQP connection string (amqp://user:pass@host:5672)

JWT Authentication

VariableRequiredDefaultDescription
JWT_SECRETYesSecret for signing customer access tokens. Min 32 characters
JWT_REFRESH_SECRETYesSecret for signing customer refresh tokens. Min 32 characters
JWT_EXPIRES_INNo15mCustomer access token lifespan. Short-lived by design
JWT_REFRESH_EXPIRES_INNo7dCustomer refresh token lifespan
ADMIN_JWT_SECRETYesSecret for signing admin staff access tokens. Separate Fastify JWT namespace — admin tokens cannot authenticate on customer routes and vice versa
ADMIN_JWT_EXPIRES_INNo8hAdmin access token lifespan

App URLs

VariableRequiredDefaultDescription
APP_URLNohttp://localhost:5173Frontend URL. Used in email links (verify email, reset password, magic link)
API_URLNohttp://localhost:3000API URL. Used in OAuth callback URL construction

Email (Mailgun)

VariableRequiredDescription
MAILGUN_API_KEYYes (prod)Mailgun API key
MAILGUN_DOMAINYes (prod)Sending domain (e.g. mg.semalink.africa)
MAILGUN_FROMYes (prod)From address (e.g. Sema Link <noreply@semalink.africa>)

In development, if Mailgun is not configured, emails are logged to stdout instead.

OAuth Providers

All optional. If a provider's vars are absent, that provider's login button is hidden in the frontend.

VariableProviderNotes
GOOGLE_CLIENT_IDGoogleFrom Google Cloud Console OAuth 2.0 client
GOOGLE_CLIENT_SECRETGoogle
MICROSOFT_CLIENT_IDMicrosoftAzure App Registration client ID
MICROSOFT_CLIENT_SECRETMicrosoft
MICROSOFT_TENANTMicrosoftAzure tenant ID (or common for multi-tenant)
GITHUB_CLIENT_IDGitHubFrom GitHub Developer Settings
GITHUB_CLIENT_SECRETGitHub
APPLE_CLIENT_IDAppleServices ID from Apple Developer portal
APPLE_TEAM_IDApple10-character team ID
APPLE_KEY_IDAppleKey ID of the Sign in with Apple private key
APPLE_PRIVATE_KEYAppleContents of the .p8 private key file (newlines escaped)

Cloudflare R2 (Object Storage)

Used for profile photo uploads. Optional — photo upload returns an error if not configured.

VariableDescription
R2_ACCOUNT_IDCloudflare account ID
R2_ACCESS_KEY_IDR2 API token access key ID
R2_SECRET_ACCESS_KEYR2 API token secret
R2_BUCKET_NAMER2 bucket name (e.g. semalink-uploads)
R2_PUBLIC_URLPublic URL base for served files (e.g. https://pub-xxx.r2.dev)

SMS Aggregator (Celcom Africa)

VariableDescription
CELCOM_API_URLCelcom Africa REST API base URL
CELCOM_API_KEYCelcom Africa API authentication key

Internal use only — Sema Link Engineering