Rewrite /etc/odbc.ini to point at $MARIADB_HOST on every boot
The escomputers/freepbx:17 image bakes /etc/odbc.ini with Server=db (the docker-compose link target). On this Kubernetes deployment MariaDB lives at \$MARIADB_H...
Resolve member→extension before VM/CDR provider lookup
CallController was passing memberId where FreePBX (and other PBX-style providers) expect an extension number — voicemail listing returned empty because no PBX e...
Auto-assign first seat, Free as floor, broader org invalidation
BillingSetupService now activates the first open license slot for the creator when seeding a sub-org subscription (and same for promote-to-billing-owner) — othe...
Top-level org members get platform-owner plan, bypass billing gates
KamoCRM (top-level) org members are not subject to the billing system — they get the OWNER_UNLIMITED plan's feature matrix outright (with Free as a defensive fa...
Top-level org bypass + Free baseline fallback for orgs without subs
The org-level entitlement check **************** walks subscriptions targeting an org. With the new target_org model, orgs that don't yet have a targeting Accou...
Remove redundant Field history title from history panel
Tab label already conveys context — title and subtitle were wasting screen space. Reload button moved inline into the toolbar.
Remove layout prop causing email body bouncing
The outer motion.div's `layout` prop fought with the inner AnimatePresence height: 'auto' animation, creating a FLIP feedback loop on emails with unstable heigh...
Resolve duplicate column mapping by overriding embedded address columns to MAILING_*
Update RetailService and provider adapters for Account.notes removal and CurrencyType conversion
Always show Create Document button on doc manager page
Removed the getMemberId() > 0 guard that was hiding the button during the useUserInfo loading window. The page is already behind auth so no client-side membersh...
Restore organization import removed by accident
organization.id is still needed in the handleCreateDocument request body; only the isDocsEditor condition should have been removed.
Show Create Document button to all logged-in members
The org feature flag check (isDocsEditor → isDocs → hasFeature DOCS) was returning false because org features use deprecated key types. The button is now shown ...
Remove datagrid field-level filters and floating filter row
Disabled all column filters and the floating filter input row so the grid shows only column headers and data rows. Also removed the Filters tool panel from the ...
Move Upload button into DocManager toolbar
The Upload trigger was only in the /doc/manager page's actions prop, making it invisible when DocManager is embedded in other pages. Moved the Upload button dir...
Allow upload options to scroll in embedded DocManager
Uploads tab container was overflow:hidden, clipping per-file options (description, folder, doc type, access level) in height-constrained embedded contexts. Chan...
Fix 400 feed error and add communications sub-tabs with URL params
Fix double-? bug in MediaStream where feedEndpoint already contained query params but the fetch appended ?page=... instead of &page=..., causing a malformed URL...
Make 'All Leads' a real menu item with icons in agent filter
- Replace placeholder empty-value item with __ALL__ so the dropdown never shows blank when All Leads is selected - Add Group icon to All Leads and PersonOff i...
Consume *** secret so X-Internal-Auth matches downstream services
DaemonService -> ConversionService **************** was returning 401 Unauthorized because DaemonService was stamping its X-Internal-Auth header from INTERNAL_A...
Use @CreationTimestamp(source=DB) on ****************
The DB is the single source of truth for timestamps in this codebase. The canonical Hibernate pattern is @CreationTimestamp(source = SourceType.DB), which makes...
Let DB fill **************** via @Generated(INSERT)
INSERTs were failing with: null value in column "date_created" violates not-null constraint @ColumnDefault only declares the DB-side default for new rows; Hi...
Drop the [from-internal-custom] _X. catch-all that broke softphone calls
The catch-all exten => _X.,1 in [from-internal-custom] was intercepting every internal dial — softphones started reporting "phone is not registered" / calls wou...
Enable JPA repos for commerce + email + dao.repositories packages
ConversionService new pod CrashLoopBackOff with the same error DaemonService hit earlier: Parameter 0 of constructor in **************** required a bean of ...
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...
Write managed config files 0644 so the asterisk daemon can read them
The kamo-asterisk-support pod runs as root and writes to host-mounted **************** Asterisk inside the FreePBX pod runs as user "asterisk" and could not rea...
Use envsubst-compatible \${VAR} syntax in config template + re-render on stale placeholders
Pods were CrashLoopBackOff with "config errors: API_KEY is missing or too short" because the config template used literal __API_KEY__ markers that envsubst sile...
Drop unused watcher import
uploader.go only uses CallBatch (declared in grouper.go in the same package), not anything from internal/watcher directly. Go rejects unused imports.
Enable JPA repos for commerce + email + dao.repositories packages
DaemonService crashed on startup with: Parameter 0 of constructor in **************** required a bean of type **************** that could not be found. A r...
Capture newExtNumber as final for lambda capture in MemberVoipConfigController
newExtNumber is conditionally reassigned inside the if (isVoipEnabled && ...) block, which makes it not effectively final. The TeamMember sync block reads it fr...
Update OrgThemeProvisionServiceTest for buildConfigJson description parameter
Cast voiceActivityDetection to bypass missing TS DOM type
voiceActivityDetection is a valid WebRTC MediaTrackConstraints property but is absent from TypeScript's DOM lib, causing a type error at build time.
Configure STUN so browser ICE can complete bidirectionally
Two-party browser-to-browser calls connected at the SIP layer but had no audio either direction. Voicemail (one-way Asterisk → browser) worked because Asterisk'...
Live audio that survives load-interrupts, centered spinner, outbound ringback
Three coordinated fixes for the in-call audio path: 1. AbortError on remoteAudio.play() (visible in production console as "The play() request was interrupte...
Hangup tears down ALL live sessions, not just the primary
Self-call edge case left a session leaked: dialing your own extension creates an outbound session, then Asterisk loops the call back as a second inbound session...
Instant connecting feedback on outbound dial
Same problem the inbound Answer button had: clicking Call kicked off the SIP INVITE round-trip (1-3 seconds) but the button kept its idle "Call" appearance the ...
Connecting animation + audio that actually plays + ringtone unlock
Three coordinated fixes for the inbound-call path: 1. Visual feedback while accepting. Clicking Answer left both buttons responsive-looking but unresponsive...
Mount SoftphoneProvider above ToolDock so tool windows can read it
Opening the Softphone popup crashed the page with "This page couldn't load" because tool windows mount inside ToolDock, which lives in ToolProviders — a SIBLING...
Use Grid size prop so AV panels fill the row
MUI v7's Grid is flexbox-based, so the gridColumn sx I'd been using was a no-op — items rendered at their natural width and left empty space on the right. Switc...
Migrate stale ringtone IDs to default on load
If a user's saved AV preferences reference a ringtone that no longer exists in the catalogue (e.g. 'classic' from before the catalogue was trimmed), the Rington...
Dialpad digits now register on touch devices
The dialpad buttons called e.preventDefault() in both onTouchStart and onTouchEnd. That stops the browser from firing the synthetic click event that follows a t...
Host browser SIP WSS on internal.kamocrm.com (real cert)
Browsers refused the WebSocket connection to **************** with close code 1006 because Traefik was serving its self-signed default cert for that hostname (n...
Separate globe presence for marketing live chat vs members
Public Chat widget tickets keep org placeholder as requestorId; use only media session presence for those rows. Internal and other tickets use member presence (...
Periodic STOMP presence heartbeat for public support
Refresh Redis TTL for public session presence so agents see accurate online state.
Globe uses media session presence for marketing visitors
Request public-chat session GUIDs in presence snapshot; treat online if either session or requestor member is connected. Handle snapshot envelope and sessionGui...
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 ...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.