Declare the object-storage secret the ConfigMap no longer carries
MINIO_SECRET_KEY was moved into the minio-app-credentials secret, but the envFrom supplying it was only applied live and never committed, so a CI reconcile woul...
Declare the object-storage secret the ConfigMap no longer carries
The MinIO key was moved out of the ConfigMap into the minio-app-credentials secret, but the envFrom that supplies it was only ever applied to the live deploymen...
Declare the object-storage secret the ConfigMap no longer carries
The MinIO key was moved out of the ConfigMap into the minio-app-credentials secret, but the envFrom that supplies it was only ever applied to the live deploymen...
Declare the object-storage secret the ConfigMap no longer carries
The MinIO key was moved out of the ConfigMap into the minio-app-credentials secret, but the envFrom that supplies it was only ever applied to the live deploymen...
Declare the object-storage secret the ConfigMap no longer carries
The MinIO key was moved out of the ConfigMap into the minio-app-credentials secret, but the envFrom that supplies it was only ever applied to the live deploymen...
Declare the object-storage secret the ConfigMap no longer carries
The MinIO key was moved out of the ConfigMap into the minio-app-credentials secret, but the envFrom that supplies it was only ever applied to the live deploymen...
Declare the object-storage secret the ConfigMap no longer carries
The MinIO key was moved out of the ConfigMap into the minio-app-credentials secret, but the envFrom that supplies it was only ever applied to the live deploymen...
Declare the object-storage secret the ConfigMap no longer carries
The MinIO key was moved out of the ConfigMap into the minio-app-credentials secret, but the envFrom that supplies it was only ever applied to the live deploymen...
Declare the object-storage secret the ConfigMap no longer carries
The MinIO key was moved out of the ConfigMap into the minio-app-credentials secret, but the envFrom that supplies it was only ever applied to the live deploymen...
Never let the quota service stop a service from starting
StorageQuotaService took its five repositories as required constructor arguments. Services in this estate component-scan com.kamo with a wildcard but declare an...
Stop shipping the shared credential in this repo
The object-storage key sat in k8s/configmap.yaml, which kubectl will hand to anyone who can read the namespace, and the same string was hardcoded as the SSH pas...
Size each mailbox against the organization's storage
Dovecot now enforces a per-mailbox limit, and nothing was setting the column it reads. This writes it nightly, after the storage snapshot so the capacity being ...
Pin how the pool divides into per-mailbox limits
Dovecot needs a byte figure per mailbox, but storage is one organization-wide pool across eighteen domains. The division has to hold one property above all — th...
Stop shipping a shared credential as a config default
The platform's shared password was baked in as the fallback for DB_PASSWORD and MINIO_ROOT_PASSWORD, so it lived in this repo and in the built image as well as ...
Stop shipping a shared credential as a config default
The platform's shared password was baked in as the fallback for DB_PASSWORD and MINIO_ROOT_PASSWORD, so it lived in this repo and in the built image as well as ...
Stop shipping a shared credential as a config default
The platform's shared password was baked in as the fallback for DB_PASSWORD and MINIO_ROOT_PASSWORD, so it lived in this repo and in the built image as well as ...
Stop shipping a shared credential as a config default
The platform's shared password was baked in as the fallback for DB_PASSWORD and MINIO_ROOT_PASSWORD, so it lived in this repo and in the built image as well as ...
Stop shipping a shared credential as a config default
The platform's shared password was baked in as the fallback for DB_PASSWORD and MINIO_ROOT_PASSWORD, so it lived in this repo and in the built image as well as ...
Stop shipping a shared credential as a config default
The platform's shared password was baked in as the fallback for DB_PASSWORD and MINIO_ROOT_PASSWORD, so it lived in this repo and in the built image as well as ...
Stop shipping a shared credential as a config default
The platform's shared password was baked in as the fallback for DB_PASSWORD and MINIO_ROOT_PASSWORD, so it lived in this repo and in the built image as well as ...
Stop shipping a shared credential as a config default
The platform's shared password was baked in as the fallback for DB_PASSWORD and MINIO_ROOT_PASSWORD, so it lived in this repo and in the built image as well as ...
Stop shipping a shared credential as a config default
The platform's shared password was baked in as the fallback for DB_PASSWORD and MINIO_ROOT_PASSWORD, so it lived in this repo and in the built image as well as ...
Stop shipping a shared credential as a config default
The platform's shared password was baked in as the fallback for DB_PASSWORD and MINIO_ROOT_PASSWORD, so it lived in this repo and in the built image as well as ...
Stop shipping a shared credential as a config default
The platform's shared password was baked in as the fallback for DB_PASSWORD and MINIO_ROOT_PASSWORD, so it lived in this repo and in the built image as well as ...
Stop shipping the shared credential in this repo
The mail MySQL password sat in plaintext across fourteen files here — in ConfigMaps that kubectl will hand to anyone who can read them, in two Jobs that CI appl...
Stop shipping the shared credential in this repo
The mail MySQL password sat in plaintext across fourteen files here — in ConfigMaps that kubectl will hand to anyone who can read them, in two Jobs that CI appl...
Enforce storage quota on inbound delivery, and stop shipping the DB password
Object storage already refuses content that would take an organization past its ceiling, which covers every domain going through the object store. Inbound mail ...
Enforce storage quota on inbound delivery, and stop shipping the DB password
Object storage already refuses content that would take an organization past its ceiling, which covers every domain going through the object store. Inbound mail ...
The Dovecot quota change, written out and not applied
Object storage now refuses content that would take an organization past its ceiling, which covers every domain that goes through the object store. Inbound mail ...
The Dovecot quota change, written out and not applied
Object storage now refuses content that would take an organization past its ceiling, which covers every domain that goes through the object store. Inbound mail ...
Let a member license their own seat from the console
The panel that closes the loop on self-pay. It appears only where the organization's policy permits it, and only for people who are not already buying on the or...
Tell people their payment failed, and stand the subscription down
The dunning that did not exist. invoice.payment_failed wrote a row and returned: no email, no flag, no state change, and billing.email-service-url was configure...
Add the dunning clock columns
past_due_since and suspension_notified_at, both nullable. Null means paying and not-yet-told respectively.
Make a failed payment mean something
PAST_DUE counted as fully live in both entitlement resolvers, with no timestamp and no cap, so a customer whose card failed kept every feature for as long as St...
Let a member buy their own seat, and close a body-parameter hole
Self-pay had no route inside the console. Everything on the billing surface is account-shaped — you must already hold an AccountMember row before Plans & Billin...
Let the owner decide who can pay, and manage the groups that do
The owner had exactly one lever over self-payment and it was the wrong shape: an irreversible promote gesture, with no way to say in advance whether it was perm...
Org policy and billing group APIs
Who inside an organization may pay Kamo is now answerable and settable. Both routes are org-scoped and therefore deliberately outside /api/billing/accounts/** a...
A Plans & billing console an owner can actually find
There was no way to buy a first subscription anywhere in the product. Plan lists were reachable only through a subscription you already held, so an organization...
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...
Show the ceiling, not just the bytes
The panel reported stored, added, removed and lifetime bytes against no reference at all — so an owner looking at 400 GB had no way to tell whether that was com...
Pin the delegation-mode semantics
These predicates are what the surfaces hide themselves on, so getting one wrong either offers a button that cannot work or silently permits a charge the owner m...
Gate promotion on the owner's policy, make it idempotent, add its inverse
Promoting a member to pay for themselves was unconditional, one-way and unsafe to repeat. It now refuses when the organization's policy says the organization p...
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 ...
Drop the constraint that limited a member to one billing account
Finds the constraint by shape rather than by name — Hibernate generated it and the name is not stable across environments, so any unique constraint on account_m...
Let members and groups pay for themselves, under the owner's rules
Three things were missing and one was actively harmful. account_members carried a global unique on member_id — a member could administer exactly ONE billing ac...
Expose the fail-open impact to the operator
The app catalog page already answers the org-independent question — does any plan mention this app — and raises a warning when none does. This answers the tenan...
Show what turning off fail-open would cost
kamo.entitlement.fail-open grants any app the plan matrix never mentions. It is documented as a temporary valve for the catalog backfill — turn it off once the ...
Show whether someone is there, and their extension
Every row now carries a presence dot and word beside the name, and its extension in the detail line — so choosing a person no longer means picking a name and ho...
Carry availability, presence and extension on a directory row
Picking a person is easier when the row says whether they are there and how to reach them, so each one now carries what they last declared, whether anything of ...
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...
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.
