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...
Rebuild /notes as a paper wall with a split-pane editor
The page was the last screen still on raw Tailwind blue-600/gray-50 while everything around it moved to the house system, and every one of its ~100 `dark:` vari...
Pin and unpin a note from its floating sticky
The sticky could recolour, rename, minimize, maximize and close a note but not pin it — so pinning meant going back to /notes for the one thing the note is alre...
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,...
One quiet-hours window, governing both notification channels
There were two. The pair near the top of the page silenced the in-app cards; the pair at the bottom silenced the missed-message emails. Nothing on screen said t...
Two meanings of 100% — a reading width, and the whole pane
The percentage reset to one baseline: the page grown to the pane but capped at 920px, which on a wide monitor leaves the sheet floating in a lot of empty desk. ...
Refresh the NavTop clock the moment the editor saves
Voiding the punch a member is currently clocked in under already leaves them OFF server-side: RosterService.clockState reads the latest LIVE punch and skips voi...
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...
Zoom the document, and grab it to move it
A floating capsule in the bottom-right of the document pane: −, the current percentage, +. The READOUT IS THE RESET — a separate reset button would be a third c...
Pinned notes on the launchpad, colour rotation, and a proper send-off
Three things. Pinned notes reach the home launchpad. Every note pinned on /notes gets a chip there in its own sticky colour, with a short preview; clicking one...
Notification settings across the width, with a working model
It was one 760px column of switch rows, which reads as a form to fill in rather than something to tune — and on a wide screen left two thirds of the page empty ...
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...
Notifications become a tab on the member's own profile
They were a page of their own at /settings/notifications, which put a preference about one person somewhere other than the page about that person — and left the...
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...
Sign a package at /settings/sign, on a route of its own
Signing was inline on the member's profile tab, so the document sat under the settings tab strip AND the compliance sub-tab strip AND that tab's help panel — th...
Remember each floating note's size and position per device
Reopening a detached note now puts it back exactly where it was left, at the size it was left, on that screen. Placement is per DEVICE, deliberately. Which not...
Sign inside the app shell, behind one page header
The wizard opened as a fullScreen MUI Dialog, so signing a package threw the member out of the product: NavTop and NavPri were covered, there was no rail and no...
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)...
The lead on a callback is read, not remembered — and a call can be reopened
Two things, both about a calendar event being a poor place to keep a copy of somebody else's record. The event dialog now reads the lead from the CRM. Its name...
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...
Read one event by id
The lead page holds a callback's event id and wants to reopen it in the same dialog the calendar uses, so it needs to be able to fetch the event on its own. Sc...
Floating notes become a second class of hex head window
Hex heads now back two kinds of window: the popup tool windows they always did, and floating notes. Minimize replaces the old roll-up — a minimized sticky leave...
A control that actually opens what produced the event
The callback's description carried "Open the lead: /leads/view/123" as text, and text in a textarea cannot be clicked — the event dialog edits its description i...
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...
Rebuild against the shared-lib event-range fix
No source change here. Service CI clones kamo-shared-library at build time, so picking up c1e68a9 — which stops an omitted date window failing every calendar ev...
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...
Callbacks on the calendar, and a marker on the list
Two ways to see a call you promised to make without opening the lead. On the calendar, a callback gets its own line item rather than looking like any other app...
Callback summary for the leads list marker
Answers which leads have a call still waiting, and when the soonest one is due, for the caller's organisation in one request. Its own endpoint rather than a fie...
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...
Pending callbacks for a whole organisation in one query
Feeds the leads list's per-row callback marker. The grid holds every lead the member can see, so asking per lead would be a request per row to render one column...
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 ...
A notification centre, on every page
Reminders had nowhere to arrive. The calendar's popup was a plain alert in the top corner of whichever page happened to be open, it vanished on a timer, and any...
A callback that leads back to the lead
The callback already reached the member's calendar, as an event titled "Lead Callback" with their comment in the description. Nothing said whose call it was, no...
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...
Member notification tables, and an event's origin columns
Two halves of one feature. A callback scheduled on a lead is mirrored onto the scheduling member's calendar, and the point of the mirror is to get back to the l...
Member notification centre, and an event's origin
Adds MemberNotification and MemberNotificationPreference: one row per member per notification, because read, dismissed and snoozed are per-person answers and a ...
Detach notes into draggable, resizable floating stickies
Each note in the list (and the editor) gets a detach control that pops it onto a screen-wide overlay. Any number can float at once; each can be dragged anywhere...
Stop flashing the external-images prompt at members who allow them
Opening a message showed the "display external images" banner for a moment and then withdrew it, for anyone who had already chosen to allow images everywhere. ...
Fold the back arrow and book icon into the header title
The /kb body repeated the gradient header title verbatim. Drop the duplicate, move its book icon onto the h1 and park the back arrow to the right of it.
Ask for the unread count, not the whole folder tree
The mail badge needs one integer and was fetching every folder in the mailbox to find it, which on the IMAP providers is the most expensive call the mail backen...
One integer for the mail badge, and count what the index path is worth
Three things, all about knowing rather than assuming. The nav-top unread badge fetched the entire folder tree and picked INBOX out of the result — the most exp...
Brand chrome around a drafting board in the signing room
The desk was tinted with the org's colour and went dark in both themes, which put the brand under the document and left the chrome neutral — exactly backwards. ...
Stop storing which side a message is on
The mirrored rule was right; what was wrong is that the answer was computed once, when a message arrived, and kept. Placement needs three things — the sender, t...
Stop making the inbox wait on two lookups it can see the answer to
Two round trips still sat in front of a rendered inbox, and by this point they were the only thing left there — the folder tree and the first page already arriv...
Prove a folder unchanged with HIGHESTMODSEQ, then serve it from the index
Turns the index-backed message list on, by fixing the thing that made it unsafe rather than by flipping the flag. The old check compared message counts and UID...
Keep the session document name as the consent card's fallback heading
Extracting FieldLayer dropped detailTitleFor, and with it the fallback to session.documents[0].name — a document with a null fileName would have headed its cons...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.