500 lines
14 KiB
Markdown
500 lines
14 KiB
Markdown
|
|
# Demo Architecture - Production Demo System
|
|||
|
|
|
|||
|
|
## Overview
|
|||
|
|
|
|||
|
|
This document describes the complete demo architecture for providing prospects with isolated, ephemeral demo sessions to explore the Bakery IA platform.
|
|||
|
|
|
|||
|
|
## Key Features
|
|||
|
|
|
|||
|
|
- ✅ **Session Isolation**: Each prospect gets their own isolated copy of demo data
|
|||
|
|
- ✅ **Spanish Content**: All demo data in Spanish for the Spanish market
|
|||
|
|
- ✅ **Two Business Models**: Individual bakery and central baker satellite
|
|||
|
|
- ✅ **Automatic Cleanup**: Sessions automatically expire after 30 minutes
|
|||
|
|
- ✅ **Read-Mostly Access**: Prospects can explore but critical operations are restricted
|
|||
|
|
- ✅ **Production Ready**: Scalable to 200+ concurrent demo sessions
|
|||
|
|
|
|||
|
|
## Architecture Components
|
|||
|
|
|
|||
|
|
### 1. Demo Session Service
|
|||
|
|
|
|||
|
|
**Location**: `services/demo_session/`
|
|||
|
|
|
|||
|
|
**Responsibilities**:
|
|||
|
|
- Create isolated demo sessions
|
|||
|
|
- Manage session lifecycle (create, extend, destroy)
|
|||
|
|
- Clone base demo data to virtual tenants
|
|||
|
|
- Track session metrics and activity
|
|||
|
|
|
|||
|
|
**Key Endpoints**:
|
|||
|
|
```
|
|||
|
|
GET /api/demo/accounts # Get public demo account info
|
|||
|
|
POST /api/demo/session/create # Create new demo session
|
|||
|
|
POST /api/demo/session/extend # Extend session expiration
|
|||
|
|
POST /api/demo/session/destroy # Destroy session
|
|||
|
|
GET /api/demo/session/{id} # Get session info
|
|||
|
|
GET /api/demo/stats # Get usage statistics
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. Demo Data Seeding
|
|||
|
|
|
|||
|
|
**Location**: `scripts/demo/`
|
|||
|
|
|
|||
|
|
**Scripts**:
|
|||
|
|
- `seed_demo_users.py` - Creates demo user accounts
|
|||
|
|
- `seed_demo_tenants.py` - Creates base demo tenants (templates)
|
|||
|
|
- `seed_demo_inventory.py` - Populates inventory with Spanish data (25 ingredients per template)
|
|||
|
|
- `clone_demo_tenant.py` - Clones data from base template to virtual tenant (runs as K8s Job)
|
|||
|
|
|
|||
|
|
**Demo Accounts**:
|
|||
|
|
|
|||
|
|
#### Individual Bakery (Panadería San Pablo)
|
|||
|
|
```
|
|||
|
|
Email: demo.individual@panaderiasanpablo.com
|
|||
|
|
Password: DemoSanPablo2024!
|
|||
|
|
Business Model: Producción Local
|
|||
|
|
Features: Production, Recipes, Inventory, Forecasting, POS, Sales
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Central Baker Satellite (Panadería La Espiga)
|
|||
|
|
```
|
|||
|
|
Email: demo.central@panaderialaespiga.com
|
|||
|
|
Password: DemoLaEspiga2024!
|
|||
|
|
Business Model: Obrador Central + Punto de Venta
|
|||
|
|
Features: Suppliers, Inventory, Orders, POS, Sales, Forecasting
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. Gateway Middleware
|
|||
|
|
|
|||
|
|
**Location**: `gateway/app/middleware/demo_middleware.py`
|
|||
|
|
|
|||
|
|
**Responsibilities**:
|
|||
|
|
- Intercept requests with demo session IDs
|
|||
|
|
- Inject virtual tenant ID
|
|||
|
|
- Enforce operation restrictions
|
|||
|
|
- Track session activity
|
|||
|
|
|
|||
|
|
**Allowed Operations**:
|
|||
|
|
```python
|
|||
|
|
# Read - All allowed
|
|||
|
|
GET, HEAD, OPTIONS: *
|
|||
|
|
|
|||
|
|
# Limited Write - Realistic testing
|
|||
|
|
POST: /api/pos/sales, /api/orders, /api/inventory/adjustments
|
|||
|
|
PUT: /api/pos/sales/*, /api/orders/*
|
|||
|
|
|
|||
|
|
# Blocked
|
|||
|
|
DELETE: All (read-only for destructive operations)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. Redis Cache Layer
|
|||
|
|
|
|||
|
|
**Purpose**: Store frequently accessed demo session data
|
|||
|
|
|
|||
|
|
**Data Cached**:
|
|||
|
|
- Session metadata
|
|||
|
|
- Inventory summaries
|
|||
|
|
- POS session data
|
|||
|
|
- Recent sales
|
|||
|
|
|
|||
|
|
**TTL**: 30 minutes (auto-cleanup)
|
|||
|
|
|
|||
|
|
### 5. Kubernetes Resources
|
|||
|
|
|
|||
|
|
**Databases**:
|
|||
|
|
- `demo-session-db` - Tracks session records
|
|||
|
|
|
|||
|
|
**Services**:
|
|||
|
|
- `demo-session-service` - Main demo service (2 replicas)
|
|||
|
|
|
|||
|
|
**Jobs** (Initialization):
|
|||
|
|
- `demo-seed-users` - Creates demo users
|
|||
|
|
- `demo-seed-tenants` - Creates demo tenant templates
|
|||
|
|
- `demo-seed-inventory` - Populates inventory data (25 ingredients per tenant)
|
|||
|
|
|
|||
|
|
**Dynamic Jobs** (Runtime):
|
|||
|
|
- `demo-clone-{virtual_tenant_id}` - Created per session to clone data from template
|
|||
|
|
|
|||
|
|
**CronJob** (Maintenance):
|
|||
|
|
- `demo-session-cleanup` - Runs hourly to cleanup expired sessions
|
|||
|
|
|
|||
|
|
**RBAC**:
|
|||
|
|
- `demo-session-sa` - ServiceAccount for demo-session-service
|
|||
|
|
- `demo-session-job-creator` - Role allowing job creation and pod management
|
|||
|
|
- `demo-seed-role` - Role for seed jobs to access databases
|
|||
|
|
|
|||
|
|
## Data Flow
|
|||
|
|
|
|||
|
|
### Session Creation
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
1. User clicks "Probar Demo" on website
|
|||
|
|
↓
|
|||
|
|
2. Frontend calls POST /api/demo/session/create
|
|||
|
|
{
|
|||
|
|
"demo_account_type": "individual_bakery"
|
|||
|
|
}
|
|||
|
|
↓
|
|||
|
|
3. Demo Session Service:
|
|||
|
|
- Generates unique session_id: "demo_abc123..."
|
|||
|
|
- Creates virtual_tenant_id: UUID
|
|||
|
|
- Stores session in database
|
|||
|
|
- Returns session_token (JWT)
|
|||
|
|
↓
|
|||
|
|
4. Kubernetes Job Cloning (background):
|
|||
|
|
- Demo service triggers K8s Job with clone script
|
|||
|
|
- Job container uses CLONE_JOB_IMAGE (inventory-service image)
|
|||
|
|
- Clones inventory data from base template tenant
|
|||
|
|
- Uses ORM models for safe data copying
|
|||
|
|
- Job runs with IfNotPresent pull policy (works in dev & prod)
|
|||
|
|
↓
|
|||
|
|
5. Frontend receives:
|
|||
|
|
{
|
|||
|
|
"session_id": "demo_abc123...",
|
|||
|
|
"virtual_tenant_id": "uuid-here",
|
|||
|
|
"expires_at": "2025-10-02T12:30:00Z",
|
|||
|
|
"session_token": "eyJ..."
|
|||
|
|
}
|
|||
|
|
↓
|
|||
|
|
6. Frontend stores session_token in cookie/localStorage
|
|||
|
|
All subsequent requests include:
|
|||
|
|
Header: X-Demo-Session-Id: demo_abc123...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Request Handling
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
1. Request arrives at Gateway
|
|||
|
|
↓
|
|||
|
|
2. Demo Middleware checks:
|
|||
|
|
- Is X-Demo-Session-Id present?
|
|||
|
|
- Is session still active?
|
|||
|
|
- Is operation allowed?
|
|||
|
|
↓
|
|||
|
|
3. If valid:
|
|||
|
|
- Injects X-Tenant-Id: {virtual_tenant_id}
|
|||
|
|
- Routes to appropriate service
|
|||
|
|
↓
|
|||
|
|
4. Service processes request:
|
|||
|
|
- Reads/writes data for virtual tenant
|
|||
|
|
- No knowledge of demo vs. real tenant
|
|||
|
|
↓
|
|||
|
|
5. Response returned to user
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Session Cleanup
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Every hour (CronJob):
|
|||
|
|
|
|||
|
|
1. Demo Cleanup Service queries:
|
|||
|
|
SELECT * FROM demo_sessions
|
|||
|
|
WHERE status = 'active'
|
|||
|
|
AND expires_at < NOW()
|
|||
|
|
↓
|
|||
|
|
2. For each expired session:
|
|||
|
|
- Mark as 'expired'
|
|||
|
|
- Delete all virtual tenant data
|
|||
|
|
- Delete Redis keys
|
|||
|
|
- Update statistics
|
|||
|
|
↓
|
|||
|
|
3. Weekly cleanup:
|
|||
|
|
DELETE FROM demo_sessions
|
|||
|
|
WHERE status = 'destroyed'
|
|||
|
|
AND destroyed_at < NOW() - INTERVAL '7 days'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Database Schema
|
|||
|
|
|
|||
|
|
### demo_sessions Table
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
CREATE TABLE demo_sessions (
|
|||
|
|
id UUID PRIMARY KEY,
|
|||
|
|
session_id VARCHAR(100) UNIQUE NOT NULL,
|
|||
|
|
|
|||
|
|
-- Ownership
|
|||
|
|
user_id UUID,
|
|||
|
|
ip_address VARCHAR(45),
|
|||
|
|
user_agent VARCHAR(500),
|
|||
|
|
|
|||
|
|
-- Demo linking
|
|||
|
|
base_demo_tenant_id UUID NOT NULL,
|
|||
|
|
virtual_tenant_id UUID NOT NULL,
|
|||
|
|
demo_account_type VARCHAR(50) NOT NULL,
|
|||
|
|
|
|||
|
|
-- Lifecycle
|
|||
|
|
status VARCHAR(20) NOT NULL, -- active, expired, destroyed
|
|||
|
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
|||
|
|
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
|||
|
|
last_activity_at TIMESTAMP WITH TIME ZONE,
|
|||
|
|
destroyed_at TIMESTAMP WITH TIME ZONE,
|
|||
|
|
|
|||
|
|
-- Metrics
|
|||
|
|
request_count INTEGER DEFAULT 0,
|
|||
|
|
data_cloned BOOLEAN DEFAULT FALSE,
|
|||
|
|
redis_populated BOOLEAN DEFAULT FALSE,
|
|||
|
|
|
|||
|
|
-- Metadata
|
|||
|
|
metadata JSONB
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
CREATE INDEX idx_session_id ON demo_sessions(session_id);
|
|||
|
|
CREATE INDEX idx_virtual_tenant ON demo_sessions(virtual_tenant_id);
|
|||
|
|
CREATE INDEX idx_status ON demo_sessions(status);
|
|||
|
|
CREATE INDEX idx_expires_at ON demo_sessions(expires_at);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### tenants Table (Updated)
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
ALTER TABLE tenants ADD COLUMN is_demo BOOLEAN DEFAULT FALSE;
|
|||
|
|
ALTER TABLE tenants ADD COLUMN is_demo_template BOOLEAN DEFAULT FALSE;
|
|||
|
|
ALTER TABLE tenants ADD COLUMN base_demo_tenant_id UUID;
|
|||
|
|
ALTER TABLE tenants ADD COLUMN demo_session_id VARCHAR(100);
|
|||
|
|
ALTER TABLE tenants ADD COLUMN demo_expires_at TIMESTAMP WITH TIME ZONE;
|
|||
|
|
|
|||
|
|
CREATE INDEX idx_is_demo ON tenants(is_demo);
|
|||
|
|
CREATE INDEX idx_demo_session ON tenants(demo_session_id);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Deployment
|
|||
|
|
|
|||
|
|
### Initial Deployment
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 1. Deploy infrastructure (databases, redis, rabbitmq)
|
|||
|
|
kubectl apply -k infrastructure/kubernetes/overlays/prod
|
|||
|
|
|
|||
|
|
# 2. Run migrations
|
|||
|
|
# (Automatically handled by migration jobs)
|
|||
|
|
|
|||
|
|
# 3. Seed demo data
|
|||
|
|
# (Automatically handled by demo-seed-* jobs)
|
|||
|
|
|
|||
|
|
# 4. Verify demo system
|
|||
|
|
kubectl get jobs -n bakery-ia | grep demo-seed
|
|||
|
|
kubectl logs -f job/demo-seed-users -n bakery-ia
|
|||
|
|
kubectl logs -f job/demo-seed-tenants -n bakery-ia
|
|||
|
|
kubectl logs -f job/demo-seed-inventory -n bakery-ia
|
|||
|
|
|
|||
|
|
# 5. Test demo session creation
|
|||
|
|
curl -X POST http://your-domain/api/demo/session/create \
|
|||
|
|
-H "Content-Type: application/json" \
|
|||
|
|
-d '{"demo_account_type": "individual_bakery"}'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Using Tilt (Local Development)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Start Tilt
|
|||
|
|
tilt up
|
|||
|
|
|
|||
|
|
# Demo resources in Tilt UI:
|
|||
|
|
# - databases: demo-session-db
|
|||
|
|
# - migrations: demo-session-migration
|
|||
|
|
# - services: demo-session-service
|
|||
|
|
# - demo-init: demo-seed-users, demo-seed-tenants, demo-seed-inventory
|
|||
|
|
# - config: patch-demo-session-env (sets CLONE_JOB_IMAGE dynamically)
|
|||
|
|
|
|||
|
|
# Tilt automatically:
|
|||
|
|
# 1. Gets inventory-service image tag (e.g., tilt-abc123)
|
|||
|
|
# 2. Patches demo-session-service with CLONE_JOB_IMAGE env var
|
|||
|
|
# 3. Clone jobs use this image with IfNotPresent pull policy
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Monitoring
|
|||
|
|
|
|||
|
|
### Key Metrics
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# Session Statistics
|
|||
|
|
GET /api/demo/stats
|
|||
|
|
|
|||
|
|
{
|
|||
|
|
"total_sessions": 1250,
|
|||
|
|
"active_sessions": 45,
|
|||
|
|
"expired_sessions": 980,
|
|||
|
|
"destroyed_sessions": 225,
|
|||
|
|
"avg_duration_minutes": 18.5,
|
|||
|
|
"total_requests": 125000
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Health Checks
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Demo Session Service
|
|||
|
|
curl http://demo-session-service:8000/health
|
|||
|
|
|
|||
|
|
# Check active sessions
|
|||
|
|
kubectl exec -it deployment/demo-session-service -- \
|
|||
|
|
python -c "from app.services import *; print(get_active_sessions())"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Logs
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Demo session service logs
|
|||
|
|
kubectl logs -f deployment/demo-session-service -n bakery-ia
|
|||
|
|
|
|||
|
|
# Demo seed job logs
|
|||
|
|
kubectl logs job/demo-seed-inventory -n bakery-ia
|
|||
|
|
|
|||
|
|
# Cleanup cron job logs
|
|||
|
|
kubectl logs -l app=demo-cleanup -n bakery-ia --tail=100
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Scaling Considerations
|
|||
|
|
|
|||
|
|
### Current Limits
|
|||
|
|
|
|||
|
|
- **Concurrent Sessions**: ~200 (2 replicas × ~100 sessions each)
|
|||
|
|
- **Redis Memory**: ~1-2 GB (10 MB per session × 200)
|
|||
|
|
- **PostgreSQL**: ~5-10 GB (30 MB per virtual tenant × 200)
|
|||
|
|
- **Session Duration**: 30 minutes (configurable)
|
|||
|
|
- **Extensions**: Maximum 3 per session
|
|||
|
|
|
|||
|
|
### Scaling Up
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
# Scale demo-session-service
|
|||
|
|
kubectl scale deployment/demo-session-service --replicas=4 -n bakery-ia
|
|||
|
|
|
|||
|
|
# Increase Redis memory (if needed)
|
|||
|
|
# Edit redis deployment, increase memory limits
|
|||
|
|
|
|||
|
|
# Adjust session settings
|
|||
|
|
# Edit demo-session configmap:
|
|||
|
|
DEMO_SESSION_DURATION_MINUTES: 45 # Increase session time
|
|||
|
|
DEMO_SESSION_MAX_EXTENSIONS: 5 # Allow more extensions
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Security
|
|||
|
|
|
|||
|
|
### Public Demo Credentials
|
|||
|
|
|
|||
|
|
Demo credentials are **intentionally public** for prospect access:
|
|||
|
|
- Published on marketing website
|
|||
|
|
- Included in demo documentation
|
|||
|
|
- Safe because sessions are isolated and ephemeral
|
|||
|
|
|
|||
|
|
### Restrictions
|
|||
|
|
|
|||
|
|
1. **No Destructive Operations**: DELETE blocked
|
|||
|
|
2. **Limited Modifications**: Only realistic testing operations
|
|||
|
|
3. **No Sensitive Data Access**: Cannot change passwords, billing, etc.
|
|||
|
|
4. **Automatic Expiration**: Sessions auto-destroy after 30 minutes
|
|||
|
|
5. **Rate Limiting**: Standard gateway rate limits apply
|
|||
|
|
6. **No AI Training**: Forecast API blocked for demo accounts (no trained models)
|
|||
|
|
7. **Scheduler Prevention**: Procurement scheduler filters out demo tenants
|
|||
|
|
|
|||
|
|
### Data Privacy
|
|||
|
|
|
|||
|
|
- No real customer data in demo tenants
|
|||
|
|
- Session data automatically deleted
|
|||
|
|
- Anonymized analytics only
|
|||
|
|
|
|||
|
|
## Troubleshooting
|
|||
|
|
|
|||
|
|
### Session Creation Fails
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Check demo-session-service health
|
|||
|
|
kubectl get pods -l app=demo-session-service -n bakery-ia
|
|||
|
|
|
|||
|
|
# Check logs
|
|||
|
|
kubectl logs deployment/demo-session-service -n bakery-ia --tail=50
|
|||
|
|
|
|||
|
|
# Verify base demo tenants exist
|
|||
|
|
kubectl exec -it deployment/tenant-service -- \
|
|||
|
|
psql $TENANT_DATABASE_URL -c \
|
|||
|
|
"SELECT id, name, subdomain FROM tenants WHERE is_demo_template = true;"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Sessions Not Cleaning Up
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Check cleanup cronjob
|
|||
|
|
kubectl get cronjobs -n bakery-ia
|
|||
|
|
kubectl get jobs -l app=demo-cleanup -n bakery-ia
|
|||
|
|
|
|||
|
|
# Manually trigger cleanup
|
|||
|
|
kubectl create job --from=cronjob/demo-session-cleanup manual-cleanup-$(date +%s) -n bakery-ia
|
|||
|
|
|
|||
|
|
# Check for orphaned sessions
|
|||
|
|
kubectl exec -it deployment/demo-session-service -- \
|
|||
|
|
psql $DEMO_SESSION_DATABASE_URL -c \
|
|||
|
|
"SELECT status, COUNT(*) FROM demo_sessions GROUP BY status;"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Redis Connection Issues
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Test Redis connectivity
|
|||
|
|
kubectl exec -it deployment/demo-session-service -- \
|
|||
|
|
python -c "import redis; r=redis.Redis(host='redis-service'); print(r.ping())"
|
|||
|
|
|
|||
|
|
# Check Redis memory usage
|
|||
|
|
kubectl exec -it deployment/redis -- redis-cli INFO memory
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Technical Implementation Details
|
|||
|
|
|
|||
|
|
### Data Cloning Architecture
|
|||
|
|
|
|||
|
|
**Choice: Kubernetes Job-based Cloning** (selected over service-based endpoints)
|
|||
|
|
|
|||
|
|
**Why K8s Jobs**:
|
|||
|
|
- Database-level operations (faster than API calls)
|
|||
|
|
- Scalable (one job per session, isolated execution)
|
|||
|
|
- No service-specific clone endpoints needed
|
|||
|
|
- Works in both dev (Tilt) and production
|
|||
|
|
|
|||
|
|
**How it Works**:
|
|||
|
|
1. Demo-session-service creates K8s Job via K8s API
|
|||
|
|
2. Job uses `CLONE_JOB_IMAGE` environment variable (configured image)
|
|||
|
|
3. In **Dev (Tilt)**: `patch-demo-session-env` sets dynamic Tilt image tag
|
|||
|
|
4. In **Production**: Deployment manifest has stable release tag
|
|||
|
|
5. Job runs `clone_demo_tenant.py` with `imagePullPolicy: IfNotPresent`
|
|||
|
|
6. Script uses ORM models to clone data safely
|
|||
|
|
|
|||
|
|
**Environment-based Image Configuration**:
|
|||
|
|
```yaml
|
|||
|
|
# Demo-session deployment
|
|||
|
|
env:
|
|||
|
|
- name: CLONE_JOB_IMAGE
|
|||
|
|
value: "bakery/inventory-service:latest" # Overridden by Tilt in dev
|
|||
|
|
|
|||
|
|
# Tilt automatically patches this to match actual inventory-service tag
|
|||
|
|
# e.g., bakery/inventory-service:tilt-abc123
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### AI Model Restrictions
|
|||
|
|
|
|||
|
|
**Fake Models in Database**:
|
|||
|
|
- Demo tenants have AI model records in database
|
|||
|
|
- No actual model files (.pkl, .h5) stored
|
|||
|
|
- Forecast API blocked at gateway level for demo accounts
|
|||
|
|
- Returns user-friendly error message
|
|||
|
|
|
|||
|
|
**Scheduler Prevention**:
|
|||
|
|
- Procurement scheduler filters `is_demo = true` tenants
|
|||
|
|
- Prevents automated procurement runs on demo data
|
|||
|
|
- Manual procurement still allowed for realistic testing
|
|||
|
|
|
|||
|
|
## Future Enhancements
|
|||
|
|
|
|||
|
|
1. **Analytics Dashboard**: Track demo → paid conversion rates
|
|||
|
|
2. **Guided Tours**: In-app tutorials for demo users
|
|||
|
|
3. **Custom Demo Scenarios**: Let prospects choose specific features
|
|||
|
|
4. **Demo Recordings**: Capture anonymized session recordings
|
|||
|
|
5. **Multi-Region**: Deploy demo infrastructure in EU, US, LATAM
|
|||
|
|
6. **Sales & Orders Cloning**: Extend clone script to copy sales and orders data
|
|||
|
|
|
|||
|
|
## References
|
|||
|
|
|
|||
|
|
- [Demo Session Service API](services/demo_session/README.md)
|
|||
|
|
- [Demo Data Seeding](scripts/demo/README.md)
|
|||
|
|
- [Gateway Middleware](gateway/app/middleware/README.md)
|
|||
|
|
- [Kubernetes Manifests](infrastructure/kubernetes/base/components/demo-session/)
|