# Beans Connect organization administration

The workspace manages verified staff and synthetic applications. It never provisions a pet link, approves a Human grant, reads a household roster, or enables a production connector. OAuth/PAR and registered webhook delivery are implemented with independent pet authorization. See [OAUTH-WEBHOOKS.md](OAUTH-WEBHOOKS.md) for directional scopes, client registration, encrypted key custody, delivery/recovery and the remaining hosted/vendor acceptance gates.

## Local workspace on the free tier

Use Node 24 and Docker with the cached `postgres:17-alpine` image:

```sh
cd Services/LiveBroker
npm ci --ignore-scripts
npm run connect:lab -- --lab=partner-preview
```

Open `http://127.0.0.1:18789/workspace`. The sign-in button explicitly creates a **fictional local staff session**, lasting 15 minutes. It uses the real HTTP handler and a non-superuser `beans_sandbox_admin` PostgreSQL login. It does not validate a real Clerk identity. Local workspace identity code is imported only by the lab runner, never by the deployed service or portal bundle.

Register an app, supply its exact callback, and inspect `Review required`. Edit and disable actions are persisted and audited. A production review creates a local review record only. The separate `/sandbox` still exercises pet consent, record import, exact reviewed summary, independent worker, and revoke. Workspace registration does not itself create a pet connection.

Stopping preserves the named lab's database and private state; restarting applies only new migrations. It neither resets staff changes nor restores revoked members. The named lab keeps the prior synthetic exchange history. Use a fresh lab name for a clean exercise.

To review an application in a running named lab, write a JSON request to a local file and pass it on stdin:

```json
{
  "action": "review_app",
  "organizationID": "00000000-0000-4000-8000-000000000008",
  "requestID": "replace-with-a-fresh-uuid",
  "appID": "copy-the-application-id",
  "expectedRevision": 1,
  "verificationReference": "local-callback-review-001"
}
```

```sh
npm run connect:provision -- --lab=partner-preview < reviewed-app.json
```

Reuse exactly the same request and UUID after an uncertain result. A changed body under the same UUID is rejected. The command locates only the named, labeled loopback lab and uses its restricted provisioning login. It prints a public configuration receipt, never a credential. The reference records operator-provided evidence; it does not automatically verify callback ownership.

## Role separation

| Role | Authority |
|---|---|
| `beans_live_runtime` | Existing authenticated Human/pet and partner APIs; no organization administration |
| `beans_connect_worker` | Existing bounded delivery and maintenance; no organization administration |
| `beans_connect_admin` | Active Clerk-session and organization-membership-scoped workspace RPCs; no direct tables or pet RPCs |
| `beans_connect_provisioner` | Reviewed synthetic organization/identity provisioning and app approval; no workspace browsing, pet grants or production enablement |

Each hosted role must have its own non-superuser login and credential. The admin HTTP entry and provisioning CLI reject a login that also inherits another Connect role or has superuser, bypass-RLS, or create-role privileges. Direct grants beyond these roles are forbidden by the deployment contract and must be audited before deployment.

Within an organization, viewers read configuration; developers register, edit and disable applications; administrators also change existing staff roles, remove access and request production review. The last active administrator cannot demote or remove themselves. Account deletion is allowed to remove the last administrator; recovering an orphaned organization requires verified operator provisioning. Deletion erases the member and their administrative mutation receipts, nulls their audit attribution, and never silently restores access after rejoin.

Staff membership is stored by principal hash, with a separately supplied display label. Neither Clerk public metadata nor a caller-supplied organization ID grants access. New members must be identity-verified through the operator role. No endpoint accepts an `enabled` flag, production environment, arbitrary SQL, pet ID or grant scope.

## HTTP contract

`GET /connect/admin/v1/workspace` returns at most 100 available organizations. Add exactly `?organizationID=<uuid>` to read that organization's applications, current roles, last 100 configuration audit events and production-review status. The UI shows the newest 12 activity entries. There are no pet identifiers, record bodies, existing secrets or subject hashes in this response.

`POST` accepts exact JSON fields:

| `action` | Fields beyond `action`, `organizationID`, `requestID` |
|---|---|
| `register_app` | `name`, `redirectURI` |
| `update_app` | `appID`, `expectedRevision`, `name`, `redirectURI` |
| `disable_app` | `appID`, `expectedRevision` |
| `member_role` | `memberID`, `expectedRevision`, `role` |
| `revoke_member` | `memberID`, `expectedRevision` |
| `request_production` | `appID`, `expectedRevision`, `workflow` |

Requests are limited to 16 KiB, responses to 256 KiB. The fixed pre-auth bucket permits 600 requests/minute; each organization permits 60 new mutations/minute and 50 registered applications/members. Failed pre-auth attempts persist in the admission counter. `429` includes `Retry-After: 60`. Production review permits one outstanding record per organization and binds to the reviewed app revision. Review adjudication and resubmission are not exposed yet.

Application updates disable the app and increase its revision when configuration changes. Existing tokens and pending authorizations are bound to the earlier revision; unused invitations expire. Re-enabling the app creates another revision, so it cannot revive old credentials. Existing completed receipt history is retained. Disabling an app prevents partner token access; it does not revoke a Human's independent owner-directed connection grant. Disabling the organization prevents future connection operations and dispatch; in-flight external work still requires receipt reconciliation.

## Reviewed provisioning

The operator RPC and `connect:provision` command support:

- `create_organization`: `organizationID`, `requestID`, `verificationReference`, `name`, `subject`, `label`. Creates only an enabled, verified **synthetic** organization and its first admin.
- `set_member`: the common IDs/reference plus `subject`, `label`, `role`. Adds a new verified principal; it does not overwrite or reactivate a revoked member.
- `review_app`: the common IDs/reference plus `appID`, `expectedRevision`. Enables the exact reviewed synthetic configuration.
- `disable_organization`: common IDs/reference. Disables the organization and its apps; there is no public re-enable shortcut.

`verificationReference` is retained privately on the configuration audit event. Verify organization ownership, staff identity and callback control externally before invoking this role. No operator credential belongs in the public portal, runtime, worker or browser.

## Hosted identity wiring: prepared, not accepted

Migration `036_connect_workspace.sql` follows 033–035. Apply it with the reviewed migration owner. No roles receive LOGIN or passwords through the migration.

The API requires all of:

- `BEANS_CONNECT_ADMIN_ENABLED=1`
- `BEANS_CONNECT_ADMIN_DATABASE_URL` for the separate admin login, TLS certificate verification enabled
- `BEANS_CONNECT_ADMIN_AUDIENCE`, distinct from the owner API audience
- `BEANS_CONNECT_ADMIN_ORIGINS`, a JSON array of exact HTTPS portal origins
- Existing pinned `BEANS_CLERK_JWT_PUBLIC_KEY`, `BEANS_CLERK_ISSUER`, revocation webhook and account lifecycle authority

The UI build requires public `BEANS_CONNECT_PUBLISHABLE_KEY` and `BEANS_CONNECT_API_ORIGIN`. Add their exact HTTPS identity/API origins to the portal's `connect-src` CSP after review; the build rejects incomplete configuration and wildcard origins. No secret or database URL is included in the build. The maintained Clerk browser SDK is bundled and pinned; its telemetry is disabled. Default builds clearly show that hosted sign-in is unconfigured.

Use Clerk **session tokens** via `session.getToken()` with the required `aud` session claim. JWT templates cannot contain session-bound `sid`, so the workspace does not use them. The API requires a signed active session, exact issuer/audience, allowed `azp`, current revocation/lifecycle state, and PostgreSQL membership. Do not add the portal to owner API origins solely to get admin login working. Any shared Clerk session-claim change must preserve installed clients and pass separate owner/admin audience and origin tests.

References: [Clerk session tokens](https://clerk.com/docs/guides/sessions/session-tokens), [customizing session claims](https://clerk.com/docs/guides/sessions/customize-session-tokens), [JWT template limits](https://clerk.com/docs/guides/sessions/jwt-templates), [Clerk JavaScript SDK](https://clerk.com/docs/js-frontend/reference/objects/clerk).

Real Clerk sign-in, exact deployed CSP, revocation webhook delivery and hosted role provisioning still require acceptance on the intended deployment. A local fixture login and signed test JWTs are separate evidence. No live Clerk setting, domain, paid resource or production database was changed by this implementation.

## Retention, release and rollback

Membership labels remain while the organization retains access; deletion removes them through the account lifecycle trigger. Application configuration, operator references, audit events and production-review text currently remain until reviewed organization cleanup; no automatic retention promise is published. Administrative mutation receipts remain with the organization or until the actor's deletion. Quotas limit creation rate, not total retention. Define and approve a partner-data retention period before hosted onboarding.

Release with the admin flag off; apply migrations in order; create separate logins; verify role grants; set public identity/CSP configuration; exercise the actual identity and session-revocation flow; then enable only reviewed synthetic organizations. Roll back by disabling the admin flag and returning the portal to the prior deployment. Keep the additive schema and application revisions intact. Do not downgrade the database or re-enable prior app credentials. Production partner gates remain closed throughout this rollout.

## OAuth and webhook continuation

Apply migrations 037–038 after 036. The workspace now shows operator-reviewed OAuth scopes/client method and endpoint verification, queue health, signing-key rotation, disable and bounded failed-event replay. Administrators and developers may configure endpoints; viewers remain read-only. Signing secrets appear only in a same-member mutation receipt, recoverable for ten minutes. Normal reads and audit history expose no key material. The deployment needs `BEANS_CONNECT_WEBHOOK_KEYRING` on administration and worker services, never in browser config. Use the separate operator CLI for OAuth client credentials, scoped invitations and master-key rewrap; see the linked protocol guide.
