Bootstrap fin-hub scaffold from hub-core (CUST-WP-0025-T22/T23)
Add hub-core editable dependency, fin-specific SQLAlchemy models, and smoke tests.
This commit is contained in:
commit
b6993d4a05
10 changed files with 1737 additions and 0 deletions
11
src/fin_hub/models/__init__.py
Normal file
11
src/fin_hub/models/__init__.py
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
"""Fin-specific SQLAlchemy models (T23 implementation target)."""
|
||||
|
||||
from fin_hub.models.budget import Budget, BurnRate, Commitment, RunwayProjection, TokenSpend
|
||||
|
||||
__all__ = [
|
||||
"Budget",
|
||||
"Commitment",
|
||||
"BurnRate",
|
||||
"RunwayProjection",
|
||||
"TokenSpend",
|
||||
]
|
||||
77
src/fin_hub/models/budget.py
Normal file
77
src/fin_hub/models/budget.py
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
"""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] = mapped_column(Integer, nullable=False, default=0)
|
||||
tokens_out: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||
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")
|
||||
Loading…
Add table
Add a link
Reference in a new issue