Changeset 0.24.0 (#156)
This commit is contained in:
1110
docs/DESIGN-0.24.0.md
Normal file
1110
docs/DESIGN-0.24.0.md
Normal file
File diff suppressed because it is too large
Load Diff
302
docs/ROADMAP.md
302
docs/ROADMAP.md
@@ -109,16 +109,23 @@ v0.22.5 Surfaces + Go Templates + Admin Bug Fixes ✅
|
||||
│
|
||||
v0.22.6 Split Deployment Fix + CI Timeout + Code Pruning ✅
|
||||
│
|
||||
|
|
||||
v0.22.7 Surface Prototypes (Theme + ChatPane + Splash) ✅
|
||||
|
|
||||
v0.22.8 Surface Integration (Wire into existing JS)
|
||||
|
|
||||
v0.23.0 @mention Routing + Persona Handles + Proxy ✅
|
||||
│
|
||||
v0.23.1 Multi-User: DMs + Group Chat
|
||||
v0.22.8 Surface Integration (Wire into existing JS) ✅
|
||||
│
|
||||
v0.24.0 Auth Strategy (mTLS/OIDC) + Full RBAC + Group permissions
|
||||
v0.23.0 @mention Routing + Persona Handles + Proxy ✅
|
||||
│
|
||||
v0.23.1 Multi-User Navigation + Conversation Taxonomy ✅
|
||||
│
|
||||
v0.23.2 Multi-User Polish + Channel Lifecycle ✅
|
||||
│
|
||||
v0.24.0 Auth Abstraction + User Identity ← active
|
||||
│
|
||||
├── v0.24.1 mTLS + OIDC Providers (parallel)
|
||||
│ │
|
||||
│ └── v0.24.3 Anonymous Sessions
|
||||
│
|
||||
└── v0.24.2 Fine-Grained Permissions (parallel)
|
||||
│
|
||||
┌───────┴──────────────┐
|
||||
│ │
|
||||
@@ -1169,34 +1176,39 @@ Depends on: surfaces + Go templates (v0.22.5), code pruning (v0.22.6).
|
||||
|
||||
---
|
||||
|
||||
## v0.22.8 — Surface Integration (Wire into Existing JS)
|
||||
## ✅ v0.22.8 — Surface Integration (Wire into Existing JS)
|
||||
|
||||
Connect v0.22.7 prototypes to the existing frontend JS modules.
|
||||
ChatPane.primary replaces singleton UI.* calls. Theme system wired
|
||||
into appearance settings. Admin surface hybrid loader completed.
|
||||
Naming cleanup: preset → persona, APIConfigID → ProviderConfigID.
|
||||
|
||||
Depends on: surface prototypes (v0.22.7).
|
||||
|
||||
**ChatPane Bridge:**
|
||||
- [ ] `ChatPane.primary` creation in `startApp()` from server-rendered mount points
|
||||
- [ ] `ui-core.js` delegation: `UI.renderMessages` → `ChatPane.primary.renderMessages`, etc.
|
||||
- [ ] `editor-mode.js` ChatPane creation for workspace chat
|
||||
- [ ] Branding init from `window.__SETTINGS__` (instanceName, logoURL)
|
||||
- [x] `ChatPane.primary` creation in `startApp()` from server-rendered mount points
|
||||
- [x] `ui-core.js` delegation: `UI.renderMessages` → `ChatPane.primary.renderMessages`, etc.
|
||||
- [x] Branding init from `window.__SETTINGS__` (instanceName, logoURL)
|
||||
|
||||
**Theme Integration:**
|
||||
- [ ] Wire `Theme` into appearance settings save/load cycle
|
||||
- [ ] CM6 theme sync on theme change
|
||||
- [ ] Persist theme preference to user settings API
|
||||
- [x] Wire `Theme` into appearance settings save/load cycle
|
||||
- [x] CM6 theme sync on theme change
|
||||
- [x] Persist theme preference to user settings API
|
||||
|
||||
**Admin Surface:**
|
||||
- [ ] Complete hybrid section loaders for all JS-loaded sections
|
||||
- [ ] Admin surface stats/overview server-rendered content
|
||||
- [x] Complete hybrid section loaders for all JS-loaded sections
|
||||
|
||||
**Settings Surface:**
|
||||
- [ ] Models visibility toggles (API.saveModelPreferences)
|
||||
- [ ] User Personas CRUD (add/edit/delete with confirm dialogs)
|
||||
- [ ] BYOK provider CRUD in settings context
|
||||
- [ ] Teams tab content
|
||||
- [x] Models visibility toggles (API.saveModelPreferences)
|
||||
- [x] User Personas CRUD (add/edit/delete with confirm dialogs)
|
||||
- [x] BYOK provider CRUD in settings context
|
||||
- [x] Teams tab content
|
||||
|
||||
**Naming Cleanup:**
|
||||
- [x] preset → persona: routes, JSON keys, Go structs, JS, CSS, DOM IDs, templates
|
||||
- [x] APIConfigID → ProviderConfigID: all Go structs and JSON fields
|
||||
- [x] Shared `app-state.js` extracted from `app.js` — available on all surfaces
|
||||
- [x] Auth tokens loaded for all surfaces via `base.html`
|
||||
|
||||
---
|
||||
|
||||
@@ -1233,78 +1245,212 @@ or `@model-id` and send.
|
||||
|
||||
---
|
||||
|
||||
## v0.23.1 — Multi-User: DMs + Group Chat
|
||||
## ✅ v0.23.1 — Multi-User Navigation + Conversation Taxonomy
|
||||
|
||||
Real human-to-human messaging. Builds on v0.23.0's participant infrastructure
|
||||
(`channel_participants`, @mention routing, WebSocket events). The @mention
|
||||
system already resolves personas — this release extends it to resolve users.
|
||||
Conversation type taxonomy (direct/dm/group/channel/workflow), three-section
|
||||
sidebar (Projects → Channels → Chats), folder system for chats, DM plumbing,
|
||||
channel configuration with `ai_mode`, presence heartbeat, and the unified
|
||||
active conversation model.
|
||||
|
||||
Depends on: @mention routing (v0.23.0), WebSocket infrastructure (exists).
|
||||
See [DESIGN-0_23_1.md](DESIGN-0_23_1.md) for the full spec.
|
||||
|
||||
**User-to-User DMs**
|
||||
- [ ] `@username` resolution in `resolveMention()`: extend DB lookup to `users` table
|
||||
- [ ] When `resolveMention()` returns a user (not persona): skip completion, deliver as notification
|
||||
- [ ] DM channel type: two user participants, no AI unless explicitly @mentioned
|
||||
- [ ] DM creation flow: user picker, creates channel with both users as participants
|
||||
- [ ] Unread count per channel per user (read cursor in `channel_participants`)
|
||||
- [ ] Real-time message delivery via WebSocket to recipient's active session
|
||||
**Conversation Types:**
|
||||
- [x] Five-type taxonomy: direct (1:1 AI), dm (human-to-human), group (multi-participant), channel (named persistent), workflow (staged, deferred)
|
||||
- [x] Channel type constraint extended: `dm`, `channel` added to `type` CHECK
|
||||
- [x] `ai_mode` column on channels: `auto` | `mention_only` | `off`
|
||||
- [x] `ai_mode` guard in completion handler — `off` returns 403, `mention_only` without @mention delivers without AI
|
||||
- [x] `topic` column on channels for header display
|
||||
|
||||
**Group Chat (Human + AI)**
|
||||
- [ ] Persona group CRUD: create/edit/delete saved roster templates (`persona_groups`)
|
||||
- [ ] "New Chat with Group" flow: pick a template, stamp onto fresh channel
|
||||
- [ ] Group leader (default responder): `is_leader` flag on `persona_group_members`
|
||||
- [ ] No @mention in group = leader responds. @mention overrides.
|
||||
- [ ] Group editing: add/remove personas, change leader — affects future chats only
|
||||
- [ ] `@all` routing: every persona participant responds (existing `multiModelStream` path)
|
||||
**Sidebar Architecture:**
|
||||
- [x] Three collapsible sections: Projects → Channels → Chats
|
||||
- [x] `renderChannelsSection()` with # / person icons, unread badges, online dots
|
||||
- [x] Channel items: context menu (rename, set topic, delete), ⋯ hover button
|
||||
- [x] Section collapse/expand state in localStorage
|
||||
|
||||
**Presence + Real-time**
|
||||
- [ ] Typing indicators for human participants (extend existing persona typing events)
|
||||
- [ ] Online/offline status per user (heartbeat-based, stored in memory not DB)
|
||||
- [ ] Participant join/leave WebSocket events
|
||||
- [ ] Unread badge on sidebar chat items
|
||||
**Folder System:**
|
||||
- [x] `chat_folders` table, CRUD handler (`handlers/folders.go`)
|
||||
- [x] Drag chats into/out of folders; folder context menu (rename, delete)
|
||||
- [x] Folder delete modal: "Keep chats" / "Delete chats too" / Cancel
|
||||
- [x] Unfiled drop zone when folders exist
|
||||
|
||||
**User @mention UX**
|
||||
- [ ] Autocomplete includes users alongside models and personas (different icon)
|
||||
- [ ] @mention pills distinguish user mentions (different color) from persona/model mentions
|
||||
- [ ] Notification center: @mention notifications with channel deep-link
|
||||
**DM Plumbing:**
|
||||
- [x] `resolveMention()` extended to resolve users (exact + prefix on username)
|
||||
- [x] User @mention skips AI, delivers `user.mentioned` WebSocket notification
|
||||
- [x] DM creation flow with user search modal
|
||||
- [x] DM dedup guard — one channel per participant pair
|
||||
|
||||
**Message Attribution**
|
||||
- [ ] Messages from human users show their avatar + display name (not "You" for other participants)
|
||||
- [ ] Messages from personas retain current avatar + handle rendering
|
||||
- [ ] Thread view: flat chronological for now, threading deferred
|
||||
**Presence:**
|
||||
- [x] `user_presence` table with heartbeat upsert
|
||||
- [x] `POST /presence/heartbeat` (30s interval), `GET /presence?users=...` (90s threshold)
|
||||
- [x] Presence WebSocket events: `presence.changed`
|
||||
|
||||
**Migration**
|
||||
- [ ] `users.handle` column (unique, auto-generated from username or display_name)
|
||||
- [ ] Read cursor columns on `channel_participants`: `last_read_message_id`, `last_read_at`
|
||||
- [ ] Notification table: `user_notifications` (type, channel_id, message_id, actor_id, read_at)
|
||||
**Channel Participants:**
|
||||
- [x] `channel_participants` CRUD handler, auto-created on channel creation
|
||||
- [x] Persona group CRUD endpoints wired (`persona_groups`, `persona_group_members`)
|
||||
- [x] DM participant auto-creation from `req.Participants`
|
||||
|
||||
**Migration:**
|
||||
- [x] 016_v023_multiuser: `ai_mode`, `topic`, `user_presence`, channel type extension
|
||||
|
||||
---
|
||||
|
||||
## v0.24.0 — Auth Strategy (mTLS/OIDC) + Full RBAC
|
||||
## ✅ v0.23.2 — Multi-User Polish + Channel Lifecycle
|
||||
|
||||
Enterprise auth modes on top of the teams + groups foundation.
|
||||
Depends on: vault passphrase support from v0.9.3 (conditional unlock for
|
||||
personal providers under external auth), user groups (v0.16.0).
|
||||
Bug fixes, unified active conversation refactor, channel lifecycle (archive/delete),
|
||||
group chat leader routing, `@all` fan-out, message attribution, and deferred
|
||||
surface integration from v0.22.8.
|
||||
|
||||
_(Shifted from v0.21.0 — enhanced with group-based permissions)_
|
||||
Depends on: v0.23.1 sidebar and conversation taxonomy.
|
||||
|
||||
- [ ] `AUTH_MODE` env var: `builtin` | `mtls` | `oidc`
|
||||
- [ ] All three resolve to the same internal user model
|
||||
- [ ] `auth_source` + `external_id` columns on users table
|
||||
- [ ] mTLS: header trust, auto-provision from cert DN
|
||||
- [ ] OIDC: Keycloak/Okta token validation, claim extraction, role mapping
|
||||
- [ ] Per-source auto-activate policy: auto_activate, default_team, default_role
|
||||
- [ ] Vault passphrase prompt for mTLS/OIDC users (v0.9.3 conditional unlock)
|
||||
- [ ] Fine-grained permissions: model access, KB write, task create, token budgets
|
||||
- [ ] Group-based permission sets: assign permissions to groups, users inherit from membership
|
||||
- [ ] OIDC claim → group mapping: external IdP groups auto-sync to internal groups
|
||||
**Unified Active Conversation:**
|
||||
- [x] `App.activeConversation = { id, type }` replaces `currentChatId` + `currentChannelId`
|
||||
- [x] `setActive(id, type)`, `activeId` getter, `getActiveChat()` helper
|
||||
- [x] Send path, model bar, streaming, session restore all keyed off `activeConversation.id`
|
||||
- [x] Sidebar highlight works across both chat and channel sections
|
||||
|
||||
**Anonymous / Session Participants**
|
||||
- [ ] Session-based identity for unauthenticated visitors (workflow intake)
|
||||
- [ ] mTLS: cert CN/fingerprint as stable session identity (no `users` row required)
|
||||
- [ ] Non-mTLS: ephemeral session token (cookie or URL token)
|
||||
- [ ] Session participants can send messages and trigger tool calls within workflow channels
|
||||
- [ ] Session identity visible to assigned team members (cert DN, display name, or "Anonymous #N")
|
||||
**Group Chat + Persona Groups:**
|
||||
- [x] Group leader default response: no @mention in group → leader persona responds
|
||||
- [x] `@all` fan-out: routes to every persona participant, depth-1 only
|
||||
- [x] Participant mutation guards: DMs keep ≥2 humans, groups keep ≥1 persona
|
||||
- [x] "New Group Chat" flow with ad-hoc persona picker
|
||||
|
||||
**Message Attribution:**
|
||||
- [x] Human sender display: other participants show avatar + display name (not "You")
|
||||
- [x] Persona sender display verified for loaded history in channel context
|
||||
|
||||
**Channel Lifecycle:**
|
||||
- [x] Archive action via context menu (`is_archived`, `archived_at`)
|
||||
- [x] Delete gated by `channel_retention.mode` (flexible/retain)
|
||||
- [x] Admin purge with `purge_after_days` floor
|
||||
- [x] Retention config keys in `global_config`
|
||||
|
||||
**Bug Fixes:**
|
||||
- [x] Channel persistence through refresh (resp.channels → resp.data)
|
||||
- [x] Folder drag-and-drop (folderId mapping, drop handlers, unfiled zone)
|
||||
- [x] DM creation 404 → added `GET /users/search` endpoint
|
||||
- [x] Channel ⋯ menu consistency (replaced ✕ with hover ⋯ pattern)
|
||||
- [x] Folder ⋯ button reflow (visibility:hidden instead of display:none)
|
||||
- [x] Unread subquery using `last_read_at` (not migration-017-dependent column)
|
||||
- [x] Settings Models section template wiring
|
||||
- [x] `u.avatar` → `u.avatar_url` in ListMessages JOIN and treepath
|
||||
|
||||
**Surface Integration (deferred v0.22.8):**
|
||||
- [x] `ChatPane.primary` bridge from server-rendered mount points
|
||||
- [x] Theme save/load cycle wired to settings appearance
|
||||
- [x] Admin hybrid section loaders completed
|
||||
- [x] Settings surface: models toggles, persona CRUD, BYOK, teams
|
||||
|
||||
**@mention UX:**
|
||||
- [x] Autocomplete includes users alongside personas and models
|
||||
- [x] User mention pill styling (distinct color from persona pills)
|
||||
- [x] `user.mentioned` WebSocket notification with toast
|
||||
|
||||
**Migration:**
|
||||
- [x] 017_unread: `last_read_message_id` on `channel_participants`
|
||||
|
||||
---
|
||||
|
||||
## v0.24.0 — Auth Abstraction + User Identity ← active
|
||||
|
||||
Auth provider interface decoupling builtin auth from the handler/middleware
|
||||
layer. User model extended with `auth_source`, `external_id`, `handle`.
|
||||
@mention resolution upgraded to use handles. Zero behavior change for
|
||||
existing users — builtin mode goes through the new abstraction identically.
|
||||
|
||||
See [DESIGN-0.24.0.md](DESIGN-0.24.0.md) for the full spec including
|
||||
v0.24.1–v0.24.3 subversions.
|
||||
|
||||
Depends on: v0.23.0 (channel_participants), v0.16.0 (groups), v0.9.4 (vault).
|
||||
|
||||
**Auth Provider Interface (`server/auth/`):**
|
||||
- [x] `Provider` interface: `Mode()`, `Authenticate()`, `SupportsRegistration()`, `Register()`
|
||||
- [x] `BuiltinProvider`: extracts login/register from `handlers/auth.go`
|
||||
- [x] `UniqueHandle()`: collision-safe handle generation with `-2`, `-3` suffixes
|
||||
- [x] `ErrorToHTTPStatus()`: maps auth errors to HTTP codes
|
||||
- [x] `ParseMode()`: validates `AUTH_MODE` string with error return
|
||||
|
||||
**Auth Handler Refactor:**
|
||||
- [x] `AuthHandler` gains `provider auth.Provider` field
|
||||
- [x] `Login()` delegates to `provider.Authenticate()`, then vault unlock + JWT
|
||||
- [x] `Register()` delegates to `provider.Register()`, then vault init + JWT
|
||||
- [x] `generateTokens()` response includes `handle`, `auth_source`
|
||||
- [x] `BootstrapAdmin()` / `SeedUsers()` backfill handles for existing users
|
||||
|
||||
**User Model Extension:**
|
||||
- [x] `AuthSource` (builtin/mtls/oidc), `ExternalID` (nullable), `Handle` (unique)
|
||||
- [x] All user store queries (PG + SQLite) include three new columns
|
||||
- [x] `GetByHandle()`, `GetByExternalID()` on both store implementations
|
||||
- [x] Unified `scanOneUser` / `scanOne` helpers replace per-method scan blocks
|
||||
|
||||
**Config + Middleware:**
|
||||
- [x] `AUTH_MODE` env var (default `builtin`)
|
||||
- [x] `main.go` dispatch: builtin wired, mTLS/OIDC fail-fast at startup
|
||||
- [x] Middleware unchanged — JWT validation is auth-mode-agnostic
|
||||
|
||||
**@mention Resolution:**
|
||||
- [x] `resolveMention()` uses `LOWER(handle)` instead of `LOWER(username)`
|
||||
- [x] `SearchUsers` returns `handle`, filters on handle
|
||||
- [x] Frontend autocomplete matches on handle, uses handle as @mention token
|
||||
|
||||
**Migration:**
|
||||
- [ ] 018_auth_abstraction: `auth_source`, `external_id`, `handle` columns + unique indexes + backfill
|
||||
|
||||
---
|
||||
|
||||
## v0.24.1 — mTLS + OIDC Providers
|
||||
|
||||
Two external auth implementations plugging into v0.24.0's provider interface.
|
||||
|
||||
Depends on: auth abstraction (v0.24.0).
|
||||
See [DESIGN-0.24.0.md](DESIGN-0.24.0.md) §v0.24.1 for full spec.
|
||||
|
||||
- [ ] mTLS provider: trusted header extraction, cert DN parsing, auto-provision
|
||||
- [ ] OIDC provider: well-known discovery, token validation, claim extraction
|
||||
- [ ] Per-source auto-activate policy (global_config keys)
|
||||
- [ ] OIDC claim → group mapping (external groups sync to internal groups)
|
||||
- [ ] Login page adapts by `AUTH_MODE` (form / cert status / SSO button)
|
||||
- [ ] mTLS users: no personal vault (`vault_set=false`), team/global providers only
|
||||
- [ ] Migration 019: `oidc_auth_state` table, `groups.source` column
|
||||
|
||||
---
|
||||
|
||||
## v0.24.2 — Fine-Grained Permissions
|
||||
|
||||
Groups become capability carriers. Permission model on top of existing
|
||||
group infrastructure.
|
||||
|
||||
Depends on: auth abstraction (v0.24.0). Parallel to v0.24.1.
|
||||
See [DESIGN-0.24.0.md](DESIGN-0.24.0.md) §v0.24.2 for full spec.
|
||||
|
||||
- [ ] Permission constants (`domain.action` convention, code-level enum)
|
||||
- [ ] `permissions` JSONB column on groups
|
||||
- [ ] `ResolvePermissions()`: union of group permissions + `DefaultUserPerms`
|
||||
- [ ] `RequirePermission()` middleware
|
||||
- [ ] Token budgets: per-group daily/monthly ceilings, enforced in completion handler
|
||||
- [ ] Model access control: per-group model allowlists
|
||||
- [ ] Admin UI: permission checklist, budget fields, model picker on group edit
|
||||
- [ ] `DefaultUserPerms` override via `global_config` key `default_permissions`
|
||||
- [ ] Migration 020: permissions, budgets, allowed_models on groups
|
||||
|
||||
---
|
||||
|
||||
## v0.24.3 — Anonymous / Session Participants
|
||||
|
||||
Unauthenticated visitors for workflow intake channels. Direct
|
||||
prerequisite for v0.25.0 (Workflow Engine).
|
||||
|
||||
Depends on: mTLS provider (v0.24.1) for cert-based anonymous identity.
|
||||
See [DESIGN-0.24.0.md](DESIGN-0.24.0.md) §v0.24.3 for full spec.
|
||||
|
||||
- [ ] `session_participants` table (channel-scoped, ephemeral token)
|
||||
- [ ] Session JWT: `SessionClaims{SessionID, ChannelID}` — distinct from user JWT
|
||||
- [ ] `SessionOrAuth()` middleware: accepts either JWT type
|
||||
- [ ] Capability scoping: session participants limited to their bound channel
|
||||
- [ ] mTLS anonymous path: cert fingerprint as stable session identity
|
||||
- [ ] `channels.allow_anonymous` flag
|
||||
- [ ] Session display in participant list (team members see visitor identity)
|
||||
- [ ] Migration 021: `session_participants` table, `allow_anonymous` column
|
||||
|
||||
---
|
||||
|
||||
@@ -1316,7 +1462,7 @@ handles structured data collection. See [ARCHITECTURE.md — Workflow
|
||||
Architecture](ARCHITECTURE.md#workflow-architecture-future--v0210) for
|
||||
the conceptual model.
|
||||
|
||||
Depends on: multi-participant channels (v0.23.0), anonymous identity (v0.24.0).
|
||||
Depends on: multi-participant channels (v0.23.0), anonymous identity (v0.24.3).
|
||||
|
||||
_(Shifted from v0.22.0 — no content changes, dependency refs updated)_
|
||||
|
||||
|
||||
Reference in New Issue
Block a user