Files
bakery-ia/DEMO_ARCHITECTURE.md
2025-10-03 14:09:34 +02:00

500 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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/)