# Environment Configuration
All environment variables are stored in a single .env file at the project root. Both the client and server read from this file.
# File Location
CloudPOS/
├── .env ← Environment file (create this)
├── .env.example ← Template (if exists)
├── server/
└── client/
# Environment Variables Reference
# Server Configuration
| Variable | Description | Example | Required |
|---|---|---|---|
NODE_ENV | Environment mode | development or production | Yes |
PORT | API server port | 3000 | Yes |
# Database Configuration
| Variable | Description | Example | Required |
|---|---|---|---|
DATABASE_URL | MySQL connection string | mysql://user:password@localhost:3306/cloudpos | Yes |
Format: mysql://USERNAME:PASSWORD@HOST:PORT/DATABASE_NAME
Examples:
- Laragon (Windows, no password):
mysql://root:@localhost:3306/cloudpos - MySQL with password:
mysql://root:mypassword@localhost:3306/cloudpos - Remote database:
mysql://user:pass@db.example.com:3306/cloudpos
# JWT Authentication
| Variable | Description | Example | Required |
|---|---|---|---|
JWT_SECRET | Secret key for access tokens (min 32 chars) | your-super-secret-jwt-key-change-in-production-min-32-chars | Yes |
JWT_EXPIRES_IN | Access token expiry | 15m (15 minutes) | Yes |
JWT_REFRESH_SECRET | Secret key for refresh tokens (min 32 chars) | your-super-secret-refresh-token-key-change-in-production-min-32-chars | Yes |
JWT_REFRESH_EXPIRES_IN | Refresh token expiry | 7d (7 days) | Yes |
Generate secure secrets:
# Generate random secret (32+ characters)
openssl rand -base64 32
# CORS & Frontend URLs
| Variable | Description | Example | Required |
|---|---|---|---|
CORS_ORIGIN | Allowed frontend origin | http://localhost:5173 (dev) or https://yourdomain.com (prod) | Yes |
FRONTEND_URL | Frontend URL for email links | http://localhost:5173 (dev) or https://yourdomain.com (prod) | Yes |
# Encryption
| Variable | Description | Example | Required |
|---|---|---|---|
ENCRYPTION_KEY | AES-256-GCM encryption key (32+ chars) | Generate with: openssl rand -base64 32 | Yes |
⚠️ Important: Change this in production! Used to encrypt sensitive data.
# Email Configuration (SMTP)
| Variable | Description | Example | Required |
|---|---|---|---|
SMTP_HOST | SMTP server hostname | smtp.gmail.com | Optional |
SMTP_PORT | SMTP port | 587 (TLS) or 465 (SSL) | Optional |
SMTP_SECURE | Use SSL/TLS | false (for port 587) or true (for port 465) | Optional |
SMTP_USER | SMTP username | your-email@gmail.com | Optional |
SMTP_PASSWORD | SMTP password or app password | your-app-password | Optional |
SMTP_FROM_EMAIL | From email address | noreply@cloudpos.com | Optional |
SMTP_FROM_NAME | From name | CloudPOS | Optional |
Gmail Setup:
- Enable 2-factor authentication
- Generate app password: https://myaccount.google.com/apppasswords
- Use app password in
SMTP_PASSWORD
# Stripe Payment Gateway
| Variable | Description | Example | Required |
|---|---|---|---|
STRIPE_SECRET_KEY | Stripe secret key | sk_test_... (test) or sk_live_... (prod) | Optional |
STRIPE_WEBHOOK_SECRET | Webhook signing secret | whsec_... | Optional |
Note: Stripe configuration can also be done via Admin Panel (recommended). See Payment Gateway.
# Demo Mode
| Variable | Description | Example | Required |
|---|---|---|---|
DEMO_MODE | Enable demo mode (blocks mutations) | false (prod) or true (demo) | Optional |
When enabled: Blocks all POST, PUT, PATCH, DELETE requests. See Security & Demo Mode.
# Client Configuration (Vite)
Important: Vite only loads variables prefixed with VITE_ for security.
| Variable | Description | Example | Required |
|---|---|---|---|
VITE_API_URL | API base URL | http://localhost:3000/api (dev) or https://yourdomain.com/api (prod) | Yes |
VITE_APP_NAME | Application name | CloudPOS | Optional |
VITE_APP_VERSION | Application version | 1.0.0 | Optional |
# Complete .env Example
# Development
# Server
NODE_ENV=development
PORT=3000
# Database
DATABASE_URL="mysql://root:@localhost:3306/cloudpos"
# JWT
JWT_SECRET=dev-jwt-secret-key-min-32-characters-long-change-in-production
JWT_EXPIRES_IN=15m
JWT_REFRESH_SECRET=dev-refresh-secret-key-min-32-characters-long-change-in-production
JWT_REFRESH_EXPIRES_IN=7d
# CORS & Frontend
CORS_ORIGIN=http://localhost:5173
FRONTEND_URL=http://localhost:5173
# Encryption
ENCRYPTION_KEY=dev-encryption-key-change-in-production-use-strong-random-string
# Email (Optional)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-app-password
SMTP_FROM_EMAIL=noreply@cloudpos.com
SMTP_FROM_NAME=CloudPOS
# Stripe (Optional)
STRIPE_SECRET_KEY=sk_test_your_stripe_secret_key_here
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret_here
# Demo Mode
DEMO_MODE=false
# Client (Vite)
VITE_API_URL=http://localhost:3000/api
VITE_APP_NAME=CloudPOS
VITE_APP_VERSION=1.0.0
# Production
# Server
NODE_ENV=production
PORT=3000
# Database
DATABASE_URL="mysql://cloudpos:STRONG_PASSWORD@localhost:3306/cloudpos"
# JWT (Generate strong secrets!)
JWT_SECRET=GENERATE_STRONG_SECRET_MIN_32_CHARS_USE_OPENSSL_RAND_BASE64_32
JWT_EXPIRES_IN=15m
JWT_REFRESH_SECRET=GENERATE_STRONG_SECRET_MIN_32_CHARS_USE_OPENSSL_RAND_BASE64_32
JWT_REFRESH_EXPIRES_IN=7d
# CORS & Frontend
CORS_ORIGIN=https://yourdomain.com
FRONTEND_URL=https://yourdomain.com
# Encryption (Generate: openssl rand -base64 32)
ENCRYPTION_KEY=GENERATE_STRONG_ENCRYPTION_KEY_32_CHARS_MIN
# Email
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=noreply@yourdomain.com
SMTP_PASSWORD=your-app-password
SMTP_FROM_EMAIL=noreply@yourdomain.com
SMTP_FROM_NAME=CloudPOS
# Stripe
STRIPE_SECRET_KEY=sk_live_your_production_stripe_secret_key
STRIPE_WEBHOOK_SECRET=whsec_your_production_webhook_secret
# Demo Mode
DEMO_MODE=false
# Client (Vite)
VITE_API_URL=https://yourdomain.com/api
VITE_APP_NAME=CloudPOS
VITE_APP_VERSION=1.0.0
# How to Set Environment Variables
# 1. Create .env File
# From project root
cp .env.example .env # If .env.example exists
# Or create manually
nano .env
# 2. Edit Variables
nano .env
# Add or modify variables
# Save: Ctrl+O, Enter, Ctrl+X
# 3. Restart Services
After changing .env:
# Development
# Stop servers (Ctrl+C) and restart
# Production
pm2 restart cloudpos
# Security Best Practices
✅ Never commit
.envto Git- Already in
.gitignore - Use
.env.exampleas template
- Already in
✅ Use strong secrets in production
# Generate JWT secrets openssl rand -base64 32 # Generate encryption key openssl rand -base64 32✅ Restrict file permissions
chmod 600 .env✅ Use different secrets for production
- Never use development secrets in production
- Generate new secrets for each environment
✅ Rotate secrets periodically
- Change JWT secrets every 90 days
- Change encryption key if compromised
# Multi-Environment Setup
# Development
- File:
.env.development(optional) - Load: Automatically by NestJS/Vite
# Production
- File:
.env.production(optional) - Load: Automatically by NestJS/Vite
# Staging
- File:
.env.staging(optional) - Load: Set
NODE_ENV=staging
# Troubleshooting
# Variables Not Loading
Issue: Environment variables not being read
Solutions:
- Check file location:
.envmust be in project root - Check variable names: Vite variables must start with
VITE_ - Restart servers after changes
- Check for typos in variable names
# Database Connection Fails
Issue: DATABASE_URL not working
Solutions:
- Test connection string format
- Verify MySQL is running
- Check credentials
- Test with:
mysql -u USER -p -h HOST DATABASE
# CORS Errors
Issue: Frontend can't connect to API
Solutions:
- Check
CORS_ORIGINmatches frontend URL exactly - Include protocol:
http://orhttps:// - No trailing slash
- Restart API server after changes
Next: See Database Setup for database configuration details.