Mabadiliko
Nini kipya.
Kila kuboresha jukwaa, kama ni meli.
· kamo-shared-library
Delete VIEW_DASHBOARD, VIEW_REPORTS and EXPORT_REPORTS
All three named pages that existed on disk and were backed by nothing: app/dashboard rendered sample posts straight out of i18n, app/reports imported framer-motion and next-intl and no data at all, and there is no reports engine or export path anywhere in the platform. Neither page was linked from navRegistry and no AppType claimed them — the test that kept the referral-code rights alive, since MARKETING advertises those as COMPLETED. VIEW_TASKS (120) was triaged alongside these and is deliberately kept. app/tasks is indistinguishable from the other two in the source — unreachable, unbacked, pure useState, i18n translated into 22 languages — and is scheduled to be completed. One is abandoned and one is next on the roadmap, and only the product owner knew which. Taxonomy 193/130/33/30 becomes 190/129/32/29, 61 roots. All four numbers move: one standalone, one root that loses its only child, and that child. Ids 0, 1 and 2 are burned. Note that 0 is a real id — VIEW_DASHBOARD was the first right ever declared — so any predicate that touches these must include zero rather than lean on truthiness.
· kamo-internal
App icons on the wizard's Apps & Features step
The create-network wizard drew each app as the first letter of its name, so the same app was a storefront on Settings -> Features and an "S" here. The icons already existed -- they were locked inside FeaturesManager's local iconMap. Moved that table to **************** keyed by ServiceType, and pointed both surfaces at it so they cannot drift. Added the two apps the Features screen never had entries for (CALCULATOR takes the nav rail's Calculate, FEED takes DynamicFeed), the deprecated-name aliases, and an app-grid fallback -- same shape as nav/settingsTopicIcons.ts. Every glyph is flat var(--color-primary) whether the app is on or off: twenty products each arriving in its own colour would read as a ransom note. On/off stays with the tile tint and the switch. The guard test fails the build if a live ServiceType has no icon -- otherwise a newly catalogued app ships as an anonymous grey square and nothing complains.
· kamo-internal
A solid-colour overlay for the loading screen logo too
Adds "Loading Screen Logo Overlay" directly under the home page one on **************** with the same thirteen options, applying to the logo on the screen shown between page navigations. Default No Overlay, so nothing changes for an org that never opens the field. Its own setting rather than one shared with the home page, because the two surfaces have opposite backgrounds: a white masthead and a dark gradient. The shade that reads on one is rarely the shade that reads on the other, and a single setting would force a choice that is wrong somewhere. The hint under each says so. The type is now LogoOverlay, not HomeLogoOverlay — it governs two surfaces, and a type named for one of them would misdescribe both within a week. The vocabulary, the resolver and the option list are shared; only the column each surface reads is different, so the colours cannot drift apart. loading.tsx reads OrgContext directly rather than through the throwing hook: it mounts during navigation and must never be the thing that breaks a page transition. A missing org means no overlay, which is the default anyway. The two read-only rows render identically, so they now share one helper instead of carrying a copy each. Requires the loading_logo_overlay column (KamoInitializer, applied) and a SecurityService rebuilt against the shared-lib entity.
· InitializerService
Add the loading_logo_overlay column
Second surface for the logo overlay feature: the loading screen shown between page navigations, alongside the home page masthead. Both ALTERs live in the one runner because they are one feature with one vocabulary, and someone looking for either should find both. Same shape as its sibling — nullable, no backfill, no DEFAULT, since an absent value and NONE mean the same thing to every client. The drift guard now iterates the entity's overlay fields instead of naming one, so a third surface cannot be added to the entity without an ALTER. It also pins one statement per column: a single shared ALTER would quietly leave the other column uncreated.
· kamo-shared-library
Carry the loading screen logo overlay on Organization
The same overlay vocabulary as homeLogoOverlay, applied instead to the logo on the loading screen shown between page navigations, plus its branch in the generic patch path. A column of its own rather than one shared setting, because the two surfaces have opposite backgrounds: the home page masthead is white and the loading screen is a dark gradient, so the shade that reads on one is rarely the shade that reads on the other. An org that wants both wants two answers. Null resolves to NONE on the client, so every existing org starts with no overlay and needs no backfill. The loading_logo_overlay column is already applied (KamoInitializer, OrgHomeLogoOverlayMigration).
· kamo-internal
Pick the assigned agent from the directory, not a dropdown
The Assigned Agent field is now the same control as Manager on a member's profile: a read-only field that opens the searchable member picker. A dropdown could only ever hold one page, and the list behind this one was loaded whole on every lead view whether or not anybody opened the card — two directory fetches per page load, one of which had been dead since the field last changed hands. Eligibility is unchanged in substance and better enforced: the picker asks the directory for holders of VIEW_LEADS, which is the same right the old endpoint resolved, and it stays on team members because that is the default scope. The "keep the current assignee selectable" special case is gone with the dropdown — the picker pins the current pick above the results, so it survives a search instead of needing a hand-made option. Unassigning works now. The empty option always existed but the patch collapsed it to undefined, which buildUpdateLeadRequest skips, so choosing it sent an empty patch and the lead kept its owner. The picker's Remove sends the empty id the server now reads as an explicit unassign.
· SecurityService
Narrow the member search to holders of a given right
The lead assignment picker needs the directory to return only people who can actually work a lead, so /team-members/search takes a requiredRight. An unrecognised name is a 400 rather than an ignored parameter: silently dropping a filter widens a permission boundary, which is the wrong way to fail. A right nobody holds returns an empty page without querying, since the alternative is an empty IN list the database will not parse. Who holds a right moves into RightHolderResolver, which the legacy assignable-members endpoint now uses too. The walk was already copied across five call sites and the two lead-assignment ones have to agree about who may receive a lead — better that they agree by asking the same question than by happening to hold the same code today. The remaining three are untouched.
· kamo-shared-library
Let the directory filter by right, and let a lead be unassigned
Two things the assignment picker needs. The directory queries take an allowed-id set so a caller can narrow the search to the people a thing may actually be given to — assigning a lead to somebody without VIEW_LEADS parks it where they cannot open it. The set is computed in Java rather than joined here because a right is held either by a rights row or by a grant-all role, and the second has no row to find. It travels with an unrestricted flag and is never empty: IN () is a syntax error on the Postgres wire, so the whole-directory case passes a placeholder instead of nothing. And updateLead now reads an absent assignee id and an empty one as different requests, the way it already does for country and language. A patch carries only the fields it means to change, so without that distinction there was no way to say "nobody owns this lead" — the empty string fell through the same branch as a missing field and the unassign silently did nothing. The open assignment row is closed rather than replaced, since a LeadAssignment always names a member and there is no longer one to name.
· kamo-internal
The editors say "Enforced as MANAGE_TIMECARDS" instead of "Not yet enforced"
One chip was carrying two different truths and misleading in opposite directions. Unbuilt means nothing checks the right and granting it does nothing. Superseded means the capability is real and gated, under another right's name — granting this one still does nothing, but deleting it would be wrong and the administrator needs to know which right to grant instead. The four entries are the ones the audit established: VIEW_SCHEDULES and MANAGE_SCHEDULES under MANAGE_TIMECARDS, because the Attendance tab used to open on VIEW_SCHEDULES and each HR tab was later given one right of its own; CREATE_EMPLOYEES and DELETE_EMPLOYEES under MANAGE_MEMBERS, because an employee is a member with an employment record and there is no employee CRUD endpoint. The list is hand-curated, unlike the generated one it annotates, and deliberately so: no analyzer can tell "superseded" from "nobody built it yet". Membership does not remove a right from UNENFORCED_RIGHTS — nothing passes it to a check either way — so the parity test with the committed audit is untouched. Two guards keep the annotation from rotting into a stale comment. A right that is genuinely enforced can never be labelled superseded, which would put two contradictory chips on one switch. And the covering right must not itself be decorative: the message is "grant X instead", so a dead X would send the administrator one step further from a working permission. This was worth doing before the next HR right lands. Two of these four were one check away from being deleted during the audit precisely because the editor said they were dead.
· kamo-shared-library
Carry the home page logo overlay on Organization
The solid colour an org can paint over the masthead logo on the kamo-internal home page, plus its branch in the generic patch path so the existing PUT /org/{id} persists it alongside bgWatermark. Stores a token — PRIMARY_DARKER, not 004ba0 — resolved against this org's own colours at render time, so an org that later rebrands keeps an overlay that still matches instead of a hex frozen when somebody picked it. Plain String rather than an enum, so a future token needs no CHECK-constraint sweep. Null resolves to NONE on the client, which is why every existing org starts with no overlay and needs no backfill. The home_logo_overlay column is already applied (KamoInitializer, OrgHomeLogoOverlayMigration) — this field maps a column that exists, not one a service will SELECT into a query error.
· InitializerService
Add the home_logo_overlay column
Backs the Home Page Logo Overlay setting: the solid colour an org can paint over the masthead logo on the kamo-internal home page. Holds a token rather than a hex, so the overlay resolves against the org's own palette at render time and survives a rebrand. Plain VARCHAR rather than an enum, so a later token needs no CHECK-constraint sweep. Nullable, no backfill, no DEFAULT: every client resolves an absent value to NONE, which is exactly what every org looked like before the column existed, so a backfill would write rows for no change in behaviour. @Order(0) per the column-add convention — the moment the shared-lib entity maps this column, every later runner that loads an Organization through JPA emits it in its SELECT, so a late-ordered migration would be stepped on by a runner dying first. The test is a drift guard, not a unit test: services run ddl-auto: none, so an entity field without a matching ALTER starts healthy and dies at query time — and for Organization that means org resolution, login and branding across the platform. This makes it a build failure instead.
· kamo-internal
Let an org paint the home page logo a solid colour
Adds "Home Page Logo Overlay" to Branding on **************** directly above Background Watermark: No Overlay, White, Black, and every step of the org's own primary and secondary ramps. Set it and the masthead logo at the top left of the home page renders as a solid silhouette in that colour. Default is No Overlay, so nothing changes for an org that never opens the field. What is stored is a TOKEN, not a hex — PRIMARY_DARKER, never #004ba0 — resolved against the org's palette at render time. An org that rebrands keeps an overlay that still matches its colours, instead of a hex frozen at the moment somebody picked it out of a dropdown. logoOverlay.ts owns that vocabulary and the resolution, the same way watermark.ts owns the watermark's. Three details worth knowing: - The dark shades already existed on the wire. The backend has sent all five steps of each ramp for as long as EmbColorPalette has, but Organization.fromJSON only ever mapped three, so colorDark/colorDarker fell on the floor here. They are carried now, which is what gives the darker tokens a colour to resolve to. - ThemeLogo does this with a CSS mask, not a filter. A filter can only push the existing colours around and cannot reach an arbitrary target, so the logo's own alpha becomes a mask and the colour is painted behind it. The <img> stays mounted and merely invisible: it is the only source of the naturalSize the sizing block depends on, and it keeps occupying its exact normal box so the masked layer can fill it. Callers that pass no overlayColor render byte-identically to before. - A brand token whose shade the org never set resolves to no overlay rather than falling back to a neighbouring shade. Seeing the logo you already had beats seeing a colour nobody chose. Requires the home_logo_overlay column (KamoInitializer, applied) and a SecurityService rebuilt against the shared-lib entity; until that lands the field reads and saves as No Overlay rather than erroring.
· InitializerService
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, 33 applied rows and 8 template rows — across both encodings, since the template table stores the enum NAME while the rest store the integer id. **************** needed fixing in the same change, and the reason is worth keeping. It asserted its example right had id != ordinal, guarded by "test is only meaningful while" that holds. Removing id 64 shifted every later ordinal, **************** id became equal to its ordinal, and the guard fired. Had the guard not been there the test would have kept passing while proving nothing, which is the worse outcome. It now picks its witness at runtime — any right that has an ancestor and whose id differs from its ordinal — so no future deletion can quietly hollow it out. Deleting rights is now routine enough that a hardcoded example is a liability.
· kamo-shared-library
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 — not even the checkRight that MANAGE_EMAIL_ACCOUNTS at least had. The platform does model logs where it has them, with phone_call_log, img_log_downloads, phi_access_log and contact_sync_logs all present; email has no equivalent. That is the CREATE_CHANNELS case — the noun does not exist — rather than the MANAGE_MEETINGS case where the noun is modelled and only the verb is unexposed. Taxonomy 194/131/33/30 becomes 193/130/33/30. Only the child count moves: ACCESS_MAIL keeps its four other children, so it stays a root-with-children. Id 64 is burned. Stored rows are removed by EmailLogsRightPurgeMigration.
· kamo-internal
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 same PostComposer — same lead, same org-visible note — and the timeline below it refetches its newest page in place when one lands, keeping the rows on screen instead of blinking back to a spinner.
· kamo-internal
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 included" with no switch to argue with, the optional ones as switches pre-set to the model's own default -- and sends the answers with the create. Type is what decides which apps exist to choose from, so the step sits right after it. Asking "what will this business actually do" while that is still the subject costs the customer nothing; asking it after eight screens of branding would read as a second, unrelated setup. Written for someone who has never used the platform: the header explains what an app is and that switching one off only hides it, each row carries the app's own plain-language description, "Normally on"/"Normally off" says where the pre-selection came from, and there is a way back to the recommended set. Nothing here is required and Review lists the apps the org will open with by name -- a count is a number nobody can check, and this is the last screen before an irreversible create. Selections are keyed by ServiceType name and an absent key means "whatever the model recommends", on both sides of the wire. Re-selecting the SAME branch type keeps the answers rather than rebuilding defaults: BranchTypeStep re-emits its selection every time that step is revisited, so the naive version would silently undo the whole step from one click on the step before it. Picking a different type does rebuild, because the app list is replaced wholesale. Also clamps the app description on Settings -> Account -> Branch Types to two lines. The descriptions those rows show now run to a few sentences so a non-technical reader can act on them, and unclamped they turn every collapsed row into a three-line block.
· SecurityService
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 type's security model offers -- forced ones as `required`, OPTIONAL_* ones with the model's own default -- so the wizard can render the step before the org exists. It has to come from here: the endpoints that describe apps are scoped to an existing org and gated on CONFIGURE_SYSTEM, a right the person creating a branch frequently does not hold in the parent org. NOT_AVAILABLE apps are omitted entirely rather than shown greyed out. The create payload gains `appSelections` ({ServiceType: boolean}), and the new org is provisioned from it in the create transaction, next to the role-template seeding: same kind of thing, and either it all lands or the org is not created. The part worth reading twice is that an app being switched OFF still gets an OrgFeature row. Until now a new org got no feature rows at all and they were filled in lazily the first time anyone opened Settings -> Apps -- a loop that enables everything the model does not outright block. So OPTIONAL_DEFAULT_DISABLED, an admin explicitly saying "offer this, but start it off", was silently promoted to ON for every child org ever created. Writing an inactive row is what makes the choice stick, because that loop only creates rows for types it finds none for. It is also why this cannot be a best-effort afterCommit step: the fallback would not leave the apps unset, it would leave them set to the opposite of what the creator asked for. Deliberately narrow in three places. An org with no applied model is left on the lazy path -- computeAvailabilitiesMap answers OPTIONAL_DEFAULT_DISABLED for everything there, and materialising that would hand someone a workspace where nothing is on and nothing says why. A selection naming an app the model does not offer is ignored, not refused: the wizard keeps its draft in session storage, so an admin narrowing the model mid-session must not cost a customer their create. And a null appSelections is not "no apps" -- it is an older client, and every app falls back to the model default.
· kamo-shared-library
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-org admin deciding what its child orgs may use on the branch-types screen, and now whoever is creating an organization in the network wizard -- someone who has typically never used the platform before. Two things were wrong with that copy, and both cost customers. It described the implementation. "AI-powered assistant with chat, RAG integration", "Voice Over IP PBX Phone System", "Self-hosted video conferencing", "Personal document storage with Docs editing", "Falls back to parent organization SMTP when disabled" -- accurate to an engineer, and no help at all to a business owner deciding whether they want the thing. Worse, it presented Kamo's own implementation as the whole app. E-Mail, Phone and Meetings are each a provider abstraction -- EmailProviderType, VoipProviderType and MeetingProviderType each ship a Kamo provider alongside Google Workspace / Microsoft 365 / Zoho / Exchange / IMAP, RingCentral and Teams Phone, Zoom and Teams. "E-Mail - E-Mail Hosting" reads as "tick this if you want Kamo to host your mail", so every org already on Workspace or 365 had a reason to decoder an app built for exactly them. Also fills two genuine gaps the copy never mentioned: HR owns the legal and disclosure documents staff have to read and sign, and Marketing sends bulk and drip email campaigns. ServiceTypeCustomerCopyTest pins both mistakes so they cannot come back. Constant names are untouched -- **************** persists the name as a string, so a rename would silently reassign every security model's grants.
· kamo-internal
Shorten the nav labels to Opportunities and Credits
· SecurityService
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. God is the platform's break-glass identity: its holders are what remains when everything else has been misconfigured. An administrator holding MANAGE_PLATFORM_ADMINS but not god could otherwise reach into a god account and take its rights away, which is precisely the edit that would disarm the people able to undo it. Removal is absolute because the row going away strips every right at once; changing rights stays possible, but only between peers. The peerage test is User.isGod on the caller, not an open god-mode window: being god is what makes you the target's equal here, while the window is about deliberately using that power elsewhere. isGod(Member) fails closed in the protective direction — a member whose user record cannot be read is treated as god, so an unreadable row is left alone rather than edited on the strength of a lookup that did not work. The caller's own flag fails the other way, since it only ever enables controls. Applies to all three write paths, including the add endpoint, which replaces rights on a re-add and would otherwise be a way around the rule.
· kamo-internal
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 be removed from the list — not by another god, not by itself. God is the break-glass identity, so its holders are the last way back in when everything else has been misconfigured. An administrator holding MANAGE_PLATFORM_ADMINS but not god could otherwise reach into a god account and strip it, which is the one edit that disarms the people who would undo it. Both controls are disabled with the reason attached rather than hidden — a control that vanishes reads as a missing feature, one that explains itself reads as a rule. The "+N more" chip carries the same lock, since it opens the same dialog.
· SecurityService
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 it, so the org-wide sequential/shuffle choice reaches all four on the next theme provision. Only the two known values are emitted — anything else is omitted so the client falls back to sequential rather than reading a value it does not recognise. The org PUT rejects an unrecognised value outright.
· kamo-shared-library
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 later mode does not need a CHECK-constraint sweep. The mirroring ALTER has already been run through KamoInitializer and the column is confirmed present in Yugabyte, so this is not armed.
· InitializerService
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 and logged in the same run rather than left for RoleRightsSyncService to sweep silently on some later SecurityService boot. Measured before writing it: 84 rows across the role tables, 16 template rows, 94 applied rows, and none at department, job-title or member level. Both encodings again. The rights tables and the applied snapshot store the integer id; **************** stores the enum NAME. One id-keyed DELETE would match nothing on the template table and report success, leaving 16 rows for rights that no longer resolve to be read into the force-rule map on every recalculation — which is not hypothetical, it is what happened to 24 of the 150 rows the chat-channel purge was meant to remove. No seeding and no verification gate, unlike the meet seed: deleting a right cannot remove anybody's access, because nothing ever read these. That is what made them deletable in the first place.
· kamo-shared-library
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 to name. There is no sharing modelled anywhere in the platform: no column on Note, no field on NoteDTO, no note_shares table — the note tables are notes, note_tags, note_versions and note_embedding_records — no endpoint among the ten, and no UI. The three "share" hits in FloatingNote.tsx are prose and the ones in the service are the com.kamo.z.shared package name. The architecture points the same way: a note's content key is derived from its owner, so sharing one is a re-keying problem rather than a missing endpoint. MANAGE_NOTES_SETTINGS has no settings surface either — no tab under settings/features, no route under app/settings, no config table, no config entity, no reference anywhere in the frontend. This is the CREATE_CHANNELS case, where the noun does not exist, and deliberately not the MANAGE_MEETINGS case kept last week, where the noun is modelled — MeetingStatus already has CANCELLED and ENDED, and WebinarService drives both — and only the verb is unexposed. The test that pins the taxonomy carries the reasoning. Taxonomy 196/132/33/31 becomes 194/131/33/30, 63 roots. Two numbers move rather than three: SHARE_NOTES was one of VIEW_NOTES' four children, so VIEW_NOTES stays a root-with-children instead of collapsing the way ACCESS_CHAT did. Ids 72-73 are burned. RoleRightTypeIdConverter persists the id, so a future right reusing one would inherit whatever those rows meant in the orgs that had them switched on. Stored rows are removed by NotesRightsPurgeMigration.
· InitializerService
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 existed. @Order(0) per the column-add convention: once the shared-lib entity maps it, any later runner loading an Organization emits it in its SELECT.
· kamo-marketing
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 how many images were actually up. It now reads config.json like every other Kamo surface, and honours the org's shuffle setting.
· kamo-register
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.
· kamo-login
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 key stays sequential, which is what every org had. The two Swiper screens keep their crossfade but drive their own timer when shuffled — Swiper autoplay only ever steps forward one slide.
· SecurityService
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 — so /all-networks now asks for SYSTEM_USER instead of ownership of the top-level org. A platform administrator granted System User access could previously enter any organization while being unable to see the list of them. resolveFromSession supplies the rest of the rule and replaces the hand-rolled version this handler carried: the caller must be in the top-level organization, the System User's own sessions are refused, and an owner or an open god-mode window still qualifies without an explicit grant.

Ulimwengu wako unasubiri.
Kuanza bure katika dakika. Ongeza bidhaa wakati wowote wewe ni tayari - hakuna uhamiaji, hakuna logins mpya.
Bure milele - hakuna kadi ya mkopo inahitajika