Default a new subscription's target org to the caller's
A first purchase has no existing subscription to copy targetOrganizationId from, and requiring it unconditionally is what made creating one from the console imp...
Stop revoking a member's billing access when adding them elsewhere
add() deleted the member's row on any other account to satisfy a global unique that no longer exists. Adding someone to a second billing account now leaves the ...
Buy a block when an opted-in org runs out of room
Runs shortly after the nightly snapshot sweep, because that is what produces the usage figure it decides on — expanding against yesterday's number would buy a b...
Let a catalog price change actually reach Stripe
Stripe Prices are immutable and the mapping holds one row per (org, type, code, cycle) behind a unique key, so once a price existed it could never change. A pri...
Report capacity alongside usage
The storage panel reported bytes stored against nothing at all — no allowance, no percentage, no money — so an owner looking at 400 GB had no way to tell whethe...
Make a first plan purchasable, and return real plan prices
Two things stopped an organization ever buying a first subscription. Plan lists were reachable only through sub.marketId on a subscription the org already held...
Let a sub-org reach the account that pays for it
AccountSubscription deliberately separates the payer from the organization whose members consume the seats, and auto-provisioned accounts sit on the top-level K...
Bill per-unit add-ons by units bought, not by headcount
Threads the new add-on quantity through create and update: a FLAT add-on now takes its Stripe quantity from what the subscription actually bought, so four 10 GB...
Charge what the catalog says, once, for the right quantity
Five defects that all moved real money, plus the sub-resource IDOR beneath them. Billing cycles. ANNUAL prices were sent to Stripe at the stored per-month rate...
Verify god mode against the database, not a forged header
AccountOrgScopeInterceptor short-circuited every org and member check on the raw X-God-Mode-Active header, and kamo-internal's billing proxy copies that header ...
CockroachDB-only SQL that PostgreSQL rejects
CockroachDB spells the text type STRING; PostgreSQL and YugabyteDB use TEXT. 25 casts across native queries were still emitting CAST(x AS STRING) and ::STRING, ...
Rebuild against shared-library @Lob LONGVARCHAR fix
Hibernate's PostgreSQL dialect read @Lob String columns as OIDs via getLong(). Affects notes, contacts, calendar, OAuth tokens, IMAP passwords, email campaign b...
Point at YugabyteDB and use PostgreSQLDialect
CockroachDB has been replaced by YugabyteDB. Connection strings move from cockroachdb-public:26257 to yb-tserver-service:5433, and the Hibernate dialect from **...
Read imaging usage from one deduplicated pass
Follows the shared-library change to one charge per distinct file per organization. Both the summary and the daily snapshot writer take a single imaging pass an...
Rebuild for the generated-previews domain
Picks up the shared-library change that bills thumbnails and tracks to the organization and reads derivative bytes from img_dat_derivatives.
Rebuild for the branding and docs-workspace domains
Picks up the shared-library change that reads both from object_storage_days.
Rebuild for the text message attachment domain
Picks up the shared-library change that measures MMS attachments from the data: URIs stored inline in VOIP_MESSAGES.
Rebuild against the per-category storage domains
Picks up the shared-library change that splits imgs into one domain per ImageAssocType, so call recordings, voicemails, chat attachments, HR resources and marke...
Record the corrected mailbox semantics
EMAIL now measures the mail Kamo actually hosts, attributed per mailbox to the organization that owns it, rather than summing a search index that both missed Ka...
Let a platform admin run the snapshot sweep on demand
The sweep is what makes period removals and lifetime totals for the hard-deleting domains answerable at all, so days lost to an outage are lost permanently unle...
Give each organization a real transaction boundary
StorageSnapshotSweep.catchUp carried @Transactional(REQUIRES_NEW) and was called from sweep() on the same bean. Spring applies @Transactional through a proxy, s...
Report what an organization is storing
The account stats tab has always said "No usage data available for this period", for every organization, because getCurrentUsage() in kamo-internal is a stub re...
Enforce self-or-owner on an account, not just the org boundary
Follow-up to the cross-org gate, now that the rule is decided: inside an organization you may manage your own billing account, and an organization owner may man...
Stop one organization reaching another organization billing
/api/billing/accounts scopes its listing by the X-Org-Id header, but every route beneath /{accountUid} took the id straight from the path and never checked who ...
Retry the shared-library build, which the LAN uplink keeps corrupting
Three builds died today on "Tag mismatch" pulling a jar — and the mirror added an hour ago did not help, because kbservice, mcpgatewayservice and ragservice hit...
Answer "is this sellable" from the app catalog, not the enum
Availability became operator-editable at runtime, so deriving it from ServiceType.getStage() meant publishing MLOS in Apps and Features left it invisible on the...
Mirror Maven Central through the Google GCS copy
Build 19 failed fetching tomcat-embed-core from repo.maven.apache.org with 'Tag mismatch' — a corrupted transfer, not a code error: the same commit builds clean...
Validate add-on codes before they can grant an app
active_addon_codes was written straight from the request body. That was harmless while nothing read the column, but it is now an authorization input: an add-on ...
Hide unreleased apps from the Plans & Billing catalog
**************** back the tab where a customer chooses what to subscribe to, so it must not offer a product still in the Not Available list — the same rule the ...
Keep the is-prefix on PlatformAccountSummary's wire names too
Same Lombok/Jackson hazard as PlatformOrgRow: isTopLevel() loses its `is` on serialization, so the DTO put `topLevel`/`platformProduct` on the wire while the fr...
Keep the is-prefix on the wire for isTopLevel/isPlatformProduct
Lombok generates isTopLevel() for a `boolean isTopLevel` field and Jackson strips the `is` prefix, so the live endpoint was serializing `topLevel` and `platform...
Declare security matchers explicitly so the service can start
The service has not deployed since 2026-07-03; every pod since has crash-looped before the context loaded: This method cannot decide whether these patterns a...
Serve the org directory as a filtered, sorted, paginated page
GET /orgs takes page/size/q/sort/dir plus seven filters and returns the house page envelope with estate-wide aggregates. GET /orgs/{orgId} serves full detail fo...
Batched page hydration at a constant query count
Parent titles, primary domain, the plan/market behind the entitlement and the subscription-catalog flag are each one batched IN (:ids) over the whole page, so a...
Directory row/page DTOs and the native query repository
PlatformOrgRow carries the two facets separately: entitlement (inbound subs targeting the org -- what governs it) and billing held (accounts the org owns -- non...
Org directory SQL with per-facet CTEs
Held accounts, inbound subscriptions, members, licensees and children each aggregate in their own CTE before being joined to orgs. Joining them in one pass woul...
Validated, clamped org directory request
Size clamps to [1,100] and an unrecognised sort falls back to title, so a hand-edited URL can neither request the whole estate nor reach the SQL as free text. T...
Derive entitlement mode through one shared, deterministic resolver
TrialAdminService picked its trial subscription with findFirst() over an unordered list, so an org holding both a pending and an active trial could report eithe...
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 ...
Serialize Long ids as strings to stop org-id precision loss
Org ids are CockroachDB unique_rowid() values that exceed JS MAX_SAFE_INTEGER. BillingService was serializing them as raw JSON numbers, so kamo-internal's JSON....
Expose trialExpiresAt on platform org summary for the admin trials UI
Platform-admin apply/extend/status trial endpoints + DTO trialExpiresAt
Migrate to k1m1 (clone+registry+kubeconfig from k1m1, drop k2m1, simple kubectl install)
Register esign repositories for the meter submission bean
EsignMeterSubmissionService needs EsignUsageRecordRepository, but @EnableJpaRepositories didn't scan com.kamo.z.shared.esign.repos, so the context failed to sta...
E-sign usage metering + consumer self-serve checkout
#4 metering: - EsignMeterSubmissionService (@Scheduled daily): aggregates API-origin EsignUsageRecords per org+period; first 40/period included, the rest subm...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.