Choose who a quote names as the customer's contact
The market dialog gains "Quote's Future Contact" under Enable quotes: the lead's assigned agent, a choice made per quote, or one explicit person picked with the...
Saving an article blocked on 21 translation calls
@Async was inert. **************** called translateArticle on the same bean, so the call went straight to this and never reached the proxy that makes it asynchr...
Stop Send To AI resetting the boxes while they are being typed in
A member filed this against the Send To AI dialog: the description "often resets back to the original description while you are editing it". It reset the instru...
Honour a market's contact rule wherever a quote names somebody
The staff detail, the staff preview and the customer's own page now resolve the contact through one method, so they cannot disagree about who is printed on the ...
The article corpus, and the pipeline that builds it
307 articles across 16 categories and 29 sections, from the 248 draft articles under Documentation/ plus 59 written here: every category and section landing pag...
A market decides who a quote names as the customer's contact
QuoteContactMode gives a LeadMarket three answers: the lead's assigned agent (resolved per read, which is what every quote does today and what a null column mea...
Columns for a market's quote contact and the per-quote snapshot
A market names its answer in QUOTE_CONTACT_MODE (+ QUOTE_CONTACT_MEMBER_ID when that answer is one explicit person), and each quote keeps the contact it was rai...
A window that raised itself has not been read
The chat unread badge was invisible everywhere — the Chat button, the Interaction Center, the hexhead — and the reason was not the badge. All three read one cou...
Point at the real org, keep the tree in the URL, show related articles
KB_ORG_ID was "1". The help center lives in org 1168485648209608710, so every KB read on this site missed -- /help-center rendered its empty state no matter wha...
Announce a message only once it can be read
POST /sessions/{guid}/messages is @Transactional, and the NATS publish of the message has always waited for the commit — with a comment saying exactly why: publ...
Curate an article's related articles
KbRelatedPanel is one component in three places: it curates in the composer and the editor, and reads back on the article view. Adding an article here also adds...
Related articles, and a public path that keeps the tree
Three things, all reaching the same page. Related articles. KbArticleRelationService owns the symmetric "see also" links: list, set, suggest, and a clear that ...
Migration for KB_ARTICLE_RELATIONS
Mirrors KbArticleRelation in kamo-shared-library. Written explicitly rather than left to ddl-auto so the UID and DATE_CREATED defaults live in the database, whi...
Article-to-article relations
KB_ARTICLE_RELATIONS holds the curated "see also" links between articles in one knowledge base. Rows are per direction and the pair is kept symmetric by KbArtic...
Add the missing form-fillable route, and stop offering ungranted actions
Two defects behind one report: the PDF editor would not open, and delete was offered to a member who may not delete. **The editor.** DocManager posts to /api/d...
Ride down to your own message when you had scrolled up
Sending while scrolled up into the history left the member parked where they were, with their own message appended below the fold. From the seat it looks exactl...
Design for the Help Center KB build, related articles, and public wiring
Covers the 248 source drafts under Documentation/, the tree they map to under the existing Help Center article, the new KB_ARTICLE_RELATIONS feature, and the th...
Page and search the org directory, and stop two row builders drifting
The networks endpoints answer with the whole set in one body. That is fine for a member of a dozen orgs and impossible for an operator on an estate meant to rea...
Take the two "could not start" fallbacks out of the source
Both SMS refusal paths quote the server when it gives a sentence and fall back to one of their own when it gives only a machine code. Those two fallbacks were E...
Starter base up $10 on every term
69 / 59 / 49, from 59 / 49 / 39. The commitment ladder is untouched by design — still exactly $10 off for a year and $20 for three — which is the standard every...
Offer the billing term up front, and stop hiding it over Enterprise
Two separate ways this page withheld the choice. The org console HAD a three-term control, but it was tucked into the right of the "Choose plan" heading behind...
Quote the commitment saving in dollars on the plan cards
The discount is a flat $10 a year and $20 on three years, which is how the catalog sets it and how it is advertised everywhere else. Rendered as a percentage it...
Say which subscription the launchpad pill's gate is about
"Not already paying" means the VIEWER's own seat — the same question the Plans & billing page answers when it decides whether to offer them one. Worth stating, ...
Stop offering the internal platform-owner plan for sale
listPlansForMarket filtered on isActive alone, and active is not the same as on the menu. OWNER_UNLIMITED ("Platform Owner — Internal") is active, carries no pr...
The running offer, on Plans & billing and on the launchpad
The console quoted list prices while kamocrm.com advertised a third off the same plan, because nothing in kamo-internal could see that an offer existed. It now ...
Serve the running offer, and say whether a seat is actually PAID for
Adds GET /markets/{id}/promotion. There was no way for an in-app buying surface to know an offer was running at all — the marketing site read promotions through...
Set "/seat/month" to the right of its own line
The price keeps the left edge and the unit takes the right, so the two bracket the card's width instead of stacking flush left — which left the number looking l...
The offer reaches the hero and the pricing strip
The hero had a countdown ribbon already, and it had been rendering NOTHING since the catalog moved to a percentage: `pickHeroOffer` filtered on FLAT_PER_SEAT be...
Put "/seat/month" under the price, not beside it
Three-figure rates and "/seat/month" do not share a line on a four-across card. Inline at 1rem the label either wrapped mid-text or squeezed the number it was d...
A promotion that fails to resolve must not widen to every plan
An EMPTY applicablePlanIds means "no restriction" downstream, so a restriction that fails to TRANSLATE must not be allowed to become an empty list. A Business-o...
Rebuild to pick up BillingCycle.TRIENNIAL
No source change. SecurityService clones kamo-shared-library at image-build time, and the catalog it serves is about to carry TRIENNIAL price rows. @Enumerated ...
A promo code works on its own last day
The end date is the LAST day a code works, not the first day it does not — SubscriptionPromotions.check reads it that way on the server, and the offer band's co...
A three-term commitment rail, and a promotion the page can prove
New prices: Starter $59/$49/$39 and Business $119/$109/$99 per seat per month on monthly, yearly and three-year terms. The rail replaces the monthly/annual pair...
Sell the three-year term, and stop four copies of the cycle drifting
The billing cycles were typed out by hand in five places. One of them, the plan-pricing editor, offered "BIENNIAL" — a value the server has never had — so choos...
Bill the three-year term, and quote its rate to the console
BillingCycles gains TRIENNIAL, expressed to Stripe as three YEARs rather than thirty-six MONTHs so the renewal tracks the signup anniversary — the same reason A...
A three-year term, and the promotion rules that were never read
Adds BillingCycle.TRIENNIAL so a subscriber can commit for three years. The column is varchar with no CHECK constraint anywhere, so this needs no migration — bu...
Show the report title in Send To AI, editable
The dialog let an operator edit the instruction and the description but never showed the title, and the title was not in the message either — the session at the...
Put the report title in the message, and let it be corrected
A dispatch composed the operator's instruction and the bug description with the separator between them. The title was never in it, so the session opening the me...
Carry the report title through a Send To AI dispatch
The dispatch sent the operator's instruction and the bug description and nothing else, so the one line saying what the report is ABOUT never reached the session...
Land the header's Text, Chat and Note buttons on the tab they name
The lead view keeps its tab selection in the URL — `tab` for the main tab, `commsTab` for the Communications sub-tab — and a header quick action sets both: "Tex...
Say why a number could not be opened, instead of an empty dialpad
Opening the SMS tool on a phone number resolves a conversation for it first, and that resolve can be refused — VOIPService answers "no number to text from" with...
Reply to a message, and take the reader to what it answers
MediaService has carried a reply's parent and the quote to draw for it since "send the quote with a reply, not just the pointer"; this is the half that shows it...
Stop offering an edit once somebody else has read the message
Every chat window that draws a MessageBubble — the member chat popups, and the social and ticket conversations that share ChatBox — offered Edit on the sender's...
Refuse an edit once another member has read the message
PATCH /api/media/messages/{id} was deliberately ungated on receipts, unlike the DELETE beside it. The reasoning written into it was that unsend makes read words...
Darken the xAI mark so it shows on the provider dropdown
Simple Icons ships the xAI glyph filled #FFFFFF, which is its brand color on a dark surface. The AI provider dropdown is white and the app forces light mode, so...
Offer Move on a right-clicked message, not only on a ticked one
Right-clicking a message offered Reply, Reply all, Forward, Report Spam, Archive, Label and Delete. Filing it anywhere other than Archive meant dismissing the m...
Go To Settings leads the Settings menu, above the app list
Reported with two screenshots — one org with eleven enabled apps, one with two — each circling "Go To Settings" at the bottom of the Settings sub-option menu wi...
Let a bulk move reach the folders the member made
The "Move to folder" dialog behind the selection bar was built from a literal ['INBOX', 'Archive', 'Trash', 'Junk', 'Drafts'], so the only destinations it ever ...
Never leave a blank tab when a KamoDesktop launch stalls
The tab is opened blank inside the click gesture and only navigates once a link comes back. So anything slow upstream showed as a blank white page with no expla...
The agent health preflight must fail in seconds, not twenty
health() inherited the client's 20-second default. It is a liveness check in front of every KamoDesktop launch, and when the dev machine ran out of memory on 20...
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.