Give the workspace path the same post-login work as the host path
Two gaps found by re-reading the original login tail against the new one, before enabling the picker. The form-encoded /login endpoint built its LoginRequest w...
Let the shell fetch its org from the session, not the host
kamo-internal's root layout reads the Host header, strips "internal." and fetches /org/domain/<that>. On a host serving one tenant that is the same question as ...
Let a member sign in without a host naming their org
Adds the second half of the split: a sign-in that names no organization authenticates the user, then asks which workspace. POST /api/security/session/select tur...
Separate the credential check from org authorization
Signing in was two questions fused into one query. "Are these credentials good" is answered by the users row -- the password lives there, so it was never org-sc...
Stop requiring DNS verification to sign in
OrgHostResolver.resolveByDomain filtered on od.is_dns_verified = TRUE, so a domain row that existed but had not finished verifying resolved to nothing and login...
Attach stack traces to their log line, and fix levels I got wrong
printStackTrace() writes to stderr directly, so 186 of them survived the println sweep untouched — still unconditional, still unattributed, and now detached fro...
Finish taking SecurityService off System.out/err
The remaining 853 println calls across 43 files, none of which could be turned off: println has no level, so every one of them printed on every code path that r...
Take CNAME verification off System.out
With the session and Hibernate noise gone this was the largest recurring source left in the pod log: every CNAME lookup drew a seven-line box on stdout. That wa...
Take session lookup off System.out, and its *** id with it
After the previous commit removed the Hibernate session-metrics blocks and MemberController's per-request tracing, this was 88% of what remained: every session ...
Stop the pod log rotating faster than it can be read
Roughly 4,600 lines in four minutes, so the retention window was a couple of minutes: chasing a certificate problem on 2026-08-22 the probe output had already r...
Verify-dns answers for the present, not for a stored flag
The endpoint skipped probing entirely when ssl_confirmed was already true, on the reasoning that under the all-hosts rule it could only have been set when every...
Re-verify domains already marked SSL-confirmed, and heal them
findAwaitingVerification filters confirmed domains out by design, so once ssl_confirmed was set nothing ever looked at that domain again. That was fine while th...
Make post-commit org setup actually write, and heal the orgs it missed
A @Transactional method called from **************** does not open a transaction of its own. Spring fires those callbacks from processCommit BEFORE cleanupAfter...
Confirm SSL only when every org host has its own certificate
Certificates are minted one per FQDN -- a single dnsName each, so the leaf CN matches the hostname the browser connected to -- and auto-cert works through an or...
Serve frame media ourselves, with Range
Every photo rendered as a broken image. The URL pointed at MediaService's **************** which I took for a general imaging proxy because it spoke HTTP Range....
Frame and media endpoints, and seed the new rights
Self only, and enforced in the QUERY. Every read and write resolves the member from the session and every repository call takes that id, including the single-fr...
Stamp last_login so "Last Login" stops reading Never
Nothing in SecurityService has ever written users.last_login. The write lived in the retired AuthenticationService and was not carried over when authentication ...
Restore the status endpoint the frontend has been polling
kamo-internal polls GET /api/security/session/god-mode once on mount and every 60s thereafter. That endpoint was removed in 9c70cb7 along with the rest of the t...
Rebuild against kamo-shared-library 48cde37
Picks up MANAGE_ORG_MASTER_NOTE, the right that guards "Our Master Note". SecurityService is what enumerates RoleRightType for the role, job-title and departme...
Drop the universal seed; the timecard widget follows MANAGE_TIMECARDS
UNIVERSALLY_SEEDED_RIGHTS is removed entirely. It existed only because the timecard widget had no parent right to inherit from, and now it has one — so the widg...
Seed the mail and lead widgets, and add a universal seed for the timecard one
The mail and lead widgets follow their data rights exactly as the calendar ones do — ACCESS_MAIL and VIEW_LEADS — so a holder gains no data they could not alrea...
Seed the calendar widgets to everyone who can already read the calendar
Both widgets show a member exactly what /calendar already shows them, so a calendar reader gains no data they could not reach — which is what makes this a safe ...
Annotate the member roster with its chat policy verdict
SecurityService serves the roster the chat UI is built from, so it has to answer with the same verdicts MediaService enforces with -- one shared evaluator, or t...
Ask EmailService to back-fill a lead's past e-mail
Implements the shared library's LeadEmailBackfillTrigger, so ticking "Associate Past E-Mails w/ Lead" on a lead save reaches the only service that can read mail...
Accept a reservation raised for another agent
POST **************** now honours onBehalfOfMemberId, gated on EDIT_OPPORTUNITIES — the right that gates managing opportunities on the reserved list, and alread...
Publish Hibernate statement counts to Prometheus
/actuator/prometheus already carried jdbc_* and hikaricp_* but no hibernate_*, because Spring Boot 3 only auto-configures those metrics when **************** is...
Delegate AvatarObjectPaths to the shared library
MediaService now names avatar objects too — the support chats list shows the requestor's photo, and a support requestor is in somebody else's organization, so n...
Return each member's accepted-today count per product
Manage-Credits shows Max Daily Spend but nothing about how much of it is used, so a manager could not tell whether a member was one lead from their cap or had n...
Stop cutting note bodies off at 500 characters in the timeline
The All tab of a lead's communications rendered a note through LeadCommunicationMapper, which capped the body at 500 characters — with no ellipsis and no flag, ...
Report leads available for products with no allotment
/manage built its whole response by looping over allotments, calling countAssignablePool once per row. But the Manage-Credits grid lists products from the vendo...
Stop scanning every market x product after the answer is known
/leads/available-summary returns three things — hasAcceptable, hasAcceptableCredit and one example product — but visited every market x product pair regardless,...
Mint a System User session for a support agent's open ticket
enter-as gains a second reason to say yes. SystemUserEntryPolicy turns the caller's *** into the facts the shared SupportSystemAccessResolver takes, and that re...
Count in the database instead of hydrating every commit
GET /changelog/public/stats loaded all 16,571 commit logs as entities and tallied them in a Java loop to produce two small maps and a total. It takes no authent...
An opt-in probe that executes the grid's SQL, not just its HQL
/leads went down on 2026-08-20 with 'missing FROM-clause entry for table a2_1' and no test caught it, because none of them could: the library compiles against H...
Page the grid endpoint and take the PHI audit write off the request thread
GET /api/security/leads returned every lead in the organisation. It now takes page/size/sort plus the filters the grid actually uses, and returns a page with a ...
Settle each backlog payload as it is processed
processBacklog mirrored the scheduled job's two defects: it mutated payload statuses in memory and saved them in one batch at the end, and it saved the whole en...
Never fail a submission because its counter update lost a race
storePayload no longer bumps the endpoint's received counter; the receive controller now calls recordReceipt separately, in its own transaction, and swallows th...
Rebuild against kamo-shared-library 811db57
Picks up the createLead fix that moves the pool-availability recount to afterCommit. Before it, a read-after-write in the lead's own transaction hit YugabyteDB'...
Map companyName so a spreadsheet can carry the business name
setDirectFieldOnCreateRequest had no companyName case, so the field was unreachable from the manual-import wizard even though CreateLeadRequest carries it and L...
Accept the discount* signup fields, keep the mrt* ones working
The register site now sends discountVisitorGuid / discountCode. Both names are read, new first, because the two services deploy independently — for the minutes ...
Publish signup and org-created for tracked visitors
The register site now forwards the marketing visitor GUID and tracking code in the request body — not a header, because the proxy strips Cookie and the ingress ...
Enforce is_fake, and close the holes that let an unattended signup in
Two halves of one incident. An account registered, verified an address at a disposable provider, took an auto-login session and created five organizations in th...
Let a member give up their own membership
The network page has offered "Unsubscribe" since it was written. It opened a confirmation dialog and then said the feature would be implemented soon, because th...
Make the verification sweep's DNS upgrade reachable
DomainVerificationWatcher gated on **************** but **************** only ever answers ok/pending/error/na — it has never returned "verified". allVerified w...
Restore media as a required DNS alias so its card can verify
media.<domain> backs MediaService realtime websockets and is live in Traefik, auto-cert and the /setup/dns studio catalog, but it was dropped from KnownAliases ...
Stop reporting a missing column as a missing table
Four controllers each rewrote ANY message containing "does not exist" into "Database table X does not exist. Please run KamoInitializerApp to create the schema....
Delete the unauthenticated /api/security/roles/test stub
A reachability probe that returned "SecurityRoleController test endpoint is working" to anybody. Nothing calls it — no reference in any service or in kamo-inter...
Close two unauthenticated endpoints reachable from the internet
SecurityService is anyRequest().permitAll() with @EnableMethodSecurity absent, so every @PreAuthorize is inert and public is the default; APIService relays /api...
Per-member SSO credentials and a preflight that explains failures
Linux is gated on an enabled provision rather than god, and served with the member's own credentials. The connection is omitted from the token entirely when the...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.