Never forward client-supplied identity headers upstream
forward(), forwardWebhook() and forwardCallback() copied every inbound header except Host (and, for the sessionless two, the credential headers) onto the upstre...
Forward carrier SMS webhooks, which reached nothing at all
Traefik sends every path on api.kamocrm.com to this gateway with no path split, and this class forwarded /api/voip/** and nothing else. So /api/bulktext/inbound...
Forward carrier SMS webhooks, which reached nothing at all
Traefik sends every path on api.kamocrm.com to this gateway with no path split, and this class forwarded /api/voip/** and nothing else. So /api/bulktext/inbound...
Prove the deploy by digest, not by tag
The preceding commit stops `set image` being a silent no-op. This asserts the outcome: after the rollout, the tag is resolved to a digest at the registry and th...
A rebuild of the same commit deployed nothing and reported success
The image is tagged with the commit SHA, so rebuilding the same commit produces an identical image reference. `kubectl set image` then changes nothing, the Depl...
Drop the /api/settings forward, which pointed at nothing
EmailService serves the sync-integration controller at **************** not /api/settings/integrations β so that forward reached a path the service does not map...
Route /api/contacts, /api/calendar and /api/settings to EmailService
KamoMobile's contacts and calendar screens 404'd on every request. Neither path was routed at the api host, so nothing reached EmailService and the service logg...
Run two pods
replicas 1 -> 2. This service runs no @Scheduled work and binds no exclusive NATS durable, so a second pod duplicates nothing β it is stateless request serving,...
Give the rollout room for the 15s minReadySeconds now costs
progressDeadlineSeconds was 60. That is the window a rollout has to show progress before Kubernetes gives up and marks it failed, and the previous commit added ...
Restore this manifest's CRLF line endings
The previous commit rewrote the file with a script that normalised it to LF, which is a whole-file diff for a change that touched a dozen lines. No content chan...
APIService never shut down gracefully at all
Deploys replaced the only pod of each service with nothing to catch the requests in flight. Three settings, applied across the fleet: - preStop sleeps 10s befo...
API-key surface for live call events from a customer PBX
Companion to VoipRecordingUploadController, on a deliberately separate VOIP_CALL_EVENTS scope: uploading a recording after the fact and making somebody's phone ...
Forward /api/email/oauth/callback to EmailService
Google's OAuth redirect target. Same shape as the email and meet provider callbacks beside it: public and sessionless, because the popup lands on this gateway o...
Forward the tracking beacon to MediaService
Clones forwardPublicWebinar rather than the generic forward(): that method prints every URI, header map and body length to stdout with no level, and a visitor b...
Rebuild against shared-library @Lob LONGVARCHAR fix
Hibernate's PostgreSQL dialect read @Lob String columns as OIDs via getLong(). Affects notes, contacts, calendar, OAuth tokens, IMAP passwords, email campaign b...
Point at YugabyteDB and use PostgreSQLDialect
CockroachDB has been replaced by YugabyteDB. Connection strings move from cockroachdb-public:26257 to yb-tserver-service:5433, and the Hibernate dialect from **...
Mirror Maven Central through the Google GCS copy
Every Docker stage starts from a cold ~/.m2 and refetches the whole dependency tree, so Central sees the full weight of every concurrent service build. It answe...
Encode the decoded token exactly once on the way upstream
21670e5 routed SocialWebhookController through UpstreamUri's FULLY-PRE-ENCODED entry point, but its URL is a hybrid: `token` is an @PathVariable, so Spring hand...
Forward the caller's query bytes on the public-facing proxies
The gateway stopped double-encoding forwarded query strings in 3c24d32, but four other proxies in this service still concatenated already-percent-encoded bytes ...
Forward the caller's query bytes instead of encoding them twice
Every URL this gateway builds is assembled from getRequestURI() and getQueryString() β both already percent-encoded β and was then handed to RestTemplate as a S...
Enforce tenant access rules at the gateway
This filter has been inert since it was written. resolveOrgId read org:domain:<host> from Redis, nothing ever wrote that key, and the null return fell through t...
Route the meeting provider OAuth callback
Zoom and Microsoft redirect the browser to this gateway after an org authorises Kamo's app. The popup lands here with no tenant session β the org travels in ?st...
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 ...
Proxy the public AI->human handoff route
Adds POST **************** proxied to MediaService alongside its createSupportSession sibling. Without this the handoff feature was dead on arrival: MediaServi...
Route /api/email + /api/support through the api host
(EmailService) and Support (MediaService, same upstream as /api/media) were unrouted β 404. Add both forwards and fix email.service.url from a localhost default...
GET /api/public-chat/bootstrap gateway route
Add bootstrap endpoint that reuses the existing proxyWithAuth pipeline (key validation + opt-in origin + PUBLIC_CHAT scope + rate-limit + X-Public-Chat-Key-Hash...
Defer mandatory-origin to Phase 1 β OriginMatcher opt-in (empty allow-list / missing Origin allowed)
Phase-0 widgets still call via their server-side proxy, so origin-locking has no benefit yet and every live public-chat key has an empty allow-list. Strict enfo...
Don't cache-invalidate keys on transient downstream errors (only on definitive invalid)
Only cache-invalidate genuinely-invalid keys, not origin-denied (prevents valid-key DoS)
On a cold Redis cache, a valid public-chat key with a wrong/absent Origin was cached as INVALID for 60s, denying the correct origin's requests for that window. ...
Bind WS relay handshake to Origin + add cold-cache key validation fallback
Extracts PublicChatController's private validateViaDownstream() into a shared PublicChatKeyResolver bean so PublicChatWebSocketHandler can reuse the same downst...
Verify *** PoW at the edge on public session create (enforced when payload present)
Make public-chat origin allow-list mandatory (deny on missing Origin / empty list)
Proxy GET /lo-presence to MediaService
The support-session proxy already forwards the raw body, so the merged widget's preferredAgentMemberId reaches MediaService untouched. Add the presence proxy so...
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 pub...
Forward x-twitter-webhooks-signature on the social webhook edge (X/Twitter Account Activity)
Migrate to k1m1 (registry+kubeconfig from k1m1, drop k2m1, simple kubectl install)
Public programmatic e-sign API gateway (API_SIGNATURE scope)
Add /api/public/esign/** to PublicApiController: validates the org API key, requires the API_SIGNATURE scope, rate-limits, and forwards to ESigService's interna...
Proxy support-message translate endpoint
Adds a passthrough route for the new MediaService endpoint that translates a single support-chat message into the visitor's URL locale. The marketing-side chat ...
Scope concurrency to build jobs, not Kubernetes deploys
Workflow-level concurrency serialized the whole pipeline (including kubectl rollouts). Move the group to the build job only so deploy jobs from different runs c...
Carve /api/voip/recordings/** out of the wildcard VOIP forwarder
The /api/voip/** catch-all in APIGatewayController was shadowing the dedicated VoipRecordingUploadController POST /api/voip/recordings/upload mapping when Sprin...
VoipRecordingUploadController for kamo-asterisk-support uploads
POST /api/voip/recordings/upload accepts multipart bodies from kamo-asterisk-support running on FreePBX hosts. Validates the X-Api-Key has the new VOIP_RECORDIN...
Raise file upload size limit to 500MB
Spring Boot defaults cap multipart parts at 1MB, causing background image uploads to fail with 500 in request.getParts(). Match SecurityService's existing 500MB...
Move CORS to Traefik via kamo-middlewares, remove in-app CorsFilter
The CorsFilter @Bean in the Spring app was silently not applying headers after WebConfig.java was removed. CORS is now handled entirely at the Traefik layer by ...
Remove duplicate CorsFilter and strip upstream CORS headers in gateway
WebConfig.java defined a second CorsFilter bean competing with CorsConfig.java's bean, risking duplicate header writes. Deleted it so only one CorsFilter exists...
Set application/json for JSON bodies forwarded to SecurityService
RestTemplate to upstream could leave Content-Type incompatible with Spring @RequestBody, causing 415. After reading the raw body, force APPLICATION_JSON when th...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.