Purge VIEW_EMAIL_LOGS rows, and stop a test rotting when ordinals shift
VIEW_EMAIL_LOGS (64) was deleted from RoleRightType today for naming a feature that was never built. This removes what it left behind — measured at 42 role rows...
Delete VIEW_EMAIL_LOGS, which names a feature nobody built
No email log exists anywhere in the platform: no table in any schema, no endpoint among EmailService's 21 controllers, no UI, and no reference in the frontend —...
Put the note composer at the top of All Communications
The composer only existed on the Notes sub-tab, so writing a note about what you were reading meant leaving the tab you were reading it on. All now carries the ...
Choose the new org's apps while creating it
Adds an Apps & Features step between Type and Basics. It lists the apps the chosen branch type's security model actually offers -- the forced ones as "Always in...
Let the creator choose the new org's apps
The network-create wizard gains an Apps & Features step, and this is the half that makes it real. /branch-types/creatable now describes the apps each branch ty...
Rewrite the app catalog copy for the people who read it
The display name and description on ServiceType are the only description of an app most people ever see: an org admin on Settings -> Apps & Features, a parent-o...
Protect god accounts on the platform administrator list
A god account's platform rights may be changed only by another god, and a god account can never be removed from the list — by anyone, including another god. Go...
God accounts are protected on the platform admins list
Two rules the server enforces and this only mirrors: a god account's platform rights can be changed by another god and nobody else, and a god account can never ...
Bake the org's background order into config.json
kamo-login, kamo-register, the marketing site and KamoMeet all read the theme bucket's config.json for backgroundImageCount; backgroundOrder now rides alongside...
Background_order column for the public slideshow order
Nullable VARCHAR; null resolves to sequential on every client, which is what every org had before the column existed. Plain String rather than an enum so a late...
Purge the stored rows for the two retired notes rights
SHARE_NOTES (72) and MANAGE_NOTES_SETTINGS (73) were deleted from RoleRightType today for having no feature to gate. This removes what they left behind, counted...
Delete SHARE_NOTES and MANAGE_NOTES_SETTINGS, which name nothing
Notes are real, and as of today fully gated — VIEW, CREATE, EDIT and DELETE are enforced on every endpoint of KBService's NotesController. These two had nothing...
Add orgs.background_order
Nullable VARCHAR(20), no backfill and no DEFAULT — every client resolves an absent value to sequential, which is the behaviour every org had before the column e...
Read the org's real background count and play order
The hero probed for bg/1.webp and then hardcoded three frames, so an org with more never showed them and the rotation modulo'd by LOCAL_BGS.length regardless of...
Honour the org's sequential/shuffle slideshow order
Same config.json contract as kamo-login: backgroundOrder drives all three registration backgrounds, absent key stays sequential.
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 ...
All-networks follows the System User right
Seeing every organization and being able to enter one are the same decision — the list exists so an operator can find the organization they are about to support...
Platform Admins console gates every platform surface
Renames the System User tab to Platform Admins and turns it into what it was always standing in for: a list of the people who may operate the platform, each hol...
Stand up the platform administrator list
Backfills it from the retired system_user_access grants so nobody who could operate the System User before this deploy loses it: direct member grants map one-to...
Decide platform access with the shared resolver
@PlatformAdminOnly now names the platform right it requires (defaulting to MANAGE_ORGANIZATIONS, which is what this service's platform surface is about) and the...
Enforce platform rights on every platform surface
@RequirePlatformRight + PlatformRightInterceptor replace three hand-rolled "is the caller a top-level-org owner" gates that were copies of each other, one per p...
Seed the meet rights before the gate can lock anyone out
MediaService now requires START_MEETING to create a meeting and VIEW_MEETINGS to resolve one. Measured on production before writing this: 42 security roles acro...
Creating and resolving a meeting take the rights that name them
/api/meet/create checked only that you had a session, so every authenticated member of every organization could create a meeting with the org's provider — START...
Platform rights as a spine of their own
Who may operate the platform has been three different answers in three different places — a system_user_access grant table, an owner check copied into each plat...
Move the callback marker beside the contact name, add a Callback filter
The marker sits with the name because that is who the call is to, rather than in the id column where it pushed the ids out of line. The filter offers All / Sch...
Upload your own sound effects, at all three layers
The system could only ever play the thirty-nine tones it shipped with. Now any layer can add its own file — the platform's catalogue, an organization's, a membe...
List, rename, retire and stream uploaded sound effects
Bytes arrive through ConversionService (which owns ffmpeg and the scanner); everything afterwards is here, where the session and the scoping rules already live....
Transcode uploaded sound effects to Opus
Extends the ffmpeg wrapper the VoIP recording pipeline already had — this image installs ffmpeg with libopus for it, so putting a second ffmpeg in another image...
Uploaded sound effects, and the storage domain that counts them
EVENT_SOUND_ASSETS: a sound file somebody uploaded, ready to be assigned. Scope mirrors EVENT_SOUND_PROFILES exactly — same three layers, same SCOPE_ID conventi...
Let the sender edit the meeting invite email subject
The invitation subject was fixed at "<host> from <org> invited you to a meeting" and built inside the send route, so nobody could say what the meeting was actua...
Gate the personal-loan proxy on the PLOS rights
KamoLOS enforces nothing — no rights check anywhere in its source — so this proxy is the authorization boundary for the module, the position denyUnless occupies...
A kind for the meeting that is about to start
MEETING_REMINDER, so MediaService can raise the start-time nudge as a notification instead of a popup only it knows about. Its own kind rather than CALENDAR_EV...
Subscribe to the course count instead of asking for it every minute
NavTop sums two counts into one obligation badge, and only the legal half was live. A member assigned a course — or excused from one by HR — kept the old number...
Relay the outstanding-course count onto the member's own topic
The twin of the legal relay, because NavTop sums the two counts into one badge and a pair of halves that behaved differently would give the member chrome that w...
The outstanding-course badge moves when the course does, not a minute later
The NavTop obligation badge sums two counts — packages to sign and courses to take — and only one of them was live. The legal half has pushed since its NATS blo...
Publish every change of state, not only arrivals
A member has this open in more than one tab about as often as not, and often on a phone as well. Each of those holds its own socket and draws its own bell, and ...
The bell tells the truth in every tab, not just the one you clicked in
The nav-top bell was live for arrivals and nothing else. Reads, dismissals, snoozes and deletions were applied to whichever tab the member clicked in and announ...
Drop the three chat-channel rights from the frontend
Mirrors the shared-lib deletion: the enum mirror, its registry array, both hierarchy edges (ACCESS_CHAT -> CREATE_CHANNELS -> MANAGE_CHANNELS and ACCESS_CHAT ->...
Purge stored rows for the deleted chat-channel rights
Ids 74/75/76 no longer resolve. RoleRightsSyncService would sweep them on some future SecurityService boot anyway — silently, at an unpredictable moment, with n...
Delete the three chat-channel rights — 196
CREATE_CHANNELS (74), MANAGE_CHANNELS (75) and MODERATE_CHAT (76) gated nothing and could not be implemented as written: chat is real but the platform has no ch...
Move notes from account ownership onto membership
Adds notes.member_id and attaches each note to its owner's earliest membership — the organisation the account has belonged to longest, which in practice is wher...
One event-sound system, three layers, wired to what actually fires
There were two sound systems and neither knew about the other: four mp3s behind useChatSounds, and four synthesised tones behind notificationSound with a five-o...
Read and write the three layers of the event-sound stack
GET returns all three layers in one round trip plus what the caller may edit — every settings page needs the whole stack, because an org administrator editing t...
One table for the three layers of the event-sound stack
Platform defaults, an organization's overrides and a member's own are the same shape, so they are the same table: a scope, the id that scope is about, and the s...
Give the deck its slide back, without the lurch
Dropping `layout` to stop the card lurching onto the edge of the screen also took the sibling slide with it: dismissing a card left the rest snapping into its p...
Stagger the cascade, add branch bulk actions, explain the rule
The cascade highlight now travels the chain instead of flashing every affected row at once. enabledAncestors already arrives nearest-first, so the index IS the ...
Show and enforce the permission hierarchy in all five editors
Five editors granted 199 rights as five flat lists of checkboxes, and none of them showed that one right can be a prerequisite for another. Granting a child wit...
Normalise member overrides against the hierarchy
Member direct rights now go through RightsHierarchy.normalizeLevel before they are persisted: a granted child pulls its ancestors up to GRANTED at the member le...
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.
