diff --git a/TURNOVER.md b/TURNOVER.md deleted file mode 100644 index c0e6736..0000000 --- a/TURNOVER.md +++ /dev/null @@ -1,132 +0,0 @@ -# Switchboard Core — Session Turnover -**Date**: 2026-03-26 -**Author**: Jeffrey Smith (jasafpro@gmail.com) -**Session**: v0.2.0 PR 1 — Full RBAC migration - ---- - -## What Was Done - -### PR 1: Admin → RBAC group migration — COMPLETE -Branch `feat/admin-rbac-migration` (PR #1), 3 commits: - -1. **Admin → RBAC group migration** — `surface.admin.access` permission + - Admins system group replaces hardcoded `role == "admin"` checks. Admin - bypass removed from `RequirePermission`. Bootstrap/seed/OIDC/admin handlers - sync group membership. - -2. **Remove token budgets + allowed models from groups** — Provider-era cruft: - `token_budget_daily`, `token_budget_monthly`, `allowed_models` columns, - `ResolveTokenBudget()`, `ResolveModelAllowlist()`, and all store/handler/UI - code deleted. -283 lines. - -3. **Drop `users.role` column** — Full RBAC. Zero magic roles. The `role` column, - `UserRoleAdmin`/`UserRoleUser` constants, `CountByRole()`, `DefaultRole` config, - `role` in JWT claims, and all role-based shortcuts removed. Everyone group - membership is now explicit (all users added on create). 28 files changed. - -**Net result: -364 lines across 3 commits.** - -### Architecture after this PR: - -- **Everyone group** (`00000000...0001`): all users explicitly added on creation. - Carries `extension.use`, `workflow.submit`. -- **Admins group** (`00000000...0002`): carries all 7 kernel permissions including - `surface.admin.access`. Not special-cased — just a group with permissions. -- **Permission resolution**: union of all group memberships. No implicit groups, - no role shortcuts, no admin bypass. -- **Admin middleware**: checks `surface.admin.access` grant via `resolveAndCachePerms`. -- **JWT claims**: `user_id` + `email` only. No role. -- **OIDC**: `isIdPAdmin()` maps IdP role claim → Admins group membership. - No `role` column writes. -- **User creation paths**: builtin register, OIDC auto-provision, mTLS auto-provision, - admin create, bootstrap, seed — all call `EnsureEveryoneGroup()`. - ---- - -## Known Issues - -1. **Frontend test job**: FE test suite may have remaining stale references - from Phase 0 gut (pre-existing) -2. **Traefik middleware**: `rbac-traefik.yaml` needs one-time manual apply - by cluster admin (pre-existing, non-blocking) -3. **`SEED_USERS`**: Not set in K8s secrets (pre-existing) -4. **Editor modules**: `src/editor/*.mjs` still reference "Chat Switchboard" - (pre-existing, low priority) -5. **K8s deploy**: PR not yet merged to main — CI/CD will need a deploy after merge - ---- - -## What's Next - -### Merge PR #1 -Review and merge `feat/admin-rbac-migration` to main. - -### v0.2.0 — Remaining PRs - -**PR 2: Settings cascade** -- Add `user_overridable` flag to settings schema -- RBAC controls scope auth (admin → global, team-admin → team, user → personal) -- Resolution: user → team → global (first non-null wins) - -**PR 3: ICD (API contract)** -- Generate full OpenAPI spec from registered routes -- Document kernel-only endpoints - -**PR 4: Trigger system** -- Time triggers (cron), webhook (inbound HTTP), event (bus subscription) -- Extensions register match expressions at install - -**PR 5: SDK stabilization** -- `sb.slots()`, `sb.actions`, `sb.api.ext()`, `sb.storage` -- Theme tokens exposed to extensions - ---- - -## Architecture Decisions (this session) - -| Decision | Detail | -|----------|--------| -| Full RBAC — no magic roles | `users.role` column dropped entirely. All authorization through group membership + permission grants. | -| Explicit Everyone membership | No implicit "all users get Everyone perms". Every user added to Everyone group on create. `member_count` reflects reality. | -| Admins group not special-cased | Code never checks group identity — only checks for `surface.admin.access` permission. Any group can grant it. | -| No new migrations pre-MVP | Edit existing SQL files in place. Schema isn't in production. | -| JWT simplified | Claims carry `user_id` + `email` only. Permissions resolved server-side from groups on every request. | -| OIDC role → group sync | `isIdPAdmin()` replaces `resolveRole()`. IdP admin claim maps to Admins group membership, not a DB column. | -| Token budgets/allowed models removed | Provider-era cruft. Belongs in a future provider extension, not the kernel. | - ---- - -## File Locations - -| What | Where | -|------|-------| -| Roadmap | `ROADMAP.md` | -| Changelog | `CHANGELOG.md` | -| CI workflow | `.gitea/workflows/ci.yaml` | -| K8s manifests | `k8s/` | -| Docker compose (local dev) | `docker-compose.yml` (SQLite, port 3000) | -| Nginx template | `nginx.conf.template` | -| Migrations | `server/database/migrations/{postgres,sqlite}/` | -| Permission constants | `server/auth/permissions.go` | -| Admin middleware | `server/middleware/admin.go` | -| Group store | `server/store/{postgres,sqlite}/groups.go` | -| Bootstrap/seed | `server/handlers/auth.go` | -| Admin handlers | `server/handlers/admin.go` | -| Groups UI | `src/js/sw/surfaces/admin/groups.js` | -| Users UI | `src/js/sw/surfaces/admin/users.js` | -| SDK API | `src/js/sw/sdk/api-domains.js` | -| Memory (Claude) | `.claude/projects/-config-Projects-core/memory/` | - ---- - -## Gitea Secrets/Vars Needed - -**Secrets**: `POSTGRES_USER`, `POSTGRES_USER_PASSWORD`, `POSTGRES_ADMIN_USER`, -`POSTGRES_ADMIN_PASSWORD`, `ENCRYPTION_KEY` - -**Vars**: `DOMAIN`, `NAMESPACE`, `S3_BUCKET`, `S3_ENDPOINT`, `STORAGE_BACKEND`, -`STORAGE_CLASS`, `STORAGE_SIZE` - -**Not yet configured**: `S3_ACCESS_KEY`, `S3_SECRET_KEY` (using PVC for now), -`SEED_USERS` (needed for initial admin bootstrap)