File size: 1,980 Bytes
7c6ffa6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | """Monthly per-user usage tracking model.
One row per user per calendar month. Tracks granular counts for each
billable metric so the usage endpoint and admin dashboard can report
accurate numbers.
"""
from __future__ import annotations
from datetime import datetime
from sqlalchemy import DateTime, Float, Integer, String, UniqueConstraint, func
from sqlalchemy.orm import Mapped, mapped_column
from app.core.database import Base
from app.utils.ids import prefixed_id
class UserUsageMonthly(Base):
__tablename__ = "user_usage_monthly"
__table_args__ = (
UniqueConstraint("user_id", "month", name="uq_user_usage_monthly_user_month"),
)
id: Mapped[str] = mapped_column(
String(40),
primary_key=True,
default=lambda: prefixed_id("usg"),
)
user_id: Mapped[str] = mapped_column(
String(40),
index=True,
nullable=False,
)
month: Mapped[str] = mapped_column(
String(7), # YYYY-MM
nullable=False,
)
documents_uploaded_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
generations_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
quizzes_generated_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
flashcards_generated_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
videos_generated_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
audio_minutes_generated: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
storage_bytes_used: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
server_default=func.now(),
nullable=False,
)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
server_default=func.now(),
onupdate=func.now(),
nullable=False,
)
|