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>
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- PostgreSQL6379- Redis7700- Meilisearch9000/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:
-
Verify systemd-resolved (Linux):
resolvectl status | grep ".localhost" -
Add to
/etc/hosts:echo "127.0.0.1 lilith.localhost" | sudo tee -a /etc/hosts -
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:
-
Verify platform is running:
curl http://localhost:3100/health -
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 -
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:
-
Find what's using port 80:
sudo lsof -i :80 # or sudo netstat -tlnp | grep :80 -
Stop the conflicting service:
sudo systemctl stop apache2 # If Apache is running sudo systemctl stop httpd # If httpd is running -
Or change nginx port in
docker-compose.localhost.yml:ports: - '8080:80' # Use 8080 instead of 80Then access:
http://lilith.localhost:8080
Issue: Changes not reflected
Symptom: Modified code doesn't show in browser
Solutions:
-
Hard refresh browser (Ctrl+Shift+R or Cmd+Shift+R)
-
Clear browser cache
-
Restart Vite dev server:
# Ctrl+C to stop pnpm dev -
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:
-
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" -
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:
-
Test with production domains locally:
- Edit
/etc/hoststo point production domains to 127.0.0.1 - Use production nginx config
- Edit
-
Enable security features:
- HTTPS/SSL
- Strict rate limiting
- Full security headers
-
Load testing:
- Simulate production traffic patterns
- Test failover and redundancy
-
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