A read clears the indicators immediately, not on the next reload
Reading a conversation updated the server and then waited for the news to come back: PUT /read commits, MediaService broadcasts a fresh count over core NATS, th...
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 ...
Tint the mailbox loading sweep with the org's own colour
The /messages placeholders drew their travelling band of light from --accent-comms, the comms family accent (#6366f1), so every tenant watched an indigo shimmer...
Remove the payroll registration fields nothing reads
Six fields on the payroll cards were never consumed by anything. A registration field nobody loads is worse than a missing one: an operator fills it in, believe...
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 ...
Widen the expanded rail's scrollbar to 20px
At 10px it was slimmer than it needed to be — the rail has the width to spare, and a wider bar is a wider grab target. The thumb's transparent inset doubles wit...
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...
The needs-attention mark stops lying when you open a ticket
Clicking a row cleared its amber dot while the badge beside it stayed put, and a refresh brought the dot back. The badge was right and the dot was wrong. A tic...
Mark the items the navtop badge is actually counting
The badge read "5 support items need attention" and the list marked none of them. Both numbers were right about their own question and neither was the question ...
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...
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...
Side a message by which side sent it, not by who is reading
A support conversation has exactly two sides, and they are not "me" and "everyone else". One side is the person who asked for help — always exactly one member. ...
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 ...
Drop the speed dial heading
The tab is reached by its own icon and the rows say what they are, so a title and a sentence of explanation above them only cost vertical space in a panel that ...
Give the support and social windows the member chat's composer
A support ticket and a social DM are the same thing as a member chat — a media session with messages on it — but they were answered through a bare text field. A...
Department speed dial hung on Loading forever
The loader effect listed departmentsState in its deps and set it to 'loading' on entry, so React tore that effect instance down immediately, the cleanup flipped...
Make Delete actually delete, and select exactly one pill
Delete did nothing. The handler was hung off the pill's focus, and the pill never had focus: preventDefault() in the pointerdown handler — which is there to sto...
Speed dial lists the org's department extensions
The tab shipped six invented entries — Sales Team on 1001, a Conference Room permanently ringing — so dialling one reached whatever happened to answer that exte...
Widen chat, social, ai-chat and compose windows to the support size
The support ticket window opens at 460px while member chat, social chat, AI chat and the email composer all sat at 360-420. Same dock, same kind of content — th...
Show unseen messages on every queue row, not just joined ones
The badge and the row tint were already here — they were simply never populated for most of the list. getUnreadFor read only the live per-session unread map, wh...
Delete, magnets, a right-click menu, and a clock that asks which
Six additions to the period graph and the nav clock. DELETE removes the focused pill. Backspace too, because on a Mac the key labelled "delete" IS Backspace an...
One Plans & Billing screen instead of two that each answered half
The platform had two billing screens. /settings/account?tab=billing answered what the organization pays; Plans & Billing on the member profile answered what a p...
Show the market onboarding panel when no CRM markets exist
/leads rendered the lead grid with an empty, disabled market tab bar for an org that had never configured a CRM market. It now shows the same onboarding panel /...
Open at the newest message, and scroll up for the rest
Opening a long conversation showed the oldest loaded message first and then travelled down to the present while the member waited. Both chat surfaces scrolled t...
The period graph, and a timecard you edit as a draft
Replaces the one-day timeline on **************** with a whole pay period, and changes what editing one feels like. The pills carry no text. They used to carry...
Raise a support conversation when somebody replies in it
Closing a support window is not leaving the conversation, but it was treated as if it were. ChatNotificationListener returned early on every SUPPORT_TICKET noti...
Linkable tabs, a working Add Member, and a full history tab
Every tab on /account/view/{id} is a real route now — /members, /history and the rest are links somebody can send, bookmark, or land on. Old ?tab= links redirec...
Confirm a clock in/out before writing the punch
The nav clock punched straight off the click. Every other control in that bar is idempotent or trivially undoable; a punch is a wage record that afterwards only...
One strip — filter and refresh beside the sub-tabs
The controls sat in a second full-width row under the tab strip holding three short words and an icon, spending a whole band of the pane on what fits in the spa...
Make the option strip yield the room instead of the clusters colliding
The left cluster carried minWidth: 0 while its contents (correctly) refuse to shrink or wrap, so a crowded bar shrank the box below its own content and the cont...
Segmented status filter in place of the select
Pending/Complete/All are three short peers that fit on one line, so a dropdown hid two of them behind a click and spent a label and a 170px well to say nothing....
Skeleton tracks the shared grid helpers; test jsonBody's 204 guard
The loading skeleton in app/hr/overview/page.tsx still hand-wrote the 1800px breakpoint that OverviewPillars and friends extracted into primitives.tsx (WIDE_BRE...
Follow the approval figure into currentPeriod, and stop null reading as zero
SecurityService 7c55054 moved awaitingApproval inside currentPeriod, where the window it describes actually is, and omits it entirely when there is no open peri...
Two-up figure rows so no card label wraps
The figure labels are Operator Labels — uppercase, 11px, 0.12em tracking — which puts "Execution incomplete" at 158px, "Blocking exceptions" at 150px and "Await...
Stop the fixed chrome labels breaking across two lines
A flex item's automatic minimum size is its min-content width, which for wrapping text is its widest word — so a crowded bar squeezed these controls narrow enou...
One glow on the clock icon, not two around the button
The rule carried BOTH a radial-gradient and a box-shadow. The gradient filled its own box while the box-shadow painted a separate ring outside it — two concentr...
Slide a crowded nav instead of crushing its options
Pinning more options than a nav can show squeezed the tiles out of shape: both strips were raw overflow boxes and the tiles are flex children with no flex-shrin...
Line the card figures up on a shared baseline
Every figure on the masthead and the four pillar cards was its own stacked box — Operator Label above, value below. Operator Labels are uppercase with 0.12em tr...
Withheld approval state renders as not-tracked, not clear
attendanceState() marked every member 'clear' whenever blockingExceptions was 0 and timecardState wasn't 'SUBMITTED' — true for every member under a caller lack...
AwaitingApproval is nullable, and null is not zero
SecurityService now withholds the approval half of the summary from a caller without FINALIZE_PAY_PERIODS — resolveRole never admitted MANAGE_TIMECARDS to appro...
Honest compliance figure, per-section failed states, right gating
The masthead percentage mixed units and could only flatter. `complete` summed org-wide ASSIGNMENT counts while `open` counted MEMBER-DOMAINS off memberRows, cap...
Derive overview pillar deep links from sub-tab id maps; kill dead textSecondary in activity rail
OverviewPillars.tsx hard-coded **************** instead of deriving them from **************** the way AttentionLedger.tsx already does — same name-indexed patt...
Build the Overview tab as a report over the other four
Full-width reporting console: masthead readout, four tab pillars, the needs-attention ledger, the workforce compliance matrix and an activity rail. Read-only — ...
Overview attention ledger, compliance matrix and activity rail
useMemberNames sources /api/security/members/names rather than the brief's guessed .../org-config shape: org-config never returns a member list (confirmed by re...
Strengthen hrOverview id-precision and attendance-state coverage
The precision test used a 15-digit memberId, which round-trips through Number() losslessly and never proved the join key stays a string. Switch to an id past Nu...
Overview data hook and shared visual primitives
useHrOverview fetches attendance + docs summaries with allSettled so one dead service degrades only its own sections; it skips fetches entirely for sections vis...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.