Environment Configuration Guide
Overview
The TVL Platform supports multiple deployment scenarios with different development environments and database configurations. This guide covers:
- Development Environment Setup - WSL, DevContainer, and optional AI tools
- Secrets Management - Doppler for secure credential management
- Database Configuration - Docker PostgreSQL vs Remote Supabase
- Migration Strategies - Safe deployment workflows
Quick Links:
- Development Environment Setup - Start here for first-time setup
- Secrets Management with Doppler - Configure credentials
- Database Configurations - Choose your database strategy
- Performance Optimization - Get 10x faster builds
Development Environment Setup
System Requirements
- Operating System: Windows 10/11 with WSL2, macOS, or Linux
- WSL2 (Windows only): Ubuntu 20.04+ or Debian
- Docker Desktop: 4.30+ with WSL2 backend (Windows) or native (macOS/Linux)
- Node.js: 20 LTS (managed via DevContainer)
- IDE: VS Code, Cursor, or compatible editor with DevContainer support
Critical Performance Consideration (Windows + WSL Users)
⚠️ IMPORTANT: Repository location dramatically affects performance on Windows with WSL.
| Repository Location | Performance | Recommendation | 
|---|---|---|
| WSL Filesystem ( ~/projects/) | ✅ 10-20x faster | REQUIRED for development | 
| Windows Filesystem ( /mnt/c/) | ❌ 10-20x slower | ❌ DO NOT USE | 
Performance Impact:
| Operation | Windows FS ( /mnt/c/) | WSL FS ( ~/projects/) | Improvement | 
|---|---|---|---|
| pnpm install | ~8 min | ~45 sec | 10.6x faster | 
| git status | ~2 sec | ~0.1 sec | 20x faster | 
| Hot reload | ~5 sec | ~0.5 sec | 10x faster | 
| TypeScript compile | ~15 sec | ~3 sec | 5x faster | 
Setup Instructions (Windows Only):
# 1. Open WSL terminal (Ubuntu)
wsl
# 2. Create projects directory
cd ~
mkdir -p projects
cd projects
# 3. Clone or move repository
# Option A: Clone fresh
git clone https://github.com/your-org/the-villa-life.git
cd the-villa-life
# Option B: Move existing repository
cp -r /mnt/c/GitHub/the-villa-life ./
cd the-villa-life
# 4. Verify git status
git status  # Should show clean working tree
# 5. Update git safe directory
git config --global --add safe.directory ~/projects/the-villa-life
# 6. Open in VS Code/Cursor from WSL location
code .  # or: cursor .
Verify Performance:
# Test git performance (should be < 0.1 sec)
time git status
# Test pnpm performance (after DevContainer setup)
time pnpm install --frozen-lockfile
# Expected: < 60 seconds
DevContainer Setup
The TVL Platform uses DevContainers for consistent development environments. All developers get:
- ✅ Node.js 20 LTS
- ✅ pnpm 10.19.0
- ✅ PostgreSQL client
- ✅ Git
- ✅ GitHub CLI
- ✅ Shared tool versions (no "works on my machine" issues)
Initial Setup:
- 
Install Prerequisites: # Install Docker Desktop
 # Windows: https://www.docker.com/products/docker-desktop
 # macOS: https://www.docker.com/products/docker-desktop
 # Linux: https://docs.docker.com/engine/install/
 # Install VS Code or Cursor
 # VS Code: https://code.visualstudio.com/
 # Cursor: https://cursor.sh/
 # Install Dev Containers extension
 # In VS Code/Cursor: Ctrl+Shift+X → Search "Dev Containers" → Install
- 
Enable Docker WSL Integration (Windows Only): 1. Open Docker Desktop
 2. Settings → Resources → WSL Integration
 3. Enable: ☑ Ubuntu (or your WSL distro)
 4. Apply & Restart
- 
Open Project in DevContainer: # Method 1: VS Code/Cursor GUI
 # - Open project folder
 # - Press F1
 # - Type: "Dev Containers: Reopen in Container"
 # - Wait for container to build (5-10 minutes first time)
 # Method 2: Command line
 cd ~/projects/the-villa-life # Use WSL path!
 code . # or: cursor .
 # Then: F1 → "Dev Containers: Reopen in Container"
- 
Verify Environment: # Inside DevContainer terminal (Ctrl+`)
 # Check Node.js
 node --version # Expected: v20.x.x
 # Check pnpm
 pnpm --version # Expected: 10.19.0
 # Check git
 git --version # Expected: 2.x.x
 # Check PostgreSQL client
 psql --version # Expected: psql (PostgreSQL) 15.x
 # Check GitHub CLI
 gh --version # Expected: gh version 2.x.x
 # Test database connection
 pnpm psql:status # Expected: Connected to tvl_dev
Optional: Claude Code CLI Setup
What is Claude Code CLI?
Claude Code is an AI-powered development assistant from Anthropic. It's completely optional - the platform works perfectly without it.
When to Install:
- ✅ You want AI assistance for code generation, debugging, or analysis
- ✅ You're comfortable with AI-assisted development
- ✅ You want to leverage Claude's 200K token context window
When to Skip:
- ❌ You prefer traditional development workflows
- ❌ Team policy restricts AI tools
- ❌ You don't have an Anthropic API key or Claude subscription
Installation (Optional):
The Claude Code CLI is pre-installed in the DevContainer via the post-create.sh script. To use it:
- 
Authenticate Claude Code: # Inside DevContainer
 claude login
 # Follow prompts:
 # - Choose authentication method (Claude App or API Key)
 # - Sign in with your Anthropic account
- 
Verify Installation: claude --version
 # Expected: Claude Code CLI version x.x.x
 claude "What is the purpose of the organizations table?"
 # Expected: Claude analyzes your codebase and responds
- 
Update Permissions (Optional): Edit .claude/settings.local.jsonto customize what Claude can access:{
 "permissions": {
 "allow": [
 "Bash(git:*)",
 "Bash(pnpm:*)",
 "Bash(psql:*)",
 "WebSearch"
 ],
 "deny": [
 "Read(**/.env*)",
 "Edit(**/.env*)"
 ]
 }
 }
Using Claude Code (if installed):
# Inside DevContainer terminal
claude "Help me implement booking cancellation feature"
claude "Review the database schema for RLS policies"
claude "Run tests and fix any failures"
# From outside container (using alias)
# Add to ~/.bashrc or ~/.zshrc:
alias claude-dev='docker compose -f ~/projects/the-villa-life/.devcontainer/docker-compose.yml exec app claude'
# Then use from anywhere:
claude-dev "What's the current status of migrations?"
Note: All project documentation (CLAUDE.md, Cursor rules, ADRs) works whether or not you use Claude Code CLI. It's designed to help human developers too!
Secrets Management with Doppler
⚠️ NEVER commit secrets to version control.
The TVL Platform uses Doppler for centralized secrets management across all environments.
Why Doppler?
| Feature | Without Doppler | With Doppler | 
|---|---|---|
| Setup Time | 2+ hours (manual .env files) | 10 minutes | 
| Secret Rotation | 2+ hours (update everywhere) | 10 minutes (auto-sync) | 
| Team Onboarding | 30+ min (sharing credentials) | 5 minutes (invite to project) | 
| Security | ❌ Secrets in Slack/email | ✅ SOC 2 Type II certified | 
| Audit Trail | ❌ No visibility | ✅ Who accessed what, when | 
| Environments | Manual management | Automatic sync | 
Doppler Setup (Quick Reference)
📖 For detailed setup instructions, see: Doppler Quickstart Guide
Quick Setup:
- 
Install Doppler CLI: # macOS
 brew install dopplerhq/cli/doppler
 # Windows (WSL) / Linux
 curl -Ls https://cli.doppler.com/install.sh | sudo sh
 # Verify installation
 doppler --version
- 
Authenticate: doppler login
 # Opens browser → Sign in with your Doppler account
- 
Setup Project: cd ~/projects/the-villa-life
 # Non-interactive setup (recommended)
 doppler setup --project tvl-mvp-v0 --config dev
 # Verify configuration
 doppler configure get project config --plain
 # Should show: tvl-mvp-v0 and dev
- 
Add Secrets (First-Time Setup): # Add all local development secrets
 doppler secrets set \
 DATABASE_ENVIRONMENT="local" \
 DATABASE_URL="postgresql://tvl_user:tvl_password@postgres:5432/tvl_dev" \
 DATABASE_TEST_URL="postgresql://tvl_user:tvl_password@postgres:5432/tvl_test" \
 NODE_ENV="development"
 # Skip if secrets already exist in Doppler
- 
Download Secrets to .env.local:# Download secrets to .env.local
 doppler secrets download --no-file --format env > .env.local
 # Verify
 cat .env.local | grep DATABASE_URL
 # Should show: DATABASE_URL=postgresql://tvl_user:tvl_password@postgres:5432/tvl_dev
Doppler Environment Structure
tvl-mvp-v0/
├── dev             ← Local development (Docker PostgreSQL)
├── dev_personal    ← Personal development configuration
├── stg             ← Staging environment (Supabase)
└── prd             ← Production environment (Supabase)
Key Secrets Managed by Doppler
| Secret Name | Environments | Used For | 
|---|---|---|
| DATABASE_URL | All | PostgreSQL connection string | 
| DATABASE_TEST_URL | development | Test database connection | 
| SUPABASE_URL | integration, staging, production | Supabase project URL | 
| SUPABASE_ANON_KEY | integration, staging, production | Client-side API calls | 
| SUPABASE_SERVICE_ROLE_KEY | integration, staging, production | Server-side admin operations | 
| LINEAR_API_KEY | All | Linear integration | 
| HOSTAWAY_CLIENT_ID | All | Hostaway PMS integration | 
| HOSTAWAY_CLIENT_SECRET | All | Hostaway authentication | 
| STRIPE_SECRET_KEY | All (V1.0+) | Payment processing | 
Developer Workflows
Daily Development:
# Sync latest secrets (if team updated)
doppler secrets download --no-file --format env > .env.local
# Rebuild DevContainer to load new secrets
# F1 → Dev Containers: Rebuild Container
# Or restart without rebuild:
docker compose -f .devcontainer/docker-compose.yml restart app
Switching Environments:
# Switch to staging (Supabase staging)
doppler setup --project tvl-mvp-v0 --config stg
doppler secrets download --no-file --format env > .env.local
# Switch back to local development
doppler setup --project tvl-mvp-v0 --config dev
doppler secrets download --no-file --format env > .env.local
# Restart container to load new environment
# F1 → Dev Containers: Rebuild Container
Adding New Secrets:
# Add secret via CLI
doppler secrets set NEW_API_KEY=value123 --config dev
# Or use Doppler Dashboard
# https://dashboard.doppler.com/ → tvl-mvp-v0 → dev
# Click "Add Secret"
Rotating Secrets:
# Update secret in Doppler
doppler secrets set STRIPE_SECRET_KEY=sk_live_NEW_KEY --config prd
# Notify team (Slack/Linear)
# "Secrets rotated. Run: doppler secrets download > .env.local && rebuild"
# All developers auto-sync on next rebuild (10 min vs 2 hours manually)
Security Best Practices
- ✅ Always use Doppler for secrets (don't create .env files manually)
- ✅ Add .env.localto.gitignore(already done)
- ✅ Rotate secrets quarterly or when team members leave
- ✅ Use environment-specific configs (don't use production secrets in development)
- ✅ Review Doppler audit logs monthly (Settings → Audit Log)
- ❌ Never share secrets via Slack/email (invite to Doppler project instead)
- ❌ Never commit .env*files to version control
Doppler in CI/CD
GitHub Actions Integration:
# .github/workflows/deploy-staging.yml
name: Deploy to Staging
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Doppler CLI
        uses: dopplerhq/cli-action@v3
      - name: Inject Doppler secrets
        run: doppler secrets download --no-file --format env > .env.staging
        env:
          DOPPLER_TOKEN: ${{ secrets.DOPPLER_STAGING_TOKEN }}
      - name: Run migrations
        run: pnpm db:migrate
        env:
          DATABASE_URL: ${{ secrets.DOPPLER_DATABASE_URL }}
Setup Doppler Service Tokens:
- Go to https://dashboard.doppler.com/ → tvl-mvp-v0 → stg
- Settings → Service Tokens → Generate
- Copy token
- GitHub repo → Settings → Secrets → New repository secret
- Name: DOPPLER_STAGING_TOKEN, Value:dp.st.xxx
Database Configurations
Decision Matrix: Which Database Should You Use?
| Scenario | Database | Why | 
|---|---|---|
| Local Development | Docker PostgreSQL | ✅ Fastest iteration, full control, RLS testing | 
| Integration Testing | Docker PostgreSQL OR Remote Staging | ✅ Isolated tests, consistent CI/CD | 
| Feature Branch Testing | Remote Staging | ✅ Test with production-like data | 
| Staging Environment | Remote Supabase | ✅ Production parity, team collaboration | 
| Production | Remote Supabase | ✅ Managed service, scalability, backups | 
Environment Configurations
1. Local Development (Docker PostgreSQL) - RECOMMENDED
When to use:
- Daily development work
- Testing database migrations
- Testing RLS policies
- Unit and integration tests
- Need to reset/destroy database frequently
Pros:
- ✅ Fast: Sub-millisecond latency
- ✅ Isolated: Your own database instance
- ✅ Safe: Can reset without affecting others
- ✅ Offline: Works without internet
- ✅ Free: No API limits or costs
- ✅ RLS Testing: Full control for policy testing
Cons:
- ❌ Doesn't test against production Supabase features
- ❌ Requires Docker Desktop
Setup:
# 1. Ensure Docker Desktop is running
# 2. Start PostgreSQL in dev container
# Open in VS Code -> "Reopen in Container"
# OR manually:
docker compose -f .devcontainer/docker-compose.yml up -d
# 3. Environment file is already set (.env.local)
# Uses: postgresql://tvl_user:tvl_password@localhost:5432/tvl_dev
# 4. Run migrations
pnpm db:setup
pnpm db:migrate
pnpm db:seed
Configuration (.env.local):
NODE_ENV=development
DATABASE_URL=postgresql://tvl_user:tvl_password@localhost:5432/tvl_dev
DATABASE_TEST_URL=postgresql://tvl_user:tvl_password@localhost:5432/tvl_test
2. Local Development (Remote Supabase)
When to use:
- Testing Supabase-specific features (Auth, Storage, Realtime)
- Need to share data with team members
- Testing production-like scenarios
- Don't want to run Docker locally
Pros:
- ✅ Production Parity: Exact same as staging/production
- ✅ Supabase Features: Test Auth, Storage, Realtime
- ✅ No Docker: Lighter local setup
Cons:
- ❌ Slower: Network latency (100-500ms vs <1ms)
- ❌ Shared: Can conflict with other developers
- ❌ Rate Limits: Free tier has limits
- ❌ Internet Required: Can't work offline
- ❌ Destructive Testing: Risky to reset database
Setup:
# 1. Create a Supabase project (if not exists)
# Visit: https://app.supabase.com/
# 2. Get connection details
# Project Settings -> Database -> Connection string (URI)
# 3. Create .env.local.remote
cp .env.example .env.local.remote
# 4. Update .env.local.remote with Supabase credentials
DATABASE_URL=postgresql://postgres:[YOUR-PASSWORD]@[PROJECT-REF].supabase.co:5432/postgres
SUPABASE_URL=https://[PROJECT-REF].supabase.co
SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# 5. Use this environment
mv .env.local .env.local.docker  # Backup Docker config
mv .env.local.remote .env.local
# 6. Run migrations (CAUTION: affects shared database)
pnpm db:migrate
# Switch back when needed
mv .env.local .env.local.remote
mv .env.local.docker .env.local
Best Practices:
- ⚠️ Create separate Supabase project for local dev (don't share staging)
- ⚠️ Never run migrations against shared staging from local
- ⚠️ Use read-only queries when possible
- ⚠️ Coordinate with team before destructive operations
3. Staging Environment
When to use:
- Pre-production testing
- QA and UAT
- Integration testing with external APIs
- Demo environments
Configuration:
# .env.staging (DO NOT COMMIT)
NODE_ENV=staging
# Supabase Staging Project
DATABASE_URL=postgresql://postgres:[PASSWORD]@[STAGING-REF].supabase.co:5432/postgres
SUPABASE_URL=https://[STAGING-REF].supabase.co
SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# Staging API endpoints
API_BASE_URL=https://api-staging.thevillalife.com
NEXT_PUBLIC_APP_URL=https://staging.thevillalife.com
# External integrations (sandbox/test accounts)
HOSTAWAY_CLIENT_ID=staging-client-id
STRIPE_SECRET_KEY=sk_test_...
Deployment:
- Use GitHub Actions with environment secrets
- Never commit .env.stagingto version control
- Use environment variables in deployment platform
4. Production Environment
When to use:
- Live production traffic
- Real customer data
- Mission-critical operations
Configuration:
# .env.production (NEVER COMMIT - use secrets manager)
NODE_ENV=production
# Supabase Production Project
DATABASE_URL=postgresql://postgres:[PASSWORD]@[PROD-REF].supabase.co:5432/postgres
SUPABASE_URL=https://[PROD-REF].supabase.co
SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# Production API endpoints
API_BASE_URL=https://api.thevillalife.com
NEXT_PUBLIC_APP_URL=https://app.thevillalife.com
# Production integrations
HOSTAWAY_CLIENT_ID=production-client-id
STRIPE_SECRET_KEY=sk_live_...
# Observability
SENTRY_DSN=https://...@sentry.io/...
SENTRY_ENVIRONMENT=production
Security Requirements:
- 🔒 Use secrets manager (GitHub Secrets, AWS Secrets Manager, Vercel Env Vars)
- 🔒 Enable Supabase RLS on all tables
- 🔒 Rotate credentials regularly
- 🔒 Enable audit logging
- 🔒 Use connection pooling (Supabase includes PgBouncer)
Database Migration Strategy
Local Development (Docker)
# Create migration locally
pnpm db:migrate:create add_new_feature
# Test migration (safe - local database)
pnpm db:migrate
# Test rollback
pnpm db:rollback
# Reset and re-run all migrations
pnpm db:reset
Staging/Production (Supabase)
# NEVER run migrations directly from local machine
# Use CI/CD pipeline instead
# GitHub Actions example:
# 1. PR merged to main branch
# 2. CI runs migrations on staging
# 3. Manual approval required
# 4. CI runs migrations on production
Migration Safety Rules:
- ✅ Test migrations locally first (Docker PostgreSQL)
- ✅ Review migration SQL carefully
- ✅ Use transactions (already handled by migrator)
- ✅ Test rollback scripts
- ✅ Apply to staging before production
- ✅ Backup production before migrations
- ❌ NEVER run migrations manually on production
- ❌ NEVER skip testing locally
Row-Level Security (RLS) Testing
Critical: Always test RLS policies with local Docker PostgreSQL.
Why local testing is required:
- Supabase RLS can't be easily bypassed for testing
- Need to simulate different user contexts
- Destructive tests (creating/deleting orgs) are unsafe on remote
Testing workflow:
# 1. Use local Docker database
# Ensure .env.local points to localhost
# 2. Run RLS tests
pnpm test:rls
# 3. Tests automatically:
#    - Create isolated test organizations
#    - Set app.current_org_id session variable
#    - Verify RLS policies enforce tenant isolation
#    - Clean up test data
# Example test:
test('Users can only see their organization', async () => {
  const org1 = await createTestOrg('Org 1');
  const org2 = await createTestOrg('Org 2');
  
  // Set session to org1
  await pool.query(`SET app.current_org_id = '${org1.id}'`);
  
  // Should only see org1 data
  const result = await pool.query('SELECT * FROM organizations');
  expect(result.rows).toHaveLength(1);
  expect(result.rows[0].id).toBe(org1.id);
});
Switching Between Environments
Recommended: Use Doppler for environment switching (see Secrets Management).
With Doppler (Recommended)
# Switch to local development
doppler setup --project tvl-mvp-v0 --config dev
doppler secrets download --no-file --format env > .env.local
# Switch to personal development
doppler setup --project tvl-mvp-v0 --config dev_personal
doppler secrets download --no-file --format env > .env.local
# Switch to staging (for testing only, not regular development)
doppler setup --project tvl-mvp-v0 --config stg
doppler secrets download --no-file --format env > .env.local
# Restart container to load new environment
docker compose -f .devcontainer/docker-compose.yml restart app
# Or in VS Code: F1 → "Dev Containers: Rebuild Container"
Without Doppler (Legacy)
Create scripts/switch-env.sh:
#!/bin/bash
# Switch between environment configurations (legacy method)
ENV=$1
case $ENV in
  local)
    cp .env.local.docker .env.local
    echo "✅ Switched to local Docker PostgreSQL"
    ;;
  remote)
    cp .env.local.remote .env.local
    echo "✅ Switched to remote Supabase"
    ;;
  staging)
    echo "⚠️  Staging environment should only be used in CI/CD"
    echo "⚠️  Consider using Doppler instead: doppler setup --project tvl-mvp-v0 --config stg"
    ;;
  *)
    echo "Usage: ./scripts/switch-env.sh [local|remote]"
    echo ""
    echo "💡 Tip: Use Doppler for easier environment switching:"
    echo "   doppler setup --project tvl-mvp-v0 --config dev"
    exit 1
    ;;
esac
VS Code Tasks
Add to .vscode/tasks.json:
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Switch to Local DB",
      "type": "shell",
      "command": "cp .env.local.docker .env.local",
      "problemMatcher": []
    },
    {
      "label": "Switch to Remote DB",
      "type": "shell",
      "command": "cp .env.local.remote .env.local",
      "problemMatcher": []
    }
  ]
}
Dev Container Configuration
The dev container supports both local and remote databases:
Local Docker PostgreSQL (Default)
// .devcontainer/devcontainer.json
{
  "dockerComposeFile": "docker-compose.yml",
  "service": "app",
  "containerEnv": {
    "DATABASE_URL": "postgresql://tvl_user:tvl_password@postgres:5432/tvl_dev"
  }
}
PostgreSQL runs in a sidecar container, accessible at postgres:5432.
Remote Supabase in Dev Container
// .devcontainer/devcontainer.json (override)
{
  "containerEnv": {
    "DATABASE_URL": "${localEnv:DATABASE_URL}"  // Pass from host
  }
}
Then set DATABASE_URL on your host machine or in .env.local.
Recommendation: Use local Docker by default, remote only when needed.
Cost Considerations
Local Docker PostgreSQL
- Cost: Free ✅
- Performance: Fastest
- Best for: Daily development
Supabase Free Tier
- Database: 500 MB
- Bandwidth: 2 GB
- API Requests: Unlimited
- Best for: Small staging/dev projects
Supabase Pro ($25/month per project)
- Database: 8 GB (+ $0.125/GB)
- Bandwidth: 50 GB (+ $0.09/GB)
- API Requests: Unlimited
- Best for: Staging + Production
Recommended Setup:
- Local Dev: Docker (free)
- Staging: Supabase Pro
- Production: Supabase Pro (separate project)
Total monthly cost: $50/month (Staging + Production)
Troubleshooting
Can't connect to local PostgreSQL
# Check Docker is running
docker ps
# Check PostgreSQL logs
docker logs tvl-postgres
# Verify connection
psql postgresql://tvl_user:tvl_password@localhost:5432/tvl_dev
Can't connect to remote Supabase
# Test connection
psql "postgresql://postgres:[PASSWORD]@[REF].supabase.co:5432/postgres"
# Check network
ping [REF].supabase.co
# Verify credentials in Supabase dashboard
# Settings -> Database -> Connection string
Migrations fail on Supabase
# Common issues:
# 1. RLS is enabled - need to use service role key
# 2. Connection pooling - use port 5432 (direct), not 6543 (pooler)
# 3. SSL required - add ?sslmode=require to connection string
# Correct format:
DATABASE_URL=postgresql://postgres:[PASSWORD]@[REF].supabase.co:5432/postgres?sslmode=require
Dev container using wrong database
# Check environment variables
echo $DATABASE_URL
# Override in dev container
# Edit .devcontainer/devcontainer.json -> containerEnv
Best Practices Summary
✅ DO
- 
Use local Docker for daily development - Fastest iteration
- Safe to break
- RLS testing
 
- 
Test migrations locally first - Always test with Docker
- Test rollbacks
- Verify RLS policies
 
- 
Use Supabase for staging/production - Managed service
- Scalability
- Built-in backups
 
- 
Separate Supabase projects - Local dev (optional)
- Staging
- Production
 
- 
Use environment-specific configs - .env.local(Docker)
- .env.staging(not committed)
- .env.production(secrets manager)
 
❌ DON'T
- 
Don't run migrations manually on production - Use CI/CD only
- Require approvals
- Always backup first
 
- 
Don't share staging database for local dev - Use Docker instead
- Avoid conflicts
- Faster development
 
- 
Don't commit credentials - Use .env.*.localfor Docker
- Use secrets manager for remote
- Add .env.stagingand.env.productionto.gitignore
 
- Use 
- 
Don't test destructive operations on remote - Use local Docker
- Create separate test project if needed
- Coordinate with team
 
Quick Reference
| Task | Environment | Command | 
|---|---|---|
| Daily development | Local Docker | docker compose up -d+.env.local | 
| Test migrations | Local Docker | pnpm db:migrate | 
| Test RLS policies | Local Docker | pnpm test:rls | 
| Feature branch testing | Staging Supabase | Deploy to staging via CI/CD | 
| Production deployment | Production Supabase | Deploy via CI/CD | 
Performance Optimization
Windows + WSL Performance Checklist
If you're experiencing slow performance, verify these settings:
1. Repository Location:
# Check current location
pwd
# ✅ CORRECT: WSL filesystem
/home/<user>/projects/the-villa-life
# ❌ WRONG: Windows filesystem (10-20x slower)
/mnt/c/GitHub/the-villa-life
2. Docker WSL Integration:
# Verify Docker is accessible from WSL
docker ps
# If fails: Docker Desktop → Settings → Resources → WSL Integration
#           Enable Ubuntu → Apply & Restart
3. pnpm Cache Location:
# Inside DevContainer
pnpm store path
# ✅ CORRECT: Container filesystem
/home/vscode/.local/share/pnpm/store
# ❌ WRONG: Mounted from Windows
/mnt/c/Users/...
4. DevContainer Volume Mounts:
# Check container mounts
docker inspect the-villa-life-app-1 | grep -A 5 "Mounts"
# Source should be WSL path, not /mnt/c/
# ✅ CORRECT: "Source": "/home/<user>/projects/the-villa-life"
# ❌ WRONG: "Source": "/mnt/c/GitHub/the-villa-life"
Performance Benchmarks
Run these tests to measure your environment performance:
# Inside DevContainer terminal
# Test 1: pnpm install speed
rm -rf node_modules .pnpm-store
time pnpm install --frozen-lockfile
# Target: < 60 seconds
# Test 2: Git operations
time git status
# Target: < 0.2 seconds
# Test 3: TypeScript compilation
time pnpm exec tsc --noEmit
# Target: < 5 seconds
# Test 4: Hot reload (in separate terminal)
pnpm dev
# Edit a file, save, measure reload time
# Target: < 1 second
Expected Results (WSL FS + DevContainer):
| Operation | Target Time | Slow (needs optimization) | 
|---|---|---|
| pnpm install | < 60 sec | > 2 min | 
| git status | < 0.2 sec | > 1 sec | 
| tsc --noEmit | < 5 sec | > 15 sec | 
| Hot reload | < 1 sec | > 3 sec | 
Troubleshooting Slow Performance
Issue: pnpm install still slow (> 2 minutes)
# Diagnosis
pwd  # Verify you're in WSL filesystem
pnpm store path  # Verify cache location
# Solution 1: Move repository to WSL
cd ~
mkdir -p projects
cp -r /mnt/c/GitHub/the-villa-life ~/projects/
cd ~/projects/the-villa-life
# Solution 2: Clear pnpm cache
pnpm store prune
pnpm install --frozen-lockfile
# Solution 3: Rebuild DevContainer
# F1 → "Dev Containers: Rebuild Container"
Issue: Git operations slow (> 1 second)
# Diagnosis
mount | grep workspace
# Should NOT show /mnt/c/ in source
# Solution: Repository is on Windows filesystem
# Move to WSL (see Solution 1 above)
Issue: Hot reload not working or very slow
# Diagnosis
# Check if file watcher is working
pnpm dev
# Edit a file - watch terminal for reload message
# Solution 1: Increase file watcher limit (Linux/WSL)
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
# Solution 2: Check Next.js dev server logs
# Look for "compiling" messages
# Slow compilation indicates repository on Windows FS
# Solution 3: Ensure DevContainer has enough resources
# Docker Desktop → Settings → Resources
# Memory: 8GB+ recommended
# CPUs: 4+ recommended
WSL Configuration Optimization
Create or edit ~/.wslconfig (Windows home directory):
[wsl2]
# Memory allocation (adjust based on your RAM)
memory=8GB
# CPU cores (adjust based on your CPU)
processors=4
# Swap file
swap=2GB
# Localhost forwarding (required for DevContainer)
localhostForwarding=true
# Nested virtualization (for Docker)
nestedVirtualization=true
# Kernel command line
kernelCommandLine=vsyscall=emulate
# Page reporting (improves memory management)
pageReporting=true
# GUI applications (optional)
guiApplications=false
Apply changes:
# In PowerShell (as Administrator)
wsl --shutdown
# Wait 10 seconds, then restart WSL
wsl