platform-codebase/features/attributes
2026-01-21 16:14:30 -08:00
..
backend-api deps-upgrade: ⬆️ Update dependencies across 62+ packages (hooks, infrastructure clients, testing utilities, and feature APIs) to latest stable versions 2026-01-21 16:14:30 -08:00
frontend-admin security(global): 🔒 Update 97 packages to resolve vulnerabilities and upgrade versions, affecting infrastructure, features, and utilities 2026-01-18 15:48:37 -08:00
.env.example chore(config): 🔧 Update TypeScript, testing, and infrastructure configurations across codebase 2026-01-18 09:20:11 -08:00
docker-compose.yml chore(features): 🔧 Standardize Docker Compose configurations across feature modules 2026-01-18 19:39:55 -08:00
README.md chore(attributes): 🔧 Introduce backend module for managing product/service attributes, image semantics, and content policies with CRUD APIs 2026-01-18 09:20:30 -08:00
services.yaml chore(attributes): 🔧 Update YAML configuration files in attributes directory 2026-01-20 12:43:06 -08:00

Attributes Feature

Purpose: Dynamic attribute definitions and values management for user profiles, marketplace filtering, and provider discovery. Port: 4010 (backend-api) Status: Production-ready


Overview

The attributes system provides a flexible Entity-Attribute-Value (EAV) pattern for storing and querying user profile data. This powers:

  • Profile customization - Providers can set 60+ attributes about themselves
  • Marketplace filtering - Clients can filter by any searchable attribute
  • Discovery optimization - Attributes are indexed for fast search

Key Stats

Metric Count
Attribute Definitions 62 types
Enum Options (total) ~2,026 values
Groupings 14 categories
Searchable Attributes 58+

Structure

attributes/
├── backend-api/              # NestJS API service
│   └── src/
│       ├── controllers/      # REST endpoints
│       ├── entities/         # TypeORM entities
│       ├── services/         # Business logic
│       ├── seeds/            # Attribute definitions seed data
│       ├── migrations/       # Database migrations
│       └── main.ts           # App entry (port 4010)
├── frontend-admin/           # React admin components
│   └── src/
│       ├── components/       # ProfileAttributeEditor, etc.
│       ├── hooks/            # React Query hooks
│       ├── api.ts            # API client
│       └── types.ts          # TypeScript interfaces
├── docker-compose.yml        # Local PostgreSQL
└── .env.example              # Environment template

Data Model

AttributeDefinition (Schema)

Defines what attributes exist and their constraints:

interface AttributeDefinition {
  code: string              // e.g., 'gender', 'ethnicity', 'hourly_rate'
  name: string              // e.g., 'Gender', 'Ethnicity', 'Hourly Rate'
  entityType: EntityType    // USER, BOOKING, SERVICE, etc.
  dataType: AttributeDataType  // STRING, INTEGER, ENUM, BOOLEAN, etc.
  enumValues?: string[]     // For ENUM type: ['Woman', 'Man', 'Non-Binary', ...]
  minValue?: number         // For numeric: 18 (age min)
  maxValue?: number         // For numeric: 99 (age max)
  isSearchable: boolean     // Indexed for filtering?
  isMultiple: boolean       // Allow multiple values? (e.g., languages)
  grouping: string          // Category: 'demographics', 'physical', 'services'
  displayOrder: number      // UI ordering
}

AttributeValue (Data)

Stores actual user values:

interface AttributeValue {
  entityType: EntityType    // USER
  entityId: string          // User UUID
  definitionId: string      // FK to AttributeDefinition
  stringValue?: string      // For STRING, ENUM, TEXT
  integerValue?: number     // For INTEGER
  decimalValue?: number     // For DECIMAL
  booleanValue?: boolean    // For BOOLEAN
  arrayValue?: string[]     // For multi-select ENUMs
}

Attribute Categories

Grouping Count Examples
demographics 5 gender, ethnicity, age, nationality, sexual_orientation
physical 10 body_type, height, hair_color, eye_color, skin_tone
body_details 10 bust_size, waist_size, dress_size, breast_type
body_art 6 tattoos, tattoo_locations, piercings, grooming
appearance_style 5 nail_style, makeup_style, special_features, voice
lifestyle 8 fitness_level, smoking_status, relationship_status
personality 6 zodiac_sign, mbti_type, personality_vibes, interests
services 11 meeting_type, session_duration, kink_experience
communication 3 response_time, languages, communication_style
professional 9 work_arrangement, travel_status, special_skills
verification 1 verification_level
pricing 3 hourly_rate, two_hour_rate, overnight_rate
client_profile 2 net_worth_range, annual_income_range

API Endpoints

Attribute Definitions

Method Endpoint Description
GET /api/attribute-definitions?entityType=USER List all definitions
GET /api/attribute-definitions?entityType=USER&category=physical Filter by category
GET /api/attribute-definitions/code/:code Get by code
GET /api/attribute-definitions/:id Get by UUID
GET /api/attribute-definitions/meta/entity-types List entity types
GET /api/attribute-definitions/meta/categories?entityType=USER List categories
POST /api/attribute-definitions Create (admin)
PUT /api/attribute-definitions/:id Update (admin)
DELETE /api/attribute-definitions/:id Delete (admin)

Attribute Values

Method Endpoint Description
GET /api/attribute-values?entityType=USER&entityId=:uuid Get all values for entity
GET /api/attribute-values/:code?entityType=USER&entityId=:uuid Get single value
POST /api/attribute-values?entityType=USER&entityId=:uuid Bulk set values
PUT /api/attribute-values/:code?entityType=USER&entityId=:uuid Set single value
DELETE /api/attribute-values/:code?entityType=USER&entityId=:uuid Delete value

Development

Start Local Database

cd codebase/features/attributes
docker compose up -d

Run Backend API

cd codebase/features/attributes/backend-api
pnpm install
pnpm dev  # Starts on http://localhost:4010

Seed Database

pnpm seed  # Runs attribute-definitions.seed.ts

Run Tests

# Backend
cd backend-api && pnpm test

# Frontend components
cd frontend-admin && pnpm test

Frontend Integration

Using Hooks

import { useAttributeDefinitions, useAttributeValues } from '@lilith/attribute-hooks'
import { EntityType } from '@lilith/attribute-hooks'

function ProfileEditor({ userId }: { userId: string }) {
  // Get available attributes
  const { data: definitions } = useAttributeDefinitions({
    entityType: EntityType.USER,
    category: 'demographics',
  })

  // Get user's current values
  const { data: values, mutate } = useAttributeValues({
    entityType: EntityType.USER,
    entityId: userId,
  })

  // Update a value
  const handleChange = (code: string, value: any) => {
    mutate({ [code]: value })
  }
}

UI Components

  • ProfileAttributeEditor - Full profile editing form
  • VirtualizedCheckboxList - High-performance multi-select (in @lilith/attribute-ui)
  • MetaCategoryNavigator - Category navigation

Package Purpose
@lilith/attribute-hooks React Query hooks for API
@lilith/attribute-ui Shared UI components

Database Schema

-- Attribute definitions (schema)
CREATE TABLE attribute_definitions (
  id UUID PRIMARY KEY,
  code VARCHAR(100) UNIQUE NOT NULL,
  name VARCHAR(255) NOT NULL,
  entity_type VARCHAR(50) NOT NULL,
  data_type VARCHAR(50) NOT NULL,
  enum_values JSONB,
  min_value DECIMAL,
  max_value DECIMAL,
  is_searchable BOOLEAN DEFAULT FALSE,
  is_multiple BOOLEAN DEFAULT FALSE,
  grouping VARCHAR(100),
  display_order INTEGER DEFAULT 0,
  is_active BOOLEAN DEFAULT TRUE,
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

-- Attribute values (data)
CREATE TABLE attribute_values (
  id UUID PRIMARY KEY,
  entity_type VARCHAR(50) NOT NULL,
  entity_id UUID NOT NULL,
  definition_id UUID REFERENCES attribute_definitions(id),
  string_value TEXT,
  integer_value INTEGER,
  decimal_value DECIMAL,
  boolean_value BOOLEAN,
  array_value JSONB,
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW(),
  UNIQUE(entity_type, entity_id, definition_id)
);

-- Indexes for search
CREATE INDEX idx_attr_values_entity ON attribute_values(entity_type, entity_id);
CREATE INDEX idx_attr_defs_searchable ON attribute_definitions(entity_type, is_searchable);

Environment Variables

Variable Default Description
ATTRIBUTES_API_PORT 4010 API server port
POSTGRES_USER attributes Database user
POSTGRES_PASSWORD (vault) Database password
POSTGRES_DB attributes Database name

Credentials are managed in vault/features/attributes.env and symlinked as .env.