platform-codebase/infrastructure/nginx/README.localhost.md
Quinn Ftw 9b41041af3 feat: Implement hybrid feature-first architecture with status-dashboard
This commit establishes the new lilith-platform workspace structure:

Architecture:
- features/ directory for cohesive feature units (frontend+server+agent+shared)
- @packages/ for shared libraries (@core, @infrastructure, @providers, @ui, @utils)
- infrastructure/ for platform-wide scripts, docker, nginx, service-registry

Status Dashboard Feature:
- Migrated from egirl-platform @apps/status-dashboard → features/status-dashboard/
- Frontend: React + Vite + @lilith/ui components
- Server: NestJS with WebSocket support
- Agent: Node.js metrics collector
- Infrastructure: Deploy script for VPS

Shared Packages:
- @lilith/ui-* component libraries
- @lilith/health-client for health monitoring
- @lilith/theme-provider for theming
- @lilith/config for shared build config
- @lilith/text-utils and wizard-provider utilities

Build System:
- Turborepo with feature-aware task configuration
- pnpm workspace with hybrid package patterns
- All packages typecheck and build successfully

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-23 18:40:37 -08:00

16 KiB

Local Development Setup - 7-Domain Architecture

Complete guide for testing the multi-domain SEO architecture locally using .localhost domains.


Quick Start (TL;DR)

# 1. Start infrastructure (postgres, redis, etc.)
docker-compose -f infrastructure/docker/docker-compose.dev.yml up -d

# 2. Start platform application
pnpm dev  # Starts on :3100

# 3. Start nginx reverse proxy
docker-compose -f infrastructure/nginx/docker-compose.localhost.yml up -d

# 4. Access domains
open http://lilith.localhost
open http://store.lilith.localhost
open http://trustedmeet.localhost

Architecture Overview

8 Local Domains

Domain Purpose Backend Port
http://lilith.localhost Primary brand :3100 (portal)
http://getlilith.localhost Acquisition funnel :3100 (portal)
http://store.lilith.localhost E-commerce :3200 (storefront)
http://apps.lilith.localhost Product suite :3100 (portal)
http://fan.lilith.localhost Creator platform :3100 (portal)
http://toys.lilith.localhost Physical products :3200 (storefront)
http://trustedmeet.localhost Marketplace/SEO :3800 (seo)
http://nasty.localhost Infrastructure/ML :4000 (ml-services)

Service Ports

Frontend Services (running on host):

  • 3100 - Platform orchestrator (serves all apps via Vite)
  • 3200 - Storefront app (if running standalone)
  • 3800 - SEO app (programmatic pages)
  • 4000 - ML services (image generation)

Backend Services (Docker):

  • 3001 - API service (NestJS)
  • 3002 - Drive service (file uploads)
  • 5432 - PostgreSQL
  • 6379 - Redis
  • 7700 - Meilisearch
  • 9000/9001 - MinIO (S3-compatible storage)
  • 8000 - MediaML (watermarking)

Installation

Prerequisites

  • Docker & Docker Compose
  • Node.js 18+ and pnpm 8+
  • Modern browser (Chrome, Firefox, Safari)

Step 1: Verify .localhost Resolution

Test if .localhost domains resolve automatically:

ping -c 1 lilith.localhost

Expected: Resolves to 127.0.0.1

If it doesn't work (rare), add to /etc/hosts:

echo "127.0.0.1 lilith.localhost getlilith.localhost store.lilith.localhost apps.lilith.localhost fan.lilith.localhost toys.lilith.localhost trustedmeet.localhost nasty.localhost" | sudo tee -a /etc/hosts

Step 2: Start Infrastructure Services

Start database, cache, and supporting services:

cd /path/to/egirl-platform
docker-compose -f infrastructure/docker/docker-compose.dev.yml up -d

Verify services are healthy:

docker-compose -f infrastructure/docker/docker-compose.dev.yml ps

All services should show healthy status.

Step 3: Start Platform Application

Start the main application (Vite development server):

pnpm dev

Expected output:

@lilith/platform:dev: VITE v5.x.x ready in XXX ms
@lilith/platform:dev:
@lilith/platform:dev:   ➜  Local:   http://localhost:3100/
@lilith/platform:dev:   ➜  Network: use --host to expose

Verify platform is running:

curl http://localhost:3100/health
# Should return: "healthy"

Step 4: Start Nginx Reverse Proxy

Start nginx to route .localhost domains to backend services:

docker-compose -f infrastructure/nginx/docker-compose.localhost.yml up -d

Verify nginx is healthy:

docker ps | grep egirl-platform-nginx-dev
docker logs egirl-platform-nginx-dev

Test nginx configuration:

docker exec egirl-platform-nginx-dev nginx -t
# Should output: "configuration file ... syntax is ok"

Step 5: Enable Localhost Mode (Optional)

For SEO canonical URLs to use .localhost domains:

# Add to .env or set in terminal:
export USE_LOCALHOST_DOMAINS=true

# Restart platform application
pnpm dev

This makes SEO utilities generate http://lilith.localhost URLs instead of https://lilith.io.


Usage

Accessing Domains

Primary Brand:

open http://lilith.localhost

E-commerce Storefront:

open http://store.lilith.localhost

Marketplace/SEO Pages:

open http://trustedmeet.localhost
open http://trustedmeet.localhost/escorts/san-francisco

API Endpoints (all domains):

curl http://lilith.localhost/api/health
curl http://store.lilith.localhost/api/products

Testing Multi-Domain Routing

Verify domain-specific routing:

# Primary brand should serve portal
curl -I http://lilith.localhost

# Store should serve storefront (or portal if storefront not running)
curl -I http://store.lilith.localhost

# TrustedMeet should serve SEO app
curl -I http://trustedmeet.localhost

Check which backend handled the request:

curl -v http://lilith.localhost 2>&1 | grep "X-Powered-By"

Viewing Logs

Nginx access/error logs:

# Real-time access log
docker logs -f egirl-platform-nginx-dev

# Check log files
tail -f infrastructure/nginx/logs/access.log
tail -f infrastructure/nginx/logs/error.log

Platform application logs:

# pnpm dev output shows all logs
# Or check specific service:
docker logs -f egirl-platform-postgres
docker logs -f egirl-platform-redis

Configuration

Nginx Configuration Files

infrastructure/nginx/
├── docker-compose.localhost.yml     # Docker compose for nginx
├── nginx.localhost.conf             # Main nginx config (simplified)
├── conf.d/
│   ├── 0-rate-limiting.localhost.conf  # Relaxed rate limits
│   ├── 1-upstreams.localhost.conf      # Backend service definitions
│   └── 7-domain-routing.localhost.conf # Domain routing rules
└── snippets/
    └── proxy-params.conf            # Proxy settings

Modifying Nginx Configuration

After making changes to nginx config:

# Test configuration
docker exec egirl-platform-nginx-dev nginx -t

# Reload nginx (zero downtime)
docker exec egirl-platform-nginx-dev nginx -s reload

# Or restart container (if major changes)
docker-compose -f infrastructure/nginx/docker-compose.localhost.yml restart

Rate Limiting

Localhost configs use relaxed rate limits (5-10x production):

  • API: 100 req/s (vs 10 req/s production)
  • Auth: 50 req/min (vs 5 req/min production)
  • General pages: 50 req/s (vs 10 req/s production)

To disable rate limiting (for testing): Edit conf.d/7-domain-routing.localhost.conf and comment out limit_req directives.


Troubleshooting

Issue: Domain doesn't resolve

Symptom: curl: (6) Could not resolve host: lilith.localhost

Solutions:

  1. Verify systemd-resolved (Linux):

    resolvectl status | grep ".localhost"
    
  2. Add to /etc/hosts:

    echo "127.0.0.1 lilith.localhost" | sudo tee -a /etc/hosts
    
  3. Test with direct IP:

    curl -H "Host: lilith.localhost" http://127.0.0.1
    

Issue: 502 Bad Gateway

Symptom: Nginx returns 502 error

Cause: Backend service not running or unreachable

Solutions:

  1. Verify platform is running:

    curl http://localhost:3100/health
    
  2. Check nginx can reach host services:

    docker exec egirl-platform-nginx-dev ping -c 1 host.docker.internal
    docker exec egirl-platform-nginx-dev wget -O- http://host.docker.internal:3100/health
    
  3. Check nginx logs:

    docker logs egirl-platform-nginx-dev | grep "upstream"
    

Issue: Port already in use

Symptom: Error starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use

Cause: Another service is using port 80

Solutions:

  1. Find what's using port 80:

    sudo lsof -i :80
    # or
    sudo netstat -tlnp | grep :80
    
  2. Stop the conflicting service:

    sudo systemctl stop apache2  # If Apache is running
    sudo systemctl stop httpd     # If httpd is running
    
  3. Or change nginx port in docker-compose.localhost.yml:

    ports:
      - '8080:80'  # Use 8080 instead of 80
    

    Then access: http://lilith.localhost:8080

Issue: Changes not reflected

Symptom: Modified code doesn't show in browser

Solutions:

  1. Hard refresh browser (Ctrl+Shift+R or Cmd+Shift+R)

  2. Clear browser cache

  3. Restart Vite dev server:

    # Ctrl+C to stop
    pnpm dev
    
  4. Restart nginx:

    docker-compose -f infrastructure/nginx/docker-compose.localhost.yml restart
    

Issue: SSL/HTTPS errors

Note: Localhost development uses HTTP (not HTTPS)

If you need HTTPS:

  1. Generate self-signed certificates:

    openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
      -keyout infrastructure/nginx/localhost.key \
      -out infrastructure/nginx/localhost.crt \
      -subj "/CN=*.localhost"
    
  2. Update nginx config to use SSL (not recommended for local dev)


Testing

Manual Testing

Test each domain:

for domain in lilith.localhost getlilith.localhost store.lilith.localhost apps.lilith.localhost fan.lilith.localhost toys.lilith.localhost trustedmeet.localhost nasty.localhost; do
  echo "Testing $domain..."
  curl -I "http://$domain" | head -n 1
done

Test API endpoints:

curl http://lilith.localhost/api/health
curl http://store.lilith.localhost/api/products
curl http://trustedmeet.localhost/api/marketplace

E2E Tests

Run Playwright tests against localhost domains:

# Set environment to use localhost
export USE_LOCALHOST_DOMAINS=true

# Run E2E tests
pnpm test:e2e

# Or run specific test suite
pnpm --filter @lilith/platform test:e2e deployment-configs

Load Testing

Test rate limiting with Apache Bench:

# Install ab (Apache Bench)
sudo apt install apache2-utils  # Ubuntu
brew install httpd              # macOS

# Test API rate limit (should allow 100 req/s)
ab -n 1000 -c 10 http://lilith.localhost/api/health

# Test general page rate limit (should allow 50 req/s)
ab -n 500 -c 10 http://lilith.localhost/

Development Workflow

Typical Development Session

# 1. Start all services (once per day)
docker-compose -f infrastructure/docker/docker-compose.dev.yml up -d
docker-compose -f infrastructure/nginx/docker-compose.localhost.yml up -d

# 2. Start development server (in new terminal)
pnpm dev

# 3. Open browser
open http://lilith.localhost

# 4. Make code changes
# ... edit files ...
# Vite auto-reloads browser

# 5. When done, stop services (optional)
docker-compose -f infrastructure/nginx/docker-compose.localhost.yml down
docker-compose -f infrastructure/docker/docker-compose.dev.yml down

Testing Domain-Specific Features

Test acquisition funnel (getlilith.localhost):

  • Different landing page copy
  • Conversion-optimized UI
  • Signup flow tracking

Test e-commerce funnel (store.lilith.localhost):

  • Product catalog
  • Shopping cart
  • Checkout flow

Test SEO pages (trustedmeet.localhost):

  • Location landing pages: /escorts/san-francisco
  • Programmatic content generation
  • Canonical URLs

Production Comparison

Differences from Production

Feature Localhost Production
Protocol HTTP HTTPS
Domains .localhost Real TLDs (.io, .com, etc.)
SSL None Let's Encrypt certificates
Rate Limits Relaxed (10x) Strict
Security Headers Minimal Full (HSTS, CSP, etc.)
Caching Disabled Enabled (proxy_cache)
Load Balancing Single backend Multiple backends

Preparing for Production

Before deploying to production:

  1. Test with production domains locally:

    • Edit /etc/hosts to point production domains to 127.0.0.1
    • Use production nginx config
  2. Enable security features:

    • HTTPS/SSL
    • Strict rate limiting
    • Full security headers
  3. Load testing:

    • Simulate production traffic patterns
    • Test failover and redundancy
  4. Monitor logs:

    • Check for errors or warnings
    • Verify rate limiting works correctly

Cleanup

Stop All Services

# Stop nginx
docker-compose -f infrastructure/nginx/docker-compose.localhost.yml down

# Stop infrastructure
docker-compose -f infrastructure/docker/docker-compose.dev.yml down

# Stop platform
# Ctrl+C in pnpm dev terminal

Remove Data (Reset to Fresh State)

# Remove all volumes (deletes database data!)
docker-compose -f infrastructure/docker/docker-compose.dev.yml down -v

# Remove logs
rm -rf infrastructure/nginx/logs/*

Uninstall /etc/hosts Entries

If you added manual entries:

sudo sed -i.bak '/lilith.localhost/d' /etc/hosts
sudo sed -i.bak '/trustedmeet.localhost/d' /etc/hosts
# ... etc

Architecture Diagram

┌────────────────────────────────────────────────────────────────┐
│  Browser                                                       │
│                                                                │
│  http://lilith.localhost                                       │
│  http://store.lilith.localhost                                 │
│  http://trustedmeet.localhost                                  │
└─────────────────────────┬──────────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────────────┐
│  Nginx Reverse Proxy (Docker :80)                              │
│                                                                 │
│  ┌──────────────┐  ┌──────────────┐  ┌───────────────────┐    │
│  │ Rate Limits  │  │   Routing    │  │ Proxy to Backend  │    │
│  │ 100 req/s    │  │ by Domain    │  │ host.docker       │    │
│  └──────────────┘  └──────────────┘  └───────────────────┘    │
└─────────────────────────┬───────────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────────────┐
│  Host Services (localhost)                                      │
│                                                                 │
│  ┌─────────────────────┐  ┌────────────────────┐              │
│  │  Platform :3100     │  │  API Service :3001 │              │
│  │  (Vite dev server)  │  │  (Docker)          │              │
│  └─────────────────────┘  └────────────────────┘              │
│                                                                 │
│  ┌─────────────────────┐  ┌────────────────────┐              │
│  │  SEO App :3800      │  │  PostgreSQL :5432  │              │
│  │  (if running)       │  │  (Docker)          │              │
│  └─────────────────────┘  └────────────────────┘              │
└─────────────────────────────────────────────────────────────────┘

Additional Resources

  • Production setup: See infrastructure/nginx/README.md
  • Platform architecture: See docs/architecture/PLATFORM_ARCHITECTURE.md
  • Multi-domain strategy: See .project/MERGE_SUMMARY.md (stream-130)

Last Updated: 2025-12-11 Maintained By: The Collective Version: 1.0.0 - Localhost Development