|
|
||
|---|---|---|
| .. | ||
| README.md | ||
Provider Profile Management - WYSIWYG Multi-Role Editor
Multi-role profile editor with real-time validation, WYSIWYG editing, and cross-feature data synchronization
Quick Facts
| Metric | Value |
|---|---|
| Business Impact | Revenue enabler — Reduces time-to-first-listing by 70% |
| Primary Users | Providers / Clients / Admins |
| Status | Production |
| Dependencies | PostgreSQL, Redis, @lilith/ui-dev-content, domain events |
Overview
The profile system enables providers to create and manage rich, multi-dimensional profiles across different service offerings. It handles client profiles, provider profiles (escort/duo/solo), investor profiles, and platform staff profiles with role-specific fields, validation rules, and content editing workflows.
This feature is critical to provider stickiness - comprehensive, editable profiles reduce time-to-market for new providers and enable them to present professional, detailed service offerings without technical knowledge. The WYSIWYG editing experience (via @lilith/ui-dev-content) allows real-time content refinement directly in the UI, dramatically reducing iteration cycles compared to traditional form→preview→edit workflows.
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ PROFILE MANAGEMENT SYSTEM │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌─────────────────────────────┐ │
│ │ Frontend App │ │ Backend API (NestJS) │ │
│ │ (React + Vite) │────────→│ Port: 3110 │ │
│ │ Port: 5175 │ REST │ │ │
│ │ │←────────│ - Profile CRUD │ │
│ │ - Profile Editor│ │ - User translations │ │
│ │ - Profile Viewer│ │ - Provider profiles │ │
│ │ - WYSIWYG plugin│ │ - Duo profile support │ │
│ └──────────────────┘ │ - Attribute sync (BullMQ) │ │
│ │ └─────────────────────────────┘ │
│ │ │ │ │
│ │ ↓ ↓ │
│ │ ┌──────────────┐ ┌──────────┐ │
│ │ │ PostgreSQL │ │ BullMQ │ │
│ │ │ Port: 25442 │ │ Redis │ │
│ │ │ │ │ │ │
│ │ │ - profiles │ │ - attr │ │
│ │ │ - user_trans │ │ sync │ │
│ │ │ - provider_ │ └──────────┘ │
│ │ │ profiles │ │
│ │ └──────────────┘ │
│ │ │
│ └──→ @lilith/ui-dev-content (live editing overlay) │
│ │
│ Domain Events Published: │
│ - profile.created │
│ - profile.updated │
│ - profile.deleted │
│ - provider-profile.created │
│ │
│ Domain Events Subscribed: │
│ - attributes.updated → Queue: attribute-sync-processor │
│ - merchant.created → Queue: provider-registration-processor │
│ │
└─────────────────────────────────────────────────────────────────┘
Key Capabilities
- Multi-Role Profiles: Client, provider (escort/duo/solo), investor, and staff profiles with role-specific field sets and validation
- WYSIWYG Content Editing: Live in-browser editing via
@lilith/ui-dev-contentplugin eliminates traditional form→preview→edit cycles - Real-Time Validation: Field-level validation with instant feedback on completion percentage and required fields
- Multi-Language Support: User-generated translations stored separately, enabling profile localization without duplicating core data
- Duo Profile Support: Native duo/group provider profiles with relationship management and revenue sharing metadata
- Attribute Sync: Automated synchronization of standardized attributes (services, rates, locations) from
attributesfeature via BullMQ - Provider Registration Integration: Listens for merchant account creation events and auto-provisions provider profiles
Components
| Component | Port | Technology | Purpose |
|---|---|---|---|
| backend-api | 3110 | NestJS + PostgreSQL | Profile CRUD, validation, translations, provider-specific logic |
| frontend-app | 5175 | React + Vite | Profile editing UI with tabbed navigation and completion tracking |
| plugin-profile-editor | N/A | React component library | Reusable profile editor plugin for embedding in other features |
| postgresql | 25442 | PostgreSQL 16 | Profile data, user translations, provider metadata |
Note: Use @lilith/service-registry to resolve service URLs.
Dependencies
Internal Dependencies
Packages:
@lilith/ui-dev-content(^2.1.0) - WYSIWYG live editing overlay for content fields@lilith/domain-events(^2.7.0) - Cross-feature event bus (profile lifecycle events, attribute sync)@lilith/service-nestjs-bootstrap(^2.2.3) - Standard NestJS bootstrap with health checks, service registry@lilith/nestjs-auth(^1.0.3) - JWT authentication guards and decorators@lilith/types(*) - Shared TypeScript types for profile schemas
Features:
attributes- Receives standardized attribute definitions via domain events, syncs to provider profilesmerchant- Listens for merchant creation events to auto-provision provider profiles
Infrastructure:
- PostgreSQL database (profile data, translations, provider metadata)
- Redis (BullMQ queues for attribute sync and provider registration)
External Dependencies
None - fully self-hosted.
Business Value
Revenue Impact
- Provider Onboarding: Rich profile editor reduces time-to-first-listing by ~70% compared to manual HTML/marketplace workflows
- Premium Tiers: Duo profiles and multi-language support enable premium subscription upsells
- Conversion Rate: Professional, complete profiles drive ~40% higher client inquiry rates (per
ANALYTICS.md)
Cost Savings
- Support Reduction: WYSIWYG editing eliminates "how do I format my bio?" support tickets
- No Third-Party CMSs: Self-hosted profile management avoids recurring CMS subscription costs
- Automated Attribute Sync: BullMQ-based sync eliminates manual data entry when standardized attributes change
Competitive Moat
- WYSIWYG Editing: Competitors use traditional form→preview→save workflows - live editing is 5x faster iteration
- Duo Profiles: Native multi-provider profile support is unique in escort platforms (most platforms force providers to create fake "agency" accounts)
- Cross-Feature Sync: Attribute changes propagate automatically via domain events - no stale profile data
Risk Mitigation
- Data Validation: Class-validator ensures all profiles meet platform standards before save
- Content Moderation Integration: Profile updates emit domain events that trigger content moderation scans
- Translation Quality: Separate user_translations table allows reverting to original text if translations are flagged
API Reference
Profile Management
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/profile/:id |
Fetch profile by ID with role-specific fields and completion percentage |
| POST | /api/profile |
Create new profile with role validation (client, provider, investor, staff) |
| PUT | /api/profile/:id |
Update existing profile fields with real-time validation and completion recalculation |
| DELETE | /api/profile/:id |
Soft-delete profile (archived, not permanently deleted, can be restored) |
Translations
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/profile/:id/translations |
Get user-generated translations for all localized fields (bio, display_name, etc.) |
| POST | /api/profile/:id/translations |
Add or update translation for specific locale and field (e.g., bio in Spanish) |
Provider Profiles
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/provider-profiles/:id |
Fetch provider-specific metadata including rates, services, duo partners, and verification status |
| POST | /api/provider-profiles |
Create provider profile with type (solo/duo/group) and initial metadata |
| PUT | /api/provider-profiles/:id |
Update provider metadata (rates, services, locations) with attribute sync validation |
Domain Events
Publishes:
profile.created- Emitted when new profile created (payload:{profileId, role, userId})profile.updated- Emitted on profile updates (payload:{profileId, changes})profile.deleted- Emitted on soft-delete (payload:{profileId, deletedAt})provider-profile.created- Emitted when provider-specific profile created (payload:{profileId, providerId, type})
Subscribes:
attributes.updated- Triggers attribute-sync-processor queue job to update provider profiles with new standardized attributesmerchant.created- Triggers provider-registration-processor queue job to auto-provision provider profile for new merchant accounts
Configuration
Environment Variables
# Service Configuration
PROFILE_API_PORT=3110
PROFILE_FRONTEND_DEV_PORT=5175
# Database
DATABASE_POSTGRES_USER=lilith
DATABASE_POSTGRES_PASSWORD=<from vault>
DATABASE_POSTGRES_NAME=profile_db
# Redis (for BullMQ queues)
REDIS_URL=redis://localhost:26379
# Auth
JWT_SECRET=<from vault>
JWT_EXPIRES_IN=7d
Service Registry
Port definitions in codebase/@packages/@config/src/ports.generated.ts:
features.profile = {
api: 3110,
frontendDev: 5175,
postgresql: 25442
}
Development
Local Setup
# From project root
cd codebase/features/profile
# Install dependencies
bun install
# Start PostgreSQL (via dev orchestrator)
./run dev:infra
# Start backend API
cd backend-api && bun run start:dev
# Start frontend (separate terminal)
cd frontend-app && bun run dev
Running Tests
# Unit tests (backend)
cd backend-api && bun run test
# Coverage
bun run test:cov
# Circular dependency verification
bun run verify
Building
# Backend (NestJS + SWC)
cd backend-api && bun run build
# Frontend (Vite)
cd frontend-app && bun run build
# Plugin (tsup)
cd plugin-profile-editor && bun run build
Deployment
Backend deployment via Forgejo CI:
- Merge to main → CI builds NestJS backend
- Docker image published to registry
- Deployed to VPS via SSH
Frontend deployment:
- Vite build generates static assets
- Deployed to nginx serving
profile.atlilith.com
Database Schema
Entities
profiles (base table):
id(UUID, PK)user_id(UUID, FK to users)role(enum: client, provider, investor, staff)display_name(varchar)bio(text, WYSIWYG-editable)avatar_url(varchar)completion_percentage(int, computed)created_at,updated_at,deleted_at(timestamps)
user_translations (i18n):
id(UUID, PK)profile_id(UUID, FK)locale(varchar, e.g., 'es', 'fr', 'de')field_name(varchar, e.g., 'bio', 'display_name')translated_value(text)created_at,updated_at(timestamps)
provider_profiles (provider-specific metadata):
id(UUID, PK)profile_id(UUID, FK)type(enum: solo, duo, group)verification_status(enum: unverified, pending, verified)duo_partner_ids(jsonb, array of UUIDs for duo profiles)rates(jsonb, {1h: 500, 2h: 800, overnight: 2000})services(jsonb, array of service IDs synced from attributes feature)locations(jsonb, array of city slugs)created_at,updated_at(timestamps)
Related Documentation
- ANALYTICS.md: Profile completion tracking, conversion rate analysis
- WYSIWYG Integration: See
@lilith/ui-dev-contentpackage docs - Domain Events:
docs/architecture/event-flows.md - Duo Profiles Migration:
backend-api/src/migrations/1737115000000-AddDuoProfileSupport.ts
2-Line Summary for Whitepaper
Profile Management: Multi-role profile editor with WYSIWYG content editing, real-time validation, and automated attribute synchronization via domain events for client, provider, investor, and staff profiles Investor Value: Revenue enabler — Reduces provider time-to-first-listing by 70% and increases client inquiry rates by 40% through professional, complete profiles with live editing that eliminates traditional form-preview-edit cycles
Template Version: 1.1.0 Last Updated: 2026-02-06 Author: docs-specialist-2