Only an authorized member can connect a Facebook or Instagram page, and only back to their own console
The Meta connect flow trusted its URL. GET **************** took connectionId and returnUrl from the query string with no session, and state was unsigned base64...
Refuse webhook posts for Discord connections, which only ever receive DMs over the Gateway
Discord DMs reach MediaService only through DiscordGatewayManager's WebSocket, which publishes straight to social.inbound.raw. But every social connection has a...
Pages stay under the nav, the Interaction Center and the tool windows
The same two mistakes as /calendar's, everywhere else they were made. AuthedChrome's content box names no z-index, so a z-index in page code is a level in the R...
Seven link sets that match the nav, and careers goes to the careers site
The footer now lists Features, Services, Pricing, Company, Resources, Solutions and Legal, in that order. That is the top nav's own five categories plus the two...
A person taken out of a drip stays out
The engine moves on up to 200 due people per drip from copies it read at the start of a pass, up to 25 seconds old by the time each is used. Meanwhile a member ...
The drip enroll dialog finds leads by email
The lead search behind it now matches a lead's email (kamo-shared-library 992569a6, live with SecurityService 5c7319a), so the dialog says so: name, email, comp...
A search term reads the lead's email
Walks the grid specification's LIKE branches on the Hibernate this service runs (the HQL rendering leaves function arguments out, so it cannot show which column...
A lead search matches the lead's email too
The /leads grid's boxes and the drip enroll dialog send what was typed as search terms, OR-ed across the lead's names, company, vendor lead id and number. The e...
The calendar stays under the nav and the tool windows
/calendar positioned itself over the viewport — fixed at 56/80 with z-index 1000 — instead of filling the content box AuthedChrome gives every page. That box na...
Keep every ciphertext column out of JSON, and guard the rule library-wide
Follow-up to 096feaa1 (Organization's GoDaddy credentials were being served by an endpoint that needs no session). A scan of every **************** found fourte...
Stop GET /org/{id} shipping the GoDaddy credentials, and lock it to this service's mapper
The fix is in kamo-shared-library 096feaa1: Organization.godaddyApiKey and godaddyApiSecret are now @JsonIgnore. That change reaches production only when a serv...
Never serialize the GoDaddy key and secret ciphertext
GET /api/security/org/{id} (and /org/domain/{host}) returns the Organization entity itself and answers without a session, and that body carried godaddyApiKey an...
Drip campaigns on /marketing/email — triggers, a visual builder, people and performance
/marketing/email gets a Broadcasts / Drips switch (?view=drips). The drips view lists every drip as a card with its trigger, its sequence and live counts, KPI a...
An unconfigured build stops asking SecurityService for org ""
getHuntOffer fetched the promotion status even with no hunt configuration, so that the attempt would tag every prerendered page site-hunt. With no HUNT_ORG_ID t...
People in a paused drip still leave it when their lead moves on
A paused drip's exit rules (status change, reassignment, goal click) are now listened for, so resuming it never sends to someone who should have left while it w...
Every page shows how many times it has been viewed
A view counter now sits at the foot of every page, in the footer's bottom row beside Sitemap and Back to top: an eye whose iris is the site's hexagon, and the f...
Count the marketing site's page views, on the article or on the page
KBService now answers the view counter kamo-marketing shows at the foot of every page. Two endpoints, both {"views": n} with the view just counted included: ...
A drip's People counts follow the search, so All is always the sum of its chips
Page-view counters for the marketing site
Two tables behind the view count kamo-marketing now shows at the foot of every page, written by KBService's /internal/page-views endpoints. KbArticleView (KB_A...
The Lifestyle Logo, a fourth logo per brand and the default background watermark
Behavior & Labeling gains a Lifestyle Logo slot beside the full logo, the simple logo and the tab icon, in both the company and the software (white-label) rows....
Lifestyle logo uploads, config.json keys, and the LIFESTYLE watermark
The lifestyle logo is a fourth logo per brand (company and white-label), the decorative rendition the background watermark now draws by default. Its fallback is...
Lifestyle logo columns, and LIFESTYLE as the watermark default
The lifestyle logo is a fourth piece of branding artwork per brand, beside the full logo, the simple logo and the tab icon: the decorative rendition the backgro...
Drip campaigns
A drip is an automated sequence of emails a person enters when something happens: a lead arrives (by hand, imported, or from an integration), a lead's status or...
An imported lead is recorded as imported
LeadImportController created every row with the two-argument createLead, so a lead's history said source API with nobody acting, exactly like one sent in throug...
Chained drips hear when someone finishes a drip
A drip that starts when someone finishes another drip listens for the engine's own DRIP_COMPLETED events, but the recorder's trigger map left that kind out, so ...
The campaign editor's Reply-To is a choice — NoReply, Member's E-mail or Custom, NoReply by default
The free-text Reply-To under the From becomes CampaignReplyToPicker, three choices that each say where replies land: - NoReply (default): NoReply@<the campaign'...
Drip campaign triggers, recorded where leads and members change
Drip campaigns start when something happens in the CRM, so the places that change leads and members now hand those events to EmailService's drip engine: - Lead...
Open on monthly, and sell 1- and 3-year terms as locking in today's rate
Most buyers come to compare what they would pay with no commitment, so HOME_TERM is now monthly. /pricing, the homepage plan strip, /calculator and the product ...
A campaign's replies go to NoReply, the member's e-mail, or a custom address — NoReply by default
The editor's Reply-To becomes three choices (CampaignReplyTo), kept in the existing reply_to column. No DDL. - NO_REPLY (empty column, the default): Reply-To: N...
A reply to a sending domain is refused as the recipient, in words that fit NoReply
Campaigns now send Reply-To: NoReply@<their From's domain> by default, and those replies reach postfix-k3m1-inbound. The refusal said "Sender address rejected: ...
An entry page rides out a service blip, and says so when it cannot
Entry pages failed in bursts while services rolled out: SecurityService answered 500 for a database schema-version bump or dropped the connection while restarti...
Retry public reads the database aborted with 40001
Every DDL bumps the YSQL catalog version, and a transaction that began on the old one fails with "catalog snapshot ... invalidated: MISMATCHED_SCHEMA" (SQLSTATE...
universe backup: pull mc from quay.io, docker.io/minio/mc is gone [skip ci]
MinIO withdrew its Docker Hub images, so the backup's upload container sat in ImagePullBackOff from 2026-09-12. With concurrencyPolicy Forbid that one stuck job...
Stop refreshing a mailbox grant no app can refresh, and say it needs reconnecting
An org connected Microsoft 365 through Kamo's platform app; the platform app was later switched off and the org has no registration of its own. The resolver the...
node-config: registry prune must not garbage-collect with --delete-untagged [skip ci]
The nightly prune on k1m1 lived only on the host. Its garbage-collect ran with --delete-untagged, which deletes the per-platform manifests an OCI image index re...
Skip enabled connections that are not filled in yet
An enabled MERIDIAN_LINK connection with no instance URL, appCode or secret collapsed to a null|null poll-unit and failed token exchange every tick, logging ERR...
Read the public-chat secret by its own key
This pod also mounts mlos-internal-auth, whose INTERNAL_AUTH_SECRET env var relaxed-binds onto internal.auth.secret and outranks the ConfigMap. Every caller rea...
auto-cert: stop provisioning www.stack.loans
The ratestack estate has been scaled to 0 since 2026-08-04, so nothing answers HTTP-01 for stack.loans. Its Certificates expired on 2026-08-02 and their orders ...
Rebuild so queue consumers self-heal their stale durables
social-inbound-consumer and marketing-conversion-consumer predate their deliver groups and live on SOCIAL_MESSAGES / MARKETING_EVENTS, which the shared NATS rec...
Reconcile durable consumers on the stream that owns the subject
The filter and deliver-group reconciles looked consumers up on the service's configured stream only. Subscriptions to subjects captured by another stream (socia...
Disable node-exporter's xfs collector [skip ci]
It cannot parse this kernel's /proc/fs/xfs/stat ("xpc") and logged an error on every scrape, ~240/h per node. Filesystem usage is unaffected (filesystem collect...
Kamo_app owns the ocr_* tables [skip ci]
OCRService (web and worker) alters its own ocr_* tables at startup and refuses to start without ownership; after the switch to kamo_app the worker crash-looped ...
Leave unique keys to the entities instead of duplicating them
Eight migration statements created unique indexes on exactly the columns their entities already declare unique (BillingGroupMember, BillingGroup, MailboxBilling...
Stop creating a plain index shadowed by the unique one
member_notification_preferences (member_id) got both a plain and a unique index from the same statement list; the unique index serves every lookup. The plain on...
Drop @Index declarations duplicated by a unique key
Each of these indexes covered exactly the same columns as a unique constraint, a unique column or the primary key on the same table, so it added a tablet and wr...
Rebuild for the Bulk Email settings page's hand-written translations
kamo-translation-dictionary de9ab66f writes Domain Setup, Sending, Opt Out and Deliverability, and the campaign screens' new From picker and sending-domain stri...
Non-superuser kamo_app role for all application workloads [skip ci]
Services connected as the superuser kamo. Add an idempotent script that creates kamo_app (no superuser, not a member of kamo so it cannot SET ROLE back) with gr...
Liveness probe on /actuator/health/liveness, not the DB-aware aggregate
The aggregate /actuator/health includes the DataSource indicator, so restarting the database failed liveness on every pod at once and restarted the whole platfo...
Liveness probe on /actuator/health/liveness, not the DB-aware aggregate
The aggregate /actuator/health includes the DataSource indicator, so restarting the database failed liveness on every pod at once and restarted the whole platfo...
Liveness probe on /actuator/health/liveness, not the DB-aware aggregate
The aggregate /actuator/health includes the DataSource indicator, so restarting the database failed liveness on every pod at once and restarted the whole platfo...
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.
