What's changed
0.6.0
2026-08-23Added
- Leads can be converted to a deal from the leads list itself, instead of only from the pipeline board
- Contact history on a lead: log calls, emails and meetings, and see what has already been tried
- Follow-up dates on leads, with a Needs chasing filter covering both overdue and never-scheduled
- Each lead now has its own page and link
- Disqualifying a lead now records why, using the same reason list deals use for losses. The reason is cleared if the lead is reopened
- Adding a lead warns if an open lead already exists for that company, with the option to add it anyway
- Deals created from a lead are now links through to the pipeline
- A lead's owner can be reassigned after creation, individually or in bulk
- Mine filter, row selection, and bulk reassign or reschedule across selected leads
- Contact history can be back-dated, so logging Fridays call on Monday records Friday
- IT can allocate a different licence than the one requested. The request records what was actually given, and shows it was a substitution
- Onboarding checklist on a person's profile in People, for HR and Operations Managers. Each item records who ticked it and when, and shows green when done or red when not
- The Timesheet Correction Form has its own place in the Timesheets menu, rather than sitting below the day's activity on the clock screen
- Clocking in asks where you are working from first, and will not start the day without an answer. The shortcut in the top bar asks the same question
- A day worked from more than one place is kept as a sequence — home in the morning, the office after lunch — with the time of each move and the address it was claimed from
- Daily sign-off shows where each day was worked, including any move part-way through
- Anyone working from home has to record a lunch before they can clock out. A lunch shorter than the minimum is flagged for Operations rather than refused
- The shortest lunch that does not get questioned is set in Admin, alongside the other timesheet thresholds
- Employees can see the org chart — colleagues and the management above them, never client contacts
- People has its own place in the main menu for HR Managers, Operations Managers and Administrators, with the pending sign-in queue alongside it
- My Team Schedule under Timesheets: anyone with direct reports on the org chart can see each report's expected hours and weekly working location
- My Team Attendance under Timesheets: a read-only fortnight of a report's clock-in, clock-out and worked-from location, covering only days Operations has signed off
- Operations Managers, HR Managers and Full Administrators can now open My Team Schedule and My Team Attendance for anyone on the active roster, not just their own direct reports — new 'My Team — See All Staff' permission, switchable per role and per user
- Scheduled jobs can be enabled or disabled individually, and given their own cadence — every X minutes/hours/days, or a one-off at a set time. The cron caller is now a tick; each job's stored schedule decides whether it runs
- Clock-in and clock-out reminders can be set to fire a chosen number of minutes before or after either the employee's expected start or their expected finish, using their own hours and timezone
- Leave suppression on the clock reminders is now a setting rather than fixed behaviour, with an optional extra for leave requests still awaiting approval
- Clock photographs now have a retention period, set in Admin to 30, 60, 90 or 365 days, or kept indefinitely. A daily job deletes expired photographs; the clock record, its time and its location are kept
- Clock photographs appear as small thumbnails in the timesheet review table, one per clock event, opening full size when clicked
- My Team Attendance shows the clock photograph for each day as a small thumbnail, opening full size when clicked. Managers can see the photographs of their own reports only
- Security headers on every response: HSTS, frame protection, referrer and permissions policy, plus a Content-Security-Policy in report-only mode ready to be switched on
- Sign-ins now last 3 days instead of 30, and the server refuses to start in production if secure cookies are not switched on
- The client portal sign-in and password reset are rate limited by IP address, which stops one password being tried against many accounts
- Approve and issue a licence in one action, instead of approving and then finding the same request again to hand it over. The licence can be swapped for a different one at the same moment
- View As is now reachable from the top bar, for administrators, without going to Admin first
- Every section has the same side navigation, including Reports and Policies, which list their entries there
- Org chart is a proper chart: cards with a photo, title, country flag, every client the person is placed with, and an email button. It opens on your own reporting line, and drags and zooms rather than scrolling
- My Team Schedule shows everybody on one page, a small table each, in Philippine time
- My Team Attendance records the lunch break taken, also in Philippine time
- Scheduled reports: a weekly digest emails the standard reports as CSV attachments to Full Administrators, HR Managers and Operations Managers. Each person receives only the reports they already have permission to open, so the contents differ by recipient. Cadence and on/off are configurable like any other job
- Operations Managers can now work the offboarding checklist and clear a leaver, not only sign for returned equipment
- The offboarding checklist lists the equipment and licence seats a leaver still holds, by name, rather than only counting them. The IT return step still cannot be ticked by hand and clearance still gates final pay
- Tests for the login throttle and the scheduled report distribution, including a guard that fails if payroll figures are ever added back to HR's weekly email
- Wise payment export: a pay run can be downloaded as a payment file for upload to Wise, replacing the retyping of bank details into a payment system. Restricted to the Payment Export permission and audited with what the file contained
- Wise is now configurable in Admin → Integrations — API token, sandbox or live, and a test button that lists the profiles the token can act for. The export works whether or not the API is connected
- The payment file is now on the Payroll screen. Open a pay run, prepare the file, and you see who will be paid, who will not and why, and the totals per currency before downloading anything
- npm run db:payroll-demo creates a small payable workforce — salaries, encrypted bank details in two currencies, and signed-off acknowledged timesheets — so a pay run and its payment file can be exercised end to end. Removable with --wipe
- Leave now accrues automatically on the first of each month for the month just ended: one vacation day a month and five sick days a year. Nothing accrues during probation, and a part month is prorated by days worked, so unpaid leave reduces what is earned
- Every accrual is recorded with the working days, days worked and the reason, so any balance can be explained months later rather than taken on trust
- Leave types for Solo Parent, VAWC, Magna Carta, maternity, paternity, miscarriage, bereavement and emergency leave. Emergency leave draws down the vacation balance while staying its own label, so the business can see how often it happens
- Probation settings: a default length in Admin, overridable per person, with the option of no probation at all
- Probation on a person's profile, for HR and Operations: start date, end date, length, outcome and how many days remain — alongside a plain statement that no leave accrues until they are regularised
- Leave requests now go through three approvals in order: Client Manager, then Operations Manager, then HR. Internal staff with no Client Manager start at Operations. A decline at any stage ends it, and the balance only moves when HR gives the final approval
- Because Client Managers are client-side contacts without Sortr logins, Operations records their decision and it is stamped with whose decision it was, rather than appearing as an Operations approval
- Every approver sees whether a request would take the employee's balance below zero, from the first stage rather than the last
- Admin → Leave Settings: probation length, the yearly vacation and sick entitlements, whether a balance may go into deficit and how far, and who needs Client Manager approval
- npm run db:leave-demo sets realistic start dates — two people inside probation, the rest with ten months to two years of service — and backfills the accruals month by month through the real engine
- The leave screen offers all twelve leave types, states who has to approve your request, and can show the month-by-month working behind your balance — including why a month credited nothing
- The approval queue shows only what you can act on, with the days requested, what it leaves the balance at, and what has already been agreed further up the chain
- Invoicing: build a client's monthly invoice from their rate cards, review the working line by line, approve it, and send it to Xero as a draft
- Xero setup under Admin → Integrations: account code, tax type and payment terms, with sending refused until they are set
- Wise setup under Admin → Integrations: environment, API token, business profile and source currency, with a connection test that lists the profiles a token can act for and moves no money
- Employee Handbook in Policies, published and requiring acknowledgement
- Daily sign-off and the period review now show worked and break time at each place a day was worked from, so a day split between home and the office reports both
Changed
- Leads list defaults to open leads, is searchable, and orders by soonest follow-up. Phone numbers are now shown and dialable
- The licence picker shows free seats per licence and greys out ones that are full or already held, rather than failing on click
- The joiner checklist now follows the twelve-item process, grouped into document issuance, items needing signature before the start date, and orientation
- Daily sign-off is laid out in columns, with a column of its own for the client. Below a wide screen each day becomes a labelled card instead of squeezing
- Menu items are hidden when there is nothing inside them you can open, instead of leading to a page that refuses you
- An approved equipment request now says it is waiting for IT to issue it, and My Items says how many are waiting. Approval and handover were always separate steps, but nothing said so
- The Help page lists HR Managers and Operations Managers, and nobody else
- Employees no longer have the Policies area while the handbook is unpublished, and onboarding no longer asks anyone to confirm they have read something they cannot open
- Employees can no longer export their assigned IT items to a file. The screen is still theirs to read
- Viewing as another user is limited to Administrators. It briefly reached HR and Operations when People moved to the main menu
- Onboarding checklist now sits beside the profile as a pinned right-hand panel rather than a block above it, so the list stays in view while you work down the person's details
- Daily sign-off shows the clock photograph in its own column, immediately after the tick box and before the employee name, instead of buried in the day's detail line. Every column in that view now has a name
- Updated the email library to close six known flaws, including one that let a crafted name inject mail headers
- Developer documentation brought up to date: CLAUDE.md described the project as an empty scaffold with no module features, README.md was still the create-next-app template, and the handover brief listed six roles, Azure hosting and Azure Key Vault. All three now match what has actually been built
- The remaining project documents brought up to date: the deployment plan no longer argues for a host that was not chosen, the backlog records this month's work and tracks the four open security items, the spec no longer calls the Client Portal a future phase, and the design spec's colour table matches what actually renders
- Roles are all on one page now, each expandable, so two roles can be compared without loading them one at a time
- Timesheet Settings, Integrations and the Scheduled Jobs run history collapse to their headings and open when needed
- The clock in the top bar is a single button showing the one thing to do next — Clock In, then Start Lunch and End Lunch on a day worked from home, then Clock Out — and clocking in no longer means leaving the page
- Policies are laid out as tiles across the full width
- Taking an asset off somebody now asks first, naming who holds it and recording why it moved. It used to happen silently and the previous holder was never told
- Offboarding withdraws equipment requests that were still waiting to be handed over, and nothing can be issued to somebody who has left
- The scheduled report digest no longer emails payroll figures to HR. Salary goes to Full Administrators only; HR keep their in-app access to it
- The default probation length is now six months and is set in Admin rather than fixed in the code, because it decides when someone starts earning leave
- Sick leave now lands on exactly five days a year. Each month was rounded on its own, which turned five twelfths into 5.04 across a year; the credit is now the difference between running totals, so a month may vary by a hundredth and the year is exact
- Client Manager approval is off by default and switched on per person in Admin. It cannot be switched on for somebody with no Client Manager assigned, which would park their leave on an approver who does not exist
- The dashboard drops the Today tile, which repeated what Hours Today already showed, and the sick and emergency leave balance tiles. Your working week becomes a normal tile beside Hours Today, the shortcuts move up under the first row, and the calendar takes half the width on a wide screen
- Dashboard tiles now share one definition of their padding, corner and shadow, so a row reads as one set of cards rather than two. Every tile in a row is the same height at any screen width, and the Hours Today tile no longer forces a fixed height on the row it sits in
- Every tile on the dashboard now labels itself the same way, as a small caps title that sits back and lets the figure lead. Fixed the underlying cause too: section headings across the platform were quietly rendering at page-title size no matter what size they asked for, so card and panel headings throughout are now the size they were written to be
- Working hours are Philippine time. The standard day is 09:00–17:00 Asia/Manila, and the two Australian staff carry their own hours instead of the default being wrong for everyone else
- A day with no clock-out cannot be approved for payment. Operations applies a time correction with the finish time first, and until then the day is marked Not logged: clock-out
Fixed
- Leads list no longer sorts converted and disqualified above the open ones you can act on
- Leads and pipeline permissions are now checked separately, so access to one no longer silently depends on holding the other
- A disqualified lead can be reopened. Previously the controls only rendered while a lead was open, so a misclick was permanent
- Lead activity now reads the timeline format correctly, so logged contact shows its subject instead of a blank row
- Operations Managers can now see and complete onboarding, which previously required an HR Manager role
- Five migrations had a date but no time, which sorts them after every timestamped migration from the same day. On a new database one of them altered a table another had not created yet, so the first deploy to a fresh environment would have failed
- Test accounts left behind by an interrupted test run appeared as real people on the Help page and in the staff org chart
- My Team Schedule read 'the person who report to you' for a manager with a single report
- My Team Schedule and My Team Attendance were invisible to HR Managers, Operations Managers and Full Administrators who happened to sit on nobody's reporting line
- The Scheduled Jobs screen reported that the scheduler was disabled and JOBS_SECRET unset whenever the page failed to load, regardless of the real cause. A failed load now says what went wrong and offers a retry, rather than describing the system from its own defaults
- The clock-in camera turned on but showed no picture, and Take photo did nothing. The video element is only rendered once the camera is live, so the stream was being handed to an element that did not exist yet; it is now attached after the element mounts, and the shutter waits for the first frame instead of ignoring the click
- The recorded IP address for sign-ins, clock events and geofencing came from a header anyone could set. It now comes only from the hosting platform, and records nothing rather than something forgeable
- A part-signed return form is no longer stranded when the item is passed to somebody else. It is closed with a reason, instead of showing for ever as an outstanding return against a person who no longer has the item
- Two people issuing the last seat on a licence at the same moment can no longer both succeed
- What was actually issued against a request is now readable in one query, so a substitution can be shown on screen rather than only found in the database
- Pages load faster: the shell fetches what it needs at once rather than one thing after another, the daily sign-off no longer asks the database for the same figure once per employee, and repeated permission checks within a page are resolved once
- The Timesheet Submission and Timesheet Calendar reports were gated on the Operations sign-off permission, so HR Managers could not open the two reports they need to close a payroll period. They now use the see-all-timesheets permission HR already holds
- Leave requests that were already pending when the approval chain arrived were left waiting on a Client Manager stage that is off by default, so they could never be cleared. They now sit at the stage that applies to them
- Emergency leave showed a permanent zero-day balance card of its own, though it draws down vacation
- An HR or Operations Manager could grant Full Administrator to anyone, including themselves. Granting it now takes an administrator, and nobody can change their own roles
- Job title, department, office location and timezone were accepted on a person's record, reported as saved, and silently discarded — so anyone who did not arrive through Microsoft sign-in could never have them set
- Someone working from home who took their lunch could be refused a clock-out and told to record the lunch they had just recorded
- A lunch under half a minute counted as no lunch at all, so a full day worked from home with no real break could read as clean
- Tapping a clock button twice recorded the action twice. The first tap now wins and the second is turned away
- Two people clocking in at the same moment could produce a server error instead of a clock-in
- Working a Saturday was scored against a full weekday and flagged as finishing early
- A short lunch and a missing photograph were shown on daily sign-off but not on the period review HR signs off, so a fortnight could be acknowledged without them ever appearing
- Screens that offered yesterday or today worked it out in UTC, so anyone in Australia opening them before mid-morning was shown the wrong day. This affected the daily sign-off date, a work calendar's start date, and the invoicing month list
- A malformed request returned a server error with an empty response on most of the API rather than saying what was wrong
0.5.1
2026-08-19Changed
- Page titles now render at the 32px specified by the design, instead of 20px — 63 headings across 59 screens
Fixed
- Schema now declares the sign-off and correction-resolution indexes it was silently missing, so migrations stop proposing to drop two indexes the queues rely on
0.5.0
2026-08-19Added
- Microsoft Entra ID sign-in can now be configured in Admin, Integrations, instead of only through environment variables. The client secret is stored encrypted and never sent to the browser
Changed
- Entra credentials are read database-first with the environment as fallback, so the app registration can be changed or rotated without a redeploy
0.4.0
2026-08-19Added
- Version badge shows a +N marker when changes are recorded but not yet released
Changed
- Recording a change and cutting a version are now separate steps: npm run changelog files it under Unreleased, npm run release closes off a version number
- Release type (patch, minor, major) is now inferred from the accumulated entries instead of guessed per session
0.3.0
2026-08-19Added
- Changelog entries are now prompted automatically: edits to src or prisma are recorded, and at the end of a session Claude is asked to summarise them and cut a release
Changed
- Version badge no longer prefetches the changelog page from every screen
0.2.0
2026-08-17Added
- Version number in the bottom-left corner of every screen, linking to the changelog
- Changelog page at /changelog, readable without signing in
- npm run release, which bumps the version and records the change in one step
0.1.0
2026-08-06Added
- Initial platform: user and role management with a permission engine, clients and rate