generated from coulomb/repo-seed
Add Coulomb observatory package with JSON registries (product, pricing models, costs, revenue, membership), economics snapshot engine, Economics Dashboard v1 CLI, sample report, and pytest coverage. Complete T01 and queue Sprint 2 Bubble.io integration.
107 lines
3.1 KiB
Python
107 lines
3.1 KiB
Python
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()) |