diff --git a/implementation-plan-api-dashboards.md b/implementation-plan-api-dashboards.md index 15a1cfe..4191f6f 100644 --- a/implementation-plan-api-dashboards.md +++ b/implementation-plan-api-dashboards.md @@ -145,9 +145,12 @@ Member (browser) ──SSO──▶ Member Dashboard (new Cloudron app, "members ### Step 2 — Teams migration (Phase 1) -- Extend the portal: create a team per member, move/create the chat key under it, keep `provision_member()` idempotent. -- Write a one-off migration script; dry-run it against the DB, then run against live members (Nathan, Liz, Dan, Ed, Lee). -- **Gate:** chat works end-to-end for a test member; `/team/list` shows one team per member; spend attributes per-team. +**COMPLETED (2026-09-13).** All 7 members now have a LiteLLM team + a fresh `sk-` key under it. + +- Added `litellm_get_or_create_team()` (idempotent team lookup by alias — `/team/new` is *not* idempotent, so we check `/team/list` first) and rewrote `litellm_create_key()` to always generate a fresh `sk-` key (never "reuse"). +- **Critical bug fixed:** the old `litellm_find_key_by_alias` returned SHA256 hashes from `/key/list` and stored them as the member's key. LiteLLM only reveals the `sk-` token at generation time, so three members (Dan, Ed, Nathan) had unusable hash "keys" → their chat was returning 401. All rekeyed; verified Dan can now complete inference. +- Added a one-off `/admin/migrate-teams/{token}` endpoint + `rekey_member()` (preserves `cloudron_user_id`/`slug`). Ran it: all 7 members rekeyed. +- Result: `/team/list` shows 7 teams (one per member, `$15/30d`), and `/spend/keys` now reports `team_id` on every key — spend is attributable per-member/team. ### Step 3 — Broker (Phase 2)