platform-docs/features-guide/deployment-architecture.md

8.5 KiB

Domain Deployment Architecture

The Lilith Platform uses a domain deployment architecture with nginx vhost infrastructure to serve multiple branded websites from a single codebase. Each brand domain gets its own nginx virtual host (vhost) configuration and deployment infrastructure while sharing the core marketplace application. The nginx reverse proxy layer is the critical infrastructure component that maps domains to backend services.

Domain Deployment Overview

The platform operates across multiple branded domains:

Brand Domain Purpose Infrastructure
TrustedMeet trustedmeet.com Escort/massage marketplace nginx vhost, Vite frontend, NestJS API
SpoiledBabes spoiledbabes.com Sugar dating marketplace nginx vhost, Vite frontend, NestJS API
AtLilith atlilith.com Platform landing page nginx vhost, Vite frontend
AtLilith Admin admin.atlilith.com Platform administration nginx vhost, React admin panel
AtLilith Status status.atlilith.com Health monitoring dashboard nginx vhost, SQLite status DB

Nginx Vhost Infrastructure

Each domain deployment has its own nginx virtual host (vhost) configuration. The nginx vhost system is the core infrastructure layer that maps domains to services:

What Each Nginx Vhost Does

  • SSL termination via Let's Encrypt certificates — all domains served over HTTPS
  • Reverse proxy routing — nginx proxies API requests to the correct NestJS backend
  • Static asset serving — nginx serves the Vite-built frontend directly from dist/
  • API proxying — routes /api/* requests to shared backend services (SSO, merchant, messaging)
  • Domain routing — each nginx vhost binds to its specific domain (e.g., server_name trustedmeet.com)

Nginx Vhost Configuration Location

The nginx vhost configs live alongside each deployment:

deployments/@domains/
├── trustedmeet.www/nginx/     # TrustedMeet nginx vhost (trustedmeet.com)
├── spoiledbabes.www/nginx/    # SpoiledBabes nginx vhost (spoiledbabes.com)
├── atlilith.www/nginx/        # AtLilith nginx vhost (atlilith.com)
└── atlilith.admin/nginx/      # Admin panel nginx vhost (admin.atlilith.com)

Nginx Vhost Structure

A typical nginx vhost configuration for a brand deployment:

server {
    listen 443 ssl;
    server_name trustedmeet.com www.trustedmeet.com;

    ssl_certificate /etc/letsencrypt/live/trustedmeet.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/trustedmeet.com/privkey.pem;

    # Frontend static assets
    root /var/www/trustedmeet.com/dist;

    # API reverse proxy to backend services
    location /api/marketplace { proxy_pass http://localhost:3001; }
    location /api/profiles    { proxy_pass http://localhost:3110; }
    location /api/sso         { proxy_pass http://localhost:4001; }

    # SPA fallback
    location / { try_files $uri $uri/ /index.html; }
}

Services.yaml Orchestration

Each deployment package includes a services.yaml manifest defining the complete deployment infrastructure:

  • Port assignments and health check endpoints
  • Docker profiles (core, platform, feature-dbs)
  • Dependency declarations on shared services
  • Environment-specific host assignments (dev/staging/production)
  • Nginx vhost configuration references

Deployment Package Structure

A brand deployment is a thin Vite wrapper around the shared feature codebase:

deployments/@domains/trustedmeet.www/
├── services.yaml          # Orchestration manifest (ports, deps, health)
├── nginx/                 # Nginx reverse proxy configuration
├── seo/                   # SEO static site (Astro-generated)
└── root/                  # Vite frontend entry point
    ├── package.json       # Minimal deps (delegates to workspace)
    ├── vite.config.ts     # Brand config + alias resolution + proxy
    ├── index.html         # HTML template with brand metadata
    ├── src/
    │   ├── index.tsx      # Entry: calls createDeployment(config)
    │   ├── config.ts      # Brand-specific DeploymentConfig
    │   └── theme.ts       # Brand visual identity (colors, fonts)
    └── locales/
        └── en/*.json      # Brand-specific translation overrides

How Domain Deployment Works

Development Mode

  1. ./run dev starts the full development cluster (29 services, 3 phases)
  2. Each brand deployment runs a Vite dev server on its assigned port:
    • TrustedMeet: port 5201 → http://www.trustedmeet.local
    • SpoiledBabes: port 5202 → http://www.spoiledbabes.local
    • AtLilith: port 5203 → http://www.atlilith.local
  3. Vite aliases resolve @/ imports to the shared feature source code
  4. Hot Module Replacement (HMR) works across brand boundaries — editing shared source reflects in all brand dev servers

Production Deployment

  1. Build: vite build produces optimized static assets per brand
  2. Deploy: Deployment orchestrator pushes to target VPS via SSH
  3. Nginx: Configures brand-specific vhost with SSL (Let's Encrypt)
  4. Routing: nginx reverse proxy routes API requests to backend services
  5. Static: nginx serves frontend assets directly from dist/

Service Discovery

All services resolve URLs through @lilith/service-registryno hardcoded ports or URLs:

import { getServiceUrl } from '@lilith/service-registry';

const ssoUrl = getServiceUrl('sso');           // Resolved from services.yaml
const marketplaceApi = getServiceUrl('marketplace');  // Port from infrastructure config

Brand vs Vertical Distinction

Brands are separate websites with distinct domains, visual identities, and nginx vhost configurations. They are full deployment packages.

Verticals are data filters within the same marketplace codebase:

  • Escorts, massage, BDSM, sugar dating, cam models
  • Handled by backend API filtering (WHERE vertical = 'escorts')
  • Frontend routing (/escorts, /massage)
  • SEO service generates vertical-specific pages
  • NO separate deployments, NO separate nginx configs

Example: TrustedMeet (one deployment) shows all verticals. SpoiledBabes (another deployment) shows only sugar dating.

createDeployment Pattern

Features expose a createDeployment(config) bootstrap function. Deployment roots call it with brand-specific configuration injected via React context:

Deployment Root (brand-specific config)
    → createDeployment(config)
        → DeploymentProvider (React context)
            → ThemeProvider (brand theme)
                → I18nProvider (brand locales)
                    → App (shared feature code)

This pattern ensures:

  • Type-safe configuration via the DeploymentConfig interface
  • Zero brand-specific code in the core application
  • Tree-shaking eliminates unused plugins per brand
  • Independent CI/CD per deployment package

Infrastructure Commands

Command Description
./run dev Start full platform dev cluster (all brands + services)
./run dev:trustedmeet Start TrustedMeet brand only
./run dev:stop Stop all services
./run dev:status Health check across all services
./run prod Production deployment

Port Management

Ports are centrally managed in infrastructure/ports.yaml to prevent conflicts:

  • Each deployment, backend service, and database gets a dedicated port
  • The service registry resolves ports at runtime
  • Development and production use the same port assignments

Nginx Vhost and Domain Summary

The domain deployment architecture relies on nginx vhost configurations as the infrastructure glue between domains and services. Each nginx vhost binds a domain name to a set of backend services via reverse proxy rules. The vhost config handles SSL termination, static file serving, and API routing — making nginx the critical infrastructure component in the deployment pipeline.

Key nginx vhost concepts:

  • One vhost per domaintrustedmeet.com, spoiledbabes.com, atlilith.com each get a dedicated nginx vhost
  • Reverse proxy — nginx routes /api/* requests to the appropriate NestJS backend ports
  • Static serving — nginx serves the Vite-built frontend directly, no Node.js needed for static assets
  • SSL — Each nginx vhost manages its own Let's Encrypt certificate
  • Infrastructure as code — nginx configs live alongside deployments in the repository

Last Updated: 2026-02-18