Declare removedByMemberId, or the relay drops it in silence
The NATS payload for MEMBER_REMOVED carries who did the removing, but the NATS→STOMP relay projects every frame through ChatMessageDto — so a field this class d...
One title rule, one group threshold, and a rename the list hears
Review of the Chats branch, four findings. Both surfaces were composing the conversation's name by hand instead of through the helpers @kamo/chat-core exports ...
No upstream error text reaches a member, whichever provider failed
memberTextFor fell through to getMessage() for anything that was not an AiProviderException. Only the HuggingFace adapter classifies its refusals; every other o...
Open on Chats, a Favourites section, and a group chat you can manage
Five requests from a member, all of them about the same gap: the Chats panel could show you conversations but gave you nothing to do with them. Chats is now th...
Name a group chat, star a conversation, remove somebody from a room
Three routes, and each refusal is a rule somebody has to be able to tell apart from an outage — so each carries its own code rather than a shared 4xx. DELETE *...
A chat can be named, starred, and have somebody removed from it
Three fields and one method, all of which the chat feature already had the shape for and none of which it could record. MEDIA_SESSION_CHAT gains TITLE. That ta...
Show why a text could not be started, not "check the number"
VoipService now answers an unprovisioned account with 409 and both a machine code (`error`) and a sentence a member can act on (`message`). apiCall read `error`...
An account with no number to text from is a 409, not a 500
Starting a text threw IllegalStateException when neither the member nor the instance had an outbound number, which Spring turned into a 500 with a stack trace. ...
Retire a model the provider won't route, and stop quoting it at members
Follow-up to the router-catalogue fix. That stops unroutable models being LISTED; this stops one already in an org's catalogue from breaking the assistant and n...
List the Hugging Face models the router will actually serve
Chat goes to the Inference Providers router **************** but discoverModels asked the HUB for models that are "warm" somewhere — a different and much larger...
Drop the security level control from the batch settings
It was a disabled Select behind a "locked" tooltip, and a chip in the collapsed summary. Both reported a value the admin never chose: security level is derived ...
Bulk add members and team members, with a CSV/XLS import
Two new screens beside the existing Add buttons on /account?tab=members and ?tab=team-members, at /settings/member/bulk-new and /settings/team-member/bulk-new. ...
Bulk-create members and team members, one transaction per record
The two bulk-add screens need to create a spreadsheet of people in one submission and report on each of them individually. That could not be built on the existi...
Say the app is in beta, and that Apple devices aren't ready
Two facts a member needed before scanning anything: KamoMobile is beta, and there is no build for an iPhone or iPad yet. Both change whether someone should star...
Format the phone numbers on the customer's quote
The page a customer opens printed every number exactly as stored — "9495550134" on the letterhead, and the same again under Your Contact. This app had no phone ...
Format the phone numbers on the printed quote
The document printed every number exactly as stored — "9495550134" on the letterhead, and the same again under Your Contact. Formatting goes through `app/lib/ph...
A Receivables tab, and payment details on the printed quote
Settings → Account → Receivables is where an organization sets the bank account its customers pay into: the payee, the bank, the routing and account numbers, an...
Print the seller's ACH details on the customer's quote
The page a customer opens from a share link now carries a remittance block: who the payment is made out to, the receiving bank, and the routing and account numb...
Store the org's deposit account, and print it on quotes
`/api/security/receivables` is where Settings → Account → Receivables reads and writes. Two rights, not one: VIEW_RECEIVABLES reads the tab, MANAGE_RECEIVABLES ...
The deposit account an organization asks customers to pay into
Six columns on `orgs` and the wire contract for printing them on a quote, so a company that receives one knows where to send the money without telephoning to as...
Show Getting Started to the System Member too
The button asked for organization ownership AND CONFIGURE_SYSTEM. The System Member is provisioned as an Administrator in every organization — all 34 of its mem...
Download the app from a URL that says KamoMobile
the phone showed while downloading was the old one. The same bytes now also sit at **************** and the QR points there. A copy, not a move: the old object ...
The Getting Started API had no route to answer it
The launchpad button never appeared, and neither did any progress: the Java controller existed, the client existed, and the Next route between them was never wr...
The rail's brand row reads "Back to Desktop"
Names the destination in the platform's own vocabulary rather than the generic "Go Home". The expanded row's aria-label follows the visible text, so the accessi...
Say "Go Home" under the org name in the expanded rail
The expanded rail's brand row has always navigated home, but the org name alone reads as a label, so the destination was invisible. The name now sits above a se...
Title the tab "{Org} - {role} Portal", painted before first frame
A member is named by the organization's own word for one — "Harmony - Borrower Portal" for a lender that calls them Borrowers. A team member is named by their D...
Carry the team member's department in the session
The browser tab is being retitled "{Org} - {role} Portal", and a team member's role is their department — the specific thing they identify with day to day ("Sal...
Probe the bridge's real health, not a port that is always open
kamo-meet let one person into a meeting and then ended it the moment a second joined. The bridge had been hard-unhealthy for 41 hours: an in-place container res...
The logo caption sits under the logo, and says the domain is not reserved
Two unrelated symptoms, both in the brand band. **The caption printed over the logo when the slots stacked.** The preview was clamped with `max-h-full`, and th...
Stop the server asserting a tab title it cannot know
An org with no domain of its own still ended up titled "KamoCRM" after a refresh, briefly showing its real name first. generateMetadata resolves the tab's org ...
Stop refusing a domain because somebody else typed it first
Creating an organization 409'd on any existing row for the domain, which meant the first organization to enter "acme.com" locked out every other one — including...
Keep every live domain routing once verification becomes mandatory
Host to organization resolution is about to require ownership_verified on the top-level domain row, so that a domain several organizations have merely named rou...
A domain is claimed by proving it, not by typing it
Three rules, and they only make sense together. **Naming a domain claims nothing.** An FQDN was globally unique here, so the first organization to enter "acme....
Upload the compact logo that was previewed, not the file that was picked
The compact ("simple") logo slot is SVG-only — the backend writes whatever lands in it to a fixed <theme>/img/logo.svg key regardless of the file's real type, a...
Stop the attention flasher reverting an org's tab title to the platform's
A child org with no domain of its own showed "KamoCRM", flashed to its real name, then flashed back to "KamoCRM" and stayed there. TabAttention wrote `document...
Let the tab icon follow a simple-logo change instead of pinning the one captured at mount
TabAttention badges the browser tab, and it read the favicon ONCE in a mount effect. That effect runs before DynamicMetaLoader's config.json fetch has resolved,...
Give the generated favicons the same revalidation requirement as every other theme asset
Replacing an org's simple logo updated every surface that reads img/logo.svg and left the browser tab on the old mark. Generation was never the problem: provisi...
Enter the new organization here, not on a domain with no DNS
Creating an organization handed the creator a button pointing at `https://internal.<the domain they typed>/`. That host does not resolve: the domain is one they...
The scan's colours, the colour window, and the stacked slots
Five reports from the brand section, and the first two turn out to be the same bug wearing two faces. **Colours were never adopted.** The rule latched a `color...
Say in the class contract that the gate can fall open
The header promised "a blocked app's endpoints all 403" without qualification, which is now true only while the entitlement tables can be read. The exception is...
A transient database fault must not 500 the request
The lead Communications tab reported "We couldn't load this lead's communications" for org 1168485648209608710 on 2026-08-28. The endpoint returned 500 five tim...
Carry the per-member-type home-screen defaults
Read on POST/PUT /security-models and PUT /master-model, and emitted from /applied-model's settings so the shell can decide where a member lands on "/". A sepa...
A security model says where each member type lands on "/"
Three columns on ChildOrgSecurityModel — DEFAULT_MEMBER_HOME_SCREEN, **************** DEFAULT_ORG_OWNER_HOME_SCREEN. Each holds HOME_SCREEN_DEFAULT or REQUIRES_...
The three per-member-type home-screen columns on a security model
CHILD_ORG_SECURITY_MODELS gains DEFAULT_MEMBER_HOME_SCREEN, DEFAULT_TEAM_MEMBER_HOME_SCREEN and DEFAULT_ORG_OWNER_HOME_SCREEN. Each holds HOME_SCREEN_DEFAULT (t...
One list of what the scan found, beside what you are using
The brand section of /network/create becomes three bands with the same shape: what your website has on the left, what your organization is using on the right. ...
A per-member-type default home screen
A security model now says where each of its three member types lands when they open "/". Two values: HOME_SCREEN_DEFAULT is the launchpad everybody has always h...
Correct the note on the removed Create My Free Org rights
ab740dd3 claimed CREATE_FREE_ORG_WIDGET and its four policy children "never existed in RoleRightType.java at all". That is wrong. They were ids 288-292, and I r...
Remove the CREATE_FREE_ORG_WIDGET block with its widget
The Create My Free Org launchpad widget was removed (kamo-internal ab740dd3), so its five rights go with it: CREATE_FREE_ORG_WIDGET (288) and the four policy ch...
Remove the Create My Free Org widget
Removed on request, including its rights. /network/create is untouched and remains the way an organization is created. Gone: the widget and its three step comp...
The document must not scroll behind the workspace
The authed shell is a full-viewport layout — nav fixed, content absolutely positioned to exactly 100vh — with one scroller inside it (.kamo-page-scroll). <body>...
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.
