Skip to content
KAMOUniverse

Changelog

What's new.

Every improvement to the platform, as it ships.

  1. · KlusterServices

    Rebrand Guacamole client connection status text to KamoDesktop

    Override **************** so the 'Connecting to Guacamole...' screen (and related status) reads KamoDesktop.

  2. · MediaService

    Recording ingest, retention/quota, storage usage, summary pipeline

    - MeetRecordingController: internal (X-Internal-Auth) ingest endpoint the jibri finalize.sh posts finished recordings to. - MeetRecordingService: uploads recordings to per-org MinIO (imaging-meet-recordings), persists MeetingRecording metadata, enforces the org storage quota (evict oldest), and — when postMeetingSummaryEnabled — runs the summary pipeline: transcribe (EmailService meeting-summary template). - MeetRecordingRetentionSweep: scheduled deletion of recordings past retention. - MeetConfigController: GET /recording-usage for the real settings storage meter. - application.yml: conversion/ai/email base URLs + internal auth secret. Requires (ops): KamoInitializer run to create MEETING_RECORDINGS; the **************** value must match across MediaService, jibri, and ConversionService.

  3. · EmailService

    Sample vars for meeting-summary template preview

    Adds a sampleVariables case for the new meeting-summary template so the steward preview UI renders realistic content.

  4. · kamo-shared-library

    Meeting-summary canonical template

    Adds the "meeting-summary" transactional template (subject + branded HTML with {{roomName}} and raw {{summaryHtml}}) and registers it in CANONICAL_KEYS so it seeds per org. Used by the post-meeting AI summary delivery. Also corrects the loader test's stale key count.

  5. · KlusterServices

    Prosody moderator module, whisper-asr, jibri recording upload

    - Meet-prosody: version-control the custom-plugins ConfigMap (captures the existing token_verification no-op override that was created out-of-band) and add the canonical mod_token_moderation module, enabled via **************** Makes the JWT `moderator` claim authoritative — members become owner, guests/anonymous cannot grab owner. - whisper-asr: self-hosted speech-to-text (faster-whisper CPU, no external key) for post-meeting transcription. - Meet-jibri: finalize.sh now uploads finished recordings to MediaService **************** with X-Internal-Auth so they land in MinIO + drive retention/quota + summaries. Secret is optional so jibri still starts if unset.

  6. · ConversionService

    Recording transcription endpoint for post-meeting summaries

    POST /api/conversion/meet/transcribe (X-Internal-Auth): normalizes an uploaded meeting recording to 16kHz mono WAV via a new additive FfmpegService helper, forwards it to the self-hosted whisper-asr service, and returns { transcript }. Whisper URL from kamo.services.whisper.url.

  7. · kamo-internal

    Calendar integration for scheduled meetings + real recording storage meter

    - calendarIntegrationEnabled: when on, a scheduled clubhouse meeting is also added to the creator's calendar (via the existing calendar system) carrying the authenticated /meet/join link. Participant reminders remain handled by the backend sweeper, so no duplicate attendee emails. - Recording settings: the storage meter now shows REAL per-org usage from GET /api/meet/recording-usage (replacing the removed placeholder).

  8. · kamo-shared-library

    MeetingRecording entity + repository for captured recordings

    New MEETING_RECORDINGS table (org, meeting ref, room, MinIO bucket/object key, size, duration, captured/expiry timestamps, summary status) — the parent record for a finished Jibri recording file, driving retention/quota and post-meeting summary processing. Table is created on the next KamoInitializer run.

  9. · kamo-internal

    Marketing app, settings hub, Canva materials

    Make Marketing a first-class org-enableable app and ship the Canva-powered Materials experience. App-enablement: - AppType.MARKETING mirror, Organization.isMarketing getter - gate marketing nav (navRegistry) + rights sections (permissionAppSections, SecurityRoleManager) on organization.isMarketing - Marketing card in FeaturesManager (/settings/account?tab=apps) Settings: - new /settings/features/marketing hub (General / Social Media Providers / Canva) - move Social Media Providers out of CRM settings into Marketing - 3 nav locations updated (settings landing, settingsMenu, SettingsButton icon); repoint SocialTimeline empty-state link Canva: - CanvaIntegrationManager settings tab + canva ProviderDef in the platform OAuth registry (+ logo) - /api/canva/* proxies (status, connect-start, designs, exports, export-proxy, disconnect) → MediaService - /marketing/materials: library grid (imaging MATERIALS assoc), upload, Create-in-Canva, Import-from-Canva, return-nav auto-import

  10. · ConversionService

    Video poster-frame thumbnails for marketing materials

    Canva MP4 exports (and any video upload) skip the Docs PDF path and get a single ffmpeg poster-frame thumbnail (_thumb_p0.png) instead of failing. - **************** VIDEO category branch - ****************

  11. · MediaService

    Canva Connect OAuth + designs/export backend

    - CanvaApiClient: PKCE authorize, token exchange/refresh/revoke, users, designs (create/list), export jobs, byte fetch - CanvaTokenService: encrypted per-member tokens (PlatformSecretCipher), single-flight proactive refresh (Canva refresh tokens are single-use/rotating) - CanvaOAuthController (permit-all): connect intent → /start → /callback, return-nav landing - CanvaController (authed): status, connect-start, create/list designs, export (create+poll+cache), byte export-proxy, disconnect

  12. · kamo-shared-library

    Canva integration + Marketing as an org-enableable app

    - **************** — platform Canva Connect client registration - ImageAssocType.MATERIALS(13, imaging-materials) — org marketing assets bucket - **************** under ServiceType.MARKETING - ServiceType.MARKETING(24) → COMPLETED/enabled so it becomes a real app (FeatureController auto-provisions it ON per org, like CRM) - CanvaConnection entity + repo: per-member encrypted (access+refresh) tokens

  13. · KlusterServices

    Enable Guacamole json-auth SSO + KamoDesktop rebrand

    - JSON_SECRET_KEY (optional) on guacamole from the shared desktop-sso secret enables the bundled guacamole-auth-json extension the god-SSO links validate against. - kamo-branding extension (title=KamoDesktop, kamocrm logo + favicon) built from desktop/guacamole/branding/ into a .jar, shipped as a binary configmap and seeded into GUACAMOLE_HOME via an initContainer. - CI creates the shared signing key in both namespaces (desktop-sso for guacamole, guac-sso for SecurityService) from the GUAC_SIGNING_KEY secret; never committed.

  14. · kamo-internal

    God-only KamoDesktop icons (Linux + Windows) opening auto-connected sessions

    Two nav icons left of Analytics, shown only to god-eligible members (isGod added to NavGateContext). Each fetches a short-lived SSO link from SecurityService and opens the KamoDesktop gateway in a new window, auto-connected to its instance. Uses the committed **************** marks.

  15. · SecurityService

    KamoDesktop SSO token endpoint for god members

    GET **************** (god-eligible only) mints a 5-minute guacamole-auth-json token (HMAC-SHA256 + AES-128-CBC, per the extension's wire format) and returns an auto-login + auto-connect URL for the KamoDesktop gateway. Signing key + RDP password injected from the guac-sso secret; never committed (blank-safe: SSO stays disabled until configured).

  16. · kamo-internal

    Org-scoped room names, room-name format, calendar Kamo meetings, start reminders; i18n settings

    - useMeeting/MeetingDialog: room names are now namespaced by org token so two orgs can never collide into the same Prosody conference, and honor the org's roomNameFormat (RANDOM vs DISPLAY_NAME_RANDOM using the member's alias). - MeetingComposer (calendar): "Kamo Meeting" button generates an org-scoped room and sets the event URL to the /meet/join click-time OTK link, so calendar invite + reminder recipients are signed in as verified members. - MeetReminderPopup: subscribes to /topic/meet/reminder/{memberId} (MediaService sweeper) and shows a "meeting starting" toast with a Join button; mounted in PresenceWrapper on the shared chat WS. - meets settings tabs: replace hardcoded English toast/error strings with next-intl t() keys ****************

  17. · MediaService

    Scheduled-meeting start reminders + guest-link expiry

    - MeetingReminderSweep: @Scheduled sweeper that fires a realtime "meeting starting" reminder to invited members at (start − reminderMinutesBefore) on **************** then transitions the meeting SCHEDULED→ACTIVE to dedupe. Meetings more than an hour past start are transitioned without a reminder (no back-fill spam). The client builds the authenticated join link from its own origin. - **************** now honors guestLinkExpiryHours: a meeting older than the org's configured window (anchored on scheduled start, else creation) is treated as not joinable (0 = never expires).

  18. · kamo-internal

    Show member availability in chats list; rename tab to Directory

    1:1 chat rows now surface the counterpart's live presence + availability the same way the Directory tab does — same useAvailability/usePresence sources and the same colours/labels as MemberItem (dot + uppercase label, pulsing when online, gray when offline), with a tooltip. Group chats keep the "someone's online" avatar dot; social/support rows are unchanged. The Members tab is renamed to "Directory" (i18n value only), which also clears the naming collision with the chats "Members" sub-tab group.

  19. · KlusterServices

    Hardened KubeVirt remote desktop + Guacamole gateway

    Adds a full remote-desktop stack, GitOps-applied via the deploy workflow: - KubeVirt + CDI installed at deploy time (pinned-stable release URLs) - desktop-1: Kubuntu 24.04 VM, 8 vCPU / 16Gi / 500Gi Longhorn block disk, masquerade net (native cluster DNS), xrdp KDE session; cloud-init installs Chrome, VS Code, NetBeans, Temurin JDK 21+17, Headlamp, Kate, LibreOffice and removes Firefox - Apache Guacamole (guacamole + guacd + Postgres config DB) at desktop.kamocrm.com; guacd runs hostNetwork on k1m1 so it can WoL-broadcast and RDP directly onto the 192.168.4.0/22 LAN while still reaching the VM via ClusterFirstWithHostNet DNS - LAN Windows PC (192.168.4.44, MAC f4:4d:30:62:8a:68) added as a connection with Guacamole native Wake-on-LAN (magic packet on connect, 30s wait) - Edge hardening: Traefik TLS + tight desktop-rate-limit + security headers, plus Guacamole built-in per-IP brute-force ban - auto-cert: desktop.kamocrm.com added to STATIC_DOMAINS + cross-ns mirror so cert-manager issues/renews tls-desktop-kamocrm-com into the desktop ns - Credentials: user 'sage'; password injected from CI secret DESKTOP_PASSWORD at deploy time (envsubst/sed + imperative Secret) — never committed

  20. · kamo-internal

    Sub-tabs for chat groups, remember last-open tab

    The chats list filtered by a row of multi-select pill chips that looked out of place under the Chats tab. Replace them with a single-select sub-tab bar (one tab per group: Team Members / Members / Social / Support) styled to match the parent Members/Chats tabs, so the selected group's list fills the whole content area. - Single activeBucket instead of a Set of active buckets; the server fetch now pulls only the selected category. - Defaults to Team Members, and persists the last-open tab per member (across devices) via the ui-preferences store (key chatsActiveBucket), gating the first fetch until the saved tab resolves so it loads directly.

  21. · kamo-internal

    Explain when email isn't configured; gate compose

    The /messages inbox previously rendered its full shell even when the org had no email provider or the member had no mailbox, silently failing every API call. Add a shared useEmailAvailability hook that resolves whether email is usable and, if not, why (provider not configured vs. no mailbox) and whether the current member can self-serve the fix based on their rights. - MessageBrowser now shows an elegant EmailNotConfigured panel instead of an empty inbox, with copy + CTA that adapt to the reason and the member's rights (link to email provider settings for MANAGE_EMAIL_SETTINGS, or to their own mailbox tab for MANAGE_EMAIL_ACCOUNTS; otherwise defer to admin). - MailButton disables "Compose New Email" until email is fully ready, with a reason-specific tooltip; NavToolButton gains disabled/tooltip item support. - Anchor the `messages/` gitignore rule to the repo root so it stops also ignoring app/components/messages/ (which silently dropped new files there).

  22. · kamo-internal

    All-types Chats list + browser-tab attention

    Chats sub-tab now lists member, group, support and social conversations together, most-recent first, with a multi-select filter (Team Members / Members / Social / Support; the first two use the org's custom labels). Team-Members vs Members is split by counterpart memberType; support rows show whether you or the other party is the agent; each row opens its native tool window (chat / support / social). Adds TabAttention: a favicon badge + flashing document.title when there are unseen messages of any chat type (red count) or a pending accept-lead (amber ⚡ bolt, matching the leads/CRM icon; takes priority). Reads the existing UnreadContext + LeadAlertContext, so no new backend.

  23. · MediaService

    Unified Chats feed across member/support/social sessions

    GET /api/media/sessions/chat now accepts a `categories` filter (chat, support, social; default all) and returns one globally most-recent-first, merge of the per-kind queries. Each row carries: - sessionType (CHAT|SUPPORT|SOCIAL) + members[].memberType so the client can split internal chats into Team-Members vs Members, - ticketId + supportRole (AGENT|REQUESTOR — support is bidirectional) for support rows, and provider + connectionTitle for social rows, so each row opens its native tool window.

  24. · kamo-shared-library

    Paged queries for support + social chat sessions

    feed so the unified Interaction Center Chats list can include all kinds: - SUPPORT (TYPE_ID=2): sessions where the member is the assigned agent OR the requestor (also returns ticket id + assigned agent id for the row). - SOCIAL (TYPE_ID=3): sessions on social connections owned by the member's organization.

  25. · kamo-internal

    Finish lead-view header actions + callbacks

    - Header: split Call into Call (Work)/Call (Personal) opening the softphone (hidden when the member has no registered extension), Email opens the composer, Text -> comms/texts, Note moved left with a rule and blinks until a note is placed since the last reassignment. Remove the Task button. - Status: drop the invalid Change Status menu and broken Edit Status button; add a STATUS > SUB-STATUS row that requires picking a sub-status and only enables Update when it changes. - Callback: dialog (date/time + timezone + comment), a pending/overdue list on the details tab with mark-contacted/cancel prompts, and leadsApi + proxy routes for schedule/list/resolve.

  26. · EmailService

    Internal endpoint to create/cancel a member's calendar event

    POST /api/internal/calendar/events (X-Internal-Auth gated) resolves member -> user -> primary calendar (creating a default if needed) and creates an event. Used by SecurityService to mirror lead callbacks onto a member's calendar.

  27. · SecurityService

    Lead callback endpoints (schedule/list/resolve)

    New **************** controller + service: persists the callback, posts scheduling/outcome notes into the lead's media stream, and mirrors the callback onto the scheduling member's calendar via EmailService's internal calendar endpoint (best-effort).

  28. · kamo-shared-library

    Add LeadCallback entity, status enum, and repository

    Backs the lead-view callback feature: a lead-owned callback record (PENDING/CONTACTED/CANCELED) keyed off leadUid, with a soft reference to the mirrored EmailService calendar event.

  29. · kamo-internal

    Create a session for group chats opened by memberIds

    ChatTool ignored props.memberIds: a group open arrived with an empty userId and no sessionGuid, so the 1:1 createSession bailed early and the window never got a session. Now when memberIds is present ChatTool resolves the session via POST /sessions/chat/find-or-create { memberIds } (the same endpoint ChatBox's initialMemberIds path uses; the backend adds the caller itself). The member list is keyed as a stable sorted string so the effect doesn't re-fire on array identity, and the resolved guid flows through the existing writeback so the group window is GUID-anchored for dedup.

  30. · APIService

    Public passthrough for email OAuth provider callback

    Forward GET **************** to EmailService sessionlessly (strips auth, no redirect following), mirroring the RingCentral OAuth callback. This is the fixed public redirect URI registered with Microsoft/Google/Zoho.

Your universe is waiting.

Start free in minutes. Add products whenever you are ready — no migration, no new logins.

Free forever — no credit card required