GET/PATCH the org's default legal text
/api/docs/legal/settings, behind the same guarded() funnel as every other mapping on this controller. The read NEVER creates a row: it resolves to LegalDefault...
Seed every organization a default legal text
One hr_legal_settings row per org, unique on org_id, carrying **************** INSERT-ONLY, never an UPDATE. An org that has edited its own wording owns it; a ...
Org-level default legal text
LegalSettings is one row per organization carrying the wording a NEW legal package starts with. It is a DEFAULT, never a live reference: creating a package copi...
The history becomes a page, and the bell rings
The bell opened a popover, which is the right shape for "what just happened" and the wrong one for "what did that reminder say on Tuesday". A panel hanging off ...
A paged, filterable history
The centre could answer one question: the most recent hundred, unread or not, with no way to ask for what had already been read. So anything a member had seen w...
Let the history be queried by specification
The browsable history filters by kind and by whether a notification has been read, and those combine freely — which as JPQL is a query per combination, or one q...
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...
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...
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 ...
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...
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...
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...
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...
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...
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...
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...
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...
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. ...
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...
Map is_answered, now that the column exists
KamoInitializer added **************** on 2026-08-13 **************** verified in Yugabyte: boolean, default false, no nulls). Mapping it is safe now and was no...
Serve a folder listing from the index when it can prove it is current
The rows behind a message list are already in Postgres — the metadata index holds sender, subject, date, size, attachment and flags for every message it has see...
Add is_answered to the mail search index
Adds **************** so the index records all three IMAP flags rather than two. The message list draws a reply marker from this one, and the index-backed listi...
Record whether a message was replied to in the mail index
email_metadata.search_index has carried is_read and is_starred since it was created but never the third IMAP flag, \Answered. That was harmless while the index ...
Clock-out indicator wears the same pulse as legal & compliance
The punch clock breathed a red radial glow while the obligations badge three pixels to its left pulsed two expanding rings. Both controls are asking the member ...
On screen is not the same as read
A support conversation was marked read the instant its window loaded, so the one kind of window that must NOT count as read — the kind that raises itself, from ...
Unread means the requestor spoke, or the ticket just became yours
The badge counted "live tickets nobody has picked up, plus the ones I hold" — message-blind, and it only ever fell when a ticket reached a terminal status. So i...
One definition of an unread support conversation
The navtop badge and the ticket list have twice drifted apart by answering different questions. findUnreadStateForViewer is the single answer both now read, so ...
Give the expanded rail a scrollbar instead of end arrows
The up/down arrows exist because a collapsed rail is 80px of tile with no room to spend on anything else. Expanded, the rail is 248px and the options read as a ...
Use the real payroll vendor logos on the provider cards
Adds the ten vendor assets and renders them in place of the lettermark placeholders. These are WORDMARKS, not square icons like the email provider set, and the...
Carry whether a ticket is one of the items the support badge counts
The navtop badge and the ticket list were answering different questions and nobody could tell. The badge counts items awaiting attention — overwhelmingly ticket...
Payroll Provider Setup, and map people to payroll on enrollment
Replaces the placeholder HRS Overview tab with the real thing. The tab is now "Provider Setup" and the screen is "Payroll Provider Setup", following the email p...
Index and REVOKE the payroll-provider tables
What Hibernate cannot express for the new hr_timecard_payroll_* tables. Two REVOKEs. PayrollDispatch and PayrollSyncIssue refuse updates and deletes in Java th...
Size an attachment by what the provider's API actually carries
The composer held every social DM to a flat 10 MB, which is Telegram's photo limit applied to four providers that do not share it. Each now gets its own ceiling...
Nightly payroll-provider sync job
Drives TimecardService's **************** which syncs every organization whose next sync is due. Cron lives here rather than in TimecardService because that de...
The authorization boundary for payroll provider setup
Relays the new **************** surface and enforces who may reach it. TimecardService holds the engine and no session; this holds the session and decides. Secu...
The payroll-provider domain behind the timecard engine
Adds the persistence spine for connecting an organization's timecards to a third-party payroll system: the connection and its encrypted per-org config, the OAut...
A wall at "now", and a card that explains a cancelled punch
Nobody can record time they have not worked yet. Dragging an edge, sliding a whole span, nudging with the arrow keys, the magnet, the right-click block and the ...
Je, unaona nini kuhusu usafiri?
Kila moja ya hizi updates ardhi katika nafasi yako ya kazi moja kwa moja. Kuanza bure na kuangalia kukua wiki baada ya wiki.