A loan id is not a credential — scope every LoanController read to the org
LoanController.get(uid) took a loan id and returned whatever it found. Any caller who reached the service got the loan, balances and borrower included, whicheve...
43 unenforced becomes 41 — the two notes placeholders are deleted
Mirrors the shared-lib removal of SHARE_NOTES (72) and MANAGE_NOTES_SETTINGS (73): the TS constants and the registry array, the one parent-map edge in both righ...
Renaming a member is an admin act, and now has a gate
The member profile's legal-name card was self-only, so an admin who typed a name wrong on the create form could never correct it — MemberCreateForm asks for pre...
46 unenforced becomes 43 — the notes endpoints are gated
Fifth cluster. The Notes backend is KBService, not SecurityService: the entity sits under donotmodify/dao/beans/security/ and kamo-internal proxies /api/notes/*...
Every notes endpoint takes the right that names it, and hasRight fails closed
NotesController checked no right on any of its ten endpoints. VIEW_NOTES was enforced in exactly one place — navRegistry.ts, hiding the Notes app in the browser...
Stop a page-2 request from cancelling the folder you just opened
Junk, Trash, Archive and every custom folder showed the same mail — whatever was on screen before them. The server was not the problem: replaying listMessages a...
Close the add-path route around the platform-admin lockout guard
POST replaces an existing administrator's rights, so it can take them away as well as give them — but only the PUT and DELETE paths checked whether the edit wou...
Let a granted administrator actually see Platform Administration
The section gate and the settings menu topic still asked useUserInfo's hasPlatformAdminAccess, which is owner-of-the-top-level-org or an open god-mode window an...
Send an operator with no Configuration tab somewhere real
SYSTEM_USER and MANAGE_UNIVERSE gate surfaces that are not tabs on this page, so somebody holding only those is a platform administrator the page guard admits a...
The meet seed recomputes applied rights instead of waiting for a boot
Granting the two rights on org_role_rights changes nothing anybody can observe. member_rights_applied is the flattened snapshot the session and the server-side ...
48 unenforced becomes 46 — meet create and join are gated
Fourth cluster of the 48, and it split three ways rather than the two the design predicted. The design attributed the enforced MANAGE_MEET_SETTINGS check to Ch...
Draw the callback markers as soon as the summary loads
The summary lands after the grid has drawn its rows, and AG Grid keeps the cellRenderer a column was built with and only re-creates a cell when its row changes....
A deleted upload now falls back instead of going silent
The previous commit claimed a retired sound "degrades to the layer beneath it rather than to silence". It did not. `isKnownSoundId` accepts a custom id on shape...
48 unenforced — the six PLOS rights are gated now
Gating the LOS proxy made PLOS_* enforced, but they stayed on the unenforced list, so the editors were showing 'Not yet enforced' against six live gates. Third ...
Put the callback marker after the lead id
Leading the cell with the marker pushed the id right on any row with a call waiting, so the ids no longer lined up down the column while scrolling.
The meeting reminder reaches the bell, and pops once
MeetReminderPopup drew its own Snackbar from its own subscription to **************** Nothing else knew a reminder had happened: the bell stayed at zero, the de...
The meeting reminder is a notification, not a popup of its own
The sweep published a bespoke event on /topic/meet/reminder/{memberId} that a dedicated Snackbar drew in the corner of the screen. That popup was the entire rem...
One calendar reminder, announced once
A reminder was arriving twice. The deck picks it up as a notification, and the older path picked it up as well: CalendarWebSocketContext opened a second STOMP c...
A note is owned by a member, not by an account
Mirrors the API: NoteDTO now carries memberId in place of userId. A member is the signed-in account inside ONE organisation, so opening a different org shows a ...
Read and write notes as a member, never as an account
Every endpoint now requires memberID on the session — reads included — and refuses the request without one. The reads used to need only a userID, which is globa...
Scope notes to a membership instead of an account
A note hung off USER_ID alone and carried no organisation at all. A user is global and a member is that user inside one organisation, so an account belonging to...
Re-derive the audit structurally — 57 decorative
The count moved 58 -> 52 -> 47 -> 57 because every version hard-coded a list of gate-helper names and the codebase has more than anyone can recall. Six were mis...
Dock popup windows beside the page scrollbar, not on top of it
Tool windows are fixed to the viewport and dock right-to-left from its edge, and the layout was told about exactly one thing occupying that edge: the interactio...
Enforce the doc-share search rights server-side
/members-subscribers and /team-members-contractors enumerate the organisation's people — names and ids — to fill the document-share autocomplete, and required o...
Enforce the doc-share alias rights server-side
GET /shares/resolve-alias turns a guessable alias into a real person's NAME and required only a valid session. The rule lived solely in ShareDocumentDialog, and...
Stop the reminder lurching to the screen edge when an option opens
The card kept framer's `layout` after it grew a fold-out options panel. `layout` animates size and position by transform, so that one height change was being an...
47 unenforced — five more were falsely reported
CREATE_ORG_CALENDAR_EVENTS is enforced: MemberCalendarService throws OrgCalendarForbiddenException when a member without it writes to the org calendar. The chec...
52 unenforced, not 58 — six were falsely reported
The audit's gate detection recognised hasRight and checkRight but not denyUnless, hasAnyRight, sessionHasRight or forbidden. Six rights that ARE enforced were t...
Make the emoji picker's search actually filter
The picker's search matched the query against the translated category name only, and fell back to pushing every emoji into the results when nothing matched — so...
Sticky scrollbars, a toolbar that never scrolls, and a dialog that clears the note
Three things, all in the floating sticky. The scrollbar was still grey. The rules were written as **************** which styles only the element CARRYING the c...
Stop the launchpad backdrop painting over the page scrollbar
The launchpad is the only page that renders the full-bleed Backdrop, and it was the only page whose scrollbar stayed invisible after the -webkit-/standard confl...
The sticky's watermark is centred from the moment it opens
It only landed correctly after the note was resized. The measurement used getBoundingClientRect, which reports the PAINTED box — and a sticky opens by animating...
Centre the sticky's watermark on the writing surface
It was centred on the whole note, so it sat high — pulled up behind the title bar — and in rich mode it drifted further every time the toolbar wrapped to a seco...
Writing the org legal settings needs BOTH HR rights
The Legal & Compliance settings tab is the only writer and is now offered only to a member holding MANAGE_HRS_SETTINGS *and* MANAGE_LEGAL_AND_COMPLIANCE, so the...
The floating sticky's pin is the same pin /notes draws
The sticky was drawing a hand-rolled bookmark path while the notes wall, the editor, the rail and the bulk bar had all moved to MUI's PushPin — outlined when lo...
Stop the page scrollbar's two halves cancelling each other out
The main content scroller declared both **************** and a block of `::-webkit-scrollbar` rules, on the theory that whichever the browser understood would w...
Draw the main content scrollbar, in the org's colour
html/body are pinned to height:100%, so the element that actually scrolls a page is the main content div in layout.tsx — and it carried no scrollbar styling at ...
Hold a launchpad card's pin chip back until its pane arrives
The panes reveal themselves on scroll (whileInView, opacity 0 -> 1), but the pin control is a sibling overlay rather than part of that animation — it has to be,...
Solid sticky paper, and a scrollbar in the note's own colour
The note's background faded to `rgba(0,0,0,0.045)` at one corner. That is not a shade — it is 95% TRANSPARENT, so the corner of a sticky showed the page scrolli...
Stop the docket flickering a scrollbar, and centre the step counter
THE FLICKER. The docket row set `overflow-x: auto` and left the other axis alone — but CSS computes `overflow-y: visible` to `auto` the moment the other axis is...
Match the enum-whitelist CHECK sweep to the YugabyteDB rendering
dropStaleEnumWhitelistChecks() looked for '% IN (%', which is how CockroachDB stored a @Enumerated(EnumType.STRING) whitelist. PostgreSQL and YugabyteDB normali...
Catch npm silently dropping Next's native SWC binary
The image build died in `next build` with Downloading swc package @next/swc-linux-x64-gnu... unhandledRejection TypeError: terminated (UND_ERR_SOCKET)...
Stop copying lead details onto the calendar event
The event carried the lead's name, number, email and best time to call, copied into its description when the call was booked. A copy of a record that is still b...
Stop writing the lead path into the callback's description
It read "Open the lead: /leads/view/123" and was not a link. It could not be: a description is edited in a textarea, where text is text — and outside the applic...
Stop an omitted date window failing every event lookup
The calendar page could never list anything. It asks for every event a member has, with no window, and these queries took the range as nullable and tested it wi...
Put a callback on a calendar the member can actually see
Callbacks were not reaching the calendar at all. This service picked the target calendar by account — findPrimaryByUser — and a user is global while a member is...
Stop the event dialog throwing "Invalid time value" on open
wallClockToInstant called toISOString() on a date it had not checked, so any unreadable input threw RangeError instead of returning something unusable. The dia...
Let "not established" be a value the images gate can see
Follows EmailService boxing **************** A folder listing now reports null for it rather than a primitive's false, so the types here admit null and the gate...
Stop envelopes claiming a consent answer nobody asked for
remoteImagesAllowed was a primitive boolean, and only the three endpoints that fetch a whole message ever assign it. The folder listing does not — answering it ...
Make event reminders actually notify someone
Three faults, one symptom. Members reported that calendar notifications did not work, and all three reasons were on this side. Reminders were never written. Th...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.