from __future__ import annotations import argparse from pathlib import Path from .economics import build_snapshot from .load import ( default_data_dir, load_costs, load_membership, load_pricing_models, load_product, load_revenue, ) from .models import EconomicsSnapshot, PricingModel, Product def render_dashboard( product: Product, models: list[PricingModel], snapshot: EconomicsSnapshot, ) -> str: active = next(m for m in models if m.id == product.active_pricing_model_id) registry_lines = "\n".join( f"| {model.id} | {model.name} | {model.model_type} | {model.status} |" for model in models ) return f"""# Economics Dashboard v1 — {product.name} **Period:** {snapshot.period} **Lifecycle phase:** {product.lifecycle_phase} **Active pricing model:** {active.name} ({active.access_fee_amount} {active.currency}/{active.access_fee_cadence}) ## Key Metrics | Metric | Value | |--------|------:| | Active members | {snapshot.active_members} | | Monthly revenue | {snapshot.monthly_revenue} {snapshot.currency} | | Monthly cost | {snapshot.monthly_cost} {snapshot.currency} | | Cost per member | {snapshot.cost_per_member} {snapshot.currency} | | Gross margin | {snapshot.gross_margin} {snapshot.currency} | | Gross margin % | {snapshot.gross_margin_pct}% | _Revenue source: {snapshot.revenue_source}_ ## Pricing Model Registry | ID | Name | Type | Status | |----|------|------|--------| {registry_lines} ## Registries Loaded - Product model (`data/product.json`) - Pricing model registry (`data/pricing-models.json`) - Cost registry (`data/costs.json`) - Revenue registry (`data/revenue.json`) - Membership registry (`data/membership.json`) """ def generate_dashboard(data_dir: Path | None = None, period: str | None = None) -> str: root = data_dir or default_data_dir() product = load_product(root) models = load_pricing_models(root) members = load_membership(root) revenue = load_revenue(root) cost_period, costs, fx_rates = load_costs(root) target_period = period or cost_period snapshot = build_snapshot( target_period, product, models, members, revenue, costs, fx_rates, ) return render_dashboard(product, models, snapshot) def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description="Coulomb Social Economics Dashboard v1") parser.add_argument("--data-dir", type=Path, default=None, help="Registry data directory") parser.add_argument("--period", default=None, help="Reporting period (YYYY-MM)") parser.add_argument( "--output", type=Path, default=None, help="Write Markdown report to this path (default: stdout only)", ) args = parser.parse_args(argv) report = generate_dashboard(args.data_dir, args.period) if args.output: args.output.parent.mkdir(parents=True, exist_ok=True) args.output.write_text(report, encoding="utf-8") print(f"Wrote {args.output}") else: print(report) return 0 if __name__ == "__main__": raise SystemExit(main())