The workspace picker shows each org's logo
Two letters standing in for a logo was a workaround for the response not carrying one. It does now, resolved server-side from the folder the org's theme was pro...
Continue stays disabled once a workspace is opening
The button already carried disabled={!selected || submitting}, but submitting was only true for the duration of the request. On success the page sets redirectin...
Only a spent token sends the member back to the start
Every non-ok status fell back to "Please sign in again", which is only true of 401 — the one status that means the selection token is really gone. SecurityServi...
Brand and scope the sign-in screen with ?org=
login.kamocrm.com is the sign-in screen for every organization that has no host of its own, so the hostname cannot say which one is signing in. ?org= does: it n...
Make the auto-login cross-tenant guard actually run
The guard read the host org's id with /"id"\s*:\s*(\d+)/ -- a bare digit straight after the colon. SecurityService's JsSafeLongSerializer writes any Long above ...
Correct the sign.pink finding
The inventory called SignLinkBuilder's sign.sign.pink fallback a "foreign apex" and I recorded it as one. It is not: sign.pink is a Kamo-owned organization (id ...
Add the workspace picker
A sign-in that names no organization now comes back with a list instead of a session. This is the client half: /api/login passes that payload through (before th...
Plan the host-independent tenancy rollout
Six phases, each independently shippable, because pushing deploys: the host path keeps working until Phase 6 removes it. Phase 1 is the crux and is additive --...
Design host-independent tenancy
Org identity comes from the hostname today: OrgHostResolver.resolveByFqdn turns <alias>.<domain> into (orgId, providerId), and its SQL requires od.is_dns_verifi...
Rebuild the welcome panel around a live status rail
The left column was a generic headline, a security platitude and a pile of ambient decoration (dot grid, floating orbs, a pulsing dash). Replace it with one sha...
Hold the token's int64 ids as digits, not as numbers
KToken could not verify a real token. The four ids it carries are int64s, and the Java signer (kamo-shared-library KToken#canonicalForMac) appends each as a raw...
Replace the stock alert with an animated status plate
The inline sign-in messages ("Login successful! Redirecting...", "Invalid username and/or password.") used MUI's default Alert, whose pastel fill plus matching ...
Honour the org's sequential/shuffle slideshow order
config.json now carries backgroundOrder alongside backgroundImageCount. Shuffle re-randomises on every advance and never repeats the frame on screen; an absent ...
Stop downloading a browser that the image never uses
Build 21 failed in puppeteer postinstall fetching chrome-headless-shell — an SSL "decryption failed or bad record mac", the same flaky-transfer class that took ...
Sync AppType/ServiceType mirrors with the MLOS rename
ServiceType.LOS became MLOS (mortgage, id 14 retained because ORG_FEATURES persists the id) and the freed LOS key is now the Personal Loan Origination System on...
Forward the login host so recovery can resolve the org
Password recovery now accepts a member's primary mailbox address, which only names an account within one org. This proxy reaches SecurityService over cluster DN...
Complete a login that stopped at the second factor
SecurityService now gates login on a second factor (§164.312(d)). When one is owed it creates the session but withholds its one-time key, returning a short-live...
Accept starter/enterprise plan handoff, carry promo code, target www /subscribe
kamo-register now whitelists starter|business|enterprise and stashes sp_checkout_code; the old pro|business filter silently dropped Starter buyers, and the apex...
Add analytics analytics + ?registered=1 welcome notice
- Mount analyticsAnalytics client component in the root layout: next/script loader for analytics.kamocrm.com scoped via data-domains to login.kamocrm.com on...
Commit outstanding work in progress
Staged and committed as-is so nothing is left uncommitted in the working tree. 26 files changed, 7894 insertions(+), 8 deletions(-)
Harden the kubectl download against flaky egress [skip ci]
dl.k8s.io over the runner's egress intermittently drops mid-transfer: curl: (56) OpenSSL SSL_read: decryption failed or bad record mac which fails the deploy ...
Show TRIAL USE ONLY pill above Powered-by for trial orgs
Self-fetches /api/trial-status (proxy to SecurityService public trial-status endpoint, resolved by login host) and renders an amber pill above the Powered-by pi...
Kamo-login honors software auth logo + tab title
- DynamicMetaLoader: read software identity + auth selectors from config.json, set tab title from resolved name (authNameBrandSource), persist auth-logo state...
Show account-linked notice on ?linked=1
When register links an existing account to a new org, it redirects here with ?linked=1. Show "You already have a Kamo account — we've added this organization to...
Stop viewport shaking on browsers with classic scrollbars
On machines whose Chrome uses layout-consuming (non-overlay) scrollbars, the login/recover pages fidgeted with both scrollbars flickering. Root cause: the root ...
Drop background images that 404 instead of showing a broken frame
Track failed background image loads and filter them out of the Swiper carousel, so an incompletely provisioned theme (e.g. optionone, whose bg/2.webp was never ...
Remove the 2s intro/loading animation screen
Drop showIntro/introComplete state, the 2s intro timer effect, and the branded early-return loading screen. The page now renders straight into the background + ...
Panel bleeds off-page left so its edge never shows on bounce; card fades ~250ms sooner
- Welcome/recover panel now extends --welcome-bleed (16rem) off the left edge with its right edge still pinned to --welcome-w; inner content padding is comp...
Choreographed entrance — panel springs in after bg loads, then card fades
Wait for the first background image (onLoad, with a 3s safety fallback), then spring-bounce the welcome/recover panel in from off-screen left (physics spring, s...
Pointer parallax (x+y) between welcome panel and background
Both layers drift with the pointer at different rates and opposite directions via framer springs. Background is scaled 1.12 and the welcome panel is oversized 1...
Move animated logo to bottom-right, centered above Powered-by pill
PoweredByKamo gains an optional logoSlot rendered centered directly above the pill within its fixed bottom-right anchor (other pages unaffected). The animated l...
Left-pinned translucent welcome panel + centered rounded form card
Welcome/Recover panel now full-height, flush to the left edge, on top of the background image with a translucent wash and square corners; hidden on mobile. Anim...
Proxy password-reset to SecurityService internal DNS
The /api/recover proxy defaulted to api.kamocrm.com, which Traefik routes to APIService (no recover controller) → 404 → "Something went wrong" on /reset-passwor...
Migrate to k1m1 (clone+registry+kubeconfig from k1m1, drop k2m1, simple kubectl install)
Route paid signups to checkout after login
After successful auth (manual or auto-login), consume the apex-domain sp_checkout_plan cookie left by kamo-register and redirect the buyer to the brand /subscri...
Resolve subdomain-tenant org bucket to its own MinIO folder
getThemePath() was reducing the hostname to apex+tld for both the themed host and the bucket folder, so subdomain tenants like gnosia.demo.kamocrm.com loaded th...
Refuse when session orgID does not match host org
auto-login accepted any *** and minted an OTK pointing back at it, regardless of which org the destination internal.* host belongs to. A stale or cross-org *** ...
Scope concurrency to build jobs, not Kubernetes deploys
Workflow-level concurrency serialized the whole pipeline (including kubectl rollouts). Move the group to the build job only so deploy jobs from different runs c...
Use org short name and description in HTML head
DynamicMetaLoader now sets document.title to "Login - {siteNameShort}" and writes the org description into the meta description tag. Static layout.tsx fallback ...
Reload ThemeLogo after config and cache-bust logo URL
ThemeLogo read kamo-logo-full-ext from sessionStorage before DynamicMetaLoader finished fetching config.json, so logo-full often used the wrong extension until ...
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.
