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...
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...
An attachment that cannot be read says so, instead of nothing
A media element gives you one bit — it failed — and no status code, and it latches on that bit: it never retries, so whatever went wrong the control simply stay...
A picture-frame image whose bytes are gone answers 410, not 500
The frame stream caught everything as stream_failed and returned 500, so a photo whose object is not in storage rendered as a broken image with no explanation -...
A recording whose bytes are gone answers 410, not 500
Same split as the imaging proxy and the docs download. A call recording that is not in storage is permanently not there, and a player handed a 500 shows nothing...
A document whose bytes are gone answers 410, not 500
The streaming download caught every storage failure as one unexpected error and returned 500, which tells a reader nothing and leaves a viewer with a blank erro...
An attachment that cannot be read says so instead of 500ing
The imaging proxy already answers 410 for revoked access and for a removed message, but let openRange's IOException escape uncaught — so the one case where the ...
Actually call the fulfillment policy
SW3 implemented FulfillmentPolicy as the first member of an interface that had none, and nothing ever called it — a grep across kamo-shared-library and Security...
The seat headline read a default, not a ceiling
The card printed "Up to 5 users" from plan.maxSeats, directly above its own feature list reading "Users (25)" and a comparison column reading 25 - the same card...
Catalog rows that made the pricing page contradict itself
COMMERCE_POS is ServiceType.POS(21), whose real name is "Lines of Business" - the umbrella switch for what an org sells, rents, services or lends. It was labell...
A CCD preview is not a disclosure
Previewing a summary recorded a disclosure naming the recipient — so a patient asking who has their record under §164.528 would be told it went to somebody who ...
Three catalog rows that made the pricing page contradict itself
Seat counts. The plan card headline reads max_seats ("Up to 5 users") while the feature list beneath it and the comparison table read the USERS feature row, whi...
The page contradicted itself, and the calculator billed email per user
Included-in badge named the wrong plan. All four per-seat modules are included in Business and Enterprise, and the badge picked the FIRST id in includedInPlanId...
The document upload publishes its row only once the bytes land
The buffered uploadDocument was the one store that wrote its ImgDat with isMissing=false BEFORE sending anything, and merely re-set it to false after a successf...
A failed upload must not become a dedup match
A member sent an 11 MB .wav to a chat, got "Cannot invoke ObjectWriteResponse.etag() because response is null", sent it again, and the second one delivered inst...
Bound the Go heap with GOMEMLIMIT and declare a real memory request
Root cause of the crash-loop was not a leak. The 485Mi steady state that kept tripping the old 512Mi limit was two normal things stacked: ~350Mi Go heap at ...
An inbound call reads properly and respects the status pill
Three things wrong with the softphone tool window's incoming-call overlay. The number was painted exactly as the INVITE carried it, so a caller arrived as "+15...
Nothing returned an account id, so nothing could be withdrawn
Withdrawing portal access and granting a proxy both take an account id, and no endpoint ever returned one. A practice could invite a patient to the portal and t...
Raise memory limit to 1Gi and relax liveness probe timeout
Traefik sat at ~485Mi against a 512Mi limit (95%). The cgroup recorded 47836 memory.max hits with oom_kill 0 — never OOM-killed, because enough of the footprint...
Price-list entry read and update spoke to the wrong endpoint
Two silent client/server mismatches made the retail price-list entry screen's write path dead: - the entries list was unwrapped with the key "entries", but C...
The extension sweep no longer erases every member assignment
MemberVoipConfigController.put writes an assignment to two places - MEMBER_VOIP_CONFIG and **************** - and **************** then cleared the second on it...
A reaction toggled twice at once is a no-op, not a 500
setReaction read, then saved, then caught the constraint violation the read was supposed to prevent — which does not work: the violation surfaces at flush, afte...
Let the database decide whether a reaction is already there
The unique constraint on (message, member, emoji) was doing nothing useful. A read-then-save loses the race with the member's own second click, and catching the...
A failed reaction or edit does not stick to the message
Takes @kamo/chat-core 0.1.9, which rolls an optimistic edit or reaction back when the connection drops rather than only when the server refuses. The bubble's sa...
The workspace you chose is the one you land in
Choose "ABC Mortgage" at sign-in and you arrived in a workspace wearing KamoCRM's logo and colours, with a left-hand menu offering White Labeling, Plans & Billi...
Stop the unread card offering mail that was read and deleted
The home-page unread-mail widget reads email_metadata.search_index directly — it must not spend an IMAP connection, which is the whole reason it exists — and th...
Keep support tickets out of the per-member unread badge
perSender is what puts a number on a person — their member-directory row, their hex head — so it has to mean "unread messages from them". It was summing every s...
An unread count names a sender only when a single member is the answer
senderId is what pins an unread badge to a person — their member-directory row, their hex head — so it has to mean "these messages are from them". It was set fo...
A per-mailbox add-on is not priced per user
PER_MAILBOX fell through to the default arm, so the public pricing page advertised the two e-mail add-ons as "/user/month" against a per-mailbox price. PER_EXTE...
Stop two first loads provisioning two of each calendar
The launchpad paints two calendar widgets and each fetches its own feed, so two requests reached listCalendars at once. Provisioning is find-then-create, both p...
Saving a settings page no longer repaints the tab as the platform
Signed into Wienerschnitzel, opened Settings → Branding, saved Company Info, and the entire workspace reverted to Kamo's logo and colours. Closing the tab and o...
Allowlist Telnyx in both fail2ban jails
Adds the Telnyx US signaling addresses (192.76.120.10, 64.16.250.10 — sip.telnyx.com) to ignoreip now that the carrier trunk is provisioned. Also overrides ign...
Predial hooks must Return(), not MacroExit() — Asterisk 21
Asterisk 21 removed the Macro() application family outright, and FreePBX reaches these hooks with Gosub() (extensions_additional.conf: **************** The stoc...
Make fail2ban actually run — enable Asterisk's security log
fail2ban has never started on this PBX. Its asterisk-security jail watches /var/log/asterisk/security, a file Asterisk never created: FreePBX generates logger_l...
Scan the shared-lib email.billing repository package
@EnableJpaRepositories lists packages explicitly, so MailboxBillingDayRepository was invisible and the service refused to start outright — caught by booting it,...
Never lock the provider an org is already using
Two production orgs run 26 and 41 live mailboxes while holding no mail add-on code, so the picker would have told them KamoMail requires the KamoMail Hosting ad...
22 of the 26 clinical rights were never enforced
Only the four population-level rights — bulk export, quality measures, portal administration and EHR settings — were ever checked. Prescribe, sign, cosign, plac...
A contested primary is a 409, not a 500
The catch-all turned an expected refusal into a server error, which lost the message the member needed and made a routine conflict look like an outage in the lo...
Ask a host that exists for the organization ?org= names
A new organization was created with its logo, colours and three backgrounds. All of it provisioned correctly into public/wienerschnitzel/ — 15 objects, the righ...
An organization can be looked up by the reference ?org= carries
GET /org/ref/{ref} — the same projected record as /org/domain/{host}, for an organization named by its id or its web alias. Nothing could answer for one. The s...
Refuse a primary mailbox another member holds
Primary is a login identifier, so a silent takeover changes which account an address authenticates from a screen that never mentions logins. Assign still works ...
Every catalogued event fires where the event actually happens
Most of the sound catalogue was configurable and inaudible. Two causes, both silent by construction: a sound that never plays looks exactly like one the member ...
Actually measure the bulk-export bucket
StorageDomain.BULK_EXPORTS shipped declared, documented as "measured by scanning the object store", and referenced by nothing. It reported zero for every practi...
Dropping in the goal scores, and aiming at it no longer gathers
Two complaints about the same gesture — taking a head to the goal. **Dropping in the goal did nothing.** Scoring lived entirely inside the throw RAF loop, whic...
Read the platform's branding from its alias folder
The theme folder was derived from the hostname — kamocrm.com became kamocrm-com — which is where branding was written until a domain became optional and the org...
A signing page wears the sender's brand, not Kamo's
getThemePath took a hostname and used its FQDN with dots turned into dashes as the bucket folder. That could only answer for an org that HAD a hostname, and a d...
The lobby wears the meeting owner's brand, not the platform's
The overlay derived its theme folder from the browser's hostname. On the shared meet host that is the platform's for every tenant, so the CSS, favicon and logo ...
Brand the signup screen from the org's alias, not the host
register.kamocrm.com is the signup page for every organization with no register host of its own, so a host-derived theme folder painted all of them in the platf...
Brand the sign-in screen from the org's alias, not the host
login.kamocrm.com is the sign-in screen for every organization that has no host of its own. The theme base was derived from that hostname, so all of them were p...
Je, unaona nini kuhusu usafiri?
Kila moja ya hizi updates ardhi katika nafasi yako ya kazi moja kwa moja. Kuanza bure na kuangalia kukua wiki baada ya wiki.