Standardize demo account type naming from inconsistent variants to clean names: - individual_bakery, professional_bakery → professional - central_baker, enterprise_chain → enterprise This eliminates naming confusion that was causing bugs in the demo session initialization, particularly for enterprise demo tenants where different parts of the system used different names for the same concept. Changes: - Updated source of truth in demo_session config - Updated all backend services (middleware, cloning, orchestration) - Updated frontend types, pages, and stores - Updated demo session models and schemas - Removed all backward compatibility code as requested Related to: Enterprise demo session access fix 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
93 lines
3.8 KiB
Python
93 lines
3.8 KiB
Python
"""
|
|
Demo Session Models
|
|
Tracks ephemeral demo sessions for prospect users
|
|
"""
|
|
|
|
from sqlalchemy import Column, String, Boolean, DateTime, Integer, Enum as SQLEnum
|
|
from sqlalchemy.dialects.postgresql import UUID, JSONB
|
|
from datetime import datetime, timezone
|
|
import uuid
|
|
import enum
|
|
|
|
from shared.database.base import Base
|
|
|
|
|
|
class DemoSessionStatus(enum.Enum):
|
|
"""Demo session status"""
|
|
PENDING = "pending" # Data cloning in progress
|
|
READY = "ready" # All data loaded, safe to use
|
|
FAILED = "failed" # One or more services failed completely
|
|
PARTIAL = "partial" # Some services failed, others succeeded
|
|
ACTIVE = "active" # User is actively using the session (deprecated, use READY)
|
|
EXPIRED = "expired" # Session TTL exceeded
|
|
DESTROYED = "destroyed" # Session terminated
|
|
|
|
|
|
class CloningStatus(enum.Enum):
|
|
"""Individual service cloning status"""
|
|
NOT_STARTED = "not_started"
|
|
IN_PROGRESS = "in_progress"
|
|
COMPLETED = "completed"
|
|
FAILED = "failed"
|
|
|
|
|
|
class DemoSession(Base):
|
|
"""Demo Session tracking model"""
|
|
__tablename__ = "demo_sessions"
|
|
|
|
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
session_id = Column(String(100), unique=True, nullable=False, index=True)
|
|
|
|
# Session ownership
|
|
user_id = Column(UUID(as_uuid=True), nullable=True)
|
|
ip_address = Column(String(45), nullable=True)
|
|
user_agent = Column(String(500), nullable=True)
|
|
|
|
# Demo tenant linking
|
|
base_demo_tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
|
|
virtual_tenant_id = Column(UUID(as_uuid=True), nullable=False, index=True)
|
|
demo_account_type = Column(String(50), nullable=False) # 'professional', 'enterprise'
|
|
|
|
# Session lifecycle
|
|
status = Column(SQLEnum(DemoSessionStatus, values_callable=lambda obj: [e.value for e in obj]), default=DemoSessionStatus.PENDING, index=True)
|
|
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), index=True)
|
|
expires_at = Column(DateTime(timezone=True), nullable=False, index=True)
|
|
last_activity_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
|
|
destroyed_at = Column(DateTime(timezone=True), nullable=True)
|
|
|
|
# Cloning progress tracking
|
|
cloning_started_at = Column(DateTime(timezone=True), nullable=True)
|
|
cloning_completed_at = Column(DateTime(timezone=True), nullable=True)
|
|
total_records_cloned = Column(Integer, default=0)
|
|
|
|
# Per-service cloning status
|
|
cloning_progress = Column(JSONB, default=dict) # {service_name: {status, records, started_at, completed_at, error}}
|
|
|
|
# Session metrics
|
|
request_count = Column(Integer, default=0)
|
|
data_cloned = Column(Boolean, default=False) # Deprecated: use status instead
|
|
redis_populated = Column(Boolean, default=False) # Deprecated: use status instead
|
|
|
|
# Session metadata
|
|
session_metadata = Column(JSONB, default=dict)
|
|
|
|
def __repr__(self):
|
|
return f"<DemoSession(session_id={self.session_id}, status={self.status.value})>"
|
|
|
|
def to_dict(self):
|
|
"""Convert to dictionary"""
|
|
return {
|
|
"id": str(self.id),
|
|
"session_id": self.session_id,
|
|
"user_id": str(self.user_id) if self.user_id else None,
|
|
"virtual_tenant_id": str(self.virtual_tenant_id),
|
|
"base_demo_tenant_id": str(self.base_demo_tenant_id),
|
|
"demo_account_type": self.demo_account_type,
|
|
"status": self.status.value,
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|
"expires_at": self.expires_at.isoformat() if self.expires_at else None,
|
|
"last_activity_at": self.last_activity_at.isoformat() if self.last_activity_at else None,
|
|
"request_count": self.request_count,
|
|
"metadata": self.session_metadata
|
|
}
|