Changeset 0.20.0 (#85)

This commit is contained in:
2026-03-01 12:40:15 +00:00
parent eb74180611
commit 817062e5fc
57 changed files with 5435 additions and 72 deletions

View File

@@ -76,7 +76,7 @@ v0.19.1 Active Project + System Prompt + Detail Panel ✅
v0.19.2 Project Persona Default + Archive + Reorder ✅
v0.20.0 Notifications + @mention Routing + Multi-model
v0.20.0 Notifications + @mention Routing + Multi-model
v0.21.0 Extension Surfaces + Modes (depends on CM6 from v0.17.2)
@@ -601,31 +601,56 @@ Depends on: v0.19.1.
---
## v0.20.0 — Notifications + @mention Routing + Multi-model
## v0.20.0 — Notifications + @mention Routing + Multi-model
Notification infrastructure that makes collaboration real-time, plus
the channel schema already supports multiple models — this adds routing.
multi-model routing for channels. Three-phase delivery: notifications
core (in-app), @mention parsing + fan-out completions, email transport
+ per-user notification preferences.
_(Notifications shifted from v0.19.0; @mention routing shifted from v0.17.0)_
**Notifications**
- [ ] `notifications` table: `id`, `user_id`, `type`, `title`, `body`, `resource_type`, `resource_id`, `is_read`, `created_at`
- [ ] In-app notification bell (header bar, unread count badge)
- [ ] Notification dropdown: grouped by type, mark read, click-to-navigate
- [ ] WebSocket push: real-time delivery via existing EventBus (`notification.new` event)
- [ ] Notification sources: group membership changes, grant updates, KB processing complete, project invites, team invites
- [ ] Email transport (optional): SMTP config in admin settings, per-user opt-in/out
- [ ] Email templates: HTML + plaintext, branded with instance name
- [ ] Digest mode: batch low-priority notifications into periodic email (hourly/daily)
- [ ] Admin settings: enable/disable email, SMTP config, default notification preferences
- [ ] User preferences: per-type toggles (in-app, email, off)
Depends on: v0.19.2 (Projects complete), EventBus + WebSocket hub (v0.9.x),
`channel_models` table (v0.16.0 schema). See
[DESIGN-0.20.0.md](DESIGN-0.20.0.md) for full spec.
**@mention Routing**
- [ ] @mention parsing in messages (users and AI models)
- [ ] Resolve mentions against `channel_models`
- [ ] Multi-model channels: fire completions per mentioned model
- [ ] "Add a model" UI per channel
- [ ] Enables: second opinions, cross-model conversations
**Phase 1 — Notifications Core (in-app)**
- [x] `notifications` table: `id`, `user_id`, `type`, `title`, `body`, `resource_type`, `resource_id`, `is_read`, `created_at` (Postgres + SQLite migrations)
- [x] `NotificationStore` interface + both implementations: Create, ListByUser (paginated), MarkRead, MarkAllRead, Delete, UnreadCount
- [x] `notifications.Service` with `Notify()` / `NotifyMany()` — centralized creation + WebSocket dispatch
- [x] EventBus routes: `notification.new`, `notification.read` (badge sync across tabs)
- [x] API endpoints: list, unread-count, mark-read, mark-all-read, delete (5 endpoints, all user-scoped)
- [x] Initial sources: `role.fallback` (EventBus subscription), `kb.ready`/`kb.error`, `grant.changed`
- [x] Frontend: bell icon + unread badge (capped 9+), notification dropdown (latest 10, click-to-navigate), full panel via PanelRegistry
- [x] WebSocket handler: real-time push + toast for high-priority types
- [x] Background cleanup goroutine (configurable retention, default 90 days)
**Phase 2 — @mention Parsing + Multi-model Routing**
- [x] `mentions.Parse()`: extract @mentions, resolve against channel model roster (case-insensitive, longest-match-first, trailing punctuation tolerant)
- [x] Parser tests: no mentions, unresolved, multiple, overlapping names, punctuation edge cases
- [x] Channel model CRUD handlers (4 endpoints: list, add, remove, update)
- [x] Completion handler: mention extraction → target resolution → sequential fan-out → N assistant messages
- [x] SSE streaming: model attribution in delta events (`model_display` field)
- [x] Frontend: model pills in chat header with add/remove UI
- [x] Frontend: @mention autocomplete via CM6 `mentionCompletion` extension (roster-backed)
- [x] Frontend: model attribution labels on multi-model assistant messages
- [x] Backward compat: channels with no extra `channel_models` rows work exactly as before
**Phase 3 — Email Transport + Notification Preferences**
- [x] `notification_preferences` table (Postgres + SQLite): per-user, per-type in_app/email toggles
- [x] Preference resolution chain: specific type → user wildcard `*` → system default (in_app=true, email=false)
- [x] `EmailTransport`: SMTP with implicit TLS (port 465) and STARTTLS (port 587), multipart MIME (HTML + plaintext)
- [x] Email templates: branded HTML + plaintext, domain-prefixed subjects, Go `html/template`
- [x] Preference CRUD endpoints (3: list, set with partial patch, delete)
- [x] Admin SMTP configuration: enable toggle, host/port/user/password/from/TLS fields, test email button
- [x] User notification preferences UI (Settings → Notifications tab, per-type checkboxes)
- [x] Notification service: preference check before dispatch, async email delivery (goroutine, 30s timeout)
- [x] Tests: preference resolution chain (7 tests), email templates (4 tests)
- [x] Deferred: digest mode (batched email), SMTP password vault encryption
**Hotfix (carried forward from v0.19.2 investigation)**
- [x] `user_model_settings` NULL scan fix: COALESCE on `hidden`/`sort_order` in SELECT + INSERT for both dialects
- [x] Gin release mode: auto-set `gin.ReleaseMode` when `ENVIRONMENT=production`, suppress health check log spam
---