R4 backend: team org-chart + leaderboard, Stripe credits, workspace apps

- GET /api/team/orgchart — each member grouped with the claws they manage
  (agents.managed_by); GET /api/team/leaderboard — every claw ranked by
  its real usage_events rollup (credits/tokens/runs, zeros included).
  Both tested against real Postgres.
- Stripe Buy-credits (the Slack/Clerk integration pattern): [billing]
  config (stripe keys + price + webhook secret + credits_per_pack);
  POST /api/credits/checkout opens a real Checkout Session; POST
  /api/billing/stripe verifies Stripe's t=,v1= HMAC (constant-time) and
  grants one credit lot, idempotent on the session id; GET
  /api/billing/config gates the button (honest degradation when unset).
  Offline tests: signed grant + replay no-double-grant + forged-sig 400 +
  config flag. Live checkout creation deferred to a CM_LIVE_STRIPE test.
- /apps global page support: clawId now optional on connect + directory;
  absent => workspace-wide connection (app_connections.agent_id NULL) via
  new connections::list_for_workspace.
- ApiError gains a From<sqlx::Error> so inline queries use ? cleanly.

cm-api 10 test files incl. team_tabs (2) + stripe_billing (3); clippy clean.

Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
Omar Sobh
2026-06-10 19:58:09 -05:00
co-authored by Claude Fable 5
parent 67b80da695
commit f3f08a8edd
14 changed files with 813 additions and 3 deletions
+1
View File
@@ -185,6 +185,7 @@ async fn run() -> Result<(), String> {
cm_api::AppState::new(pool, runtime)
.with_broker(PathBuf::from(&config.broker.socket_path))
.with_oauth(config.oauth.clone())
.with_billing(config.billing.clone())
.pipe_auth_verifier(auth_verifier),
);
if e2e::enabled() {