Carry the application claim token across the register handoff
A candidate can now apply from the public careers site without an account. The application is stored against the email address they typed, and the receipt carri...
Benefits, the public funnel, the network opt-in, and claiming an application
Five changes, all of them the workspace half of something the public careers site now does. - Benefits & perks on the posting editor. It reaches the public adv...
A Publish switch on a god-mode bug report
An operator with an open god-mode window filing a bug or enhancement now gets a Publish switch. It is off when the window opens and does not remember its last p...
Let a god-mode operator file a system bug privately
Posting a report now offers a Publish switch to an operator with an open god-mode window. It defaults to off: the report stays with god mode until somebody rele...
The Publish flag on a system bug, and the query rule behind it
A system bug already crossed the tenancy line in one direction. This adds the second visibility rule on top of it: a report a god-mode operator filed privately ...
System_bug.published, defaulting to TRUE
The column behind the Publish flag: a god-mode operator can now file a report that stays with god mode until somebody releases it. DEFAULT TRUE is the whole re...
Guard the provider catalog's interpolated i18n keys
check-i18n-keys.mjs reads literal t('...') calls, and the catalog builds its keys by interpolation — **************** and oauthClients.field.${labelKey} — so no...
Personal mailboxes read the OAuth registry, not dead config
Connecting a personal Gmail or Outlook mailbox has been building its consent URL with client_id= empty, and every attempt was refused by the provider. The cred...
Apply-first, the job network, alerts, translation and retention
Eight things, all behind the anonymous careers surface, and all sharing the rules the single-org board already enforces rather than growing their own. APPLY-FI...
Make hr_job_application.member_id nullable
ddl-auto adds columns; it never relaxes constraints. Flipping optional=false to true on the entity changes what the ORM believes and nothing about what the data...
The schema behind apply-first, the network, alerts and retention
member_id on hr_job_application becomes NULLABLE, which is the whole of apply-first: five steps stood between pressing Apply and answering the first question, a...
The navigator opened popups instead of switching
Clicking a row beside a maximized terminal opened a small window over the top of it. It was a launcher, not a switcher. `openConversation(row, { maximized: tru...
25 pages titled themselves KamoCRM twice
Every page's <title> read `X | KamoCRM | KamoCRM`. The root layout sets `title.template: "%s | KamoCRM"`, and each page's own `title` already ended in the same ...
Force KamoMobile Logout on a member's account activity
Force Logout deletes sessions, which ends a browser. It does not end a phone: KamoMobile holds a durable device token and mints a fresh session from it immediat...
Handing back to Kamo's app writes only the switch
Choosing "use Kamo's application" sent the whole form with the disable, so an edit the member had typed and not saved was persisted by a choice they would not h...
Force KamoMobile Logout — revoke a member's mobile devices
Force-logout deletes *** sessions, which ends a browser. It does NOT end a phone: KamoMobile holds a durable device token and mints a fresh *** from it the mome...
Drop the unused dense prop from OrgOAuthAppSection
No call site passed it, and all eight embeds want the full header. A prop kept for a caller that does not exist is API surface someone has to reason about later...
Build against the two-field SystemBugDispatchDTO
Unrelated to the OAuth work in the previous commit — MediaService main has not compiled since kamo-shared-library ad78dfa8 added terminalSessionId and terminalT...
An empty platform registration is not "connect with Kamo's app"
isPlatformEnabled now also requires a client id, matching what OrgOAuthClientController reports as platformEnabled. Without that the meetings screen and the bri...
A switch per platform registration, and bring-your-own on the org side
Each OAuth2 card on Platform Configuration → Advanced gets an enable/disable switch in its top-right corner. It writes only the enabled flag, is unavailable unt...
Teams Phone falls back to the org's own Entra app
The per-phone-server credentials still win — that is the most specific source. What changes is the fallback underneath them: the org's own MICROSOFT_TEAMS regis...
Resolve Canva, Meta, X and meeting credentials per organization
Every flow here now reads whichever app the org is on — its own registration if it brought one, otherwise Kamo's platform app. The Canva and Meta entry points ...
Resolve mailbox OAuth credentials per organization
Google, Microsoft 365 and Zoho mailbox connects now read whichever app the org is on — its own registration if it brought one, otherwise Kamo's platform app. T...
Org-side CRUD for an organization's own OAuth2 client
The org-scoped twin of PlatformOAuthClientController, behind **************** Same DTO shape, same encrypt-on-write, same never-return-a-secret rule, plus platf...
An organization can bring its own OAuth2 client
Until now the client id and secret for every OAuth provider came from one platform-wide registration, so an org could only connect what Kamo had registered — an...
A product gallery at /screenshots
A page for showing the product as it actually looks. It is built around a data module rather than markup, because more screenshots are coming and adding one sho...
Start one from the Interaction Center tab
The tab listed terminals and gave a member no way to open one — the only starting points were the Linux Desktop submenu and the navigator's header, neither of t...
The profile endpoint stops loading the whole board
Its own comment said it existed so a page could paint the employer "without pulling every advert down with it", and the line under that comment called board() —...
Read the theme folder from the host on a white-label workspace
orgSlug reached DynamicMetaLoader only when the organization was named via ?org=, so on internal.<customer domain> - where the host names exactly one organizati...
A country is not its enum name
Every card on every careers surface has been printing "United states" — the words after the first lose their capitals when an enum name is prettified — and "Côt...
Paint a white-label signup screen from the host's organization
Same defect as kamo-login a200fc6, same cause. getThemePath()'s last resort derives a theme folder from the hostname - the name folders had BEFORE the 2026-08-2...
Paint a white-label sign-in screen from the host's organization
Every image and colour was missing on login.<customer domain> for any organization created after the 2026-08-26 alias migration. getThemePath() resolves an exp...
Remember which job advert brought a candidate here
The public careers site links to /team?jobId=<uid>. Registration is several steps, crosses hosts and bounces through email verification, so the uid is parked in...
Publish an advert externally, and pick the candidate back up
Three changes, all in service of the new public job board at careers.<apex>. The posting editor gains "list on our public careers site". It sits with status an...
Careers joins the documented alias list
kamo-careers serves the org's public job board at careers.<apex>. The list is informational — the log-scan mechanism is what actually mints certificates — but t...
Baseline the by-host branding endpoint
**************** refused /org/public/by-host/{host}, which is exactly its job — a new mapping that resolves no session is reachable without credentials through ...
The anonymous API behind careers.<apex>
The public job board reads this. It is the only surface in Careers with no session, so the safety comes from the QUERY rather than from a rights check: PublicCa...
The two columns a public job board needs
publish_externally decides whether an advert reaches careers.<apex> at all. It is a separate axis from status: an internal-only posting is fully AVAILABLE and m...
Serve an org's branding from the host it is browsed on
A white-label sign-in screen is reached at login.<customer domain> with no ?org= on the URL and nothing in sessionStorage, so the front end has no way to name t...
Careers is a platform alias, not an org's own
OrgResolutionService.byHost reads a leading label that is not a known platform alias as an ORGANIZATION's alias within the domain behind it, so without this ent...
The tab strip declared minHeight twice, so the build never type-checked
Adding icons to the panel tabs appended a second `minHeight` to the same `& .MuiTab-root` literal instead of replacing the old one. TypeScript rejects a duplica...
The incoming-call deep link must use kamocopilot://
KamoMobile's kamomobile:// scheme is step 2 of a rename that has not happened. The published binary registers kamocopilot alone, and a deep link to an unregiste...
Footer Badges — a row of images under the signature
The Content tab's 'Footer Image' was one picture chosen from three fixed sources and sized by a percentage. It is now 'Footer Badges': the same three plus anyth...
Email_signature_badges, and the columns that order them
The footer badge library plus footer_badges / footer_badge_spacing / footer_badge_height on email_signature_templates. A runner and not just ddl-auto for the u...
The AI hand-off raced tmux, so nothing was typed and nothing named
Caught by running it on the machine: the terminal opened at the right path, with no command in it and no title. One race, both symptoms. `bootstrap` runs strai...
A library of footer badges, and the row each scope prints
The signature footer went from one image to a row of them. The library is org-wide; the selection and its order are per scope, so an image uploaded while editin...
Resize an image by height, keeping its format and transparency
Backs the email signature footer badges, which are downscaled to 150px tall on upload. resize-bg could not be reused. It exists to make a wallpaper cheap to sh...
The schema behind a row of footer badges
The email signature footer held one image, named by footer_image_source and sized by a percentage. It now holds a ROW of them: the three built-in sources plus a...
Add the VOIP_CALL_EVENTS scope
Lets an org issue kamo-asterisk-support a key for reporting ringing extensions, separately from VOIP_RECORDING_UPLOADS. Uploading a recording after the fact and...
Report ringing extensions so a member's mobile rings
The AMI client logs in with 'Events: off' and only sends actions, so nothing on a customer's FreePBX ever told the platform a call was arriving. That silence is...
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.
