Five catalog tables:
- plans — plan identity (code, name); the stable thing.
- plan_versions — versioned pricing (base_price_cents, currency,
status draft/active/retired). A subscription binds
to a version; raising prices = publish a new
version, existing subs unaffected until migrated.
- plan_items — what a version includes per resource_kind, plus
overage terms (overage_unit, overage_price_cents,
hard_cap_qty).
- addons — a la carte upgrades (code, resource_kind, qty,
price_cents).
- resource_prices — effective-dated fallback per-unit pricing for
ad-hoc items not covered by a plan.
ArcadiaCloud.Catalog context: plan + version CRUD, active_version/1
(what a new signup gets), publish_version/1 (retires the prior active
version transactionally then activates the new one),
current_resource_price/2 (effective-dated lookup).
Seed (priv/repo/seeds/catalog_seed.exs, idempotent) creates three AUD
plans — Starter $20, Studio $50, Pro $120/mo — with included
droplet_hours / spaces_gb_month / snapshot_gb_month / bandwidth_gb /
dns_zones (and LLM token allowances on Studio + Pro), plus three storage
/ LLM addons. Prices are placeholders to tune against real DO COGS once
the cost-vs-revenue dashboard lands.
API (authenticated tenants — the catalog is what they pick from):
- GET /api/v1/catalog/plans — plans with active version + items
- GET /api/v1/catalog/addons
Smoke verified: seed creates 3 plans + 3 addons; endpoints return the
shaped catalog.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
33 lines
758 B
Elixir
33 lines
758 B
Elixir
defmodule ArcadiaCloudWeb.Router do
|
|
use ArcadiaCloudWeb, :router
|
|
|
|
pipeline :api do
|
|
plug :accepts, ["json"]
|
|
end
|
|
|
|
pipeline :authed do
|
|
plug ArcadiaCloudWeb.Plugs.RequireAuth
|
|
end
|
|
|
|
scope "/api", ArcadiaCloudWeb do
|
|
pipe_through :api
|
|
|
|
get "/health", HealthController, :show
|
|
end
|
|
|
|
scope "/api/v1", ArcadiaCloudWeb do
|
|
pipe_through [:api, :authed]
|
|
|
|
get "/inventory", InventoryController, :index
|
|
|
|
get "/billing/balance", BillingController, :balance
|
|
get "/billing/cost-lines", BillingController, :cost_lines
|
|
|
|
get "/drift", DriftController, :index
|
|
post "/drift/:id/accept", DriftController, :accept
|
|
|
|
get "/catalog/plans", CatalogController, :plans
|
|
get "/catalog/addons", CatalogController, :addons
|
|
end
|
|
end
|