Environment Variables
This document lists the main environment variables used by the system.
Do not commit real .env files or secrets to GitHub.
Backend Variables
Backend folder:
codes/Backend
Server
| Variable | Purpose |
|---|---|
NODE_ENV |
development locally, production on Render |
PORT |
API server port. Render commonly uses 10000 |
Database
| Variable | Purpose |
|---|---|
DB_HOST |
MySQL host |
DB_PORT |
MySQL port |
DB_USER |
MySQL username |
DB_PASSWORD |
MySQL password |
DB_NAME |
MySQL database name |
DB_SSL |
Set true for Aiven |
DB_SSL_REJECT_UNAUTHORIZED |
Set true for Aiven |
DB_SSL_CA |
Aiven CA certificate |
First Admin
These are used by admin setup scripts:
| Variable | Purpose |
|---|---|
SEED_ADMIN_NAME |
Initial admin display name |
SEED_ADMIN_EMAIL |
Initial admin email |
SEED_ADMIN_DEPARTMENT |
Initial admin department |
SEED_ADMIN_PASSWORD |
Initial admin password |
Authentication
| Variable | Purpose |
|---|---|
JWT_SECRET |
Long random JWT secret |
JWT_REFRESH_SECRET |
Long random refresh-token secret |
JWT_EXPIRE |
Access token lifetime, for example 24h |
JWT_REFRESH_EXPIRE |
Refresh token lifetime, for example 7d |
SESSION_TIMEOUT_SECONDS |
Idle timeout, for example 3600 |
GOOGLE_CLIENT_ID |
Google OAuth web client ID; the backend accepts a comma-separated list of allowed client IDs, while the frontend uses one client ID |
Audit Log Retention
| Variable | Typical Value |
|---|---|
AUDIT_LOG_RETENTION_ENABLED |
true |
AUDIT_LOG_RETENTION_DAYS |
180 |
AUDIT_LOG_CLEANUP_INTERVAL_HOURS |
24 |
AUDIT_LOG_CLEANUP_BATCH_SIZE |
5000 |
AUDIT_LOG_ARCHIVE_BEFORE_DELETE |
false |
By default, the retention job runs every 24 hours and deletes audit_logs rows older than 180 days in batches of 5,000. When AUDIT_LOG_ARCHIVE_BEFORE_DELETE=true, each batch is copied to the audit_logs_archive table before the original rows are deleted. The archive table is created automatically when archiving is enabled.
Automatic Appointment Reminders
The automatic reminder job starts with the backend. These variables control its polling and concurrency behavior:
| Variable | Default | Purpose |
|---|---|---|
REMINDER_AUTO_SCAN_MS |
10000 |
Interval between scans for upcoming scheduled visits |
REMINDER_AUTO_WINDOW_HOURS |
48 |
How far ahead to search for appointments |
REMINDER_MAX_CONCURRENT |
3 |
Maximum reminder jobs processed concurrently |
For local simulation, set EMAIL_SIMULATION=true and leave the SMTP connection variables unset. With the current implementation, a complete SMTP configuration takes precedence and sends real email even when EMAIL_SIMULATION=true. Simulated reminders are still recorded as processed.
Uploads
| Variable | Default | Purpose |
|---|---|---|
UPLOAD_DIR |
./src/uploads |
Temporary/local upload folder |
MAX_FILE_SIZE |
10485760 |
Maximum upload size in bytes (10 MiB by default) |
ALLOWED_FILE_TYPES |
* |
Comma-separated allowed upload extensions; * permits all extensions |
Local development can use:
UPLOAD_DIR=./src/uploads
Production with Cloudflare R2 should use:
UPLOAD_DIR=/tmp/uploads
Cloudflare R2
FILE_STORAGE_PROVIDER=r2
R2_ENDPOINT=https://ACCOUNT_ID.r2.cloudflarestorage.com
R2_BUCKET=orthoflow-documents
R2_ACCESS_KEY_ID=your_r2_access_key_id
R2_SECRET_ACCESS_KEY=your_r2_secret_access_key
R2_REGION=auto
R2_FORCE_PATH_STYLE=true
Alternative:
R2_ACCOUNT_ID=your_cloudflare_account_id
If R2_ENDPOINT is set, it is used directly.
For another S3-compatible provider, use FILE_STORAGE_PROVIDER=s3 and the corresponding S3_ENDPOINT, S3_BUCKET, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_REGION, and S3_FORCE_PATH_STYLE variables. When both naming schemes are present, the S3_* value takes precedence over the matching R2_* value.
SMTP2GO Email
EMAIL_SIMULATION controls what happens only when a complete SMTP transport is unavailable: true logs a simulated email, while false raises a configuration error. It does not override a complete SMTP configuration.
EMAIL_SIMULATION=false
SMTP_HOST=mail.smtp2go.com
SMTP_PORT=2525
SMTP_SECURE=false
SMTP_USER=your_smtp2go_smtp_username
SMTP_PASS=your_smtp2go_smtp_password
SMTP_FROM=no-reply@dental.pdn.ac.lk
SMTP_USER and SMTP_PASS must be SMTP2GO SMTP credentials, not the SMTP2GO web login password.
Brevo Email
EMAIL_SIMULATION=false
SMTP_HOST=smtp-relay.brevo.com
SMTP_PORT=2525
SMTP_SECURE=false
SMTP_USER=your_brevo_smtp_login
SMTP_PASS=your_brevo_smtp_key
SMTP_FROM=no-reply@dental.pdn.ac.lk
Brevo may show port 587. If Render times out on 587, use 2525 with SMTP_SECURE=false. If needed, try:
SMTP_PORT=465
SMTP_SECURE=true
SMTP_PASS must be a Brevo SMTP key, not a Brevo API key and not the Brevo web login password.
Rate Limiting and CORS
| Variable | Purpose |
|---|---|
RATE_LIMIT_WINDOW_MS |
Login rate-limit window in milliseconds; defaults to 900000 (15 minutes) |
RATE_LIMIT_MAX_REQUESTS |
Maximum login attempts per IP per window; defaults to 5 |
CORS_ORIGIN |
Frontend URL allowed to call backend |
The rate limiter applies to POST /api/auth/login and POST /api/auth/google; it does not currently apply to every API route.
Production example:
CORS_ORIGIN=https://orthoflow-frontend.onrender.com
Frontend Variables
Frontend folder:
codes/Frontend
VITE_API_BASE_URL=https://your-backend-service.onrender.com
VITE_GOOGLE_CLIENT_ID=your_google_client_id.apps.googleusercontent.com
Local development:
VITE_API_BASE_URL=http://localhost:3000
VITE_GOOGLE_CLIENT_ID=your_google_client_id.apps.googleusercontent.com