Route texts by NUMBER, and add Telnyx on both sides of it
An organization can buy its DIDs and its texting from one company and answer the calls with another. Kamo could not express that: a member's texting was a prope...
One source of truth, and a build that can actually reach it
Every price on this site had a second copy in the repo, and the second copy was the one being served. kamo-prices.ts said so in its own comment: the fallback t...
Telnyx, the first provider that is both a phone server and a carrier
Telnyx sells SIP trunking, DIDs and messaging, and an organization can buy those halves independently. The case this is for: DIDs and texts bought from Telnyx, ...
Drop the frozen type_id CHECK that blocked every bug thread
`media_sessions` is created by Hibernate's ddl-auto, not by a migration, so it carries the constraint ddl-auto writes for an `@Enumerated(ORDINAL)` column — fro...
The shelf replaces the per-app cards, and four fixes to its rows
The launchpad was a wall of one card per app. The App Shelf lists every one of those apps in a single pane, with what each does and everything inside it, so the...
A plan's startup fee, and the live offer, on the wire
PlanDto carried only the recurring rate, so every surface quoting a plan quoted a price the customer would not be charged: KamoCRM's startup fee is $99 a seat, ...
Quote the real price, and stop the Free plan looking like the best one
Two things on this page were wrong in a way that reaches customers. The price. bestRate() took the cheapest rate across all three terms and printed it as "per ...
The templates button called an endpoint that could not answer
Found by reading the controller rather than the code calling it, and it was broken twice over in a way that LOOKED fine: - The list asked for `status=ACTIVE`...
The report's thread in the drawer, shelving, and Issue Persists
`SystemBugThread` renders everything anybody has said about a report and every status it has passed through, under the current-status callout: the callout answe...
Preview variables for SYSTEM_BUG_COMMENT
Without them the template editor renders the new letter with holes where the report number, the sender and the button go, which reads as a broken template rathe...
System_bug.media_session_guid, and its lookup index
The column behind a report's comment thread, matching **************** — VARCHAR(36), because MEDIA_SESSIONS.GUID is itself a 36-character string column and a t...
Send To AI tells everybody on the thread, not just the reporter
The dispatch sends the same letter MediaService does, so its audience has to move the same way: every participant in the report's thread minus whoever acted, ea...
Two rows tall, and it opens by widening rather than by a second pane
The pane was 861px tall, not the 496 its two rows ask for. The launchpad grid is gridAutoRows: minmax(106px, auto), and an auto maximum sizes a track to its ite...
The thread behind a report, and the two statuses that need one
`SystemBugThreadService` is the whole feature: a report's MediaSession, the status events written into it with the reason their author gave, the comments anybod...
Shelving, failed fixes, and a report's whole comment history
A report kept exactly one sentence. `system_bug.denial_reason` was overwritten by every subsequent status move, so a bug that was denied, explained, reopened, f...
No explanation that lasts one frame, and a failure you can act on
A refused member was shown an info alert and redirected home in the same breath, so the message appeared for one frame and was replaced by the launchpad. That i...
Wire the god guard into the identity-rights test's policy
UserAccountEditPolicy took a third constructor argument and this test still built it with two, so test-compile failed — and CI runs `mvn package -DskipTests`, w...
A document outline, and a skeleton in the page's own shape
Only the hero was a real heading. Everything else — the ledger's nine categories, the account panels, the covenant, each upgrade option — was a styled div, so a...
One module owns the link from the plan page to the billing tab
Every action on /myplan is a link into Plans & billing, and it has to land on the right sub-tab or "Payment and invoices" opens on Subscriptions and looks broke...
The upgrade section said the opposite of the truth during a trial
A trialling organization's plan row really is FREE — the subscription points at it — while the trial has the whole catalogue switched on. The difference this se...
Draw the god rules the server now holds
The Users tab locked every god row for everybody, and both halves were wrong. Too loose, because the lock lived only in this component — the endpoints behind it...
Only a god may administer a god, and no god is impersonable
MANAGE_USERS reached the break-glass identity. UserAdminController guarded only the System User, so a non-god holder could disable a god account and revoke its ...
Type the nav-option fixture the shelf tests hand the launcher
The helper took { id: string }[], so every fixture with a kind, an href or a toolKey on it was a type error the test run never saw and tsc did.
Staff can write the sentence the customer reads
The customer-visible note had a column, a DTO field and a plan page ready to render it, and no way for anyone to set it — so Harmony's was the only one that wou...
Bridge SMS unread across the boundary the tool dock sits above
ToolDock is mounted in ToolProviders ABOVE AuthedChrome, deliberately, so it never unmounts across a navigation -- the single fact that keeps a member's typing ...
Clear the shelf's edge, cap the pane's height, and read apps from one source
Three things a real browser found that the tests could not: - The pane anchored to the shelf's inner content column, so it opened a dozen pixels INSIDE the w...
The softphone gets an inbox, and an SMS window is one thread
The SMS tool window opened on a twelve-key dialpad and then became a three-tab window -- Chat / Templates / CRM -- titled "Conversation #a3f1c8de-...". None of ...
A Free Plan pill, and a page at /myplan behind both pills
The trial pill lived twice — the nav rail and the launchpad — with the countdown, the member-type gate and the styling copied between them. Both gated on a live...
One endpoint behind the customer's own plan page
GET /api/billing/self/plan answers everything /myplan renders: the plan, what the organization can actually use, the catalogue to compare against, seats and the...
Say which plan an organization is on, and who may change it
The console could tell that a trial was running and nothing else. entitlementSource is "TRIAL" or null, so free, expired-trial, paid and comped organizations we...
A customer-readable note on a negotiated agreement
The internal `notes` field is where staff record what was conceded and to whom. The customer's own plan page needs prose it can show them, and one careless sent...
The shelf, its slide-out pane, and its place on the first row
Every app the member may open, with a pin, a search, and a pane that slides out of whichever side has room for it. Locked to the launchpad's first row by lib/ho...
One send contract across all five providers, and stop dropping inbound texts
The SMS abstraction layer had five providers disagreeing about how to fail and an inbound path that discarded real customer messages in silence. Sending - Se...
Design for the App Shelf launchpad widget
A system widget with no rights, locked to the first row of the launchpad by arithmetic rather than a band of its own, with a portalled flyout carrying each app'...
Stop every scene re-rasterising its sprite bank on resize
An audit of all eighteen scenes found the same defect in twelve of them, and it is the shape that degrades a tab over a minute or two and then stalls it in garb...
Remove the footer picker, keep the ?holiday= parameter
The dropdown was a temporary control for the initial review of the eighteen scenes and it has served its purpose. The query parameter stays — it is the only way...
Stop the page-rotation easter egg re-firing on every trip to the footer
The reported lockup was never the holiday scenes. It is `HiddenAnimations`, which has been in this repo the whole time, and the report described it exactly: "so...
Stop the scenes hanging the tab
Reported: "after about a minute or two the page looks to animate away then animate back and its completely locked up. Browser wants to close the tab." Reproduce...
Dress the site for eighteen days of the year
On ~84 days a year the marketing site now decorates itself, automatically, from the reader's own calendar. Snow falls through December and settles on the cards ...
One scrollbar on a data grid, not two
Every grid in the app drew two vertical bars — ours and the library's, side by side. Measured on /leads: ours at x∈[868,900], ag-Grid's at x∈[900,915]. ag-Grid...
Fix Verified, a reason on every denial, and a Requires Verification filter
The status menu on /support?tab=system-bugs leads with "Requires Verification" and a rule, then the individual statuses. It stands for NEW, IN_PROGRESS and FIXE...
Add denial_reason, and sweep the three retired status names
status_name holds a NAME read back through @Enumerated(STRING), so a row still saying TRIAGED after the constant is gone does not read as a default — it throws ...
Give the bug-status preview the denial block it now renders
SystemBugStatusEmail pre-renders two conditional blocks, and the admin preview has to supply both. Present and empty rather than absent: an unsupplied placehold...
Keep the dispatch's status write in step with the denial reason
Two services move a system bug's status, and only one of them knew about the new denial_reason column. A dispatch applying IN_PROGRESS to a report that had been...
Let the reporter confirm their own fix, and carry a denial's reason
Adds POST /{id}/verify-fix — the one status change in this feature that is not gated on MANAGE_SYSTEM_BUGS. A separate endpoint rather than a hole in the one be...
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.
