chore(architecture): 🔧 update domain event patterns documentation with clearer event handling workflows and refined worker protection safety checks for production
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
efe5eddfdb
commit
b539c0096f
2 changed files with 222 additions and 0 deletions
132
architecture/domain-events-guide.md
Normal file
132
architecture/domain-events-guide.md
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
# Domain Events: Publish/Subscribe Guide
|
||||
|
||||
Domain events are the primary mechanism for cross-feature communication on the Lilith Platform. Features publish events when something significant happens, and other features subscribe to react to those events asynchronously.
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### What Are Domain Events?
|
||||
|
||||
Domain events represent meaningful occurrences within the platform — a booking confirmed, an email sent, an image generated, a user signing up. When a feature publishes an event, any other feature that has subscribed to that event type receives it and can react independently.
|
||||
|
||||
### Why Publish/Subscribe?
|
||||
|
||||
Before domain events, features communicated via synchronous HTTP calls or polling:
|
||||
- The SEO pipeline made blocking HTTP chains through 4 services
|
||||
- The status dashboard polled 6 services every 30 seconds (17,280 requests/day)
|
||||
- Image generation completed silently with no notification to analytics
|
||||
|
||||
Domain events decouple features: the publisher doesn't need to know who subscribes, and subscribers don't block the publisher.
|
||||
|
||||
## How to Publish Events
|
||||
|
||||
### 1. Import the Domain Events Package
|
||||
|
||||
```typescript
|
||||
import { DomainEventsEmitter, DomainEventType } from '@lilith/domain-events';
|
||||
```
|
||||
|
||||
### 2. Inject the Emitter
|
||||
|
||||
```typescript
|
||||
@Injectable()
|
||||
export class MyService {
|
||||
constructor(
|
||||
private readonly events: DomainEventsEmitter,
|
||||
) {}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Emit Events
|
||||
|
||||
```typescript
|
||||
await this.events.emit({
|
||||
type: DomainEventType.IMAGE_VARIATION_COMPLETED,
|
||||
payload: {
|
||||
variationId: '123',
|
||||
familiesCompleted: 4,
|
||||
totalGenerationTimeMs: 5200,
|
||||
publicUrls: ['https://...'],
|
||||
completedAt: new Date().toISOString(),
|
||||
},
|
||||
source: 'image-generator',
|
||||
correlationId: requestId,
|
||||
});
|
||||
```
|
||||
|
||||
Events are non-blocking — emission failures are logged but don't throw, so the publishing feature continues uninterrupted.
|
||||
|
||||
## How to Subscribe to Events
|
||||
|
||||
### 1. Create an Event Processor
|
||||
|
||||
```typescript
|
||||
import { Processor, WorkerHost } from '@nestjs/bullmq';
|
||||
import { DOMAIN_EVENTS_QUEUE } from '@lilith/domain-events';
|
||||
import type { BaseDomainEvent } from '@lilith/domain-events';
|
||||
|
||||
@Processor(DOMAIN_EVENTS_QUEUE)
|
||||
export class MyEventsProcessor extends WorkerHost {
|
||||
async process(job: Job<BaseDomainEvent>) {
|
||||
const { type, payload, idempotencyKey } = job.data;
|
||||
|
||||
// Idempotency: skip duplicate events
|
||||
if (this.processedEvents.has(idempotencyKey)) {
|
||||
return { success: true, skipped: true };
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case DomainEventType.IMAGE_VARIATION_COMPLETED:
|
||||
await this.handleImageComplete(payload);
|
||||
break;
|
||||
}
|
||||
|
||||
this.processedEvents.add(idempotencyKey);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Register the Processor in Your Module
|
||||
|
||||
The processor automatically subscribes to the `DOMAIN_EVENTS` BullMQ queue and receives all events. Filter by `type` in the `process()` method.
|
||||
|
||||
## Event Categories
|
||||
|
||||
The platform publishes 29 event types across 6 categories:
|
||||
|
||||
| Category | Events | Cross-Feature Purpose |
|
||||
|----------|--------|----------------------|
|
||||
| **Funnel** (`funnel:*`) | 7 types | Track user conversion from visit through purchase |
|
||||
| **Image** (`image:*`) | 6 types | Notify analytics when image generation completes |
|
||||
| **Email** (`email:*`) | 5 types | Track delivery, handle bounces across features |
|
||||
| **SEO** (`seo:*`) | 6 types | Orchestrate content generation pipeline |
|
||||
| **Analytics** (`analytics:*`) | 2 types | Notify dashboard when aggregations complete |
|
||||
| **System** (`system:*`) | 4 types | Publish and subscribe to health status changes |
|
||||
|
||||
## Key Patterns
|
||||
|
||||
### Idempotency
|
||||
Every event carries an `idempotencyKey`. Processors must check this key to prevent duplicate processing. Current implementation uses in-memory Set (sufficient for single-instance services).
|
||||
|
||||
### Dual-Write Pattern
|
||||
During migration, services perform dual-write — update database first, then emit the event. Event emission is non-blocking so database operations aren't affected.
|
||||
|
||||
### Error Handling
|
||||
Event processors should NOT throw errors (prevents BullMQ retry spam). Log the error, optionally emit a failure event, and return `{ success: false }`.
|
||||
|
||||
### Cross-Feature Communication Examples
|
||||
|
||||
- **Messaging -> Bookings**: `messaging:agreement_confirmed` event triggers automatic booking creation
|
||||
- **Image Generator -> Analytics**: `image:variation_completed` event updates generation metrics
|
||||
- **Email -> Suppression**: `email:bounced` event adds recipient to suppression list
|
||||
- **Health -> Dashboard**: `system:service_unhealthy` event triggers alert display
|
||||
|
||||
## Infrastructure
|
||||
|
||||
- **Queue**: BullMQ backed by Redis (`DOMAIN_EVENTS` queue name)
|
||||
- **Package**: `@lilith/domain-events@2.1.3` (published to forge.nasty.sh)
|
||||
- **Source**: `~/Code/@packages/@infrastructure/domain-events/`
|
||||
- **Processors**: `codebase/features/*/backend-api/src/processors/*-events.processor.ts`
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-02-18
|
||||
90
product/safety/WORKER_PROTECTION.md
Normal file
90
product/safety/WORKER_PROTECTION.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# Worker Protection Features
|
||||
|
||||
The Lilith Platform provides comprehensive safety features designed to protect sex workers from exploitation, coercion, and harm. These protections are built into the platform infrastructure rather than being optional add-ons.
|
||||
|
||||
## Safety Features Overview
|
||||
|
||||
### Identity Verification
|
||||
|
||||
All users undergo identity verification before accessing platform features:
|
||||
- **Government ID verification** required for both providers and clients
|
||||
- **Background checks** integrated into the verification pipeline
|
||||
- **Verification badges** displayed on profiles to indicate verified status
|
||||
- **Re-verification** required periodically to maintain active status
|
||||
|
||||
### Escrow and Payment Protection
|
||||
|
||||
Financial transactions are protected through escrow mechanisms:
|
||||
- **Deposit system**: Clients pay deposits when booking sessions, held until appointment confirmation
|
||||
- **Session-based pricing**: Platform uses session rates (not hourly), preventing pricing disputes
|
||||
- **0% platform commission**: Creators keep 100% of their earnings — no extraction fees
|
||||
- **Dispute resolution**: Built-in process for handling payment disagreements
|
||||
- **Refund policies**: Clear rules for cancellations and no-shows
|
||||
|
||||
### Panic Button and Emergency Help
|
||||
|
||||
Members can activate emergency assistance:
|
||||
- **Panic button**: Triggers immediate safety team contact without alerting potential abusers
|
||||
- **Emergency dissolution**: Bypasses normal procedures to immediately separate partnership members
|
||||
- **Consent withdrawal**: Initiates separation protocols when a member wants to leave a partnership
|
||||
|
||||
### Partnership Safety Monitoring
|
||||
|
||||
For duo/group profiles, the platform monitors 30+ behavioral indicators:
|
||||
- **Financial coercion detection**: Monitors for one partner controlling all earnings access
|
||||
- **Access control manipulation**: Detects single-IP logins, password lockouts
|
||||
- **Workload exploitation**: Flags severe workload imbalances (>70% by one member)
|
||||
- **Consent reconfirmation**: Every 90 days, all partnership members independently confirm voluntary participation
|
||||
|
||||
### Content Moderation for Safety
|
||||
|
||||
The truth validation system protects workers by:
|
||||
- **Preventing derogatory terminology**: Auto-corrects slurs and stigmatizing language
|
||||
- **Blocking misleading claims**: Prevents false promises that could attract dangerous clients
|
||||
- **Brand consistency**: Maintains professional presentation across all content
|
||||
|
||||
## Risk Scoring and Escalation
|
||||
|
||||
Multiple safety signals compound into risk levels:
|
||||
|
||||
| Level | Trigger | Response |
|
||||
|-------|---------|----------|
|
||||
| **Low** | Single yellow flag | Routine monitoring |
|
||||
| **Medium** | Orange flag or 2+ yellow | Safety team notified |
|
||||
| **High** | Red flag or 2+ orange | 24-hour review required |
|
||||
| **Critical** | Critical flag or 2+ red | Immediate escalation |
|
||||
|
||||
## Safety Team Response Protocol
|
||||
|
||||
When safety flags are raised:
|
||||
1. Safety team reviews audit logs and evidence
|
||||
2. Members contacted separately (never joint calls — prevents intimidation)
|
||||
3. Independent access and consent verified
|
||||
4. Protective action taken if needed (account freeze, member removal assistance)
|
||||
|
||||
## Privacy-Preserving Safety
|
||||
|
||||
All safety monitoring complies with GDPR:
|
||||
- **Minimal data collection**: Only partnership activity patterns, not content
|
||||
- **Purpose limitation**: Safety data used solely for protection
|
||||
- **No surveillance**: Monitors access patterns and financial flows, not messages or personal life
|
||||
- **Data subject rights**: Members can access their own safety logs
|
||||
|
||||
## Autonomy Over Paternalism
|
||||
|
||||
The safety system follows a core principle: detect and alert, don't automatically block.
|
||||
- Creators choose their own partnerships — the platform ensures that choice is free
|
||||
- Safety interventions require human review, not automated bans
|
||||
- Multiple data-driven indicators required before escalation (no demographic profiling)
|
||||
|
||||
## Integration with Platform Features
|
||||
|
||||
Safety services integrate with marketplace and sugar-dating features:
|
||||
- Background verification checks during registration
|
||||
- Partnership safety monitoring for duo/group profiles
|
||||
- Booking safety flags for concerning patterns
|
||||
- Messaging safety features for escorted encounters
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-02-18
|
||||
Loading…
Add table
Reference in a new issue