Record the FIN-WP-0007 split after checking resource-control: they keep intelligence resource identity and provision-level class I metering; session tokens stay with State Hub; work-effectiveness is a reporting join. Missing token counts are now unknown, not zero.
77 lines
No EOL
4 KiB
Python
77 lines
No EOL
4 KiB
Python
"""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") |