Drop client SENDs to guarded topics, and repair the build at HEAD
TWO THINGS, both of which stop MediaService main from shipping. 1. main does not compile. MediaController:1361 calls **************** which does not exist: ...
Announce a message once, when it is whole
Both callers that finish building a message after the row is saved now tell createMessage not to announce it: MediaController attaches the images and publishes ...
Store attachments through the dedup pipeline instead of one object per upload
Attachments wrote their own "<imgId>/<fileName>" object on every upload, bypassing the content-addressed store entirely — the same logo-draft.png attached three...
Scan the shared MFA repositories
MfaEnrollmentService is a @Service in kamo-shared-library, so the wildcard @ComponentScan("com.kamo") in this application constructs it whether or not this serv...
Harden the kubectl download against flaky egress [skip ci]
dl.k8s.io over the runner's egress intermittently drops mid-transfer: curl: (56) OpenSSL SSL_read: decryption failed or bad record mac which fails the deploy ...
Mount the live per-host cert instead of the expired wildcard secret
The cert-converter init container built its PKCS12 keystore from wildcard-kamocrm-com, a legacy multi-SAN secret that cert-manager orphaned when its Certificate...
Reject cross-org sales agents; widen bootstrap cache busting
salesAgentId was persisted from the request body unchecked, so a cross-org or dangling agent id could be stored on a WebChatIntegration. It failed safe only bec...
Exclude non-ACTIVE members from chat participation & routing
A non-ACTIVE **************** member must not appear as, or be targeted as, a live chat participant. Gate every chat path on the shared-lib **************** pre...
Make WebChatIntegration create() @Transactional (no orphaned key on integration-save failure)
Resolve public-chat system member per-org (drop hardcoded snadjafinia alias)
createSupportSession, createPublicTicket, and the owner notification helpers all resolved the org's "system member" via a hardcoded usernameAlias="snadjafinia" ...
Stop putting message content into missed-message emails
Remove messagePreview computation, the ledger PREVIEW write, and the messagePreview template variable; drop the includePreview preference. Emails now carry send...
Persist scheduled-material thumb flags via targeted update
Same detached-entity orphanRemoval issue as the conversion pipeline: the headless sweep held a detached ImgDat and save()/merge() cascaded into the images colle...
Wrap recording upload so MediaService compiles
MinIOStorageService.upload throws a checked Exception that ingest() neither caught nor declared — build break on top of the isGuest fix. Wrap it and rethrow as ...
MeetingParticipant.isGuest() (was getGuest, won't compile); repoint transcribe to generic endpoint
MeetingParticipant exposes isGuest() (primitive boolean getter), not getGuest(). Also point the summary transcribe call at the shared /api/conversion/transcribe...
Persist invited participants, enforce MANAGE_MEET_SETTINGS, drop double-invite path
- createMeeting: invited members are numeric snowflake IDs, not UUID strings — route them through longToUUID like the creator. Previously UUID.fromString th...
Use cluster MinIO service DNS; drop deprecated WireGuard/CGNAT IPs and retired k2m1/k0m1
Publish NATS CREATE event after transaction commit to fix image attachment race
The NATS message was published inside the @Transactional body, which meant recipients could receive the CREATE event and request the image via /imaging/proxy/{o...
Serialize attachments in WS relay and message history; allow attachment-only sends
Three bugs fixed: 1. ChatSessionSubscriptionManager was building the STOMP messageMap manually and omitting attachments, sourceLanguageId, readMemberId, msg...
Fix NPE in getChatSessions from Map.of() rejecting null nextcoder
java.util.Map.of() throws NullPointerException when nextcoder is null (no more pages). Replace with HashMap that accepts null values. Also wrap entire handler i...
Fix upload 500 (missing EmbRecordState) and empty chats tab (Timestamp cast)
Defect A: ChatAttachmentService.upload omitted **************** causing a NOT NULL violation on imgs.is_active. Added the default recordState. Also hardened Cha...
Prefer usernameAlias over User.name in memberDisplayName
Switches display name priority to: Member.usernameAlias → User.name → User.alias → User.username. Also includes the paged query dispatch fix from the previous c...
Use split First/After queries for chat sessions paged endpoint
Addresses empty Chats tab by dispatching to ****************
Raise client read timeout to 120s for long messages
LibreTranslate runs CPU-only argos models — a paragraph-length chat message takes 20-30s to translate, and longer ones can push past 60s. The 8-second read time...
Track public support chat by session GUID in Redis
Marketing visitors use /ws/public-chat-native without memberId; tickets still reference the org placeholder member as requestor. Increment PRESENCE_PUBLIC keys ...
Expand JPA repository scan to include commerce package
The new kamo-shared-library brings in **************** which requires **************** (in com.kamo.z.shared.commerce). MediaService only scanned donotmodify.da...
Restore HashMap import in ChatWebSocketController
The previous refactor removed the HashMap import but the handleTyping method still constructs a HashMap for the typing event payload, causing the Forgejo build ...
Proactively create NATS consumer at session creation to prevent message loss
Previously the NATS JetStream push consumer was only created when a STOMP client sent /app/chat/subscribe. With DeliverPolicy.New, any messages published before...
Relay theme provision from core NATS
Match SecurityService core publish: subscribe with Dispatcher on security.theme.provision.* instead of JetStream (stream only covers chat).
Use PublicChatVisitor displayName for requestorName on visitor tickets
Visitor-initiated tickets hardcode requestor to the org system member, so the DTO was surfacing the org owner's name in the Requestor column. Fall back to the P...
Build error in GeoLookupService and add NATS publish for agent messages
- Fix Optional vs List type mismatch in **************** - Inject NatsMessageService into MediaController - Publish to chat.session.{guid} after agent creates a...
Real-time chat delivery, message sides, notifications, and name sync
- Keep NATS subscription alive on client unsubscribe to avoid breaking agent real-time delivery - Tag visitor messages with messageType=VISITOR_MESSAGE in getMe...
Tag visitor messages as VISITOR_MESSAGE type, add senderName to GET messages
- PublicChatService: set messageType=VISITOR_MESSAGE so frontend can distinguish visitor echoes from agent responses on the STOMP topic - MediaController.getM...
Three support/chat issues — NATS relay, auto-popup, topic fallback
1. Switch SupportNotificationService and SupportStompRelayController from JetStream to core NATS — the CHAT_MESSAGES stream only covers chat.> so JetStrea...
Write contact form description as chat message on public ticket creation
The description was only stored on the ticket entity and never appeared in the chat window. Added writeTextMessage() helper and call it after the system event s...
Add debug logging and robust rights parsing for webinar controller
Adds info/warn logging for session data and rights on POST /types to diagnose 403 errors. Also adds fallback parsing for rights stored as JSON strings in Redis ...
Resolve org theme backgrounds not appearing in meet virtual backgrounds
- Add domain-based theme URL resolution for internal K8s service-to-service calls - getPublicBackgrounds now accepts optional domain param to derive correct the...
Upload meet backgrounds to public MinIO bucket with hash-based naming
Was uploading to private 'imaging-meet-recordings' bucket via **************** which caused: - MinIO region mismatch errors on the primary node - Connection tim...
Return serialization-safe Maps instead of raw JPA entities in MeetConfigController
All config/background endpoints were returning raw JPA entities with @ManyToOne(fetch=LAZY) Organization references. Jackson failed to serialize the Hibernate p...
Remove duplicate endpoints from MeetController, add org-themes to MeetConfigController
MeetConfigController already handled config/background endpoints. The duplicate endpoints in MeetController caused ambiguous mapping. Added org-theme background...
Update health probes to HTTP port 80 to match new server config
Startup, readiness, and liveness probes were still pointing to port 8443 with HTTPS scheme, causing pod restart loops.
Switch MediaService to HTTP port 80 — TLS termination at Traefik
Internal cluster traffic doesn't need HTTPS. Traefik handles TLS for external clients. This aligns MediaService with all other services.
Send chat invites to correct WebSocket topic /topic/chat/incoming/{memberId}
Was publishing to /topic/chat/member/{id} but kamo-internal subscribes to /topic/chat/incoming/{id}. Also fixed Member entity field access **************** inst...
Add voip.> to NATS stream subjects and handle IllegalStateException in VoipStompRelayController
The NATS stream only covered chat.> so subscribing to voip.> threw IllegalStateException ([SUB-90007] No matching streams). Added voip.> to the stream subjects ...
Retain VoipStompRelayController subscription reference and add PreDestroy
Accept *** from query param for cross-subdomain WebSocket auth
Read *** ID from ?***= query parameter first, falling back to cookie. This allows the frontend on internal.kamocrm.com to authenticate WebSocket connections to ...
Handle stale NATS consumer binding with unique consumer retry
- Extract message handler into createNatsMessageHandler() method - Add retry logic with unique consumer name when "Consumer already bound" error occurs after ...
Route WebSocket through Traefik on port 443
- service.yaml: fix port 80→8443 to match pod's actual listen port - ingressroute.yaml: use scheme https + port 8443 for backend - serverstransport.yaml: add in...
Like what you see shipping?
All of it arrives in your workspace on its own. Start on the free plan and read this page again in a month.
