Files
orion/app/modules/monitoring/models/capacity_snapshot.py
Samir Boulahtit 9c27fa02b0
Some checks failed
CI / ruff (push) Failing after 8s
CI / pytest (push) Successful in 36m5s
CI / architecture (push) Successful in 11s
CI / dependency-scanning (push) Successful in 27s
CI / docs (push) Has been skipped
CI / audit (push) Successful in 8s
refactor: move capacity_forecast_service from billing to monitoring
Resolves the billing (core) → monitoring (optional) architecture violation
by moving CapacityForecastService to the monitoring module where it belongs.

- Create BillingMetricsProvider to expose subscription counts via stats_aggregator
- Move CapacitySnapshot model from billing to monitoring
- Replace direct MerchantSubscription queries with stats_aggregator calls
- Fix middleware test mocks to cover StoreDomain/MerchantDomain fallback chains

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 20:58:22 +01:00

72 lines
2.3 KiB
Python

# app/modules/monitoring/models/capacity_snapshot.py
"""
Capacity snapshot model for platform capacity monitoring.
Stores daily snapshots of platform metrics for growth trending and capacity forecasting.
"""
from sqlalchemy import (
Column,
DateTime,
Index,
Integer,
Numeric,
)
from sqlalchemy.dialects.sqlite import JSON
from app.core.database import Base
from models.database.base import TimestampMixin
class CapacitySnapshot(Base, TimestampMixin):
"""
Daily snapshot of platform capacity metrics.
Used for growth trending and capacity forecasting.
Captured daily by background job.
"""
__tablename__ = "capacity_snapshots"
id = Column(Integer, primary_key=True, index=True)
snapshot_date = Column(DateTime(timezone=True), nullable=False, unique=True, index=True)
# Store metrics
total_stores = Column(Integer, default=0, nullable=False)
active_stores = Column(Integer, default=0, nullable=False)
trial_stores = Column(Integer, default=0, nullable=False)
# Subscription metrics
total_subscriptions = Column(Integer, default=0, nullable=False)
active_subscriptions = Column(Integer, default=0, nullable=False)
# Resource metrics
total_products = Column(Integer, default=0, nullable=False)
total_orders_month = Column(Integer, default=0, nullable=False)
total_team_members = Column(Integer, default=0, nullable=False)
# Storage metrics
storage_used_gb = Column(Numeric(10, 2), default=0, nullable=False)
db_size_mb = Column(Numeric(10, 2), default=0, nullable=False)
# Capacity metrics (theoretical limits from subscriptions)
theoretical_products_limit = Column(Integer, nullable=True)
theoretical_orders_limit = Column(Integer, nullable=True)
theoretical_team_limit = Column(Integer, nullable=True)
# Tier distribution (JSON: {"essential": 10, "professional": 5, ...})
tier_distribution = Column(JSON, nullable=True)
# Performance metrics
avg_response_ms = Column(Integer, nullable=True)
peak_cpu_percent = Column(Numeric(5, 2), nullable=True)
peak_memory_percent = Column(Numeric(5, 2), nullable=True)
# Indexes
__table_args__ = (
Index("ix_capacity_snapshots_date", "snapshot_date"),
)
def __repr__(self) -> str:
return f"<CapacitySnapshot(date={self.snapshot_date}, stores={self.total_stores})>"