Files
bakery-ia/services/demo_session/app/models/demo_session.py
Urtzi Alfaro fd657dea02 refactor(demo): Standardize demo account type names across codebase
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>
2025-11-30 08:48:56 +01:00

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
}