Distinct Erlang node names for apps and ecallmgr
One image runs as two nodes. They need different names or they refuse to coexist, and both need the shared cookie that FreeSWITCH's mod_kazoo also uses.
Run the OTP release, not make release
The image now ships a relx release rather than the source tree, so passing 'make release' to the entrypoint failed with 'No rule to make target release'. foreg...
Say why the transaction guard stops at ehr/
The two rules generalise and both shapes exist elsewhere in this service, so the obvious next move is to widen the scan — and doing that would fail the build on...
Say why the overload's @Transactional is inert on the afterCommit path
Prompted by a peer session finding a @Transactional(REQUIRES_NEW) Spring never advised — protected, and self-invoked, so the record of a failed query rolled bac...
Bootstrap script and operational README
bootstrap.sh creates the master account, promotes it to reseller and writes the non-secret platform configuration. Idempotent: a second run detects the existing...
Fail the build on a @Transactional Spring cannot advise
Two shapes get no transaction advice at all, and neither is visible at a call site or in a unit test: a non-public method, which the proxy cannot intercept, and...
Implement KamoPBX extension, user and device management
The provider advertised extensionManagement, userManagement and deviceManagement as true while implementing none of them, so the UI would have shown buttons tha...
The outbound audit row was written by an inert REQUIRES_NEW
It was a method on ExchangeQueryService annotated @Transactional(REQUIRES_NEW), called from two private helpers on the same class. Spring's transaction advice l...
Main did not test-compile — PhiExportAuditTest missed a constructor arg
SystemConfigurationController gained a twelfth parameter, PlatformSecretCipher, when platform secrets began being encrypted at rest. This test still passed elev...
Two icon buttons were announced with no name at all
MUI's Tooltip spreads its aria-label onto its DIRECT child. Both of these wrap the button in a <span> — the standard workaround so the tooltip still fires while...
Job lines, notes and vendors so the work-order tabs can persist
Labour and parts become ServiceJobLine rows on the job rather than ServiceLineItem rows, because OrderLineItem.order is optional = false: a ServiceLineItem cann...
A failed clinical load must not render as an empty result
Two of these shipped before anyone noticed, and the guard found two more in the newest panel the moment it ran — failing to load what a patient's other practice...
A failed load was rendering as a clinical fact
Two screens turned a fetch failure into an empty result, which on a chart is not a neutral outcome — it is an assertion. The trend graph caught an error and se...
Expose platform settings through the system-config API
toDto is an explicit allowlist and updateConfig takes a typed body, so the seven new SYSTEM_CONFIGURATION columns would have been invisible and unsettable — the...
Decrypt the KamoPBX credential; test the refusal path
The master credential is stored as ciphertext by the platform settings UI, so it must be decrypted before use — handing ciphertext to the API as a password woul...
Pin the reason dialog, and let app/patients be tested at all
app/patients/** was in no vitest include pattern, so a test written beside the clinical console's own kit was collected by nothing and would have passed by neve...
Swap the inbound greeting to KamoCRM-Main-Intro-3
Third take, 40s (down from 60s). Uploaded alongside the previous two rather than over them, so rolling back to either is a one-line change to KAMO_ATTENDANT_INT...
Eight clinical reasons were being collected by window.prompt
Stopping a medication, closing an order loop, cancelling an appointment, merging two patients, declaring two records not a match, withdrawing portal access, dec...
Per-seat storage, and a flat Enterprise pool
2 GB per seat on Free, 4 on Starter, 5 on Business. Enterprise stops scaling with seats entirely - a flat 150 GB for the organization - which "N GB per seat" ca...
Stop putting green text on green, and switch storage to per seat
CONTRAST. I only fixed the solid gradient buttons last time and left green ink on green-tinted surfaces, which is the thing that actually reads badly. Audited e...
Plan SW6b, making the six tabs persist
Labour and parts become ServiceJobLine rows on the job, not ServiceLineItem rows: OrderLineItem.order is optional=false, so a ServiceLineItem cannot exist witho...
Platform settings card, and stop showing FreePBX copy
Three problems on the KamoPBX phone-server page, all mine: - The PHONE_SERVER_ID card was ungated, so every provider — KamoPBX, RingCentral and Teams include...
Read KamoPBX platform config from the database
Adding a KamoPBX phone server failed with a raw Kubernetes DNS error — 'I/O error on PUT ... **************** — shown to an organization admin who can neither r...
KamoPBX platform settings on SYSTEM_CONFIGURATION
KamoPBX is Kamo's own platform, so all of its configuration is platform-wide: base URL, master account id, account name, admin credential, SIP realm suffix and ...
Seed KamoPBX platform defaults
Hibernate ddl-auto adds the SYSTEM_CONFIGURATION columns; @ColumnDefault only applies to newly inserted rows, so the existing singleton needs backfilling. Seed...
Seed Starter at 5 seats and Business at 25
The USERS rows read 25 and 100 while max_seats, the card headline and the plan quiz all said 5 and 25. The volume-discount bands that run past those ceilings ar...
Starter is 5 seats, Business is 25
I had this right, then reversed it on bad reasoning and shipped 25 / 100. The volume-discount bands (Starter 11-25, Business 26-50, 51-100) are seat PRICING ro...
Scale edge to 0 until its config is rewritten
Kamailio cannot start on 2600Hz's vendored configs — they need 2600Hz's patched build (spec 16). Leaving it at replicas:1 restart-storms k3m1 indefinitely for n...
2600Hz ships a patched Kamailio (spec 16)
kazoo-configs-kamailio does not run on stock Kamailio. bflags and import_files are both absent from kamailio/kamailio's own src/core/cfg.lex, and both are rejec...
The platform org is not gated by its own catalog
The platform org was told "Requires the KamoPBX Hosting add-on" on its own phone-server screen, for an add-on it publishes. It owns the plan catalog, the add-o...
The NAT is in place; a closed port means no listener
The router forwards for 5060/5061 TCP+UDP and 20001-29999/UDP to 192.168.4.36 are confirmed. My gate reported PHASE 0 BLOCKED against them while Kamailio was cr...
Close out SW6a
Nine departures. The plan's Spring claim was measured false, its sketched test was near-tautological, and its ServiceTrade-labels-are-new claim was wrong — ther...
The work-order grid reads real service jobs
Every row in this grid was a dead link by construction. generateMockWorkOrders minted ids String(8000 + i), the row click pushed /commerce/service/8001, and the...
Plan cards show what a tier ADDS, not everything it has
The cards listed every included feature - 16 on Free, 30 on Starter, 52 on Business, 57 on Enterprise. Four cards of wildly unequal height, each a wall of text,...
Pull a patient's history from the practices they used to attend
The outbound half of exchange, on the records tab beside the release surface — records leaving and records arriving are one person's job, and somebody who has j...
The outbound half of TEFCA — ask, don't only answer
Everything built so far answers other people's queries: discovery, document query, document retrieve, the match-review queue, the accounting. A practice could b...
A line for documents retrieved from other organizations
Its own domain rather than a share of DOCUMENTS, for the reason bulk exports got one: a practice that queries a health information network routinely accumulates...
Provision a KamoPBX account when a phone server is created
Adding a KamoPBX phone server now creates the underlying account and writes the account id and realm back to configJson. Any configJson the client sent is DISCA...
KamoPBX is selectable
The provider is implemented in VOIPService, so the coming-soon gate comes off. Description no longer names the upstream project and says what actually matters t...
Right-gated service job API
**************** — list, get, update, and PATCH status. Copies ServiceTaskBookController's idiom: orgId(req) or 401, a right check or 403, a String path variabl...
An org-scoped read/write API for service jobs
ServiceJob has been a mapped entity with repositories and passing tests and no way to read a row. This gives it the header the finished work-order UI already re...
Reveal the preselected workspace, and give the list the org's scrollbar
Two things about the workspace picker, both about the same list. The workspace a member used last is preselected and named on the button, because this screen i...
Implement the KamoPBX provider
Replaces the stub. KamoPBX is Kamo's own platform, so the organization holds no credential at all: KamoPBXAccountProvisioner creates the account when a phone se...
Stop telling implementers to run git commit --allow-empty
--allow-empty PERMITS an empty result, it does not force one. With no pathspec it still commits the index, and these checkouts always have another session's wor...
Stop telling implementers to run git commit --allow-empty
--allow-empty PERMITS an empty result, it does not force one. With no pathspec it still commits the index, and these checkouts always have another session's wor...
Unbreak the build - undo a sweep I caused
c8ec175 was meant to be an empty rebuild commit. It was not: `git commit --allow-empty` PERMITS an empty result, it does not force one - it still commits the in...
Apps, media, edge manifests and network policy
- config.ini carries a [zone] block from day one so a second region is a config edit, not surgery. Secrets are substituted by an entrypoint at container start...
The Interaction Center bucket tabs never wrap to two lines
Six full-width tabs share the 550px conversations pane, leaving ~80px each, and "Team Members" did not fit — it wrapped and doubled the strip's height. Both mem...
K3m1 is 47.181.8.87 (pbx.k3.kluster.kamocrm.com)
Reverts an incorrect change of mine. I had propagated 42.181.8.87 and edited coturn/deployment.yaml's comment, which was right all along. Verified by DNS: pbx...
**************** and lock the Enterprise card
Registers the right client-side - list, colour, icon - and adds it to the coverage test's non-tab set with a note on what it actually gates, since it guards an ...
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.
