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...
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...
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...
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...
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...
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...
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...
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...
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...
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...
A dispatch names the terminal it is running in
Send to AI is hosted in a Remote Terminal now, so the answer has to say which one — the console opens that window, and opening it is what starts the session. B...
Host a Send-to-AI dispatch in a Remote Terminal
composed prompt — and answers with an opaque TOKEN. A terminal that connects command typed into it. THE TOKEN IS THE WHOLE SECURITY DESIGN. `bootstrap=<command...
Jobs Available on /hr, and a Careers tab for every member
Two surfaces over one feature. /hr/careers is where HR writes the adverts and reads who applied; **************** is the internal board an employee browses and ...
Scan hr.careers, and drop the frozen work-location CHECK
Two changes, both required before the careers entities can reach the database. The @EnableJpaRepositories list is an explicit array while @EntityScan is wildca...
Seed the two careers rights onto HR's existing authoring group
MANAGE_JOB_POSTINGS and VIEW_JOB_LISTINGS are inserted as NOT_SPECIFIED like every new right, so without a seed the /hr/careers tab and the member Careers tab w...
/api/docs/careers — job postings, the member board, and applying
Two controllers behind one feature, and the split is the point. /careers/** is HR's and requires MANAGE_JOB_POSTINGS; /careers/member/** is the employee's and r...
Job postings and applications — the schema behind /hr/careers
Two entities, six enums and two repositories under com.kamo.z.shared.hr.careers, plus the three shared types the feature had to widen. JobPosting is three grou...
A list of your live shells, in the panel and beside the window
Terminals joins the Interaction Center to the right of Sales Scripts, gated on a provisioned dev machine — the same gate as the Linux Desktop nav option, read o...
A "why can't I accept?" override on the filter bar
Right-aligned on the /leads filter bar, wearing the Leads nav icon with the same prohibited emblem — so the thing on the nav that says "you are blocked" and the...
List, rename and end a member's terminals
GET **************** DELETE and PATCH on /terminals/{id}. Every one of them resolves the Linux account from the CALLER'S OWN SESSION and passes no account name...
List, rename and end a member's terminals
GET /terminals?user=X, POST /terminals/<id>/kill, POST /terminals/<id>/title. THERE IS NO DATABASE BEHIND THIS, and that is the design rather than a shortcut. ...
A password shortcut in the hero, and a narrower gate
Two halves of the same subject. The shortcut. Changing your password was three rooms deep behind the rail — the one thing the room layout made genuinely harder...
Prohibited nav emblem, Assign to Myself, and obfuscated contact masking
**The Leads nav icon says when you cannot accept.** A member who holds leads they have not worked gets a red block emblem over the Leads icon and a tooltip nami...
Serve the widened accept gate, add self-assignment, and close two contact-mask bypasses
**Endpoints for the new gate.** /leads/available-summary and /leads/available now report both reasons a member is blocked — leads owed a note since they were as...
Widen the accept gate, obfuscate masked contact info, let free-for-all leads be claimed
Three related changes to the lead-assignment core. **The accept gate now asks two questions, over every assigned lead.** LeadAcceptEligibilityService replaces ...
Flags on languages, and stop copying platform lists
Completes c20bac57. Languages now carry their flag, the same one the NavTop switcher shows and from the same source — the closed value as well as every row in ...
Rebuild My Profile as a hero and five rooms
**************** was one 1,999-line component rendering thirteen identical cards down a single column. One SectionCard helper gave all of them the same radius, ...
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.
