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...
API-key surface for live call events from a customer PBX
Companion to VoipRecordingUploadController, on a deliberately separate VOIP_CALL_EVENTS scope: uploading a recording after the fact and making somebody's phone ...
Let an on-premise PBX report a ringing extension
RingCentral and JustCall publish INBOUND_RINGING from their webhooks. FreePBX and KamoPBX publish nothing -- they are the customer's own Asterisk and nothing wa...
Ring a member's phone for an incoming call
VoipStompRelayController relayed voip.call.* ringing events to the browser and deliberately never pushed them, reserving incoming-call alerting for 'the future ...
Send to AI opens the terminal it runs in, and the tabs get icons
A dispatch now comes back naming a terminal, and the console opens it. That is not a courtesy view of something already underway — the hand-off is PREPARED on t...
Pin the session id, and link the terminal session into VS Code
`--session-id <uuid>` is chosen at prepare time rather than left to the CLI, which is what makes the editor hand-off deterministic: the id is known before the s...
Apply in one request, and say why a role cannot be applied to
Follow-up to a review of my own commit. Six real findings. APPLYING IS NOW ONE REQUEST. The résumé used to upload after the application was created, and a fail...
A REQUIRED resume is now actually enforced
A review of my own commit found the enforcement it claimed. JobApplicationService carried the comment "a REQUIRED resume is enforced at that point by requireRes...
Send to AI now runs in a Remote Terminal the operator can watch
The dispatch prepares the hand-off on the dev machine — screenshots, video and the composed prompt written to disk — and answers with the terminal it will run i...
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.