# Security & Demo Mode
This guide covers security best practices and Demo Mode configuration.
# Demo Mode Overview
Demo Mode is a security feature that blocks all mutation operations (create, update, delete) while allowing read-only access.
# When to Use Demo Mode
- ✅ Public demos: Show system without allowing changes
- ✅ Testing environments: Prevent accidental data changes
- ✅ Client previews: Let clients explore without modifying data
# When NOT to Use Demo Mode
- ❌ Production: Should always be
falsein production - ❌ Development: Usually disabled for development
# Enabling/Disabling Demo Mode
# Method 1: Environment Variable
Edit .env file:
# Enable demo mode
DEMO_MODE=true
# Disable demo mode (production)
DEMO_MODE=false
Restart server after changing:
# Development
# Stop server (Ctrl+C) and restart
# Production
pm2 restart cloudpos
# Method 2: Admin Panel (If Available)
- Admin Panel → Settings → Security
- Toggle Demo Mode
- Save changes
# What Demo Mode Blocks
# Blocked Operations
Demo Mode blocks all mutation operations:
- ✅ POST requests (create)
- ✅ PUT requests (update)
- ✅ PATCH requests (partial update)
- ✅ DELETE requests (delete)
- ✅ GET requests to mutation endpoints:
/toggle/sync/assign/approve/activate/deactivate/complete/cancel
# Allowed Operations
Demo Mode allows read-only operations:
- ✅ GET requests (view data)
- ✅ Login/Register (auth endpoints)
- ✅ View subscriptions (read-only)
- ✅ View plans (read-only)
- ✅ Public CMS pages (read-only)
# Error Message
When an operation is blocked, users see:
Demo mode enabled. Changes are disabled.
This appears as:
- Toast notification (warning style)
- 403 Forbidden HTTP status
- Error code:
DEMO_MODE
# Security Best Practices
# 1. Environment Variables
Never commit .env to Git:
- Already in
.gitignore - Use
.env.exampleas template
Use strong secrets:
# Generate JWT secret
openssl rand -base64 32
# Generate encryption key
openssl rand -base64 32
Restrict file permissions:
chmod 600 .env
# 2. Database Security
Use dedicated database user:
CREATE USER 'cloudpos'@'localhost' IDENTIFIED BY 'STRONG_PASSWORD';
GRANT ALL PRIVILEGES ON cloudpos.* TO 'cloudpos'@'localhost';
FLUSH PRIVILEGES;
Don't use root user in production.
Regular backups:
# Daily backup
mysqldump -u cloudpos -p cloudpos > backup_$(date +%Y%m%d).sql
# 3. SSL/HTTPS
Always use HTTPS in production:
- Required for secure authentication
- Required for Stripe webhooks
- Use Let's Encrypt (free SSL)
Configure Nginx:
server {
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# ... rest of config
}
# 4. Password Security
Strong password requirements:
- Minimum 8 characters
- At least one uppercase letter
- At least one lowercase letter
- At least one number
Change default passwords:
- Admin:
admin@cloudpos.com/admin123→ Change immediately - Test users:
admin@acme.com/password123→ Change in production
Password hashing:
- Passwords are hashed with bcrypt (automatic)
- Never store plain text passwords
# 5. JWT Tokens
Use strong secrets:
- Minimum 32 characters
- Generate with:
openssl rand -base64 32 - Different secrets for access and refresh tokens
Token expiry:
- Access tokens: 15 minutes (short-lived)
- Refresh tokens: 7 days (longer-lived)
Token storage:
- Stored in
localStorageorsessionStorage - Automatically refreshed before expiry
# 6. CORS Configuration
Restrict CORS origins:
# Development
CORS_ORIGIN=http://localhost:5173
# Production (single domain)
CORS_ORIGIN=https://yourdomain.com
# Production (multiple domains)
# Configure in server code if needed
Never use: CORS_ORIGIN=* in production
# 7. Rate Limiting
CloudPOS includes rate limiting to prevent abuse:
- API endpoints: Limited requests per minute
- Authentication: Stricter limits on login/register
- Automatic: Enabled by default
# 8. Input Validation
All API endpoints use:
- Validation pipes: Automatic DTO validation
- Type checking: TypeScript types
- SQL injection protection: Prisma ORM (parameterized queries)
- XSS protection: Input sanitization
# 9. File Upload Security
Restrict file types:
- Only allow specific file types (images, PDFs)
- Validate file extensions
- Check MIME types
Limit file size:
# Nginx config
client_max_body_size 10M;
Store uploads securely:
- Outside web root (if possible)
- Restrict access permissions
- Scan for malware (optional)
# 10. Admin Panel Security
Limit admin access:
- Only create admin users when needed
- Use role-based permissions
- Audit admin actions (if audit logging enabled)
Strong admin passwords:
- Use password manager
- Enable 2FA if available
- Rotate passwords periodically
# Security Checklist
# Pre-Launch Security
- [ ] Change all default passwords
- [ ] Generate strong JWT secrets
- [ ] Generate strong encryption key
- [ ] Use dedicated database user (not root)
- [ ] Enable HTTPS/SSL
- [ ] Configure CORS properly
- [ ] Set
DEMO_MODE=falsein production - [ ] Restrict file permissions (
.env, uploads) - [ ] Enable firewall (only allow 80, 443, 22)
- [ ] Set up regular database backups
- [ ] Monitor error logs
- [ ] Review admin user access
# Ongoing Security
- [ ] Keep dependencies updated
- [ ] Monitor security advisories
- [ ] Review access logs regularly
- [ ] Rotate secrets periodically (90 days)
- [ ] Test backups regularly
- [ ] Update SSL certificates (auto-renewal)
- [ ] Review and remove unused admin users
# Troubleshooting
# Demo Mode Not Working
Issue: Changes still allowed when DEMO_MODE=true
Solutions:
Verify environment variable:
# Check .env file cat .env | grep DEMO_MODERestart server:
# Development: Stop and restart # Production: pm2 restart cloudposCheck server logs:
pm2 logs cloudpos | grep -i demo
# Can't Disable Demo Mode
Issue: Demo mode stays enabled
Solutions:
Check
.envfile:- Must be
DEMO_MODE=false(notFalse,FALSE, or0) - No quotes around value
- Must be
Clear environment cache:
- Restart server completely
- Clear PM2 cache:
pm2 delete cloudpos && pm2 start ecosystem.config.js
# Security Warnings
Issue: Browser shows security warnings
Solutions:
Mixed content (HTTP/HTTPS):
- Ensure all resources use HTTPS
- Check API calls use HTTPS
- Update
VITE_API_URLto use HTTPS
Invalid SSL certificate:
- Renew SSL certificate
- Check certificate expiry
- Verify domain matches certificate
Next: See Troubleshooting for common issues and solutions.