from __future__ import annotations import json from decimal import Decimal from pathlib import Path from typing import Any from .economics import build_liquidity_summary, build_snapshot from .load import ( default_data_dir, latest_period, load_budget, load_expense_records, load_market_signals, load_membership, load_monthly_ledger, load_payment_records, load_pricing_models, load_product, load_value_range, ) from .allocation import build_cost_allocation from .credits import build_credit_summary, load_credit_wallets from .membership_analytics import build_membership_analytics from .pricing_context import build_cost_floor, build_market_price_view, build_value_range_view from .recommendations import build_pricing_recommendations from .simulator import build_pricing_simulations from .usage import build_usage_summary, load_usage_records def _serialize(value: Any) -> Any: if isinstance(value, Decimal): return str(value) if hasattr(value, "__dataclass_fields__"): return {key: _serialize(getattr(value, key)) for key in value.__dataclass_fields__} if isinstance(value, list): return [_serialize(item) for item in value] if isinstance(value, dict): return {key: _serialize(item) for key, item in value.items()} return value def _load_json_catalog(data_dir: Path, name: str) -> dict: path = data_dir / "infrastructure" / name if not path.exists(): return {} return json.loads(path.read_text(encoding="utf-8")) def build_dashboard_payload(data_dir: Path | None = None, period: str | None = None) -> dict: root = data_dir or default_data_dir() product = load_product(root) budget = load_budget(root) models = load_pricing_models(root) members = load_membership(root) payments = load_payment_records(root) expenses = load_expense_records(root) ledger = load_monthly_ledger(root) target_period = period or latest_period(ledger) snapshot = build_snapshot(target_period, product, models, members, payments, ledger) liquidity = build_liquidity_summary(budget, payments, ledger, target_period) payment_by_period = {record.period: record for record in payments} history = [] for month in sorted(ledger, key=lambda row: row.period): if month.period > target_period: continue payment = payment_by_period.get(month.period) net_payment = payment.net_amount if payment else Decimal("0") history.append( { "period": month.period, "active_members": month.active_members, "gross_revenue": month.gross_revenue, "infrastructure_cost": month.infrastructure_cost, "payment_processing_cost": month.payment_processing_cost, "total_platform_cost": month.total_platform_cost, "net_payment": net_payment, "net_liquidity": net_payment - month.infrastructure_cost, } ) value_range_raw = load_value_range(root) market_raw = load_market_signals(root) usage_records = load_usage_records(root) usage_summary = build_usage_summary(usage_records, target_period) cost_floor = build_cost_floor(snapshot, models) value_range = build_value_range_view(value_range_raw, snapshot, product, models) market_price = build_market_price_view(market_raw) cost_allocation = build_cost_allocation(snapshot, usage_records) ai_cost_per_member = usage_summary["cost_per_active_user_eur"] simulations = build_pricing_simulations(snapshot, models, ai_cost_per_member) credit_wallets = load_credit_wallets(root) credit_summary = build_credit_summary( credit_wallets, {key: value for key, value in usage_summary["by_member"].items()}, target_period, ) recommendations = build_pricing_recommendations( cost_floor, value_range, market_price, simulations, usage_summary ) return _serialize( { "design_reference": "https://claude.ai/design/p/fb2eef8c-c1fc-4c75-bff4-3782552e5511", "period": target_period, "product": product, "budget": budget, "snapshot": snapshot, "liquidity": liquidity, "history": history, "pricing_models": models, "members": members, "payments": payments, "expense_record_count": len(expenses), "membership_analytics": build_membership_analytics( members, target_period, [row["period"] for row in history] ), "cost_floor": cost_floor, "value_range": value_range, "market_price": market_price, "usage": usage_summary, "cost_allocation": cost_allocation, "pricing_simulations": simulations, "credit_wallets": credit_summary, "recommendations": recommendations, "infrastructure": { "domains": _load_json_catalog(root, "domains.json"), "virtual_servers": _load_json_catalog(root, "virtual_servers.json"), "stripe": _load_json_catalog(root, "stripe.json"), }, } ) def payload_json(data_dir: Path | None = None, period: str | None = None) -> str: return json.dumps(build_dashboard_payload(data_dir, period), indent=2)