""" Database models for billing and usage tracking. """ from sqlalchemy import Column, String, Integer, Float, DateTime, Boolean, ForeignKey, Text from sqlalchemy.orm import relationship from datetime import datetime from typing import Optional from app.db.database import Base class Tenant(Base): """Tenant/organization model.""" __tablename__ = "tenants" id = Column(String, primary_key=True, index=True) name = Column(String, nullable=False) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) # Relationships plan = relationship("TenantPlan", back_populates="tenant", uselist=False) usage_events = relationship("UsageEvent", back_populates="tenant") daily_usage = relationship("UsageDaily", back_populates="tenant") monthly_usage = relationship("UsageMonthly", back_populates="tenant") class TenantPlan(Base): """Tenant subscription plan.""" __tablename__ = "tenant_plans" id = Column(Integer, primary_key=True, autoincrement=True) tenant_id = Column(String, ForeignKey("tenants.id"), unique=True, nullable=False, index=True) plan_name = Column(String, nullable=False, index=True) # "starter", "growth", "pro" monthly_chat_limit = Column(Integer, nullable=False) # -1 for unlimited created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) # Relationships tenant = relationship("Tenant", back_populates="plan") class UsageEvent(Base): """Individual usage event (each /chat request).""" __tablename__ = "usage_events" id = Column(Integer, primary_key=True, autoincrement=True) request_id = Column(String, unique=True, nullable=False, index=True) tenant_id = Column(String, ForeignKey("tenants.id"), nullable=False, index=True) user_id = Column(String, nullable=False, index=True) kb_id = Column(String, nullable=False) # LLM details provider = Column(String, nullable=False) # "gemini" or "openai" model = Column(String, nullable=False) # Token usage prompt_tokens = Column(Integer, nullable=False, default=0) completion_tokens = Column(Integer, nullable=False, default=0) total_tokens = Column(Integer, nullable=False, default=0) # Cost tracking estimated_cost_usd = Column(Float, nullable=False, default=0.0) # Timestamp request_timestamp = Column(DateTime, default=datetime.utcnow, nullable=False, index=True) # Relationships tenant = relationship("Tenant", back_populates="usage_events") class UsageDaily(Base): """Daily aggregated usage per tenant.""" __tablename__ = "usage_daily" id = Column(Integer, primary_key=True, autoincrement=True) tenant_id = Column(String, ForeignKey("tenants.id"), nullable=False, index=True) date = Column(DateTime, nullable=False, index=True) # Aggregated metrics total_requests = Column(Integer, nullable=False, default=0) total_tokens = Column(Integer, nullable=False, default=0) total_cost_usd = Column(Float, nullable=False, default=0.0) # Provider breakdown gemini_requests = Column(Integer, nullable=False, default=0) openai_requests = Column(Integer, nullable=False, default=0) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) # Unique constraint: one record per tenant per day __table_args__ = ( {"sqlite_autoincrement": True}, ) # Relationships tenant = relationship("Tenant", back_populates="daily_usage") class UsageMonthly(Base): """Monthly aggregated usage per tenant.""" __tablename__ = "usage_monthly" id = Column(Integer, primary_key=True, autoincrement=True) tenant_id = Column(String, ForeignKey("tenants.id"), nullable=False, index=True) year = Column(Integer, nullable=False, index=True) month = Column(Integer, nullable=False, index=True) # 1-12 # Aggregated metrics total_requests = Column(Integer, nullable=False, default=0) total_tokens = Column(Integer, nullable=False, default=0) total_cost_usd = Column(Float, nullable=False, default=0.0) # Provider breakdown gemini_requests = Column(Integer, nullable=False, default=0) openai_requests = Column(Integer, nullable=False, default=0) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) # Unique constraint: one record per tenant per month __table_args__ = ( {"sqlite_autoincrement": True}, ) # Relationships tenant = relationship("Tenant", back_populates="monthly_usage")