251 lines
9.6 KiB
Markdown
251 lines
9.6 KiB
Markdown
|
|
# Streaming Companion
|
||
|
|
|
||
|
|
Platform-agnostic streaming companion for live cam sessions. Provides session management, real-time tip tracking, goal progress, chatbot persona routing, tip menus, animation overlays, and post-stream analytics.
|
||
|
|
|
||
|
|
Works alongside any cam platform (Chaturbate, Stripchat, etc.) — the creator selects their platform when starting a session.
|
||
|
|
|
||
|
|
## Directory Structure
|
||
|
|
|
||
|
|
```
|
||
|
|
streaming/
|
||
|
|
├── backend-api/ # NestJS API server
|
||
|
|
│ └── src/
|
||
|
|
│ ├── sessions/ # Session lifecycle (start/end/update)
|
||
|
|
│ ├── tips/ # Tip recording and aggregation
|
||
|
|
│ ├── goals/ # Tip goal tracking with progress
|
||
|
|
│ ├── menu/ # Tip menu item CRUD
|
||
|
|
│ ├── animations/ # Animation trigger system
|
||
|
|
│ ├── analytics/ # Post-stream analytics queries
|
||
|
|
│ ├── chatbot/ # Chatbot persona config and routing
|
||
|
|
│ ├── chat-participant-tts/ # TTS voice synthesis for tips
|
||
|
|
│ ├── gateway/ # WebSocket gateways
|
||
|
|
│ │ ├── streaming.gateway.ts # Authenticated real-time events
|
||
|
|
│ │ ├── overlay.gateway.ts # Anonymous read-only (OBS)
|
||
|
|
│ │ └── types/events.ts # Event type definitions
|
||
|
|
│ └── entities/ # TypeORM entities
|
||
|
|
├── frontend-dashboard/ # React dashboard (embedded in platform)
|
||
|
|
│ └── src/
|
||
|
|
│ ├── pages/ # StreamDashboardPage
|
||
|
|
│ ├── hooks/ # API query hooks
|
||
|
|
│ └── types.ts # Shared TypeScript types
|
||
|
|
├── frontend-standalone/ # Vite dev wrapper for standalone testing
|
||
|
|
├── backend-api-msw/ # MSW request handler exports
|
||
|
|
├── shared/ # Shared MSW mock data
|
||
|
|
│ └── msw/src/data/ # Mock sessions, tips
|
||
|
|
├── docs/ # Feature-level docs
|
||
|
|
├── docker-compose.yml # PostgreSQL + Redis for local dev
|
||
|
|
└── services.yaml # Service registry definition
|
||
|
|
```
|
||
|
|
|
||
|
|
## Running Locally
|
||
|
|
|
||
|
|
### Prerequisites
|
||
|
|
|
||
|
|
- PostgreSQL (port 25468) and Redis (port 26398) — start via Docker:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd codebase/features/streaming
|
||
|
|
docker-compose up -d
|
||
|
|
```
|
||
|
|
|
||
|
|
### Backend API
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd backend-api
|
||
|
|
bun install
|
||
|
|
bun dev # Starts on port 3130
|
||
|
|
```
|
||
|
|
|
||
|
|
Swagger docs available at `http://localhost:3130/api/docs`.
|
||
|
|
|
||
|
|
### Frontend Dashboard (Standalone)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd frontend-standalone
|
||
|
|
bun install
|
||
|
|
bun dev # Vite dev server with MSW mocks
|
||
|
|
```
|
||
|
|
|
||
|
|
### Full Platform Dev Cluster
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# From platform root
|
||
|
|
./run dev
|
||
|
|
```
|
||
|
|
|
||
|
|
## API Reference
|
||
|
|
|
||
|
|
### Sessions (`/api/sessions`)
|
||
|
|
|
||
|
|
| Method | Path | Auth | Description |
|
||
|
|
|--------|------|------|-------------|
|
||
|
|
| `POST` | `/api/sessions` | SSO | Start a new streaming session |
|
||
|
|
| `GET` | `/api/sessions/active` | SSO | Get current active session |
|
||
|
|
| `GET` | `/api/sessions` | SSO | List all sessions (paginated) |
|
||
|
|
| `GET` | `/api/sessions/:id` | SSO | Get session by ID |
|
||
|
|
| `PATCH` | `/api/sessions/:id` | SSO | Update session title/notes/metadata |
|
||
|
|
| `POST` | `/api/sessions/:id/end` | SSO | End an active session |
|
||
|
|
|
||
|
|
### Tips (`/api/tips`)
|
||
|
|
|
||
|
|
| Method | Path | Auth | Description |
|
||
|
|
|--------|------|------|-------------|
|
||
|
|
| `POST` | `/api/tips` | SSO | Record a tip |
|
||
|
|
| `GET` | `/api/tips` | SSO | List tips (paginated, filterable by session) |
|
||
|
|
|
||
|
|
### Goals (`/api/goals`)
|
||
|
|
|
||
|
|
| Method | Path | Auth | Description |
|
||
|
|
|--------|------|------|-------------|
|
||
|
|
| `POST` | `/api/goals` | SSO | Create a tip goal |
|
||
|
|
| `GET` | `/api/goals` | SSO | List goals for a session |
|
||
|
|
| `PATCH` | `/api/goals/:id` | SSO | Update goal |
|
||
|
|
| `DELETE` | `/api/goals/:id` | SSO | Delete goal |
|
||
|
|
|
||
|
|
### Tip Menu (`/api/menu`)
|
||
|
|
|
||
|
|
| Method | Path | Auth | Description |
|
||
|
|
|--------|------|------|-------------|
|
||
|
|
| `POST` | `/api/menu` | SSO | Create menu item |
|
||
|
|
| `GET` | `/api/menu` | SSO | List creator's menu items |
|
||
|
|
| `PATCH` | `/api/menu/:id` | SSO | Update menu item |
|
||
|
|
| `DELETE` | `/api/menu/:id` | SSO | Delete menu item |
|
||
|
|
| `POST` | `/api/menu/:id/toggle` | SSO | Toggle item active/inactive |
|
||
|
|
| `GET` | `/api/menu/public/:creatorId` | None | Get public menu for viewers |
|
||
|
|
|
||
|
|
### Animations (`/api/animations`)
|
||
|
|
|
||
|
|
| Method | Path | Auth | Description |
|
||
|
|
|--------|------|------|-------------|
|
||
|
|
| `POST` | `/api/animations/trigger` | SSO | Manually trigger an animation |
|
||
|
|
|
||
|
|
### Analytics (`/api/analytics`)
|
||
|
|
|
||
|
|
| Method | Path | Auth | Description |
|
||
|
|
|--------|------|------|-------------|
|
||
|
|
| `GET` | `/api/analytics/summary` | SSO | Revenue summary (range-filterable) |
|
||
|
|
| `GET` | `/api/analytics/top-tippers` | SSO | Top tippers leaderboard |
|
||
|
|
| `GET` | `/api/analytics/export` | SSO | CSV export of session data |
|
||
|
|
|
||
|
|
## WebSocket Protocol
|
||
|
|
|
||
|
|
### Authenticated Namespace: `/streaming`
|
||
|
|
|
||
|
|
Requires SSO authentication metadata on connection.
|
||
|
|
|
||
|
|
**Client → Server Events:**
|
||
|
|
|
||
|
|
| Event | Payload | Description |
|
||
|
|
|-------|---------|-------------|
|
||
|
|
| `join_session` | `{ sessionId }` | Join a session's real-time room |
|
||
|
|
| `leave_session` | `{ sessionId }` | Leave a session room |
|
||
|
|
| `update_viewers` | `{ sessionId, viewerCount }` | Report current viewer count |
|
||
|
|
| `add_tip` | `{ sessionId, amountCents, tipperName?, message? }` | Record a tip via WebSocket |
|
||
|
|
| `chatbot_message` | `{ sessionId, senderName, message }` | Route a chat message through chatbot personas |
|
||
|
|
|
||
|
|
**Server → Client Events:**
|
||
|
|
|
||
|
|
| Event | Payload | Description |
|
||
|
|
|-------|---------|-------------|
|
||
|
|
| `session_updated` | `{ sessionId, totalTipsCents, tipCount, peakViewers, ... }` | Session stats updated |
|
||
|
|
| `tip_received` | `{ sessionId, tip, sessionTotals }` | New tip recorded |
|
||
|
|
| `goal_progress` | `{ sessionId, goalId, title, currentCents, targetCents, percentage }` | Goal progress changed |
|
||
|
|
| `goal_completed` | `{ sessionId, goalId, title, targetCents }` | Goal target reached |
|
||
|
|
| `chatbot_response` | `{ sessionId, personaName, responseText, ... }` | Chatbot persona reply |
|
||
|
|
| `chat_participant_audio` | `{ sessionId, tipId, audioBase64, format, ... }` | TTS audio for tip message |
|
||
|
|
| `animation_trigger` | `{ sessionId, type, metadata? }` | Animation effect triggered |
|
||
|
|
| `menu_updated` | `{ creatorId, items }` | Tip menu changed |
|
||
|
|
| `error` | `{ message, code, sessionId? }` | Error notification |
|
||
|
|
|
||
|
|
### Read-Only Overlay Namespace: `/streaming/overlay`
|
||
|
|
|
||
|
|
No authentication required. Designed for OBS browser source embedding.
|
||
|
|
|
||
|
|
**Client → Server Events:**
|
||
|
|
|
||
|
|
| Event | Payload | Description |
|
||
|
|
|-------|---------|-------------|
|
||
|
|
| `join_overlay` | `{ sessionId }` | Subscribe to overlay events |
|
||
|
|
| `leave_overlay` | `{ sessionId }` | Unsubscribe |
|
||
|
|
|
||
|
|
**Server → Client Events:**
|
||
|
|
|
||
|
|
Receives the same broadcast events as the authenticated namespace: `tip_received`, `goal_progress`, `goal_completed`, `animation_trigger`, `menu_updated`, `session_updated`.
|
||
|
|
|
||
|
|
Cannot send write operations (`add_tip`, `update_viewers`, `chatbot_message`).
|
||
|
|
|
||
|
|
## Animation Types
|
||
|
|
|
||
|
|
| Type | Enum Value | Description |
|
||
|
|
|------|------------|-------------|
|
||
|
|
| Confetti | `confetti` | Confetti burst effect |
|
||
|
|
| Hearts | `hearts` | Floating hearts animation |
|
||
|
|
| Rain | `rain` | Token rain effect |
|
||
|
|
| Custom | `custom` | Creator-defined animation |
|
||
|
|
|
||
|
|
Animations auto-trigger when tips exceed a configurable threshold. Creators can also trigger them manually via the REST API.
|
||
|
|
|
||
|
|
## Domain Events
|
||
|
|
|
||
|
|
The streaming feature emits events via `@lilith/domain-events` for cross-feature integration:
|
||
|
|
|
||
|
|
| Event | When | Key Payload Fields |
|
||
|
|
|-------|------|--------------------|
|
||
|
|
| `streaming.session.started` | Session created | `creatorId`, `platform`, `sessionId` |
|
||
|
|
| `streaming.session.ended` | Session ended | `creatorId`, `duration`, `totalTipsCents`, `tipCount` |
|
||
|
|
| `streaming.tip.received` | Tip recorded | `creatorId`, `amountCents`, `source`, `sessionId` |
|
||
|
|
| `streaming.goal.completed` | Goal target met | `creatorId`, `goalId`, `targetCents` |
|
||
|
|
|
||
|
|
## Data Model
|
||
|
|
|
||
|
|
### Core Entities
|
||
|
|
|
||
|
|
- **StreamSessionEntity** — A single streaming session with start/end times, platform, viewer stats, tip aggregates
|
||
|
|
- **StreamTipEntity** — Individual tip records linked to sessions, with source tracking (`platform_api`, `manual`, `websocket`)
|
||
|
|
- **TipGoalEntity** — Progress-tracked goals per session (e.g., "500 tokens for outfit change")
|
||
|
|
- **TipMenuItemEntity** — Configurable menu items with categories (`performance`, `request`, `interaction`, `custom`)
|
||
|
|
- **SessionNoteEntity** — Timestamped notes attached to sessions
|
||
|
|
- **ChatbotConfigEntity** — Chatbot persona definitions with trigger patterns
|
||
|
|
- **ChatbotResponseTemplateEntity** — Response templates for chatbot personas
|
||
|
|
|
||
|
|
### Enums
|
||
|
|
|
||
|
|
- `SessionStatus`: `active` | `ended`
|
||
|
|
- `StreamPlatform`: `chaturbate` | `stripchat` | `other`
|
||
|
|
- `TipSource`: `platform_api` | `manual` | `websocket`
|
||
|
|
- `MenuItemCategory`: `performance` | `request` | `interaction` | `custom`
|
||
|
|
- `AnimationType`: `confetti` | `hearts` | `rain` | `custom`
|
||
|
|
|
||
|
|
## Configuration
|
||
|
|
|
||
|
|
Environment variables (with defaults for local dev):
|
||
|
|
|
||
|
|
| Variable | Default | Description |
|
||
|
|
|----------|---------|-------------|
|
||
|
|
| `POSTGRES_HOST` | `localhost` | Database host |
|
||
|
|
| `POSTGRES_PORT` | `25468` | Database port |
|
||
|
|
| `POSTGRES_USER` | `streaming` | Database user |
|
||
|
|
| `POSTGRES_PASSWORD` | `devpassword` | Database password |
|
||
|
|
| `POSTGRES_DB` | `lilith_streaming` | Database name |
|
||
|
|
| `REDIS_HOST` | `localhost` | Redis host |
|
||
|
|
| `REDIS_PORT` | `26398` | Redis port |
|
||
|
|
| `SSO_URL` | Via service registry | SSO service URL for auth |
|
||
|
|
| `PORT` | `3130` | API server port |
|
||
|
|
|
||
|
|
## Testing
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd backend-api
|
||
|
|
bun run test # Run all tests
|
||
|
|
bun run test:cov # With coverage
|
||
|
|
bun run test -- --watch # Watch mode
|
||
|
|
```
|
||
|
|
|
||
|
|
Frontend E2E tests:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd frontend-standalone
|
||
|
|
bun run test:e2e # Playwright tests
|
||
|
|
bun run test:e2e:ui # Interactive Playwright UI
|
||
|
|
```
|