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
+21
View File
@@ -159,6 +159,25 @@ impl Default for SandboxConfig {
}
}
#[derive(Debug, Clone, Default, Deserialize)]
pub struct BillingConfig {
/// Stripe secret key (sk_*); enables Buy-credits when set.
pub stripe_secret_key: Option<String>,
/// Price id (price_*) of the credit pack sold at checkout.
pub stripe_price_id: Option<String>,
/// Webhook signing secret (whsec_*) for verifying Stripe callbacks.
pub stripe_webhook_secret: Option<String>,
/// Credits granted per completed checkout (one pack).
#[serde(default = "default_pack_credits")]
pub credits_per_pack: i64,
/// Public base URL for the checkout success/cancel return.
pub return_base: Option<String>,
}
fn default_pack_credits() -> i64 {
1000
}
#[derive(Debug, Clone, Default, Deserialize)]
pub struct TelemetryConfig {
/// OTLP/HTTP collector base (e.g. http://otel-collector:4318).
@@ -195,6 +214,8 @@ pub struct AppConfig {
pub sandbox: SandboxConfig,
#[serde(default)]
pub telemetry: TelemetryConfig,
#[serde(default)]
pub billing: BillingConfig,
}
#[derive(Debug, thiserror::Error)]