"""Financial viability models — initial schema for CUST-WP-0025-T23.""" from __future__ import annotations import uuid from datetime import date, datetime from sqlalchemy import Date, DateTime, Float, Integer, String, Text from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column from hub_core.models.base import Base, TimestampMixin class Budget(Base, TimestampMixin): __tablename__ = "fin_budgets" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) domain_slug: Mapped[str] = mapped_column(String(64), nullable=False, index=True) period_start: Mapped[date] = mapped_column(Date, nullable=False) period_end: Mapped[date] = mapped_column(Date, nullable=False) allocated: Mapped[float] = mapped_column(Float, nullable=False, default=0.0) committed: Mapped[float] = mapped_column(Float, nullable=False, default=0.0) spent: Mapped[float] = mapped_column(Float, nullable=False, default=0.0) currency: Mapped[str] = mapped_column(String(3), nullable=False, default="EUR") notes: Mapped[str | None] = mapped_column(Text, nullable=True) class Commitment(Base, TimestampMixin): __tablename__ = "fin_commitments" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) domain_slug: Mapped[str] = mapped_column(String(64), nullable=False, index=True) commitment_type: Mapped[str] = mapped_column(String(32), nullable=False) title: Mapped[str] = mapped_column(String(256), nullable=False) amount: Mapped[float] = mapped_column(Float, nullable=False) cadence: Mapped[str] = mapped_column(String(16), nullable=False, default="monthly") start_date: Mapped[date] = mapped_column(Date, nullable=False) end_date: Mapped[date | None] = mapped_column(Date, nullable=True) currency: Mapped[str] = mapped_column(String(3), nullable=False, default="EUR") class BurnRate(Base, TimestampMixin): __tablename__ = "fin_burn_rates" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) domain_slug: Mapped[str] = mapped_column(String(64), nullable=False, index=True) period_month: Mapped[str] = mapped_column(String(7), nullable=False, index=True) actual_spend: Mapped[float] = mapped_column(Float, nullable=False, default=0.0) projected_spend: Mapped[float] = mapped_column(Float, nullable=False, default=0.0) currency: Mapped[str] = mapped_column(String(3), nullable=False, default="EUR") class RunwayProjection(Base, TimestampMixin): __tablename__ = "fin_runway_projections" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) current_balance: Mapped[float] = mapped_column(Float, nullable=False) monthly_burn: Mapped[float] = mapped_column(Float, nullable=False) months_remaining: Mapped[float] = mapped_column(Float, nullable=False) alert_threshold_months: Mapped[float] = mapped_column(Float, nullable=False, default=3.0) computed_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) currency: Mapped[str] = mapped_column(String(3), nullable=False, default="EUR") class TokenSpend(Base, TimestampMixin): __tablename__ = "fin_token_spends" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) provider: Mapped[str] = mapped_column(String(32), nullable=False, index=True) model: Mapped[str] = mapped_column(String(64), nullable=False) tokens_in: Mapped[int | None] = mapped_column(Integer, nullable=True) tokens_out: Mapped[int | None] = mapped_column(Integer, nullable=True) cost: Mapped[float] = mapped_column(Float, nullable=False, default=0.0) session_id: Mapped[str | None] = mapped_column(String(128), nullable=True) recorded_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False) currency: Mapped[str] = mapped_column(String(3), nullable=False, default="EUR")