Preview variables for the two email-change letters
Both new canonical templates render in the console the moment this service is rebuilt onto the shared library that carries them; without a sampleVariables arm t...
A right for user accounts, and a parked address for changing one
Three additions, all of them the shared half of work that lands in SecurityService and kamo-internal. PlatformRightType.MANAGE_USERS, appended. A user account ...
Public rides the SEND TO AI row, and arms the hand-off for god
The Publish control was a bordered block of its own further down the form, carrying two lines of hint under the switch. It is now a compact toggle on the headin...
Draw the Publish switch on god eligibility
Reported: "my user has god enabled, yet I still don't see the new publish field." The gate was isGodModeActive(), which is getIsGod() AND an open break-glass wi...
Publish needs GD, not an open god-mode window
The switch was invisible to god-eligible operators. It was gated on **************** — GD plus an opened break-glass window — and holding GD is not the same fac...
Gate Publish on god ELIGIBILITY, not an open window
The Publish flag shipped gated on godModeActive — GD plus a deliberately opened 30-minute break-glass window. Every god-eligible operator then found the switch ...
Three self-invoked transactions that were doing nothing
@Transactional and @Async are PROXIES. A call from inside the same bean never reaches one, so all three of these annotations were inert. Found by audit, not by ...
The SPF card had no proxy route, so it never reached the API
The card shipped calling /api/security/domains/{id}/spf, and every request 404'd at Next.js before SecurityService ever saw it — which the card reported as "We ...
Ending a terminal takes its window and hexhead with it
Ending a terminal from the Interaction Center killed the shell and left the window behind, showing a red `closed` status over something that no longer exists. T...
Read a domain's live SPF record and say what it actually needs
GET /api/security/domains/{id}/spf, for the SPF step on /setup/dns. The setup page cannot give one set of SPF instructions to everybody, because the right inst...
Tell each domain what its SPF record actually needs
/setup/dns walked a customer through ownership, subdomains and SSL and then said nothing about the record that decides whether the mail we send for them is beli...
A member's work address must name them without a mail provider
Forgot-password resolved the address typed on the form against two sources: the account e-mail, and the org mailbox flagged Primary on the member's settings. Th...
System mail must not send as a domain we do not authenticate
Transactional mail always went out as NoReply@{org primary domain} through our own relay. That is only safe while Kamo hosts the org's mail: then we control the...
Seeding is bounded by the JAR, not by the database — and rebuild
The lazy seedForOrg call in sendToUser reads as though a missing template always heals itself. It does not. The catalogue is CanonicalTemplateLoader's and lives...
Name the allow-list this PUT actually goes through, and rebuild on it
Two things, one of which is the point of the commit. The comment: patchOrganization is an ALLOW-LIST and it lives in the shared library, not here. This control...
System_bug.published needs a column DEFAULT, or it is never created
The field was declared `@Column(nullable = false)` with no columnDefinition, so ddl-auto emitted `ADD COLUMN published boolean not null` — which Postgres REFUSE...
Copy your referral link from any public role
Referrals are the highest-converting channel a job board has, and what stops them here is friction rather than unwillingness: the careers site answers on a diff...
The CV reader, employee referral links, and the form shape on the public listing
Three things the public careers site needed from this service. The form shape now rides on the public listing (the twelve ask* settings, the additional-info pr...
Three public transactional templates, and the org patch keys behind them
The careers site now writes to people who have no account, which is new for this platform: every other transactional template goes to a member. Three canonical ...
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...
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.