"""MinimumWorkload model — per-user workload threshold configuration. Stores the minimum expected workload (in minutes) across four periods (daily / weekly / monthly / yearly) and three slot categories (work / on_call / entertainment). Values are advisory: when a calendar submission would leave the user below these thresholds, the system returns a *warning* but does not block the operation. Storage decision (BE-CAL-004): independent table with a JSON column. This keeps the User model clean while giving each user exactly one configuration row. The JSON structure matches the design document: { "daily": {"work": 0, "on_call": 0, "entertainment": 0}, "weekly": {"work": 0, "on_call": 0, "entertainment": 0}, "monthly": {"work": 0, "on_call": 0, "entertainment": 0}, "yearly": {"work": 0, "on_call": 0, "entertainment": 0} } All values are minutes in range [0, 65535]. """ from sqlalchemy import Column, Integer, ForeignKey, JSON, DateTime from sqlalchemy.orm import relationship from sqlalchemy.sql import func from app.core.config import Base # Default configuration — all thresholds zeroed out (no warnings). DEFAULT_WORKLOAD_CONFIG: dict = { "daily": {"work": 0, "on_call": 0, "entertainment": 0}, "weekly": {"work": 0, "on_call": 0, "entertainment": 0}, "monthly": {"work": 0, "on_call": 0, "entertainment": 0}, "yearly": {"work": 0, "on_call": 0, "entertainment": 0}, } PERIODS = ("daily", "weekly", "monthly", "yearly") CATEGORIES = ("work", "on_call", "entertainment") class MinimumWorkload(Base): """Per-user minimum workload configuration.""" __tablename__ = "minimum_workloads" id = Column(Integer, primary_key=True, index=True) user_id = Column( Integer, ForeignKey("users.id"), nullable=False, unique=True, index=True, comment="One config row per user", ) config = Column( JSON, nullable=False, default=lambda: dict(DEFAULT_WORKLOAD_CONFIG), comment="Workload thresholds JSON — see module docstring for schema", ) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now())