# Member Portal — membership middleware for the Inference Cooperative Reconciles three systems into one membership lifecycle: | System | Role | Source of truth for | |--------|------|---------------------| | Open Collective | Billing | Who is a *paying* member | | Cloudron | Identity/SSO | Who can *log in* | | LiteLLM | Inference | Who can *use models*, and how much | ## Architecture ``` Open Collective (billing) │ webhook ▼ ┌─────────────────────────────┐ │ Member Portal (this app) │ │ - OC webhook handler │ │ - Cloudron user management │ │ - LiteLLM key management │ │ - key-injection proxy │ └─────────────────────────────┘ ▲ │ X-User-Email header (LibreChat forwards identity) │ LibreChat ──→ Member Portal ──→ LiteLLM ──→ backend ``` ## The three responsibilities 1. **Webhook handler** (`POST /webhook/opencollective`) — listens for Open Collective membership events and activates/deactivates members. 2. **Key injector** (`/v1/*`) — reads the member's email from the `X-User-Email` header, looks up their LiteLLM key, and forwards the request to the gateway with that key. 3. **Admin** (`/health`, `/`) — health and status. ## Configuration (environment variables) | Variable | Purpose | |----------|---------| | `CLOUDRON_API` | Cloudron API origin (auto-set by Cloudron) | | `CLOUDRON_TOKEN` | Cloudron API token (Read+Write) | | `MEMBERS_GROUP_ID` | Cloudron group ID for members (grants chat access) | | `LITELLM_BASE` | LiteLLM gateway URL | | `LITELLM_MASTER_KEY` | LiteLLM master key | | `OPENCOLLECTIVE_WEBHOOK_SECRET` | Optional webhook signature secret | ## Tier budgets Governance decision (set in Loomio). Defaults: - `free` — $2/month of tokens - `member` — $15/month - `supporter` — $30/month ## LibreChat wiring Point LibreChat's custom endpoint at this portal (not directly at LiteLLM), and add the identity header: ```yaml endpoints: custom: - name: "Inference Cooperative" apiKey: "${LITELLM_KEY}" baseURL: "https://portal.inference.coop/v1" headers: X-User-Email: "{{LIBRECHAT_USER_EMAIL}}" models: default: ["deepseek-v4-flash", "gpt-oss-120b"] fetch: true ``` ## Status **Scaffold** — the three handlers are stubbed with the correct integration points. Remaining work before production: - [x] Verify Open Collective webhook event names + payload shape → `order.processed` (every payment), `new member` (first only), `firstPayment` flag - [x] Verify Cloudron user-creation API payload (role/group assignment) → `POST /api/v1/users` with `{username, email, displayName, role, active}` → group assignment via `PUT /api/v1/users/:userId/groups` with `{groupIds: [...]}` - [x] Add a persistent store (SQLite) for email→key mapping → `key/list` returns token strings (not objects), so we store email→token locally - [x] Verify LiteLLM key/generate + key/list payload shapes against live gateway → `key/generate` returns `{key: "sk-..."}`; `key/list` returns `{keys: ["", ...]}` - [ ] Add HMAC signature verification for the OC webhook (if OC supports it) - [ ] Wire the OIDC addon for admin access