feat: sidebar nav (default), group member management, per-customer ticketing identity mapping

- Navigation: new per-user setting (default "side") renders the page links as a
  left sidebar while keeping theme/bell/avatar/logout in the top-right; falls
  back to a top bar under 760px or when set to "top". Profile selector added.
- Group conversations: record a creatorId; the creator gets a "Manage members"
  button to add/remove participants (new GET/POST/DELETE members endpoints,
  creator-only). Existing groups backfilled.
- Customer ticketing: admin can map each assigned consultant to their username
  in that customer's ticketing system. Per-customer mapping takes precedence
  over the consultant's global ticketingIdentities during sync.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
etalon
2026-06-13 11:05:33 +02:00
parent 0d28f69320
commit e8beb7d4f3
16 changed files with 367 additions and 19 deletions
+9
View File
@@ -45,6 +45,7 @@ func (s *Server) handlePatchProfile(w http.ResponseWriter, r *http.Request) {
Extra *map[string]any `json:"extra"`
Settings *struct {
Theme *string `json:"theme"`
NavLayout *string `json:"navLayout"`
Notifications *domain.NotificationPrefs `json:"notifications"`
LeaderboardOptOut *bool `json:"leaderboardOptOut"`
} `json:"settings"`
@@ -83,6 +84,14 @@ func (s *Server) handlePatchProfile(w http.ResponseWriter, r *http.Request) {
}
set["settings.theme"] = theme
}
if req.Settings.NavLayout != nil {
nav := *req.Settings.NavLayout
if nav != "side" && nav != "top" {
writeError(w, http.StatusBadRequest, "invalid_nav", "navLayout must be side or top")
return
}
set["settings.navLayout"] = nav
}
if req.Settings.Notifications != nil {
set["settings.notifications"] = *req.Settings.Notifications
}