<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>BookYourPTO Changelog</title>
    <link>https://changelog.bookyourpto.com</link>
    <description>The latest changes, improvements, and bug fixes in BookYourPTO.</description>
    <language>en</language>
    <atom:link href="https://changelog.bookyourpto.com/rss.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>v1.1.2</title>
      <link>https://changelog.bookyourpto.com/releases/v1.1.2</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.1.2</guid>
      <pubDate>Thu, 01 Oct 2026 20:15:42 GMT</pubDate>
      <description>## Highlights

### Home — the page you land on after signing in

Signing in used to drop you on the Dashboard, a calendar grid built for planning team coverage.
It answers &quot;who is off when&quot; well and almost nothing else, so anything waiting on you personally
lived behind a sidebar entry you had to think to visit.

**Home** is now the landing page. It gathers what needs you, your own records, and — for people
who manage or administer — their team and the organization. The Dashboard is unchanged and still
in the sidebar; nothing was taken out of it.

What appears depends on your role, on whether anyone reports to you, and on which modules the
organization has switched on:

| Card | Who sees it |
| --- | --- |
| **Action Required** — documents awaiting your signature, assessments you owe somebody, onboarding tasks and training past their date, expired certifications | Everyone. Cannot be switched off |
| **Waiting on You** — leave, expense and time requests routed to you | Anyone requests are routed to |
| **Time Off** — your balances and your next booked leave | Everyone |
| **Today&apos;s Hours** — hours logged today and whether you are clocked in | When time tracking is on |
| **Next 1:1** — who you next speak to, and when | Everyone |
| **My Stuff** — goals, training, certifications, benefits and equipment | Everyone |
| **Who&apos;s Out** — who is away today, plus upcoming public holidays on your own calendar | Everyone |
| **Celebrations** — birthdays and work anniversaries over the next two weeks | Everyone |
| **What&apos;s Happening** — recent updates about your requests and documents | Everyone |
| **Probation Reviews** — reviews falling in the next two weeks | The employee, their manager, their department head, administrators and executives |
| **My Team** — your people, who is away, and when you next speak to each | Anyone with reports, by org chart rather than by role |
| **Onboarding** — onboarding and offboarding still running | Administrators, executives, and department heads for their own department |
| **Headcount**, **Review Cycles**, **Needs Attention** | Administrators and executives |

Every row links to the page that shows exactly what it counts, so a count and the page behind it
cannot disagree.

### Arrange the board yourself

**Customise** turns the board into the editor. Each card gains a grip and a **&amp;times;** on its
corners, and an **Add cards** tray appears along the bottom. Drag a card to move it and the rest
close up around it; arrow keys move the focused card too, so the board can be arranged without a
mouse. Nothing is saved until you select Save, and Cancel puts it back.

The tray is not only the cards you have removed. There is a library of optional cards that start
switched off, so Home does not open with twenty at once:

- **Company Holidays** — the next public holidays on your own calendar.
- **Workforce Mix** — headcount by division, work location or employment type.
- **Length of Service** — how long people have been with the organization.
- **Profile Completeness** — records missing a start date, department, job title, date of birth or
  mobile number, the fields leave accrual, approval routing and reminders depend on.

The last three are for administrators and executives. Each tile shows the card&apos;s own icon, so the
tray says what you are about to add. Your layout is stored on your account rather than in the
browser, so it follows you to another device, and a card added to the product later appears next
to the cards it belongs with rather than at the bottom of a board you already arranged.

Switching a card off changes only what you see. It grants no access, and every endpoint behind a
card still checks permission for itself.

### Nothing on the Dashboard is missing from Home

Everything the Dashboard surfaces now has a home on the new page: upcoming absences for the next
fortnight, upcoming public holidays resolved per person rather than per organization, and
probation reviews. Probation visibility follows the same rule the Dashboard uses — self, their
manager, their department head, administrators and executives — and that rule now lives in one
place both pages read rather than being written out twice.

### The org chart follows Reports To

The org chart was drawn from **roles**, not from the reporting structure. Department heads were
handed to administrators round-robin and administrators to executives the same way, so the lines
it drew were invented: the third person in a list reported to the first administrator purely
because of their index. Anyone reading it as a reporting structure was being misled, and the
**Reports To** field people had carefully filled in was ignored.

It is now built from Reports To and from nothing else:

- An executive is no longer automatically at the top. If an executive reports to somebody — a
  founder, a board, a parent company — they appear beneath them. Role now affects only the order
  the top-level people are listed in.
- Anyone who reports to nobody is a top-level person, so a chart can have several.
- Somebody whose manager is deactivated, somebody recorded as their own manager, and a reporting
  loop each surface at the top rather than vanishing, so the record that needs fixing is visible.

**Export** on the chart offers a PNG of the chart as drawn, the same image as a PDF, and a `.csv`
shaped for Visio, for Lucidchart, or unformatted for a spreadsheet. The files are built from the
same Reports To field, so a download and the chart always agree.

Who can download is set separately from who can browse, under **Download Access** in Company
Directory settings. It defaults to all employees. Somebody who cannot view the chart can never
download it, whichever option is chosen — export can be narrower than viewing but never wider.

---

## Improvements

- **The New menu** — starts the things you can start: a time off request, an expense report, a
  time entry, an employee, a signature request, a report. Entries appear only for actions you have
  permission to complete, and each opens the form rather than merely landing you on the page.
- **&quot;Other departments: Hidden&quot; is honoured** — with that setting on, Who&apos;s Out and Celebrations
  are limited to a non-administrator&apos;s own department, matching the Dashboard. Administrators and
  executives are exempt, as the setting says.
- **Private leave types** read as &quot;Private&quot; to anyone not entitled to the detail, through the same
  helper the calendar and the digest emails use.
- **Who&apos;s Out sends only what it draws** — a name, a date range and a leave type. The reason
  somebody gave for being off, their notes and any approver comment stay on the server.
- **Onboarding and offboarding runs follow the existing rule** — administrators, executives, and a
  department head for their own department. Having somebody report to you is not enough: that a
  colleague is being offboarded is not something their reporting line should learn from a card.
- **Compensation and demographic breakdowns were considered and left out.** Pay figures do not
  belong on a landing page, and a demographic split over a small team identifies individuals.
- **Balance visibility follows the organization setting** — the Time Off card respects the calendar
  balance-display choice in General settings, so an organization that hides the sick bucket does
  not have it reappear on Home.
- **Deep links into create forms** — `?new=1` on the calendar, expenses and users pages opens the
  create form on arrival and then clears itself from the URL, so a refresh or a shared link does
  not reopen it.
- **One landing route** — where a signed-in session begins is now a single constant rather than a
  literal repeated across eight files, so a password sign-in, a Google sign-in, email verification
  and the end of first-run setup cannot land people in different places. Permission-denied
  redirects deliberately still go to the Dashboard: where a session starts and where somebody is
  bounced to are different decisions.
- **A guided tour for Home**, replayable from Settings → Guided Tours.
- **Expenses and Documents cards.** **My Expenses** shows your own claims by where they have got
  to — drafts, awaiting approval, approved but unpaid, sent back — with what the organization still
  owes you, and appears only when the expenses module is switched on. **My Documents** shows what is
  waiting on your signature, what is expiring, and what is waiting on somebody ahead of you in a
  signing order. Both link straight to the filtered list.
- **The first-run setup checklist has moved to Home.** It was on the Dashboard, which is no longer
  where a signed-in session lands, so an administrator who had just created an organization had to
  navigate away from their landing page to find the one thing asking them to finish setting it up.
  It still shows only to administrators and executives, and still disappears once dismissed or
  completed.
- **Four more cards for the Home tray.** **Leave Balance** gives the full picture the calendar
  sidebar shows — allowance, carry-over, used and remaining per bucket, with a bar for each.
  **Deductible Leave** and **Non-deductible Leave** split the per-type breakdown into two cards,
  because &quot;what has my allowance gone on&quot; and &quot;what have I taken that costs me nothing&quot; are
  different questions. Leave Balance follows the organization&apos;s Calendar Balance Display setting,
  so a bucket hidden on the calendar stays hidden here; the two breakdown cards list exactly what
  the calendar&apos;s Deductible and Non-deductible lists show.
- **Organization Time**, for anyone whose own timezone differs from the organization&apos;s: both
  clocks side by side with how far apart they are right now, computed from the actual instant so it
  stays right across daylight saving. It is not offered at all when the two match — a second clock
  showing the same time is noise.
- **Home respects the Time Tracking &amp; Projects switch.** With the module off, Today&apos;s Hours no
  longer appears and cannot be added from the tray, and the approvals card drops its Time entries
  row and leaves those requests out of its total. The page now reads the organization&apos;s switch
  directly rather than inferring it from whether a clock request happened to succeed.
- **Download Access** — a new Company Directory setting controlling who can export the org chart,
  independent of who can browse it. An export is a roster in a file: it leaves the product,
  outlives the session, and forwards like any other attachment.
- **Employee # is now an optional column on the People list**, switched off by default and offered
  to administrators and executives. It used to be on for everyone and blank for everyone: the page
  reads the directory view of each person, which carried the employee number for nobody, so the
  column took width from the name and job title beside it and showed a dash. The directory view now
  carries the number for those two roles, which is what makes the column work at all. Employee
  numbers remain searchable for everyone, and still appear on the profile.
- **Home names what it counts.** The My Expenses and My Documents cards used to give a status
  and a number — &quot;Awaiting approval: 1&quot; — and leave you to open the list to find out which.
  Each row now names the most recent reports or documents under it, each opening the record
  itself, with &quot;and N more&quot; when there are others. A document waiting on your signature opens
  straight into signing.
- **Who&apos;s Out says who.** The Coming up list read &quot;1 person away&quot; against each day. It now lists
  the people whose time off begins that day, with their photo and the type of leave, drawn the
  same way as the people out today. Private leave types still read as &quot;Private&quot; to anyone not
  entitled to the detail, and nothing beyond a name, a date and a leave type leaves the server.
- **Work anniversaries name the organization.** Celebrations read &quot;2 years with the team&quot;; it now
  reads &quot;2 years with&quot; followed by the organization&apos;s name, falling back to &quot;the team&quot; only when
  the organization has no name set.

---

## Bug fixes

- **A failed load printed the server&apos;s error.** When a database query failed, that meant the full
  column list of the `User` table — every field name, including the sensitive ones — rendered on
  the landing page in place of an explanation. Home now shows one neutral line and writes the real
  failure to the console, and the three endpoints behind it replace any unexpected error with a
  clean refusal before it leaves the server. Deliberate refusals (not signed in, not permitted)
  still say what they mean.
- **A department head with no department could see probation data** for every employee who also had
  no department, because the two empty values matched each other. Both sides must now be set for
  the department rule to apply.
- **Celebrations could never show a photo.** Birthdays and work anniversaries drew a cake or a medal
  where the person&apos;s face belongs, and the query behind the card fetched neither the photo nor the
  person&apos;s id, so no amount of styling could have fixed it. The card now shows profile photos,
  keeping the colour that distinguishes a birthday from an anniversary as a ring and moving the
  glyph to a corner badge. People without a photo still show their initials.
- **Cards were invisible in dark mode** — they were painted with the page background. They now use
  the same card surface and border treatment as the calendar and profile pages.
- **The board collapsed into a single column while editing.** The corner controls were positioned to
  overhang each card, and a control that overflows its column makes the browser abandon column
  balancing for the whole board. Cards now keep an identical layout whether or not you are editing.
- **A heading repeated the card beneath it.** The board was split by section headings, one reading
  *My Team* directly above a card whose own header also read *My Team*, and one announcing the
  organization&apos;s name to the only person who already knew it. The board is now one continuous run
  of cards, flowing in columns so a short card sits under a tall one instead of leaving a gap.
- **Three cards could render as an empty box** — a header and a border with nothing in them — when
  the section they summarised had no entries. They are now left out until they have something to
  say. Action Required still says so when you are clear, which is the point of that card.
- **The org chart invented reporting lines** — see the highlight above. It is now built from the
  Reports To field rather than from roles.
- **The org chart could not be exported at all.** It now downloads as a PNG, a PDF or one of three
  CSV shapes.
- **Everyone could see everyone&apos;s work anniversary.** The dashboard sent each colleague&apos;s hire date
  to every viewer, so the whole organization saw the whole organization&apos;s anniversaries — and a
  department head saw into departments they have no part in. The daily and weekly digests mailed
  them just as widely. A work anniversary is derived from the hire date, which is employment
  information: it reveals tenure, relative seniority and who is new.

  It is now limited to the employee themselves, their manager, their department head and
  administrators and executives, on the dashboard, on Home and in both digests. Birthdays are
  unchanged — they carry no employment information and the year is never sent.
- **Security advisories cleared** in axios, @grpc/grpc-js, devalue and dompurify. `npm audit` reports
  no vulnerabilities.
- **The greeting and the date came from different clocks.** &quot;Good afternoon&quot; was read from the
  browser while the date beside it was resolved in the viewer&apos;s own timezone, so somebody whose
  profile says Asia/Calcutta reading from Vancouver could be greeted for an afternoon that, by the
  date in the same sentence, had already ended. Both now use the viewer&apos;s timezone.
- **The monthly anniversary email ignored its own rule.** It narrowed to a department only when the
  recipient was a department head *with* a department assigned; a head who had not been given one
  yet fell through the condition and was mailed every anniversary in the organization. It now uses
  the same rule as the dashboard, Home and the digests, and so also reaches a head&apos;s direct reports
  outside their department, which it previously missed.
- **An onboarding task assigned to you opened your own profile.** Action Required linked every
  onboarding task to your own Onboarding tab, but a task assigned to you is usually part of
  somebody else&apos;s onboarding and lives on their profile — so the link opened an empty tab. The
  card now lists one row per person, named, opening the Onboarding or Offboarding tab on their
  profile, which is where the onboarding notifications already pointed.
- **Time Off disagreed with the calendar.** The card read each leave type&apos;s default allowance and
  ignored the person&apos;s own allowance and anything carried over, so somebody with 15 days plus 5
  carried and 20 used saw &quot;-10, 10 over allowance&quot; on Home and 0 remaining on their calendar. It
  now shows the Annual and Sick balances the calendar shows, from the same figures.
- **My Documents counted a different set from the page it links to.** &quot;N in total&quot; counted every
  signature request ever sent to you, while All documents opens your folder, which lists the
  documents filed to you. The two now share one definition of what a folder holds, so the number
  in the header is the number of documents you find when you follow the link.
- **Non-deductible Leave on Home was always empty.** The card looked for non-deductible types
  among the deductible ones, where by definition there are none, so it said &quot;No non-deductible
  leave yet&quot; to everybody. It now lists the same types and days as the calendar&apos;s
  Non-deductible leave panel.
- **Deductible Leave on Home left out some leave.** A type that draws down a balance without an
  allowance of its own — Sick Leave - Paid, typically — was dropped, so the card could read 20
  days where the calendar read 22. It was also narrowed by the Calendar Balance Display setting,
  which the calendar&apos;s own list does not apply, so an organization showing only the annual balance
  lost its sick leave from the card. It now lists every deductible type with days taken, in the
  calendar&apos;s order, with each type&apos;s own icon, and shows a capped non-deductible type as
  &quot;6 / 5 days&quot; as the calendar does.</description>
    </item>
    <item>
      <title>v1.1.1</title>
      <link>https://changelog.bookyourpto.com/releases/v1.1.1</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.1.1</guid>
      <pubDate>Wed, 30 Sep 2026 19:03:27 GMT</pubDate>
      <description>### Review cycles that actually run, 1:1s with a time and a calendar entry, and a clear answer to who sets performance up

Performance has been rebuilt around a simple split: a **review cycle** says when reviews fall
due and who they cover, a **1:1** is the conversation itself, and the two can be linked so a
review is something worked towards rather than an event that arrives.

The largest change is that review cycles now do something. A cycle was a name and a pair of
dates: the scope section on the form was never saved, so a department-wide cycle came out
covering everyone, and every cycle ever created was stuck in Draft because nothing in the
product could open it. Cycles now run on either a shared window or each employee&apos;s own hire
anniversary, cover everyone or one department or a chosen list, and send reminders to the people
responsible for holding the review.

1:1s gained a time, a duration and a place in the participants&apos; real calendars, and a 1:1
arranged by an administrator now pairs the right two people — previously it paired the
administrator with whoever&apos;s profile they were standing on.

Alongside those: performance is now something an organization runs for its people rather than
something people set up for themselves, destructive actions ask before they act, and several
dates that shifted a day west of UTC have been fixed.

### Review cycles

- **A cycle can follow each employee&apos;s hire date** — Annual meant two different things depending
  on who set it up: a company-wide window, or a review on each person&apos;s own anniversary. One
  pair of date columns could not express the second at all. A cycle now chooses between
  **specific dates** — one window for everyone in scope — and **employee hire date**, measured
  from each person&apos;s own start date with no shared window.

- **A hire-date cycle is not only the one-year mark** — It says how far after the start date the
  review falls and whether it recurs: every year on the anniversary, once N months in, or every
  N months. Without that, a cycle named &quot;3 Months Probation&quot; would have reminded on the
  employee&apos;s first anniversary. A 29 February start is reviewed on 28 February in years that
  have no 29th, and a 31st is held to the last day of a shorter month rather than spilling into
  the next one.

  This does not replace the probation review on a profile, which keeps its own period, its
  extension date and its own reminders.

- **The Type field is gone** — Annual, Semi-annual, Quarterly, Probation and Custom were a label
  no code ever read. It implied a schedule it did not set: &quot;Probation&quot; connected to none of the
  probation machinery, and &quot;Custom&quot; offered nothing to customise. The schedule now says what the
  cycle is, and the name says what to call it.

- **The scope you choose is the scope that is saved** — The form had department and employee
  pickers and the endpoint discarded every one of those fields, so an administrator could
  configure a department-wide cycle, watch it save, and get a row covering the whole company.
  There was no column to record a department in. Scope is now stored, the department is checked
  against the caller&apos;s own organization, and the list shows how many people each cycle currently
  covers, so a department that has been emptied does not read the same as one with thirty people
  in it.

- **A new cycle is running, not stuck in Draft** — The create endpoint ignored the status
  entirely, so every cycle fell through to Draft, and no control anywhere could move it out. A
  cycle is now created Active, and Status is a switch on the form: **Active** sends reminders,
  **Draft** sends nothing.

- **&quot;Completed&quot; is gone, and &quot;Ended&quot; is worked out from the dates** — Completed was a third state
  that no code ever set and no administrator remembered to. Whether a review is finished is a
  fact about one person&apos;s assessment, not about the cycle. A cycle whose end date has passed now
  reads as **Ended** without anyone marking it, and sends nothing further.

- **The question-set picker has been removed** — It stored a preference that nothing ever read.

### Reminders

- **Reviews are now chased at all** — A cycle creates no forms and assigns no assessors, so
  without a reminder it was a row nobody ever heard about. A daily job now sends them, and it is
  scheduled in both deployment files in the same change — every reminder endpoint in this product
  had previously been written, tested and merged while no scheduler ever invoked it.

- **Two reminders by default, and as many as you want** — 14 days ahead, when there is still time
  to arrange something, and 3 days ahead, when it has to be done. One reminder is either too
  early to act on or too late to prepare for. Administrators can choose 30 days, a week, a day,
  the day itself, or any other number, up to six per cycle.

- **Setting a cycle up late still produces one timely reminder** — Configuring a hire-date cycle
  two days before somebody&apos;s anniversary means both the 14-day and 3-day marks have already
  passed. Sending nothing would lose the reminder entirely, and sending both would deliver two
  emails at once, one of them claiming the review is a fortnight away. Only the most recent
  milestone that has come due is sent, and it counts the days from the real dates.

- **Reminders reach the people who have to act** — The employee&apos;s department head, plus
  executives and administrators. Where a department has no head, the employee&apos;s manager is
  reminded instead, so two people are not each left assuming the other owns it. The employee is
  not reminded about their own review; anyone matching several of these receives one email rather
  than one per role.

- **1:1 reminders go out a week ahead, the day before, and on the day** — A single reminder the
  evening before is too late to prepare for and too late to move.

### 1:1 meetings

- **A 1:1 has a time and a duration** — Previously only a date, which meant nothing could be put
  in a calendar. The time is a wall-clock time in the organization&apos;s timezone, so a recurring 1:1
  stays at the same hour across a daylight-saving change. Thirty minutes by default, changeable.

- **The meeting appears in Google Calendar and Outlook** — One event with both people invited as
  attendees, so it can be accepted or declined like any other invitation, rather than two
  disconnected copies that cannot be declined at all. Cancelling a meeting, or deleting the
  series, removes the invitation from the calendars it reached — the cancellation email already
  said it had.

- **A 1:1 arranged for somebody pairs the right two people** — The series was always built as
  &quot;whoever is signed in&quot; and the person selected. An administrator standing on an employee&apos;s
  profile is arranging a 1:1 **for** that employee, not with them, so every 1:1 set up on
  somebody&apos;s behalf paired the administrator with the employee and left out the manager who was
  meant to hold it. Left on the default, the other participant is now the employee&apos;s department
  head, or their manager if the department has no head.

- **Everyone with a stake is told** — Both attendees, whoever arranged it, and the employee&apos;s
  manager. It previously notified only &quot;the other participant&quot;, so one attendee received nothing
  and the arranger received nothing either.

- **A 1:1 can say which review it is preparing for** — Choosing a running cycle marks the
  conversation as preparation for that review, and the list shows which one. A review
  conversation happens once, so choosing a cycle makes the meeting a single occurrence rather
  than a series.

- **The list says when the next one is** — Rows named a person and a cadence and left the obvious
  question unanswered. They now read as a date and a time, with the end time too, since a
  calendar entry without a finish cannot be checked for clashes.

- **A 1:1 is visible to the people with a reason to see it** — Its two participants,
  administrators and executives, the employee&apos;s manager, and the head of their department.
  Private notes stay visible only to whoever wrote them.

### Seeing your own schedule

- **A profile now says when the next review is due** — A review cycle records no assessment until
  one is written, so nothing about it reached the person it covered: an administrator could set up
  a cycle across the whole company and every profile still read &quot;Not in a review cycle&quot;. The
  schedule existed only in Settings and in the reminder emails leadership received.

  The Reviews tab now opens with **Coming up** — the cycles covering that person and the date each
  one falls due, worked out from their own start date for a hire-date cycle or from the window for
  a fixed one. Recorded assessments follow underneath.

  Only running cycles appear, and only where the scope covers the person. A closed window, a
  one-off milestone that has passed, and anyone with no start date on file are left out rather
  than shown as overdue.

### Recording a review

- **A review can be marked complete** — The Coming up list said when a review was due and
  offered nothing to do about it. Opening one now records that it happened, who recorded it and
  when. Reopening clears that stamp, so the record never claims a completion that was undone.

- **Notes, with three levels of visibility** — A note on a review says who may read it, named by
  the roles the product actually has: **Employee and above**, **Department Head and above**, or
  **Administrator and Executive only**. Each level is readable by everyone above it, and the
  author always sees their own. Hovering a level spells the roles out in full.

  Administrator and Executive only is how something is kept from a department head as well as
  from the employee. A department head writes at the first two levels for their own department,
  and cannot write a note their own leadership could not read.

  Visibility is stored as a level rather than a list of people, so it stays correct when somebody
  changes department or is promoted — a note written for &quot;managers&quot; is readable by whoever heads
  that person&apos;s department today.

- **A Review mode on the upload page** — A third way to send, beside Upload to folder and
  Send for signature. It asks in the order the work happens: the review cycle, the document,
  the people who sign, and then which of them is being reviewed. The document is then openable
  from that person&apos;s Performance tab instead of being hunted for in the documents list.

  The first attempt put a single picker inside the Recipients panel listing every recipient
  crossed with every review they had — &quot;Aiden Ramirez — FY26 Annual Review — Aug 24, 2026&quot; and
  five more lines like it. That list grows multiplicatively, it put the review after the people
  it depends on, and the part that identifies the document, the cycle, was the part repeated
  rather than the part chosen. A review is a cycle plus a person, so those are now two separate
  questions and there is no combined list at all.

  Only cycles that are running are offered, and every review the person is scheduled for counts
  — a cycle&apos;s dates are derived, so an active cycle covering somebody is a real review with
  nothing stored against it yet. Offering only already-recorded ones left the list empty for
  almost everybody. The record is created as the document is sent. A cycle that does not cover
  the chosen person says so in words rather than going blank.

- **The employee owns the review document, whoever signs first** — A review form is routinely
  countersigned by the department head and then the employee. The document used to belong to
  whoever was added as the first recipient, so listing the manager first put the form on the
  manager&apos;s profile and then refused the upload outright, because the review belongs to the
  employee. Whose review it is and who signs in what order are now separate questions: the
  employee owns it either way, and the signing order is yours to set as on any other document.

  With a single recipient there is nothing to decide and the answer fills itself in. Adding a
  second clears it rather than leaving the first person marked — which is precisely how a
  manager would otherwise end up recorded as the subject of their own report&apos;s review.

- **A review exists only once somebody acts on it** — Dates are derived from the cycle, so there
  is nothing to store until a review is completed, noted or has a document attached. Creating
  that record is idempotent on the cycle, the person and the date, so two people acting at once
  get one review rather than two.

### What an employee can see of their own performance

- **The Performance tab is on your own profile** — Your goals, the 1:1s you attend and the
  reviews you are the subject of were all gated to administrators, executives and department
  heads, so an employee could not see a goal set for them or when their own review falls due.
  The tab is now on your own profile, read-only: every control that writes stays gated, and
  notes and comments are still filtered to what was shared with you.

  Nothing was unlocked on the server to do this. Every read already allowed your own record —
  only the tab was in the way.

- **An unfinished assessment is no longer readable by its subject** — An assessment is created
  before anybody writes in it, and the assessor fills in the rating and comments before
  submitting. The endpoint applied no status filter, so the person being assessed could read a
  half-written candid rating of themselves while its author was still drafting it. Only
  completed assessments are returned to their subject now; the assessor still sees their own
  work in progress.

- **Peer and upward feedback is no longer attributed to its author** — A PEER or DIRECT_REPORT
  assessment came back to its subject with the assessor&apos;s name and id attached, which defeats
  the confidentiality those two kinds of review are collected under. The content is still
  shown; the author is not. A manager assessment keeps its attribution, which is the point of
  one.

  Both were pre-existing, and both became reachable through ordinary use the moment the
  Performance tab opened to employees — so they are fixed in the same change rather than left
  for the next one to find.

- **Goal comments carry a visibility level** — The same three levels as review notes, so a
  manager can note something about a goal without it being readable by the person the goal
  belongs to. The control, the wording and the levels are identical to the ones on a review, on
  the principle that a comment about somebody is the same kind of writing wherever it is
  written.

  The default is **Employee and above**, where a review note defaults to Department Head and
  above. A review note is written about somebody; a goal comment is a conversation with them on
  a goal whose progress they own. Existing comments are all Employee and above, so no thread
  that was readable yesterday stopped being readable.

- **A department head can read the discussion on their own department&apos;s goals** — They could
  already read the goals themselves, but the comments on them were restricted to administrators
  and executives, which is the same inconsistency the write side had.

### Documents

- **Word documents and images preview instead of refusing** — Filing accepts PDF, DOC, DOCX,
  PNG, JPG and JPEG, and the preview handled only the first of those. Everything else got &quot;Only
  PDF documents are supported for preview&quot;, which reads as a fault rather than a limitation,
  above a Try Again button that could never succeed. A `.docx` now renders as pages in the
  browser, and an image renders as an image.

  The rendering happens in the browser, so the file never goes to a conversion service. The
  older binary `.doc` format has no browser renderer, so it says so by name and offers the
  download, rather than being lumped in with everything else.

- **The same click behaves the same everywhere** — Opening a document from an employee&apos;s folder
  used to fetch the bytes and hand them to the browser, which downloaded a Word file instead of
  showing it, while the same document opened from the documents list previewed. Both now use
  the preview.

- **A damaged file says so in our own words** — A truncated upload kept its PDF header, so it
  reached the browser&apos;s viewer and drew that viewer&apos;s black &quot;Failed to load PDF document&quot; panel
  inside the preview, with a Reload that could not help. The file is checked for both its header
  and its closing marker first, and a file that fails gets a plain explanation and the download
  button, which is the thing that actually works.

### Rescheduling a 1:1

- **The date of the next 1:1 can be changed** — Editing a 1:1 offered the cadence, the time and
  the duration, but no date, so moving one to another day meant deleting it and setting it up
  again — losing the agenda, the notes and the calendar entry with it. Changing the time still
  moves every upcoming meeting that follows the series; changing the date moves only the next
  one.

### Who sets performance up

- **Performance is run for people, not by them** — Creating a 1:1 or a goal was allowed for
  &quot;you, or an administrator&quot;, which put a **New 1:1** and an **Add Goal** button on every profile
  for everyone, including people arranging their own reviews. Now an executive may act for
  anyone including themselves; an administrator for anyone except themselves; a department head
  for their own department, but not for themselves; and nobody else at all.

- **A department head can finally set one up for their own people** — The previous rule gave them
  no way to, despite being the person who actually holds those conversations.

- **The same rule now covers goal comments** — Commenting on a goal was gated separately on &quot;an
  administrator, or your own goal&quot;, which disagreed with that rule in three directions at once:
  an employee could annotate their own goal, an administrator could annotate their own, and a
  department head could create a goal for one of their people and then not comment on it. The
  **Add Comment** button is gated to match, as are the delete controls on 1:1s, reviews and
  goals. Whoever wrote a comment may always remove it.

- **A link to a person&apos;s reviews now opens their reviews** — The Reviews tab is stored
  internally under an older name, so a link ending `?perfTab=reviews` quietly opened the 1:1s tab
  instead. It looked like the reviews having vanished rather than like a mistyped address.

- **The employee still owns their progress** — They move the percentage and the status on a goal
  set for them. The goal&apos;s definition — its category and weight — stays with whoever may set it,
  which now includes the department head.

- **Removing follows the same rule as creating** — Deleting a goal, or a whole 1:1 series, is done
  by whoever runs the conversation. Both previously allowed the subject: an employee could delete
  a goal their manager had set, or a 1:1 series their department head had arranged, along with
  every agenda item and note on it. The buttons are gone for people who may not use them, and the
  endpoints refuse regardless of the buttons.

### Dates and timezones

- **A 1:1 books the day the form showed** — The meeting date is a calendar day, with the time of
  day held separately, and it was being parsed as an instant. Every 1:1 booked from a browser
  west of UTC landed on the day before the one displayed. With no date given, &quot;a week from today&quot;
  was also counted on the server&apos;s clock rather than the organization&apos;s.

- **Anniversaries are counted in the employee&apos;s own timezone** — It is their anniversary, so the
  day is resolved for them rather than for the server or whoever is looking.

### Everywhere else

- **Destructive actions ask first** — Deleting a 1:1 series, a goal, a goal comment or an agenda
  item now says what is about to be lost and names it. Several of these were a single unguarded
  click, and the ones that did ask used the browser&apos;s own dialog, which cannot describe what is
  being removed and which Chrome suppresses after a few uses.

- **Lists show what is loading** — Goals, reviews and 1:1s rendered their empty state while the
  request was still in flight, so a profile read as &quot;this person has no goals&quot; rather than &quot;not
  loaded yet&quot;.

- **The profile page uses the full width** — Matching the people and expenses pages.

- **Vendor names removed from customer-facing copy** — Guided tour text named the specific AI
  models behind a feature. That is an implementation detail, and it dates.

### Under the hood

- Review cycle scope, anniversary dates and &quot;is this cycle running&quot; each have one implementation
  shared by the screens and the job that sends reminders, after a second copy of the last one let
  the settings list call a cycle Ended while the 1:1 picker still offered it.
- The reminder job de-duplicates on a stored marker keyed by the cycle, the person, the
  anniversary and the milestone, so a retry, restart or overlapping run sends nothing twice.
- The Google and Outlook adapters had each declared their own copy of the same calendar event
  type, and the build was silently discarding one of them.
- The demo lockdown guard is now documented as needing to be run the way CI runs it — scoped to
  the branch&apos;s own changes rather than against the whole API, where new handlers were being lost
  in a pre-existing backlog.</description>
    </item>
    <item>
      <title>v1.0.21</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.21</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.21</guid>
      <pubDate>Thu, 24 Sep 2026 00:15:05 GMT</pubDate>
      <description>### Invitations that lead somewhere, profile photos that actually work, and documents that close their own onboarding tasks

This release fixes two ways a person could be left stuck at the front door. Someone invited by
an administrator was chased with an email asking them to verify their address, when what they
needed was to set a password — and following it stranded them for good. Separately, signing a
document sent by hand left the matching onboarding task open, so employees were asked to sign
the same thing twice.

Profile photos also work properly for the first time: there is a way to choose and frame one,
a photo appears everywhere that person is shown rather than in a handful of places, and it
updates the moment it changes instead of after a page refresh or a sign-out.

Alongside those: new organizations now start with a full set of leave types and departments
rather than a blank structure, an import can invite the people it creates, departments and data
import are restricted to administrators, and a signature that fails validation no longer leaves
the signer unable to retry.

### Invitations

- **An invited employee is now chased with the right email** — Two kinds of account sit in the
  &quot;email not yet verified&quot; set and they need opposite things. Someone who registered themselves
  chose their own password, so what is unproven is their address. Someone an administrator
  invited is the other way round: the address was vouched for by the person who typed it, and
  the password is one the system generated and never showed them.

  Invitees were being sent &quot;Please verify your email address&quot;. It does not unblock them, and
  following it made things worse: verifying marked the address proven, dropped them out of the
  follow-up schedule for good, and still left them with no password. The real invitation expired
  quietly in the background. They now receive their setup link again instead, with a fresh
  fourteen-day token.

- **Follow-ups are timed to when someone actually needs access** — Reminders counted from the day
  the record was created, but administrators routinely set people up weeks before they start.
  That meant every reminder fired, and the invitation lapsed, before the new starter&apos;s first day.
  Invitations are now chased on day 3, 7 and 13 counted from a week before the start date, or
  from the day the account was created if that is later. The last nudge lands the day before the
  first link expires, so it arrives while the original is still usable.

- **Former employees are never chased** — Anyone whose employment end date has passed is skipped
  entirely, so a roster containing leavers cannot produce an email inviting them to activate an
  account.

### Data import

- **An import can invite the people it creates** — Imported employees were created with no usable
  password and nothing to tell them the account existed. The preview step now offers **Invite
  these employees to set up their accounts**: ticked, each person is emailed a link to choose a
  password and is followed up on the same schedule as any other invitation.

  It is **off by default**. An import is as often a historical roster — leavers, closed leave —
  as it is a live workforce moving across, and emailing a former employee a link to activate an
  account is the one outcome nobody wants. Anyone whose employment has already ended is skipped
  even when the box is ticked, so the file decides rather than anyone&apos;s memory of what is in it.

- **Imports no longer report failure after succeeding** — Every import finished by writing an
  audit entry with an action the database does not recognise. The records were created, then the
  write was rejected, so the job was marked failed and the administrator was told the import had
  not worked and invited to run it again.

### Documents

- **A document sent by hand now closes the onboarding task it satisfies** — An administrator
  can send a template straight from **Documents → Templates**, and the same document can also
  be attached to an onboarding or offboarding task. Signing the one sent by hand left the task
  open, so the employee was asked to sign a document they had already signed.

  The machinery to close the task already existed; what was missing was the link. Only
  documents created *by* an onboarding task recorded which template they came from, so a
  hand-sent document was an orphan with nothing to match on. Both the one-off send and the
  bulk send now record it, which closes the loop in both directions: signing a hand-sent
  document completes the task, and a task that later needs that document reuses the one
  already sent instead of issuing a second copy.

  A task is only ever closed by the employee it belongs to signing their own copy. Where a
  document carries more than one signer — an agreement counter-signed by a manager, say —
  the counter-signature closes nothing for the manager, who still has their own copy to sign.

- **A signature that fails validation can now be corrected** — Submitting a signature with a
  required field still empty marked the assignment as signed and *then* rejected the
  submission. The document was never actually signed, the onboarding task never closed, and
  every retry was refused with &quot;This document has already been signed&quot; — leaving the signer
  with no way forward at all. The signature is now recorded only after the submission passes
  validation, so a rejected attempt leaves everything as it was and can simply be retried.

- **Templates and bulk send are reachable from the upload page** — &quot;Add a document&quot; only ever
  uploaded a fresh file, and the links to saved templates and bulk send existed on the
  documents list alone. Administrators who started from the upload page had no route onward
  and no sign that either feature existed, and were re-uploading files they already had as
  templates.

### Onboarding for new organizations

- **Ten leave types instead of eight, with the right icons** — A new organization was missing
  Sick Leave (Unpaid) and Special Event Leave, and Annual Leave carried the umbrella icon that
  belongs to Unpaid Leave — the two had been swapped. The full set is now Annual Leave
  (Vacation Time), Sick Leave (Paid and Unpaid), Working from home, Special Event Leave,
  Maternity, Paternity, Meeting, Compassionate and Unpaid Leave. Each requires manager
  approval, deducts from the correct balance, and carries the privacy setting its category
  calls for.

- **Six departments to start from** — Sign-up left an organization with a single department
  named after the company itself, created only so the founding user had somewhere to belong;
  everything else had to be built by hand before anyone could be invited into a department.
  New organizations now start with Executive, Software Development, IT Operations, Finance &amp;
  Accounting, Sales and Operations, each with its own colour. The placeholder becomes the
  Executive Department rather than sitting alongside the new ones, so the founder keeps their
  membership.

  Seeding only ever runs on an organization&apos;s first trip through setup, and the rewrite only
  touches a department still untouched since sign-up — an administrator who renames it first
  keeps their name, code and colour.

### Profile photos

- **Choosing and framing a photo** — There was no way to set a profile picture after the
  first-run wizard, and no way to say which part of an image to use: whatever was uploaded was
  centre-cropped by the browser, so a photo that was not already square was cropped by luck.
  Picking a photo now opens a framing step — drag to reposition, scroll or use the slider to
  zoom, and what sits inside the circle is what is saved.

  Framing on a canvas also drops the orientation data that makes phone photos appear sideways,
  and normalises every upload to one size and format regardless of what was chosen.

- **Photo actions live on the profile, next to Edit Profile** — Clicking the picture opens the
  actions directly: see the picture, choose a new one, or remove it. The same entries are in
  the **Edit Profile** menu, which is where someone looks when they want to change a colleague&apos;s
  photo rather than their own. An employee with no other editing rights sees only the photo
  entries there; the information sections stay with administrators.

- **Photos open in a viewer with zoom** — Opening a picture used to give a flat, fixed-size
  image, which is not much use for the one thing people open a photo to do. It now opens in a
  viewer with zoom in, zoom out, a percentage that returns to fit when clicked, drag to pan,
  scroll and keyboard shortcuts, and Escape to close.

- **A new photo appears everywhere at once** — Uploading a photo changed it on the profile page
  while the sidebar beside it carried on showing initials until the page was reloaded — and for
  anyone whose photo was set after they signed in, not even a reload helped, only signing out
  and back in. Each part of the app kept its own private copy of the image and none of them
  could tell the others that it had changed; the sidebar, separately, read the photo from a
  snapshot written once at sign-in and never updated. There is now one shared copy, and a photo
  changed anywhere is picked up in place by everything showing that person.

- **Photos now show where only initials did** — Around thirty places drew their own initials
  circle and could never show a photo at all: the people directory and org chart, approvals,
  timesheets, schedules, projects and issues, time tracking, the team map, reports and client
  activity. They now all render the same component.

  Four of those could not show a photo even when asked to, because the data behind them left the
  photo out; those queries now include it. Two more were worse than empty: the Time and Leave
  report tabs passed a storage path straight to the browser as an image address, so every person
  with a photo rendered as a broken image, and the initials fallback never ran because the path
  looked like a valid value.

### Permissions

- **Departments are administrator-only** — Creating a department and running organization
  setup had no role check at all, so any employee could add departments or re-run setup and
  rewrite the leave year, default allowance and timezone. Both now require an administrator or
  executive. Reading the department list is unchanged, since everyone needs it for filters.

- **A department head can rename the department they lead** — Previously they could not correct
  even the name of their own team. They can now change its name, description and colour. The
  code, the active state and the head assignment stay with administrators, because those decide
  the department&apos;s identity and who controls it rather than how it reads.

- **Data import is administrator-only, and hidden from everyone else** — Creating an import
  job already required an administrator, but nothing else in the pipeline did. With a job left
  part-finished, any employee could run it, roll it back or delete it — and running one writes
  employee and department records. The row-level error report was readable too, which quotes
  the uploaded file and therefore colleagues&apos; details. Every import endpoint now requires an
  administrator or executive. The settings entry was already hidden, but the page itself had no
  guard, so a typed URL rendered the whole import interface.

### Security

- **Values are escaped before they reach an email** — Email bodies are assembled as text, and
  names were being placed into them without escaping. A name containing a link would have
  rendered as a working link inside a message carrying our branding and sent from our domain,
  sitting above the genuine button. Every value interpolated into an email is now escaped;
  ordinary names are unaffected.

- **Invitations sent by an import are held to the plan&apos;s user allowance** — Inviting turns one
  upload into one email per row from our own sending domain, so the number that can be sent is
  bounded rather than left to the size of the file.

### Fixes

- **Calendar tooltips are no longer cut off** — Hovering a day near the right-hand edge of the
  dashboard calendar showed a tooltip clipped by the card, so the leave type and status were
  unreadable exactly where the grid is busiest. Tooltips now stay within the window wherever
  the day sits, and still point at the day they describe.</description>
    </item>
    <item>
      <title>v1.0.20</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.20</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.20</guid>
      <pubDate>Wed, 26 Aug 2026 19:12:49 GMT</pubDate>
      <description>### Data import and migration from 48 HR platforms, plus a security and stability pass

This release adds **Data Import &amp; Migration**, a guided way to bring an existing HR system&apos;s
people, departments, and time-off history into BookYourPTO. It ships with built-in column
mappings for 48 platforms, direct API connections for four of them, and a preview step that
writes nothing to the database until it is approved. Alongside it: the framework and its
dependencies were moved onto patched releases, and three regressions that came with that
upgrade were found and fixed before release.

### Data Import &amp; Migration

- **A four-step wizard** — Upload a file, confirm how its columns map onto BookYourPTO
  fields, review a preview of exactly what will be created, then import. The wizard is at
  **Settings → Data Import** and is available to administrators and executives.

- **Nothing is written until you approve it** — The preview validates the first 100 rows
  and shows what each one would create, so problems with the mapping surface before anything
  reaches the database. Rows that cannot be imported are reported with the reason and
  skipped, so a single malformed date does not fail the whole file.

- **Imports can be rolled back for 72 hours** — A completed import can be reversed from its
  detail page within three days, which matters when a mapping turns out to have been wrong on
  the second look rather than the first.

- **48 platforms recognized automatically** — Built-in templates cover 63 column layouts
  across 48 platforms. The uploaded file&apos;s headers are matched against them, so in most
  cases the mapping is already filled in when the step opens. Any column can still be
  remapped by hand, and unmatched columns are skipped rather than guessed at.

- **Employees, leave history, and departments** — Each is imported separately, so a
  migration can be done in stages: people first, then their historical time off. Leave rows
  are matched back to employees by email within the organization.

- **CSV and Excel** — Both `.csv` and Excel workbooks (`.xlsx`, `.xls`) are accepted, since
  most HR systems export one or the other and few offer a choice. Files can be up to 25MB
  and 10,000 rows; larger migrations can be split across several imports.

- **Sample files** — A sample CSV for each of the three data types can be downloaded from
  the import page, for teams building a file by hand rather than exporting one.

- **Save your own column mappings** — An organization can save a custom mapping as a
  reusable template. Custom templates take priority over the built-in ones, which covers
  systems that export a bespoke report layout.

- **Canadian coverage** — 12 of the supported platforms are Canada-first: Collage HR,
  Employment Hero (formerly Humi), Folks HR, Payworks, Rise People, Wagepoint, Payment
  Evolution, Avanti Software, Nethris, PurelyHR, Wave Payroll, and Knit People. Folks HR serves
  Quebec employers and exports in the account language, so its templates recognize both
  English and French column headers rather than requiring every column to be remapped by
  hand.

### Direct platform connections

- **Import without exporting a file** — BambooHR, Timetastic, Employment Hero (formerly
  Humi), and Zoho People can be connected directly. Once connected, employees and leave
  history are pulled straight from the account and can be re-imported at any time without
  producing a new export.

- **BambooHR, Timetastic, and Employment Hero** connect with an API key. BambooHR also
  needs the account subdomain.

- **Zoho People** connects by signing in to Zoho, so no key needs to be copied between
  systems. The connection uses the Canadian Zoho region.

- **Connections are tested before they are saved** — Credentials are verified against the
  provider when the connection is created, so a mistyped key is reported immediately rather
  than at the first import.

### Security

- **Framework and dependency updates** — The application framework and its build toolchain
  were moved onto patched releases, closing every advisory raised by automated security
  scanning. These covered remote code execution and cross-user data disclosure in
  server-side rendering, an authentication bypass on mixed-case route paths, a
  cross-site-scripting issue in HTML sanitization, and a development-tools issue that could
  allow command execution on a developer&apos;s own machine. Automated scanning reports no
  remaining advisories.

- **The full test suite and a production build were verified on the new versions**, and the
  three regressions the upgrade introduced were found and fixed rather than shipped. They
  are listed below.

### Fixes

- **Authenticated requests could be sent without their credentials** — A framework change
  altered when the shared request helper is bound, with the effect that the authorization
  header stopped being attached. The application would load and then every request to the
  API would be rejected. Requests now resolve the helper at call time, and a regression test
  pins that behavior so a future upgrade fails the build instead of the login.

- **The production server would not start** — The build stopped emitting part of a required
  runtime dependency, so every page request returned an error while the API kept answering
  normally. That combination would have reported a deployment as healthy. The dependency is
  now bundled directly, with a test that fails if the incomplete form reappears.

- **Leave records on the edge of a time zone were skipped on import** — The API connectors
  ended their fetch window on the server&apos;s UTC day. An organization running ahead of UTC had
  already moved into a day UTC had not reached, so time off booked on their current day fell
  outside the window and was never imported, with the job still reporting success. The
  window now extends past every real time zone offset.

- **Hours could be imported as days** — The Payworks leave template mapped an hours column
  onto the day-count field, which would have recorded 7.5 hours as 7.5 days. The row would
  have validated and imported cleanly while overstating the employee&apos;s usage. The mapping
  was removed and a check now scans every leave template for the same class of mistake.

- **Platform logos were missing from the templates list** — The built-in templates page
  showed a generic icon for all 63 entries. Logos are now served from a single shared list
  used by every screen that shows them.

- **Searching the platform picker returned an error** — Typing in the platform search field
  raised an error instead of filtering the list.</description>
    </item>
    <item>
      <title>v1.0.19</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.19</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.19</guid>
      <pubDate>Fri, 07 Aug 2026 03:44:41 GMT</pubDate>
      <description>### Probation review tracking, accurate leave carry-over, and a stricter browser security policy

This release adds **Probation Milestone Tracking** — a new employee event that sits
alongside birthdays and work anniversaries on the dashboard and calendar, with automated
reminder emails so a probation review never quietly slips past its date. It also lands a
substantial correctness pass on leave carry-over, where the balance shown on the calendar
and the balance the booking form enforced could disagree. Rounding it out: leave allowance
becomes a proper administrator control, the browser-side security policy is now enforced
rather than advisory, and product analytics is added under the existing consent flow.

### Probation Milestone Tracking

- **Probation period on every employee** — When creating or editing an employee you can now
  set a probation period of **None**, **3 Months**, or **6 Months**. The Add User form also
  gained a Hire Date field, so a new starter can be set up with their probation in one pass.

- **The review date calculates itself** — The probation review date is derived from the hire
  date plus the probation period (hired Jan 15 on a 3-month probation → review due Apr 15).
  Both the employee form and the Add User form show a live preview of the resulting date as
  you choose, and month-end dates are handled sensibly — a Nov 30 hire on a 3-month
  probation reviews on Feb 28 (or Feb 29 in a leap year), never spilling into March.

- **Extend probation when you need to** — Administrators can override the calculated date
  with a custom **Probation Review Date**. When set, it takes precedence everywhere the
  milestone appears and is labelled as extended, so it is obvious the date was moved by
  hand rather than calculated.

- **On the dashboard and the calendar** — Probation reviews now render as their own employee
  event, using a dedicated icon and colour distinct from birthdays and work anniversaries,
  with a tooltip naming the employee, the probation length, and whether it was extended.
  Managers can spot an upcoming or overdue review at a glance without working the date out
  by hand.

- **On the employee profile** — The Job tab now shows Hire Date, Probation Period, and the
  calculated (or overridden) Probation Review Date together, giving HR a single reference
  point when reviewing someone&apos;s record.

- **Automated reminder emails** — A reminder now goes out **14 days before**, **7 days
  before**, and **on** the probation review date. Each email carries the employee&apos;s name,
  position, department, hire date, probation length, and review date, plus a direct link to
  their profile so the reviewer can start immediately. A matching in-app notification is
  raised at the same time.

- **Choose who gets reminded** — Reminder recipients are configurable per organization from
  the notification settings: the employee&apos;s **direct manager**, their **department head**,
  all **administrators**, all **executives**, or any combination. Reminders can also be
  switched off organization-wide. Manager and department head are resolved per employee, so
  each reminder reaches the people who actually run that person&apos;s review.

- **Reminders follow the employee&apos;s calendar** — The countdown to a review is evaluated in
  the employee&apos;s own timezone (falling back to the organization&apos;s), so a review due &quot;today&quot;
  means today where that person works, not where the server happens to run.

- **Probation status stays confidential** — Unlike a birthday, whether someone is on
  probation is only visible to the employee themselves, their direct manager, their
  department head, and administrators or executives. Other colleagues simply do not see the
  milestone.

### Leave carry-over accuracy

- **The calendar and the booking form now agree** — A user with a custom allowance plus a
  manual carry-over adjustment could see one figure on their calendar balance card and be
  told a different, smaller number when they tried to book. Every place that computes a
  leave balance — the balance card, the dashboard people list, the booking check, and the
  leave edit check — now runs through one shared calculation, so the number you are shown is
  the number that is enforced.

- **Carry-over no longer repeats every year** — A manual carry-over adjustment is now
  anchored to the fiscal year it was granted for. Previously an adjustment had no year of
  its own, so every subsequent fiscal year kept counting it — days granted for one year
  still appeared in the next.

- **No more double-counted carried days** — The allowance tile on the balance card was adding
  carried days on top of a total that already included them, so someone with 15 base days
  plus 5 carried read &quot;16 / 25 days&quot; instead of &quot;16 / 20&quot;. The tile now shows the
  entitlement before carry-over, so the row reads base + carried − used = remaining.

- **Bookings check the right year** — A leave request is now balanced against the fiscal year
  the leave actually falls in, rather than the year the request happens to be filed in.
  Booking next January&apos;s holiday in December is checked against next year&apos;s allowance.

- **Expired adjustments clear themselves** — Once a carry-over adjustment&apos;s expiry date
  passes, the days stop counting toward the balance and the figure is now cleared from the
  profile automatically. Previously it lingered on the record and an administrator had to
  zero it by hand.

- **A week&apos;s warning before days lapse** — A new daily reminder notifies the employee&apos;s
  department head — falling back to administrators and executives when they have no manager
  — seven days before a carry-over adjustment expires, in-app and by email, so someone can
  extend the expiry or top the days up before they are lost. Day counting runs in the
  employee&apos;s own timezone, and the reminder cannot fire twice for the same adjustment.

- **Clearer allowance wording** — The Leave Allowance tab now names the fiscal year an
  adjustment applies to and states that the days are cleared automatically afterwards,
  instead of implying they are permanent.

### Permissions

- **Leave allowance is an administrator control** — The fields that decide how many paid days
  someone can book — custom allowance, carry-forward settings, and carry-over days — are now
  restricted to administrators and executives organization-wide, and to department heads for
  members of their own department. Nobody can change their own.

- **Probation is an administrator control** — Probation period and the probation review date
  override are restricted the same way, so the date that drives the reminder emails cannot be
  moved by the person being reviewed.

### Privacy &amp; Security

- **Stricter browser security policy, now enforced** — The application&apos;s content security
  policy moved from advisory to actively enforced, so the browser blocks anything outside the
  vetted allowlist. Additional cross-origin isolation protections were added at the same
  time, and the server no longer advertises its underlying framework in responses.

- **Security disclosure contact published** — The application now publishes a standard
  machine-readable security contact so researchers have a clear route to report an issue.

- **Dependency security updates** — Third-party dependencies flagged by automated security
  scanning were updated to patched releases across the tree, with the full test suite and a
  production build verified on the new versions.

### Product analytics &amp; consent

- **Product analytics added under the analytics consent category** — A product-analytics
  tool was added to help us understand how features are actually used. It loads **only**
  after a visitor grants analytics consent, only on our own canonical web domains, and never
  inside the mobile app&apos;s web session or on white-label customer domains. Withdrawing
  analytics consent switches it off immediately.

- **Everyone is asked to consent again** — Because a new vendor joined the analytics
  category, the consent banner reappears once for every visitor, with no pre-ticked toggles
  and nothing loading until a fresh choice is made. The new vendor is disclosed by name in
  the cookie Customize panel and the category description was updated to match.

### Fixes

- **Icons render across the app again** — Icons are now bundled with the application rather
  than fetched at runtime, restoring them everywhere under the enforced security policy and
  removing a network round trip on every page.

- **Document and PDF previews render again** — Document previews, template detail views,
  expense receipt viewing, and the personal data-drive preview all display correctly under
  the enforced policy.

- **Location maps render again** — The map pane on the document and timesheet location views
  displays again, including for organizations without their own maps key configured.

### Behind the scenes

- Probation review dates resolve through a single shared implementation used by the server,
  the dashboard, the calendar, the profile, and the reminder job — so a date shown in the UI
  can never disagree with the date a reminder fires on. Leave carry-over math was
  consolidated the same way, replacing four drifting copies with one.

- All calendar-day handling in the new code follows the project&apos;s date-only convention, with
  regression tests exercising non-UTC organization timezones on both sides of UTC, month-end
  clamping, and leap years.

- Demo data now includes probation periods, extended reviews, and reminder recipients, so the
  demo environment reflects the new feature.

**Full Changelog**: https://github.com/anhourtec/BookYourPTO-SaaS/compare/v1.0.18...v1.0.19</description>
    </item>
    <item>
      <title>v1.0.18</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.18</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.18</guid>
      <pubDate>Wed, 15 Jul 2026 05:29:23 GMT</pubDate>
      <description>### Privacy hardening for leave, safer sign-in, and expense workflow polish

This release closes a set of leave-privacy gaps so a leave marked **Private** stays
private everywhere it is surfaced — the dashboard, the calendar, the iCal feed, digest
emails, and the mobile app — and tightens who can act on a cancellation request. It also
hardens the sign-in forms and brings a batch of expense-workflow improvements on the web.

### Privacy &amp; Security

- **Private leave stays private, end to end** — A private leave type no longer leaks its
  purpose to people who shouldn&apos;t see it. Every free-text field on a leave (the reason,
  notes, approver comments, and rejection / cancellation reasons) is now hidden from
  anyone who isn&apos;t the leave&apos;s owner, an admin/executive, or the owner&apos;s department head.
  Previously a colleague in another department could read a private leave&apos;s cancellation
  reason from the details view.

- **Consistent redaction across every surface** — The same rule is now applied wherever
  leaves are shown to others: the dashboard, the per-user calendar, the subscribable iCal
  calendar feed, and the scheduled digest emails. A department head subscribing to a
  direct-reports iCal feed no longer receives the real type name or reason of a private
  leave belonging to someone outside their department.

- **Cancellation review limited to the right approvers** — Approve / Decline actions on a
  leave cancellation are now shown only to the people actually authorized to review that
  request (the owner&apos;s department head, or an admin/executive), on both web and mobile.

- **Safer authentication forms** — The login, registration, and SSO sign-in forms now
  submit explicitly over POST, and the UI library was updated to a version that guarantees
  the same, so credentials can never be placed in a URL if a form is submitted before the
  page finishes loading.

### Expenses

- **Download all receipts as a single ZIP** — Export every receipt on an expense report in
  one archive instead of saving them one at a time.

- **All Claims filter** — The expenses list gains an &quot;All Claims&quot; filter so you can see
  every claim in one place.

- **Clearer receipt uploads** — Upload prompts now list every supported receipt format, and
  the claim header carries a hover help note explaining the workflow.

- **Verify scanned figures** — After a receipt scan, a reminder now prompts you to confirm
  the extracted amounts before submitting.

- **Cleaner per-diem view** — The per-diem Actions column is hidden once a report is no
  longer editable, removing controls that would not do anything.
</description>
    </item>
    <item>
      <title>v1.0.17</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.17</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.17</guid>
      <pubDate>Mon, 29 Jun 2026 03:59:55 GMT</pubDate>
      <description>### Mobile parity: provided meals, world currency, and full document signing in the app

This release brings the iOS and Android apps up to parity with the web product. The
expense, per-diem, and document-signing features that shipped on the web in v1.0.16 are
now fully available on mobile, alongside more reliable geofenced clock-in and a fix for
off-by-one expense dates.

### Mobile

- **Per-diem provided meals** — Individual per-diem meals (breakfast, lunch, dinner) can
  now be marked as provided rather than reimbursed in the app, each with its own source
  (third party, company card, or a colleague). The provided meal&apos;s value is deducted from
  that day&apos;s per-diem, and the per-diem grid shows the provider per meal per day with
  per-day editing and removal — matching the web bookkeeper view.

- **World-currency support** — The app now offers the same full list of world currencies
  as the web settings (up from a short list), with the correct currency symbol rendered
  consistently across line items, expense detail, mileage, receipts, and approvals
  instead of a hard-coded &quot;$&quot;.

- **Multi-field document signing** — The mobile signing flow now fetches the signer&apos;s
  assigned fields and fills them in: signature and initials are auto-filled with the drawn
  mark, and the app prompts for any text, date, or checkbox fields before submitting the
  real field values. Field-based documents that previously failed to sign on mobile now
  complete correctly.

- **Turn-order signing privacy** — In sequential signing, a signer whose turn has not yet
  arrived no longer sees the fill-and-sign screen. Non-assignees get a read-only monitor
  view, and a signer who is next in line but not yet up sees a clear &quot;It&apos;s not your turn to
  sign yet&quot; message instead of a raw error.

- **Document audit trail** — Administrators, executives, and department heads can now open
  a document&apos;s full audit trail from the document view in the app, mirroring the web
  History timeline.

- **More reliable geofenced clock-in** — The app now sends GPS accuracy with every
  clock-in, so organizations that require location for clock-in no longer reject a valid
  punch when accuracy data was missing.

### Bug Fixes

- **Off-by-one expense dates** — Trip ranges and line-item / mileage dates in the app
  rendered some calendar-day fields a day early for users west of UTC. They now read the
  stored UTC day correctly, matching the web fix from v1.0.16.</description>
    </item>
    <item>
      <title>v1.0.16</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.16</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.16</guid>
      <pubDate>Mon, 29 Jun 2026 03:59:19 GMT</pubDate>
      <description>### Document E-Signatures, a Reworked Time-Tracking Suite, a Redesigned Profile, and a Big Security Pass

This is a large release. The headline is **document e-signatures** — you can now route a document (or a finalized timesheet) for a dated, audit-trailed signature without leaving the app. Around it, the **time-tracking suite** was substantially reworked (period timesheets that finalize into a signable PDF, configurable approval routing, a guided setup wizard, multi-day manual entry, and a live Team Status board), the **profile page** was rebuilt in a tabbed, HR-suite-style layout, **documents and onboarding documents** got a design refresh, and we closed **every open dependency advisory (25 → 0)** alongside a round of CSP and SSRF hardening.

### New Features

- **Document e-signatures** — Documents can be sent for signature with field placement, sequential or parallel multi-signer ordering, per-signer due dates, a SHA-256 content hash, a multi-signer completion certificate, and a full audit trail, all stored encrypted. Signers are notified in-app and by email at each step. The signing UI deliberately avoids ESIGN-Act / &quot;legally binding&quot; language.

- **Period timesheets that finalize into a signable document** — Time entries now roll up into a **period timesheet** (weekly / biweekly / semi-monthly / monthly) with an `OPEN → SUBMITTED → APPROVED → FINALIZED → SIGNED` lifecycle. When a manager finalizes a period, the system generates a complete, branded timesheet PDF (daily breakdown, regular/overtime/break/leave/holiday totals, pay snapshot) and routes it into `/documents` for a dated e-signature, reusing the same signing pipeline. Finalizing also advances the payroll lockdown window.

- **Configurable timesheet approval routing** — A new **Approval routing** setting decides who signs a finalized timesheet: **No signature** (finalize straight to payroll), **Single approver** (one chosen person signs every sheet), or **Department head** (routes to the employee&apos;s department head, escalating to a chosen approver for heads/admins). Routing is paired with a separate &quot;who signs&quot; order (employee, approver, or employee-then-approver) and a per-signer signing window.

- **Time Clock setup wizard** — Admins and executives get a guided, three-step setup on `/time-tracking` (opened from a &quot;Time clock setup&quot; button): the **payroll cycle** (week start, cycle, period anchor), **location tracking** (capture clock-in/out location, or off), and **what time is tracked against** (nothing, projects, or projects and tasks — wired to the real Projects/Tasks system). It writes straight to the existing settings.

- **Multi-day and break-aware manual time entry** — The Add/Edit time-entry panel now supports an unpaid **break** (subtracted from the worked total) and a **Multiple days** mode that stamps one time-of-day across a weekday-filtered date range — one entry per employee per selected day, instead of adding days one at a time.

- **Team Status board** — A manager-only board (`/time-tracking/team`) showing who is on shift right now: a live &quot;who&apos;s working&quot; list, a full-width GPS map with a marker per clocked-in user (using their real profile photo), clock-in address and elapsed time, plus an &quot;Everyone&quot; roster with today&apos;s hours.

- **Redesigned profile page** — The profile was rebuilt as a tabbed, HR-suite-style layout (Personal, Job, Time Off, Documents, Performance, and more) for a far richer, more navigable employee record.

- **Onboarding documents** — New hires can be assigned documents to read and sign as part of onboarding, tracked to completion.

- **Per-diem provided meals** — Individual per-diem meals (breakfast, lunch, dinner) can be marked as provided rather than reimbursed, each with its own source (third party, company card, or a colleague), and the provided meal&apos;s value is deducted from that day&apos;s per-diem. Providers are managed per-meal in expense settings, and the per-diem grid lets a bookkeeper set the provider per meal per day.

- **Guided workspace setup checklist** — New organizations get a dismissible &quot;Finish setting up your workspace&quot; card on the dashboard, visible to administrators and executives only, that tracks four quick settings: timezone &amp; business days, public-holiday location, leave types, and expenses &amp; per-diem. Each step&apos;s status is auto-detected from real configuration. Crucially, settings we pre-fill at sign-up (timezone, a starter set of leave types, default expense rates) are surfaced as **&quot;pre-filled — review&quot;** with a one-click **Looks good** confirmation rather than silently shown as complete, so the values we guessed actually get verified before they count as done. The progress bar reflects only confirmed steps. The first-run welcome dialog and the product tour are now sequenced so they never appear at the same time — the profile dialog comes first, then the tour on the next dashboard load.

### Improvements

- **Documents design refresh** — The documents experience was reorganized (Inbox / Sent / Action Required style surfacing) so it&apos;s clearer what needs your signature versus what you&apos;ve sent.

- **Row actions consolidated into an ellipsis menu** — Timesheet finalization rows now use a compact ellipsis action menu (Submit / Approve / Reject / Finalize &amp; send / Finalize only / View document) instead of a row of buttons, which also reads cleanly on mobile.

- **Finalize actions follow the auto-send setting** — When the org has &quot;Automatically send finalized timesheets for signature&quot; enabled, finalizing is a single **Finalize &amp; send** action (it always routes for signature). With auto-send off, both **Finalize &amp; send** and **Finalize only** are offered so a manager can choose per timesheet, and the two are genuinely distinct — &quot;Finalize only&quot; never sends. With no signature configured, a single **Finalize for payroll**.

- **Finalized timesheets file into a Timesheets folder** — A signed/finalized timesheet PDF now appears in a dedicated **Timesheets** folder under `/documents` (it was previously only findable via search), and the folder shows a live count. The category is system-managed, so it isn&apos;t offered as a manual upload option.

- **Geofencing available on Pro and above** — Plan limits were updated so geofencing is included from Pro upward.

- **Faster, reliable approvals counts** — The pending-approvals badge cache is now busted immediately on approve/reject, and `/api/approvals/counts` is scoped to the caller&apos;s approval rights.

- **Referral tracking** — Referral attribution now captures the `?via=` parameter and persists it via cookie fallback.

- **Per-diem bookkeeper summary** — The per-diem display was rebuilt as a per-day summary that reads cleanly for bookkeepers, showing each day&apos;s meals, their provided/excluded status, and the amount actually paid.

- **Redesigned travel route entry** — The travel and mileage route entry was redesigned to resemble a turn-by-turn directions view, with address autocomplete that falls back to a plain text input when autocomplete isn&apos;t available.

- **View Audit Trail from any folder** — Administrators, executives, and department heads get a &quot;View Audit Trail&quot; row action on every document folder, opening the document with its History expanded. Previously the trail was only reachable from the Sent view.

- **Compact document audit trail** — The History timeline is now a fixed-height scroll area and collapses repeated views by the same person into a single counted row, so a heavily-opened document no longer stretches the detail page.

- **Upload defaults to signing** — The document upload entry points open the send-for-signature flow by default; filing to a folder stays available via the mode toggle or a `?mode=store` link.

- **Per-recipient field placement** — The signing-field placer no longer forces signature/initials parity across signers; it only requires that each recipient has at least one field, and it previews the burned-in &quot;Signed by&quot; label and timestamp around placed signature and initials boxes.

- **Themed sidebar counts** — The sidebar count badges (Approvals, Action Required, and others) now use the primary color instead of amber.

- **Currency-neutral expense settings** — The expense per-diem and rate fields now offer a full list of world currencies (up from four) and render the selected currency&apos;s symbol live across every input and the per-diem section heading. Region-specific guidance copy was removed so the defaults read neutrally for any organization, wherever it operates.

### Responsive layout

- **Tables no longer overlap their headers on small screens** — Wide data tables (approvals, expenses, timesheets, documents, projects, security logs, and more) compressed their fixed columns on narrow viewports until the header labels overlapped. They now keep a minimum width and scroll horizontally instead, with non-wrapping headers; desktop is unchanged.

- **Create/Edit Shift opens as a side drawer** — Scheduling a shift now opens a right-side push drawer (matching the time-entry panel) that sits beside the page and collapses the sidebar, rather than a centered modal over the content.

- **Sidebar no longer flickers on resize** — Crossing the desktop/mobile breakpoint used to briefly animate the sidebar into a broken-looking state; layout transitions are now suppressed while the window is actively resizing.

### Security

- **All dependency advisories closed (25 → 0)** — A sweep of dependency vulnerabilities brought the dependency audit to zero, including switching the PDF rendering library to its legacy build, hardening the PDF worker CSP, and patching an HTTP-client SSRF advisory.

- **CSP and framing hardening** — The web analytics script was added to the CSP `script-src`/`connect-src`; `X-Frame-Options` was relaxed to `SAMEORIGIN` so in-app PDF receipts render; the PDF worker runs under a tightened policy.

- **Tighter notification and approval scoping** — Leave-submission notifications are scoped to the submitter&apos;s department, and approval counts to the caller&apos;s rights, so neither leaks cross-team activity.

- **Safer defaults** — &quot;Remember me&quot; now defaults to off at login.

- **Administrators can view security logs** — Audit-log, sign-in-log, and leave-transaction views (and their exports) are now open to administrators as well as executives, all strictly org-scoped.

- **Sequential signing visibility** — In sequential signing, a later signer whose turn hadn&apos;t come could view and list the document (including its fields and stored signature data) before the earlier signer signed. Not-yet-their-turn assignments are now excluded from every document read path; administrators, owners, and uploaders are unaffected.

- **No signing on another user&apos;s behalf** — Administrators can open any assignment for monitoring, but the signing page presented the full fill-and-sign UI for it. Non-assignees are now redirected to the read-only document view; the sign endpoint already rejected the submission server-side.

### Bug Fixes

- **Role changes apply immediately** — Promotions, demotions, and deactivations now take effect on the user&apos;s next request instead of waiting up to the access-token lifetime, and a role change no longer forces a disruptive re-login.

- **Timesheet PDF period dates** — The period header on the generated timesheet renders the calendar boundaries in UTC so a &quot;May 18 – May 31&quot; period never shifts a day for a reader in another timezone.

- **Timesheet signature/date alignment** — On the generated timesheet, the signature image and date were landing below the Signature/Date lines because the signing fields were placed at a fixed position while the lines move with the number of entries. The fields are now positioned to the actual drawn lines (and on the correct page for multi-page timesheets). Applies to timesheets finalized after this release.

- **Schedule week-clear fix** — Clearing a published week referenced a non-existent model and threw at runtime; it now uses the correct schedule-publication record with timezone-aware week matching.

- **Training auto-assignment timing** — Corrected a comparison in the training auto-assign scheduler that mis-evaluated due windows.

- **Off-by-one expense dates** — The expense detail and overview views rendered some calendar-day fields a day early in timezones west of UTC; they now read the stored UTC day correctly.

- **Initials-only signers couldn&apos;t sign** — A signer asked only to initial (with no signature field) submitted an empty signature and was rejected with a 400; the signing flow now uses the initials image as the signature.

- **Right-panel space released on navigation** — Leaving a page with an open right-side push drawer (for example a schedule or timesheet entry) without closing it left the reserved content-shell width behind; it is now released when the page unmounts.</description>
    </item>
    <item>
      <title>v1.0.15</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.15</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.15</guid>
      <pubDate>Tue, 02 Jun 2026 20:56:49 GMT</pubDate>
      <description>### Leave Cancellation &amp; Editing, a Redesigned Expenses Overview, and Smarter Dashboards

This release rounds out the leave workflow: employees can finally **edit or cancel a pending request**, and **request cancellation of an already-approved leave** with manager sign-off, all from the dashboard or calendar — no more emailing HR when plans change. Alongside it, the expenses list gets a redesigned overview with a status funnel and an interactive spend chart, the dashboard learns to surface the people you actually work with, approvers get a live count of what&apos;s waiting on them, and we close two dependency security advisories. There&apos;s also a new consent-gated cookie banner and proactive white-label domain-expiry reminders.

### New Features

- **Cancel or edit a pending leave request** — From the leave detail view on the dashboard or calendar, the person who filed a still-**pending** request can now **Edit** it (re-opens the booking form pre-filled, then re-validates dates, balance, notice period, and overlaps) or **Cancel** it outright. Editing notifies the approvers with a distinct &quot;Leave Request Updated&quot; message rather than looking like a brand-new submission.

- **Request cancellation of an approved leave** — Plans change after a leave is approved. Instead of an off-system email, the employee can now submit a **cancellation request** on an approved leave; it goes to the admins / executives / department heads who can **Approve** it (the leave is cancelled and the balance freed) or **Reject** it (the leave stays approved). Everyone is notified in-app and by email at each step. Users who already have direct-cancel power (admins/execs) just cancel outright — they don&apos;t see the redundant &quot;Request cancellation&quot; button.

- **Pending-cancellation indicator on the calendar &amp; dashboard** — An approved leave that has a cancellation request waiting now carries a distinct marker (a small primary-coloured dot, separate from the yellow &quot;pending approval&quot; dot) and an &quot;Approved · Cancellation requested&quot; tooltip, so the state is visible at a glance on both the year calendar and the dashboard timeline.

- **Pending-approvals count on the sidebar** — The **Approvals** sidebar entry now shows a live badge totalling everything waiting on you across leave, expenses, and time — an amber pill when the sidebar is expanded, a dot when collapsed, &quot;99+&quot; past ninety-nine, hidden at zero. Unlike a notification it&apos;s a persistent &quot;still to do&quot; signal that doesn&apos;t clear when you dismiss notifications, and it only appears for users who can actually approve. Each queue is scoped to the viewer&apos;s approval rights, so the badge never counts work you can&apos;t action.

- **Expenses overview: status funnel + spend chart** — `/expenses` gains a redesigned header card: a reimbursed-amount hero with active / paid context, a clickable **status donut** with a legend for filtering, and a **spend-over-time chart** you can switch between Spend and Claims, Monthly and Daily, and Bar / Line / Area. It&apos;s primary-themed, fully responsive, and animates on load. The list&apos;s counters were reconciled so &quot;All&quot; matches the toolbar&apos;s active total and the info bar reflects the true server-side filtered count.

- **&quot;Sort by relevance&quot; on the dashboard** — A smarter default ordering for the user timeline: it puts **you** first, then blends how often you open and search for each person (a private, in-browser &quot;frecency&quot; signal that favours frequent *and* recent contacts) with each user&apos;s leave-request volume. Your filter and sort choices now also **persist across refreshes and sessions**. The personalization signal never leaves your browser.

- **Approver context: the requester&apos;s timezone &amp; local time** — The leave approval slide-over now shows the employee&apos;s timezone and their current local time (e.g. &quot;3:26 PM · America/Toronto&quot;, or the org default when they haven&apos;t set a personal one), so an approver in another zone has the context before they decide.

- **Proactive white-label domain-expiry reminders** — For customers on white-label custom domains, the app now looks up the domain&apos;s registrar expiry date (via RDAP) and reminds the org&apos;s admins at **T-30 / T-14 / T-7 / T-1 days** before it lapses — in-app and by email — so a branded URL never silently goes dark because a renewal was missed. Privacy-redacted TLDs (common in the EU) fall back to the existing reactive DNS-failure path.

- **Consent-gated cookie banner** — A new cookie-consent banner loads analytics and affiliate tracking **only after the visitor consents**. EU visitors (detected by timezone) must choose explicitly; others get an auto-accept countdown that an explicit choice cancels immediately. Trackers load only on the canonical site — white-label custom domains get no banner and no third-party scripts. The banner is themed off the app&apos;s design tokens so it adapts to white-label brand colours.

- **Dashboard user search &amp; pagination** — A search-by-name/email box (inline in the header row alongside the filter, count, and period controls) plus a rows-per-page footer, so large teams are easy to find and the desktop timeline stays manageable; mobile still shows everyone.

- **Obsolete-browser upgrade nudge** — A tiny standalone script (loaded as a classic, non-module script so it runs even on browsers too old to parse the app) feature-detects modern capabilities and, when they&apos;re missing, shows a self-contained &quot;please upgrade your browser&quot; banner. Dismissal is remembered.

### Improvements

- **Calendar honours the org&apos;s week-start-day** — The year calendar grid was hardcoded to a Sunday start regardless of the organisation&apos;s setting. A Monday-start org now sees Monday-first columns; the setting threads through the month/year builders and grid headers.

- **Tidier calendar day cells** — Day content is now vertically centred so numbers sit on a consistent grid (the previous top-hugging layout made row spacing look uneven), and the cell no longer clips the top of leave pills or the pending-status dot.

- **Cookie banner clears the sidebar on desktop** — When signed in, the bottom-left banner now shifts past the fixed sidebar (expanded or collapsed) instead of overlapping it, and stays in the corner on public / logged-out views.

- **Removed a dead &quot;My favourites&quot; filter** — The dashboard&apos;s account-type filter offered a &quot;My favourites&quot; option that had no backing feature; it&apos;s been removed.

### Accessibility

- **Calendar day cells are now screen-reader friendly** — Event days render an icon with no visible number, so assistive tech previously announced only &quot;button&quot;. Both the year-calendar cell and the dashboard timeline cell now carry a descriptive label (the date plus any holiday / leave / birthday summary).

### Bug Fixes

- **Approval dates no longer shift a day for approvers in another timezone** — Leave start/end are calendar-day values stored at UTC midnight, but the approvals slide-over and the CSV/PDF export were formatting them in the approver&apos;s local zone — so a June 3 leave showed as June 2 for anyone west of UTC. Those are now read in UTC (real timestamps like &quot;submitted&quot; stay local). The same fix was applied to the date strings in pending-edit validation messages.

- **Editing a pending request reads as an update, not a new request** — Re-submitting an edited leave now sends a &quot;Leave Request Updated&quot; notification (in-app and email) instead of the original &quot;has requested …&quot; copy, with timezone-safe dates.

- **Cancellation-request notification now opens the right place** — The &quot;Cancellation Request Pending&quot; notification deep-links to the dashboard (where an approver opens the leave to act on it) instead of doing nothing.

- **Expenses overview survives filtering** — The overview card stays mounted across refetches, so clicking a status segment updates it in place instead of remounting and resetting the chart&apos;s metric / granularity toggles.</description>
    </item>
    <item>
      <title>v1.0.14</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.14</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.14</guid>
      <pubDate>Fri, 22 May 2026 18:23:49 GMT</pubDate>
      <description>This release tightens up two areas that have been quietly accumulating rough edges: how billing limits are explained to admins, and how the app handles users whose personal timezone differs from their organisation&apos;s. It also adds plan-aware gating around the Document Templates feature so Free-plan customers see a clear upgrade path instead of empty screens, and closes a handful of quota loopholes that could let a single request push an org past its plan limit.

### New Features

- **Per-user timezone, end-to-end across booking modals** — Following on from v1.0.13&apos;s per-user timezone groundwork (searchable picker, profile field, calendar grid highlighting), every booking and date-picker modal now resolves &quot;today&quot; against the **viewer&apos;s** resolved timezone rather than UTC or the browser clock. A Vancouver-based employee in a Toronto-based org now sees their own calendar day pre-filled in Book Time Off, Group Booking, Lock Dates, the expense Add Meal / Add Travel cards, the document upload / assign / template send / personal upload modals, and the onboarding welcome DOB picker. The same rule used for calendar-grid highlighting is now applied everywhere date pickers default to &quot;today&quot;.

- **Document Templates usage card on /billing** — The Plan Usage panel gains a dedicated &quot;Document Templates&quot; row that shows your current template count against your plan cap (Free 0, Pro 5, Business 50, Enterprise unlimited). On Free plan the card shows an inline &quot;Not available on the Free plan — Upgrade to use templates&quot; prompt instead of an unhelpful 0 / 0 progress bar.

- **Per-counter reset timer on /billing** — Each monthly metric (Documents, Receipts Scanning, Projects, Expense Claims) now displays when it next resets — &quot;Resets in 7 days&quot; up close, &quot;Resets Jun 22&quot; further out. The label is computed in the org&apos;s timezone and renders only on plans where the counter actually resets (Free is lifetime for most metrics).

- **Subscription-anniversary monthly resets** — Counters now roll over on the date Stripe charges your card next, not on the 1st of the calendar month. An org that subscribed on the 22nd resets on the 22nd. Previously a customer who subscribed mid-month would get their counter reset on the 1st (sometimes only days after they paid), which was both confusing and inconsistent with how their invoices arrive.

- **Plan-aware Document Templates landing pages** — `/documents/templates` and `/documents/templates/create` now render a clean upgrade card for Free-plan organisations explaining what Templates do and what unlocks them, instead of an empty list / disabled wizard. The data fetch is skipped on Free plan so there&apos;s no loading flicker before the upgrade card appears.

- **&quot;Pro&quot; lock badges on Template and Bulk Send entry points** — The Templates and Bulk Send buttons on the documents toolbar, the &quot;Use a Template&quot; / &quot;Bulk Send&quot; items in the Start menu, and the Document Templates jump button on the onboarding / offboarding settings header now wear a small &quot;Pro&quot; lock pill on Free plan. Tooltips explain the dependency (e.g. &quot;Pro plan required — depends on Document Templates&quot; on Bulk Send).

- **Bulk Send page gated on Free** — `/documents/bulk-send` now renders an upgrade card explaining that Bulk Send needs Document Templates, instead of letting Free users build a bulk-send wizard they can&apos;t submit.

- **Add Task modal explains the upgrade requirement inline** — The &quot;Attach Document Template&quot; picker inside the onboarding / offboarding Add Task modal now swaps its dropdown for an inline upgrade prompt when the org is on Free, so admins know why the picker is empty and can still save the task without a template.

### Improvements

- **State-aware trial-ending banner** — The &quot;Trial ending soon&quot; banner previously fired a single &quot;Upgrade Now&quot; call-to-action for every trialing org, even when the trial was set to auto-convert and the customer had a card on file. The banner now picks one of two paths: a soft, no-CTA informational banner for trials that will auto-convert (&quot;Your Pro subscription will start automatically on May 29. Cancel anytime.&quot;), and an actionable warning with a Reactivate CTA only for trials the customer has actively cancelled. Matches the pattern Stripe, Linear, and Notion all use.

- **/billing usage display now lines up with the actual server gate** — Several monthly counters were computing &quot;this month&quot; using the server&apos;s local timezone (UTC in production), while the receipts counter already used the org&apos;s timezone. Around month boundaries the billing UI could show a different counter from what the gate enforced at submit time. Documents, Projects, Expense Claims, and the usage display all now bucket by the same boundary the gate uses, so the page and the API agree.

- **TypeScript hygiene in the Leave Request modal** — Replaced a handful of `string.split(&apos;:&apos;).map(Number)` destructures with a shared `hmToMinutes` helper, resolving the &quot;possibly undefined&quot; complaints TypeScript was raising on every time-slot arithmetic. The `/api/leaves/schedule` client fetch was also switched from `params` to `query` to match how the Nitro handler reads its arguments and to resolve a type-instantiation-depth error.

### Bug Fixes

- **Booking modal no longer prefills tomorrow&apos;s date in the evening** — In any timezone west of UTC, opening the Book Time Off floating action button after roughly 5 PM local time used to pre-fill the date pickers with the next day&apos;s date (the UTC day had already rolled over even though the user&apos;s calendar still showed today). All booking, expense, document, and onboarding date pickers now resolve &quot;today&quot; in the user&apos;s resolved timezone, so the picker always matches the day the user sees on their wall clock.

- **Documents Templates feature respects the documented Pro / Business cap** — The endpoint for creating reusable templates previously ran only a role check and never consulted the per-plan quota. A Pro org could create more than the documented 5 active templates. The endpoint now enforces the cap (Free 0, Pro 5, Business 50, Enterprise unlimited) and the billing page surfaces the live count.

- **Template send and direct upload can no longer overshoot the document quota** — A single template send or document upload that creates multiple Document and DocumentAssignment rows is now pre-checked against the projected delta (1 file + N signers) rather than just the current count. An org at 49 / 50 documents sending a template to 10 signers used to push the count to 60; that request is now rejected up front with a message explaining how many units would be consumed.

- **Receipt-scan counter is now race-free** — Two simultaneous receipt scans submitted at the per-month boundary used to both pass the limit check before either incremented, allowing one extra AI call past the cap. The counter is now reserved atomically through a single conditional update; the second concurrent request is rejected before the AI provider is called, and a failed AI call refunds the reserved slot so the user isn&apos;t billed against their quota for a scan that couldn&apos;t be read.

- **Dashboard &quot;Book time off&quot; picker honours the per-user timezone override** — Earlier in the release the calendar grid started highlighting &quot;today&quot; in the viewer&apos;s per-user timezone, but the dashboard&apos;s Book Time Off modal was still pulling the user&apos;s timezone from a JWT-and-localStorage cache that isn&apos;t refreshed after a profile edit. The modal now sources the timezone from the same bootstrap data the grid uses, so a user who changes their personal timezone sees the change reflected everywhere immediately.

- **Group Booking and Lock Dates modals are now timezone-aware** — Both modals defaulted &quot;today&quot; using UTC, which mismatched the highlighted day on the calendar in any negative-offset timezone late in the day. They now use the same per-user-then-org resolution rule as Book Time Off.

- **Add expense (Meal / Travel) date pickers no longer pre-fill UTC today** — Same class of bug, same fix: meal and travel expense cards prefill the date in the viewer&apos;s resolved timezone instead of UTC.

- **Document upload, assign, and template send `minDate` honours the org timezone** — The minimum-due-date constraints on document upload modals are now computed in the org&apos;s resolved timezone so users in negative-offset zones can still pick &quot;today&quot; late in the evening.

- **Onboarding DOB picker max bound is now in the viewer&apos;s timezone** — Same fix applied to the onboarding welcome modal&apos;s `max` attribute on the date-of-birth input.</description>
    </item>
    <item>
      <title>v1.0.13</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.13</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.13</guid>
      <pubDate>Wed, 20 May 2026 01:58:43 GMT</pubDate>
      <description>This release rounds out the onboarding-documents workflow that started in v1.0.12, finishes the profile-page redesign that began in v1.0.9, ships a number of authentication and security fixes (TOTP, refresh tokens, dependency CVEs, Redis), and polishes the document signing UX top-to-bottom.

### New Features

- **Per-employee onboarding document copies, finished end-to-end** — The per-recipient document generation introduced in v1.0.12 is now fully wired across the onboarding lifecycle. Every new hire gets their own copy of every required onboarding doc, with their own audit trail, their own signature, and their own signing certificate. Existing organisations have been backfilled.

- **Read-only acknowledgment paths cleaned up** — The &quot;I have read this&quot; footer button and the implicit-on-view acknowledgment from v1.0.12 are now stable across both onboarding and offboarding flows. Edge cases where a read-only doc would only surface after signing a sibling document have been closed.

- **Stable behaviour after rapid back-to-back deletes** — Deleting two documents in quick succession could leave a stale row visible on the documents page for a moment before the second delete caught up. The list now reconciles deletes the moment each response returns, so rapid keyboard- or mouse-driven cleanup feels predictable instead of &quot;did that one save?&quot;.

- **Onboarding-doc workflow refinements** — Several smaller flow fixes shipped on top of the v1.0.12 foundation: the per-user generation runs in more places that previously only generated on profile-tab visits, the sidebar Action Required badge stays in sync after every acknowledgment, and template-scoped documents flow through to instance-scoped per-user copies in every path that creates a task.

- **Profile page redesign shipped** — The profile redesign that started in v1.0.9 is now the only profile experience: sidebar vitals on the left, tabbed sections on the right, inline edit per section. Multiple iteration rounds finalised the layout, inline-edit interactions, completeness indicator, and the per-tab navigation chrome.

- **All section editors land inline** — The legacy modal-based edit flow is fully retired. Each section (basic info, social links, address, contact, emergency contact, employment, leave allowance, holidays, education, languages, certifications, visa, assets, compensation, bonuses, job history, employment status, notes, termination) opens its own inline editor with a sticky save / cancel footer.

- **Faster paint on large profiles** — Build configuration was tuned to give Node a 6 GB heap during production builds so the redesign compiles cleanly under load. End users will notice quicker first-paint on the heaviest profile pages.

- **Continued time-tracking improvements** — The time-tracking module received another wave of refinements building on v1.0.10&apos;s expansion: list-view interactions, schedule auto-generation behaviour, edit-flow safety nets, and a handful of cross-cutting bug fixes across the timesheet, schedule, and approvals surfaces.

- **Geofencing now included in Pro and above** — Geofencing (allowed clock-in locations, circle / polygon shapes, the compliance dashboard, audit trail — all introduced in v1.0.10) is now part of the Pro plan and above instead of being Business / Enterprise only. Existing Pro customers gain access without any billing change.

- **Approval counts scoped to the caller&apos;s rights** — `/api/approvals/counts` (the endpoint that powers the badges on the approvals dashboard) now scopes its numbers to whatever each viewer is actually allowed to act on. Department heads see the count of items in their own queue rather than the org-wide total.

- **Pending-approvals badge updates immediately after approve / reject** — Approving or rejecting any leave, expense, or time entry now busts the cached approvals count so the sidebar and overview badges drop in real time instead of waiting on the next poll.

- **Cleaner copy throughout the signing flow** — Multiple iterations on the document signing pages refined the copy, the recipient picker, the field placement UX, and the post-signing confirmation. The Sign mode upload page is faster and more obvious to use end-to-end.

- **No more &quot;legally binding&quot; / ESIGN Act claims in the UI** — Removed copy that asserted the in-app signature was ESIGN-Act-compliant or legally binding. The signature flow still records full audit context (IP, user-agent, timestamp, signing certificate) for evidentiary purposes, but the product no longer makes legal claims it isn&apos;t qualified to make. Customers who need full e-signature legal force are still expected to use a dedicated provider.

- **Email logos render correctly in Outlook for Windows** — A long-standing rendering bug caused organisation logos to balloon to the full email width in Outlook for Windows specifically. Logos now render at the intended size across Outlook, Gmail, Apple Mail, and the major email clients.

- **Leave-submission notifications are scoped to the submitter&apos;s department** — When an employee submits a leave request, the approver notification used to fan out to managers across the entire org. It now goes only to the submitter&apos;s own department head plus administrators and executives, matching how every other approval queue is scoped. Cross-department managers are no longer pulled into approvals that aren&apos;t theirs.

- **&quot;Remember me&quot; now defaults to off** — The login screen&apos;s &quot;Remember me&quot; checkbox defaults to unchecked. Long-lived sessions are now an explicit opt-in rather than the silent default.

- **TOTP login fix** — Two-factor login was being rejected by the API interceptor before the verification request could reach the server, because the TOTP-verify endpoint wasn&apos;t in the public route list. Users with 2FA enabled can now log in without a transient &quot;Unauthorised&quot; error.

- **Email verification fixes** — `verify-code` and `resend-verification` were treated as public endpoints, which interacted badly with rate-limiting and session continuity for users who&apos;d partially registered. They now flow through the authenticated path, so verification works correctly on first try.

### Bug Fixes

- **Training auto-assign computed due dates in the past** — When a training requirement was created with a &quot;due X days from hire date&quot; rule, the auto-assign logic could resolve a `dueDate` earlier than today for new hires whose hire date was already past the offset window. The check is now resolved against &quot;today in the org&apos;s timezone&quot; so brand-new requirements assigned to existing employees get sensible due dates instead of arriving pre-overdue.

- **PDF receipts wouldn&apos;t render in some browsers** — A stricter X-Frame-Options policy (`DENY`) was preventing inline PDF receipt previews from rendering inside the app on Safari and a few Chrome configurations. Relaxed to `SAMEORIGIN` so receipts preview correctly without weakening cross-site protection.

- **Rapid back-to-back document deletes left a stale row** — See &quot;Onboarding Documents&quot; above. Two deletes in quick succession could leave a phantom row visible until the next refresh; the list now reconciles after each response.

- **Outlook for Windows email logo size** — See &quot;Document Signing&quot; above.</description>
    </item>
    <item>
      <title>v1.0.12</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.12</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.12</guid>
      <pubDate>Tue, 05 May 2026 02:31:02 GMT</pubDate>
      <description>### Onboarding &amp; Offboarding Documents

A focused release on the document side of the onboarding/offboarding lifecycle. Templates can now be scoped to multiple departments at once; per-user copies of onboarding documents are generated from a single canonical template (closing a long-standing signature edge case where multiple new hires could overwrite each other&apos;s signature on the same file); read-only documents (employee handbook, code of conduct, exit-policy reads) automatically mark the linked task complete the moment they&apos;re read; and the global sidebar gains an amber &quot;Action Required&quot; badge so employees see at a glance how many docs they still owe.

### New Features — Document Templates

- **Multi-department scope** — A template can now be scoped to multiple departments at once instead of just one. Existing single-department templates were migrated automatically, so every previously scoped template kept its scoping intact. Department heads see a template if any linked department is theirs; administrators and executives see all.

- **Edit department scope from the template list** — `/documents/templates` rows now have a settings-cog menu next to the rename action that opens an Edit Template modal. Name and multi-select department scope live in one form. Department heads are locked to their own department in the picker, and the server re-validates on save so a tampered request can&apos;t escalate. Department updates are applied atomically — an interrupted save can&apos;t leave a template half-scoped.

- **Pill-segmented Active / Archived tabs** — The Active and Archived rails on the templates page were redesigned as a pill-segmented control matching the audit-logs styling (constrained width, rounded selection background) instead of the old underline tabs.

- **Archive and restore** — Templates can now be archived (hidden from the active picker without deleting the row) and restored. Archive preserves the template&apos;s history — the docs already generated from it are unaffected.

- **Multi-select department picker on create** — `/documents/templates/create` replaces the single department dropdown with a multi-select checkbox grid. Department heads see only their own department in the picker.

- **Templates redirect renders cleanly for employees** — Employees who land on `/documents/templates` are now redirected to `/documents` cleanly, replacing the previous redirect that left a blank white screen until the user manually refreshed.

### New Features — Per-User Document Generation

- **Per-employee copy of every onboarding document** — When an onboarding or offboarding task with a doc attachment first surfaces for an employee, the system now reads the canonical template and creates a per-employee copy. This closes a quiet edge case where the same Document file was being signed in place by multiple new hires — subsequent signers could overwrite the first signature, and there was only ever one shared audit trail. Per-employee copies give every recipient their own audit trail, signature record, and signing certificate.

- **Read-only mode for informational templates** — Templates with no required signers generate as a read-only document in the employee&apos;s drawer that doesn&apos;t require any signing flow to surface. The employee just sees the document in their files. Repeat generation is a no-op.

- **Backfill for existing organizations** — Existing organizations have a one-time migration that walks every onboarding task with a legacy attached document, derives a template from it, and re-points the task at the new template. Safe to re-run on rows already migrated.

### New Features — Onboarding/Offboarding Workflow

- **Instance delete returns immediately** — Removing an onboarding or offboarding instance from a user&apos;s profile previously appeared to &quot;come back for 30 seconds&quot; — the row stayed visible until the email notification finished sending to all recipients. The delete now returns the moment the row is gone; the email is dispatched in the background. Refreshes during the email-send window now show the deletion correctly.

- **Standalone /onboarding page retired** — Templates and per-user instances were both surfaced from `/onboarding`, duplicating UX that already lived on each employee&apos;s profile (Onboarding / Offboarding tabs). The standalone page is now a thin redirect to `/users`; the Guided Tours setting was updated to match. `/settings/onboarding` absorbs the template management UI for administrators.

- **Default assignee resolved per-instance** — Onboarding template tasks with no explicit assignee previously resolved a default per-task at create time, which could bounce unassigned tasks across multiple administrators on the same instance. The default is now resolved once per instance creation, so all unassigned tasks for that import land on the same administrator — easier to track and matches what an administrator expects when they kick off a new hire.

### New Features — Read-Only Document Acknowledgment

- **&quot;I have read &amp; acknowledge&quot; button on read-only docs** — Read-only onboarding/offboarding documents (employee handbook, code of conduct, exit policy, return-of-equipment acknowledgment) now have a footer button in the document preview that explicitly records &quot;I have read this&quot;. Clicking it marks the linked onboarding task complete with a real timestamp + audit row, fires the standard task-completed notifications, and rolls the parent instance status forward (Not Started → In Progress → Completed). Only the document owner can click — administrators and department heads keep their existing path for marking tasks complete on someone else&apos;s behalf.

- **Implicit acknowledgment on view** — Opening a read-only doc whose linked task is still pending also fires the same acknowledgment quietly in the background. Both paths are recorded distinctly in the audit log (`ACKNOWLEDGE` vs `ACKNOWLEDGE_ON_VIEW`) so explicit and implicit signals stay distinguishable. Document views are already audit-logged with IP and user-agent, so the implicit path retains enough trail to defend in a compliance dispute.

- **Identical behavior for offboarding** — The same flow closes return-of-equipment and exit-policy reads when a leaving employee opens the doc, not just onboarding handbooks. Notifications correctly say &quot;Offboarding&quot; vs &quot;Onboarding&quot;.

- **Self-heal on the documents page** — When an employee opens `/documents` *before* visiting their onboarding tab, any per-employee copies of onboarding documents that haven&apos;t been generated yet are now generated lazily on the list request. Previously employees only saw their read-only onboarding doc *after* signing the sibling signature-required document, because the page reload happened to trigger the generation through a different code path.

- **Document list stays in sync after deletes and acknowledgments** — Browser caching for the documents list was loosened so deletions and acknowledgments show up immediately instead of requiring a hard refresh. Server-side caching still handles the speedup.

### New Features — Action Required Sidebar Badge

- **Amber count badge on Action Required** — The global app sidebar&apos;s &quot;Action Required&quot; entry now shows an amber pill with the user&apos;s outstanding count: pending signature requests + overdue signatures + pending read-only acknowledgments. Hidden when zero. When the sidebar is collapsed, the badge becomes a small amber dot in the corner of the icon so the signal survives the narrow rail.

- **Refreshes without a full page reload** — The badge count refreshes on first sign-in, on every navigation into `/documents` or `/dashboard`, and inline after any acknowledgment in the documents page itself — so the count never lags behind reality.

### Bug Fixes

- **Document deletes didn&apos;t drop out of `?view=byEmployee` until refresh** — Deleting a document from the by-employee drawer view appeared to do nothing until the user manually refreshed. Fixed.

- **Onboarding instance &quot;came back for 30 seconds&quot; after delete** — See &quot;Instance delete returns immediately&quot; above; root cause was the delete waiting on email send before responding.

- **Read-only doc only appeared after signing a sibling** — Per-employee generation for onboarding read-only docs only fired when the employee opened the onboarding tab. If they hit `/documents` first, their read-only doc was missing until the page reload after signing happened to trigger generation through a different code path. Fixed via the self-heal described above.

- **Templates page redirected employees to a white screen** — Logging in as an employee and visiting `/documents/templates` redirected to `/documents` but rendered a blank page until manual refresh. Fixed.

- **&quot;New Template&quot; button on /documents/templates was silently no-op** — Clicking &quot;New Template&quot; did nothing for some users. Fixed.</description>
    </item>
    <item>
      <title>v1.0.11</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.11</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.11</guid>
      <pubDate>Fri, 01 May 2026 14:25:37 GMT</pubDate>
      <description>### Documents Redesign

A top-to-bottom rework of the Documents experience. The /documents page now opens to a familiar filing-cabinet view of every employee&apos;s drawer, custom folders sit alongside the 13 built-in categories, the upload flow has separate Store and Sign modes, and the document detail page has a large preview and a quieter sidebar. Most of this release is in the documents area; the rest is small fixes around feature-flag propagation, exports, and dependency updates.

### New Features — My Documents (filing cabinet)

- **Folder cabinet for every user** — The /documents page opens on &quot;My Documents&quot; — a 2-3 column grid of folder tiles for every employee in the org. Each user always sees the full cabinet (13 built-in categories: Contracts, Offer Letters, Salary Increments, Performance Reviews, Policy Documents, ID Documents, Certificates, Training Materials, Medical Certificates, Visa Documents, Tax Documents, Insurance, Other) — even if a folder is empty — so you can drop a new doc straight into the right category instead of routing everything through a generic Upload entry point.

- **Folder visual** — Each tile is rendered as an actual two-layer folder shape (tab + body) tinted by the category&apos;s brand color. Empty folders sit at low opacity; populated folders take a bolder tint plus a colored count badge in the corner. Hover lifts the folder graphic for a subtle &quot;pluck-out&quot; feel. The &quot;New folder&quot; tile mirrors the same shape with a dashed outline so it sits in the cabinet visually.

- **Custom folders** — Per-user custom folders sit above the 13 built-in categories. Pick a name (max 50 chars), a Lucide icon from a curated set, and a hex color from a swatch grid. Folders are scoped to a single user&apos;s drawer.

- **Folder context menu** — Edit / rename / re-icon / recolor / delete on any custom folder via the context menu that surfaces on hover. Soft-deleted folders release their name slot immediately, so you can recreate a folder with the same name without hitting a unique-constraint error.

- **Tag filter** — Folder grid carries a tag filter dropdown sourced from the docs in the currently visible scope. Selecting a tag at the top level drops you into a flat result list with cross-folder matches; inside an open folder, the tag narrows that folder. Composes with search.

- **Folder URL routing** — Open folders are encoded as `?folder=offer-letters` etc., so refresh, browser-back, and shared links keep state. Custom folders use `?folder=custom:&lt;id&gt;` for unambiguity.

- **Per-user folder pages** — `/users/{id}` now shows the same folder grid component on the Documents tab. Admins, Executives, and Department Heads (for in-scope employees) can browse a coworker&apos;s drawer; everyone else sees their own.

- **Role-gated folder creation** — The &quot;New folder&quot; tile is hidden when an employee or department head is viewing their own drawer — you don&apos;t manage your own filing structure as a non-admin. It&apos;s still available to admins / executives anywhere, and to department heads viewing an in-scope employee.

### New Features — Action Required

- **Unified attention dashboard** — Action Required is now a single dashboard that aggregates pending signatures + expiring documents into one list, with chips to filter by All / Sign / Expiring / Overdue and stat tiles that double as filters. Replaces the old separate Inbox / Completed / Expiring rails.

- **Sent-style toolbar** — Search, status filter, sort, Export, admin-only Templates / Bulk Send shortcuts, and a Start CTA on top of a desktop table + mobile card list. Pagination footer with rows-per-page selector renders whenever the list has any items.

- **Completed view folded in** — The retired ?view=completed page is now a fifth chip + filter on Action Required. URL syncs via `?filter=` so refresh and back-button preserve state.

### New Features — Drive-style Upload Page

- **Two-mode upload** — `/documents/upload` ships with a Store / Sign segmented control rendered as a sliding-pill tab, each mode laid out as a 2-column drive view: large file dropzone + live PDF or image preview on the left, metadata aside on the right. Mode is URL-synced via `?mode=store|sign` so deep-links and refresh land consistently.

- **Store mode** — A dedicated form for filing a doc in a built-in category or a per-user custom folder. Posts to the existing personal-upload endpoint. Optionally targets another user when the caller can manage that user&apos;s documents.

- **Sign mode** — Drag-and-drop a PDF, choose recipients (parallel or sequential), set a due date, place signing fields, and send. PDF preview now uses viewport-relative sizing (78vh, capped at 1100px) so the preview is actually usable on a 14&quot;+ display.

- **Description &amp; tags** — Both modes have a &quot;Description &amp; tags&quot; section: optional description (sanitized) and up to 10 tags (32 chars each, lowercase, deduped). Tags flow through to the folder grid&apos;s tag filter.

- **Categories-only upload picker with help tooltip** — Store mode&apos;s category dropdown now offers only the 13 built-in DocumentCategory values, with a help tooltip next to the Category label explaining that administrators and executives can move the file into a custom folder afterwards. Removes confusion where uploaders saw their custom folders in the picker but couldn&apos;t always file into them.

- **Expiry date tooltip** — A help tooltip next to the optional Expiry date field gives a concrete example (visa / insurance / certificate renewal) so it&apos;s clear what the field is for and when to leave it blank.

### New Features — Document Detail Page

- **Slim breadcrumb header** — Back link › title › status pill › action buttons (Place fields / Open / Download), all in one row, replacing the tall hero card.

- **Large embedded preview** — The PDF takes the dominant left column at 78vh viewport-height with a click-to-open hint floating top-right on hover. No more 280×320 thumbnail card.

- **Unified sticky sidebar** — One sticky panel on the right with internal dividers instead of four separately-bordered cards. Reads as a single neutral surface.

- **Sequential signing chips** — In sequential mode the order chip (1, 2, 3…) is color-coded — green for signed steps, primary tint for the active step, gray for queued, red for declined / expired — so the timeline reads as a checklist at a glance.

- **Initials avatar chips** — Each recipient row shows an initials avatar tinted by status, with a tiny colored dot + sentence-case status label inline (&quot;● Declined · Apr 29, 7:46 PM&quot;) instead of a chunky pastel pill chip.

- **Truncated document ID** — Doc IDs render as `CMOKVT…0T0S1` in the Details panel with a one-click copy of the full ID.

- **Audit history collapsible** — The audit timeline (admin-only) becomes a disclosure section at the bottom of the sidebar instead of a third tab. Tucked away because most visits aren&apos;t there to read it.

### New Features — Sign Page Polish

- **Header always visible** — The &quot;Review and complete / Decline / Finish&quot; header on `/documents/sign/:id` no longer hides behind the global app toolbar until you scroll.

- **Decline modal works on first click** — The decline confirmation modal opens reliably the moment you press Decline.

### New Features — Excel Export

- **AG Grid export preview for Documents** — The Documents page&apos;s &quot;Export in Excel&quot; now opens `/documents-export`, an AG Grid preview matching `/users-export`. Theme picker (Quartz / Alpine / Balham / Material), quick filter, column show/hide, sort, reset, and CSV download. Status cells are color-tinted to match the chips on the list page.

### New Features — Notifications

- **Document notifications deep-link to the right view** — Notifications for signing requests, reminders, and expiring documents now link straight to `/documents?view=actionRequired` instead of the generic /documents landing page. The user lands one click from the doc that needs them.

- **Personal-upload recipients are notified** — When an admin uploads a personal document for an employee (Store mode targeting another user), that employee now gets an in-app notification + email. Previously the upload was silent.

- **Document upload oversight notifications** — Whenever a document is uploaded for an employee, executive, department head, or administrator, leadership is now looped in: every executive is notified, administrators are notified (except in the narrow case where an executive uploads to an administrator), and a department head whose own report receives a document is included for their own department. The recipient still gets their existing notification — this is an additional oversight feed for the people responsible for HR records.

- **Daily document-expiry reminders** — A new daily reminder fires at the 60 / 30 / 7 / 0-day marks before a document&apos;s expiry date. The document owner is always notified (so they have time to renew their visa, insurance, certificate, etc.); the same oversight audience above is also notified, with mute switches per audience member. Internal de-duplication prevents repeat reminders inside the same window.

- **Document oversight settings** — `/settings/notifications` now has a Documents section (visible to administrators, executives, and department heads) with two toggles: &quot;When a document is uploaded for someone in scope&quot; and &quot;When a document is approaching expiry&quot;. Both default on so leadership has visibility out of the box.

- **Default digest scope is now &quot;Full organisation&quot;** — New users get a full-org digest by default rather than &quot;Just me&quot;, since most teams want to see who&apos;s off across the whole company. Existing users keep whatever they had.

- **Public holidays on the digest by default** — The &quot;Include public holidays in digest&quot; toggle is now on by default, so the daily / weekly digest shows holidays alongside leaves without having to opt in.

- **&quot;Anyone you manage&quot; is now manager-only** — The &quot;Anyone you manage&quot; digest scope only appears for users who actually have direct reports. Non-managers no longer see (or get clamped onto) an empty scope, and the radio is hidden in their settings.

- **Privacy settings flow into the digest** — When an organisation has &quot;Other departments — Hidden&quot; enabled in /settings/general, non-admin users can no longer pick the full-organisation digest scope, and any saved org-wide preference is automatically narrowed to their own department at dispatch time. Administrators and executives stay exempt — the privacy toggle has always carved them out.

### New Features — Calendar Privacy

- **&quot;Calendar view — Hidden&quot; is now actually enforced** — The privacy toggle in `/settings/general` for &quot;Calendar view&quot; was previously cosmetic — turning it on didn&apos;t change what users could see. It now gates the per-user year-view absence calendar at `/calendar/&lt;userId&gt;` end-to-end: when &quot;Hidden&quot;, only the user themselves, their direct manager, the department head of their department, and administrators / executives can open the page. Peers are redirected back to the dashboard with a notice. The leaves and balance APIs that power the page apply the same rule, so direct API calls can&apos;t bypass it either.

- **Calendar view defaults to Hidden** — New organisations now start with &quot;Calendar view&quot; set to Hidden out of the box, since a year-view absence calendar shows medical / bereavement / similar sensitive leaves and shouldn&apos;t be broadcast to peers without an explicit opt-in. Existing organisations are also flipped to Hidden, on the basis that the toggle wasn&apos;t enforced before so any prior &quot;Visible&quot; value reflected the legacy default rather than a deliberate choice. Admins who do want the calendar open across their org can flip it back from `/settings/general` at any time.

- **Dashboard name links respect the toggle** — On `/dashboard`, the colleague name in each row is only rendered as a clickable link when the viewer is allowed into that person&apos;s calendar. Click-through never lands on a 403 or an empty grid — the link simply isn&apos;t a link for viewers who&apos;d be blocked.

- **Private leave types are hidden on the per-user calendar too** — The &quot;Private&quot; toggle on `/settings/leavetypes` (&quot;Hide leave type name from other employees on the dashboard&quot;) already worked on `/dashboard`; it now applies on `/calendar/&lt;userId&gt;` as well. Non-self / non-admin / non-same-department-head viewers see the type as a generic &quot;Private&quot; label with the reason and notes hidden, matching the dashboard behaviour. The leave&apos;s owner and admin / dept-head viewers still see the real type name and details.

### Improvements — Visibility &amp; Billing

- **Declined / expired docs hidden from your own drawer** — A document you declined to sign or one whose deadline lapsed no longer keeps appearing in your own folder. Department heads still see those rows for their reports, and admins / executives still see the whole organization. Restored automatically if the document is reopened.

- **Multi-recipient visibility fix** — When a document is sent to multiple co-signers, every recipient now sees the doc in their My Documents folder — not just the first recipient. Previously only the primary signer saw it in their drawer; the others had to open it from the notification.

- **Document quota now gates assignment + bulk send** — Adding new signers to an existing document, and bulk-sending from a template, both now check the org&apos;s monthly document quota before creating any rows. Previously these paths could push usage past your plan&apos;s limit silently. The block surfaces a clear message with current vs. allowed counts and a link to upgrade.

- **Per-user signer counts in the Sent list** — The Sent view groups multi-recipient sends as one row with a &quot;Signed by N of M&quot; indicator, instead of one row per signer.

- **&quot;Shared&quot; and &quot;Unassigned&quot; status filters** — The status filter on `?view=sent` adds two new entries — &quot;Shared&quot; (for documents shared without a signature request) and &quot;Unassigned&quot; (for documents with no recipients yet) — so admins can split bulk-send activity from one-off shares without scanning every row.

- **Department-head Sent view scoped to their own uploads** — When a department head opens `?view=sent`, the list now shows only the documents they themselves uploaded. Previously the view could surface admin- or executive-initiated sends that happened to involve the department head, which was confusing.

### Improvements — Navigation &amp; Settings

- **Documents in the sidebar gets its own group** — The global app sidebar now has a top-level &quot;Documents&quot; section above Time &amp; Projects, with role-aware children (My Documents, Action Required, Sent, Templates, Bulk Send, By Employee).

- **By Employee moves under Management** — On the global sidebar, By Employee sits under Management next to Approvals and Reports — they&apos;re all admin oversight surfaces with the same shape. The in-page documents rail keeps its own By Employee link so admins already inside /documents don&apos;t have to bounce back to the global nav.

- **Sidebar scrollbar auto-hides** — The app sidebar&apos;s scrollbar is now hidden until hover / focus / active scroll. CSS keeps gutter stable so the rail width doesn&apos;t jump.

- **Tag filter at top level** — Selecting a tag on /documents (with no folder open and no search) now drops you into a flat result list of matching docs across folders. Previously the tag dropdown updated state but didn&apos;t change the visible cabinet, so it appeared to do nothing.

- **/approvals stat row fills width** — When time tracking is disabled, the /approvals stat row (Total Pending / Leave / Expense / Timesheet) drops to 3 columns instead of leaving an empty 4th slot.

- **Time-tracking toggle reflects immediately** — Toggling &quot;Enable Time Tracking &amp; Projects&quot; in /settings/timetracking now updates /reports and /approvals on the next visit instead of waiting on a 5-minute settings cache. The Time / Projects / Scheduling cards, charts, the Available Reports table rows, and the Timesheet Entries tile all appear or disappear in sync with the flag.

- **No more redirect flash** — Visiting `/reports/time`, `/reports/projects`, `/reports/scheduling`, or `/approvals/time` while time tracking is disabled now redirects cleanly to the parent dashboard before the page renders. Previously you&apos;d see a split-second flash of the disabled report before being bounced back.

- **All &quot;when does the org work&quot; config in one place** — `/settings/general` is now the single home for both **business days** (the day-of-week picker) and **default working hours** (start, end, break for shift auto-generation). The Default Organization Schedule card moved over from `/settings/timetracking`, so admins no longer have to bounce between two pages to set up the company calendar. The schedule card only appears when time tracking is enabled.

- **Settings search refreshed for the new sections** — The &quot;Search settings&quot; bar in the /settings header now finds the Default Working Hours card, the new notification toggles (&quot;Default digest scope&quot;, &quot;Public holidays on digest&quot;, &quot;Document upload activity&quot;, &quot;Document expiry reminders&quot;), the per-leave-type &quot;Private&quot; toggle, and gives the Calendar privacy and Other Departments privacy toggles their own dedicated entries. Searching for the old label &quot;business hours&quot; still resolves to the new Business Days section.

### Bug Fixes

- **Folder rename collision with soft-deleted rows** — Recreating a folder with the same name no longer fails with a 500. The unique index on (organizationId, userId, name) was treating soft-deleted rows as still occupying the slot. Delete now tombstone-renames the row so the slot frees up immediately.

- **Empty drawer now shows the full cabinet** — A user with zero documents now sees every category folder marked &quot;Empty&quot; plus the &quot;+ New folder&quot; tile, instead of being routed through a generic upload prompt that hid all 13 categories.

- **Personal-upload notifications were missing** — Employees received no notification when an admin uploaded a personal document for them. Fixed.

- **Multi-recipient docs vanished for co-signers** — A document with multiple recipients only appeared in the first recipient&apos;s drawer. All recipients now see the doc in their My Documents folder.

- **Decline button on /documents/sign/:id did nothing** — A z-index conflict caused the decline confirmation modal to render behind the signing pane, so clicks appeared to do nothing.

- **Personal upload would fail for some built-in categories** — Uploading a document under categories such as Insurance, Tax, Visa, Medical Certificate, Training Material, ID Document, or Salary Increment could surface a generic &quot;Server Error&quot; on submit. Fixed — every built-in category now uploads cleanly.

- **&quot;Requires signature&quot; toggle removed in sign mode** — Sign mode always requires signatures, so the redundant toggle on `/documents/upload?mode=sign` is gone. The Sign-by picker and signing-order editor are always rendered when the page is in sign mode.

- **Private leave types could leak on a colleague&apos;s calendar** — Opening another user&apos;s `/calendar/&lt;userId&gt;` page surfaced the real leave-type name (e.g. Bereavement Leave) even when the type was marked Private — only the dashboard was applying the obfuscation. Fixed; the per-user calendar now mirrors the dashboard rule.

- **&quot;Calendar view — Hidden&quot; privacy toggle did nothing** — The toggle in `/settings/general` for &quot;Calendar view — Hidden&quot; was persisted to the database but never read by the actual per-user calendar. Toggling it on / off didn&apos;t change what peers could see. Fully wired up now (see &quot;Calendar Privacy&quot; above).

- **&quot;Business hours&quot; was actually the business-days picker** — The section in `/settings/general` labelled &quot;Business hours&quot; was a row of day-of-week checkboxes (Mon, Tue, ...), not a time-of-day setting. Renamed to &quot;Business days&quot; to match what it actually does.</description>
    </item>
    <item>
      <title>v1.0.10</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.10</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.10</guid>
      <pubDate>Mon, 20 Apr 2026 16:40:11 GMT</pubDate>
      <description>### New Features

#### Geofencing

- **Allowed clock-in locations** — New `/settings/geofencing` area lets Administrators and Executives define the sites where employees can clock in / out. Department heads can also manage geofences — scoped to their own department&apos;s users and projects. Every fence carries a name, type (Site / Project Site / Client Site / Home Office / Other), optional address, and a description field visible only to admins. Fences can be toggled Active / Inactive without losing history.

- **Circle and polygon shapes** — A fence can be either a circle (centre + radius) or an arbitrary polygon (ordered list of vertices). Switch between the two with a toggle in the editor. The server stores both forms and runs the right inside/outside test per shape; polygon fences also store a centroid + bounding-sphere radius so list views, nearest-fence queries, and other circle-shaped code paths keep a sensible reference point.

- **Interactive map editor** — A full-page, split-layout editor with the map on the left and a side rail for metadata. Click &quot;Draw circle&quot; or &quot;Draw polygon&quot; to place a shape by hand; drag the marker or the polygon vertices to refine; &quot;Use current location&quot; drops the shape at the admin&apos;s own GPS fix and zooms in. Coordinates + radius inputs stay in sync with the map in real time. When `GOOGLE_MAPS_API_KEY` is missing the editor gracefully falls back to coordinate inputs.

- **Google Maps + OpenStreetMap** — Provider toggle in the editor toolbar. Google is the default when a key is configured; OpenStreetMap (Leaflet + leaflet-draw) is available as an alternative — same drawing tools, same shape edit handles, no API key required. Native map controls (zoom, map-type switcher) stay visible and out of the way of the custom toolbar on both providers.

- **Configuration + Assignments tabs** — The editor splits fence geometry (Configuration) from access control (Assignments) into two top-level tabs, matching the pattern that enterprise IAM and HRIS tools use for resources + permissions. The tab state round-trips through the URL (`?tab=assignments`) for bookmarks and back-button navigation. Newly-created fences redirect straight to the Assignments tab so the admin never forgets the follow-up step.

- **Assignment scopes** — Every fence must be assigned to at least one target before employees see it. Supported scopes are Organization (everyone), Department, User, and Project. Resolution order when an employee clocks in is Project → User → Department → Organization; the most specific match wins. Per-assignment flags control whether clock-in, clock-out, or both are enforced — useful for sites where workers must clock in at a specific location but can clock out anywhere. Assignments can be added, edited, and removed from a shared modal matching the rest of the product&apos;s dialog treatment.

- **Three enforcement modes** — `REQUIRED` blocks clock-ins that fall outside an applicable fence, `OPTIONAL` lets them through but flags the entry on the compliance dashboard, and `LOG_ONLY` silently records the out-of-bounds condition for admin review without surfacing anything to the employee. Mode + GPS accuracy tolerance + maximum acceptable GPS accuracy are all configured from `/settings/timetracking`.

- **Live status on the clock-in screen** — A full-width status banner above the Clock In / Clock Out buttons on `/time-tracking` shows the current state: inside the allowed area (&quot;At HQ&quot;), outside (&quot;1.4 km from HQ&quot;), no GPS signal, or still acquiring. Colours are muted (emerald for good, amber for warning) so the banner reads as information, not an error. Updates in near-real-time as the employee&apos;s location changes. When the employee picks a project in the clock-in modal, the banner re-evaluates against that project&apos;s fences so they see immediately whether the chosen project is clockable from here.

- **Rejection modal with nearest-fence guidance** — When an attempt is blocked, a modal shows the nearest allowed site by name, the distance to it, and a list of all allowed locations for the action — so employees know where to go without having to call their manager. GPS-accuracy rejections include a specific hint to move outdoors or near a window for a better fix.

- **Compliance dashboard + CSV export** — Administrators / Executives (and dept heads for their own department) get a paginated list of out-of-bounds clock-ins with 7-day and 30-day summary counts. CSV export uses the same filters and encodes rows safely for spreadsheet consumers.

- **Audit trail on every change** — Every create, update, delete, assignment change, and blocked clock-in attempt is recorded in the organization&apos;s audit log with actor, fence id, and the before/after payload, so compliance has a reviewable trail of every geofence policy decision.

- **Geofenced time entries record their fence context** — When an entry is created inside a fence, the fence id, the GPS accuracy at the time, and a confidence classification (HIGH / MEDIUM / LOW / UNVERIFIED) are stored on the entry. Historical entries retain this information even if the fence is later renamed, deactivated, or deleted.

- **Mobile-ready clock API** — Clock-in / clock-out endpoints emit an `X-API-Version` response header and return structured `data.error` codes so future native mobile clients can match on stable identifiers instead of parsing human messages. An offline-queue timestamp protocol (`clockInAt` / `clockOutAt` body fields with a ±15 min future / 24 h past tolerance) lets mobile apps replay clock events queued while the device was offline.

- **Shared row-action pattern** — The `/settings/geofencing` list and the Assignments table both use the same ellipsis-menu row action (Edit / Manage assignments / Delete, teleported dropdown so it escapes table clipping) that the admin dashboard already uses — one interaction pattern, one mental model, regardless of which table the user is on.

#### Time Tracking &amp; Project Management

- **Pay-period lockdown** — Admins can set a lockdown date after which time entries with a clock-in before that date can no longer be edited or deleted by employees. A configurable grace window (in days) lets managers close out late-submitted hours after the lock. Only Administrators and Executives can override the lock for corrections; every override is written to the audit log with the entry&apos;s date and the lockdown cutoff so compliance has a reviewable trail of every exception. Department heads cannot override.

- **Configurable clock time rounding** — New time-tracking setting to snap clock-in/out to a configured interval (1–60 minutes) with UP / DOWN / NEAREST direction. Disabled by default. Applied uniformly to live clock-in/out, manual entry, and edits so billable hours line up with the org&apos;s rounding policy regardless of how precisely the user clicks.

- **Free-form tags on time entries** — Each entry can carry up to 10 lowercase tags (32 characters each) for categorisation and filtering. Tags appear in the entry modal as a comma-separated input — paste anything, the system normalises (lowercase, strips punctuation, dedupes). Filterable through the entries API.

- **Project money budgets** — New `budgetAmount` field on projects complements the existing hours budget with a cost ceiling. Tracked against (hours × hourly rate) of billable entries only — non-billable time never draws down the cost budget. Project detail page renders a second progress bar alongside the hours budget with matching 80/100% colour thresholds. Currency inherits from the organization&apos;s default.

- **Bulk delete time entries** — Multi-select in the timesheet list view with a floating action bar to soft-delete up to 200 entries in one request. Fails closed: if any row in the batch is blocked, nothing is deleted. Selection clears when the week changes.

- **Restart-timer (duplicate)** — One-click duplicate on any past entry clones the project / task / description / notes and starts it as a fresh active timer. Stops any currently-running timer first so the &quot;one active timer per user&quot; invariant holds.

- **Branded PDF export for timesheets** — `GET /api/reports/timesheets.pdf` returns a per-employee branded breakdown with summary totals, billable split, and an optional money column. Same filters as the JSON report plus `projectId`. Admins/Executives get org-wide; department heads are scoped to their own department; employees see their own. New &quot;Export PDF&quot; button on the timesheet top bar.

- **Expanded timesheet filters and report drill-down** — Project, billable, and approval-status filters on the timesheet list, all bound to URL query params so filtered views are shareable. Time-report tables now drill down: clicking a row navigates to the timesheet view pre-filtered to that user / project, so a manager can go from &quot;this person logged 40h&quot; straight to the underlying entries.

- **Bulk edit on timesheets** — Multi-select in the list view now supports field-level bulk edits alongside bulk delete. Pick any combination of project, billable flag, and hourly-rate override, apply to up to 200 entries in one request. PATCH semantics: only the fields the caller explicitly ticks get written, so one column can be restamped without touching the others. Same fail-closed lockdown and ownership gates as bulk delete.

- **Cost aggregation in time reports** — The time report now surfaces fully-loaded cost alongside hours for administrators and executives. Rate is drawn from each employee&apos;s effective Compensation record at the time each entry was logged, so mid-period raises are picked up automatically. SALARY pay types are normalised to hourly at 2080 hours/year; HOURLY is used as-is. A new Total Cost summary card appears on the report, and the Employee breakdown picks up a Cost column. Entries for employees with no Compensation on file are flagged (&quot;(N unpriced)&quot;) so admins can close data gaps rather than silently under-report. Department heads continue to see hours but never cost.

#### Team Matrix View for Schedules and Timesheets

The calendar view overlays every visible employee&apos;s shifts or time entries onto one week × 24-hour grid. With a handful of users it works fine; past 20-30 it becomes unreadable — impossible to spot who&apos;s missing entries, who&apos;s scheduled for overtime, or what still needs approval. Enterprise timesheet and scheduling tools (Workday, SAP SuccessFactors, UKG/Kronos, ADP, Oracle HCM, Ceridian Dayforce, BambooHR) all solve this the same way: one row per employee, one column per day. This release ships that view alongside the existing Calendar and List views on both `/schedules` and `/time-tracking/timesheets`, and makes it the default.

- **Employee × day matrix** — Each visible employee is a row; the seven days of the current week are columns. Each cell shows the relevant aggregate (hours + status dots for timesheets; shift time range + type for schedules), color-coded by dominant state (green approved / amber pending / red rejected for timesheets; shift-type colors for schedules). A Week total column at the right gives the per-employee totals at a glance. The employee column and header row are sticky, so scrolling horizontally keeps the name and date context in view.

- **Click-to-drill** — Clicking a cell with one entry or shift opens it directly in the edit modal. Clicking a cell with multiple entries expands the row inline, grouped per day, so you can see every entry side-by-side without leaving the page. Clicking an empty cell opens an Add Entry / Add Shift modal pre-seeded to that employee and date (and a 9 AM default start time for schedules), so admins don&apos;t have to re-pick the user they just clicked on. A chevron on the employee name toggles the inline expansion for the whole week.

- **Drag-resizable columns** — Every column (Employee, each day, Week, Status) has a drag handle on its right edge. Widths clamp between 60 and 600 pixels and persist per-browser in `localStorage` so the layout you tuned last week is still there when you reload. Double-click any handle to reset that column to its default; a toolbar button clears every custom width at once.

- **Density toggle** — Compact (36–40px rows) / Normal (52–60px) / Spacious (72–84px). Remembered across sessions. Compact hides secondary lines (department name under employee, shift-type label) so a 30-person team fits on a single screen; Spacious adds breathing room around the data when you&apos;re presenting or reviewing one team closely.

- **Sort and filter** — Sort by name, week hours ↑/↓, pending count, or missing days (timesheets) / unscheduled days (schedules). Filter chips at the top toggle between All / Missing / Pending / Approved / Rejected (timesheets) or All / Unscheduled / Scheduled / 40h+ (schedules), each with a live count so you can see at a glance how many employees fall into each bucket. A text search narrows by name, email, or department. All three controls persist.

- **Holidays and leave aware** — Holiday cells are tinted green with the holiday name in the header; cells where the employee is on leave show the leave type label instead of a blank, so &quot;no shift scheduled&quot; is visibly distinct from &quot;scheduled off&quot;. Open shifts (schedules without an assigned user) render with a muted &quot;Open Shift&quot; label so they&apos;re easy to spot in the matrix.

- **Calendar and List views still available** — The top bar&apos;s toggle is now three buttons instead of two: Team (default) / Calendar / List. The URL `?view=` query parameter accepts all three values, so existing deep-links to the calendar or list view continue to work unchanged, and a team-view link can be shared with colleagues.

#### Approvals &amp; Reports UX Redesign

- **Approvals dashboard overview** — `/approvals` is now a dashboard-style overview. Four edge-joined KPI stat cards (Total Pending, Leave Requests, Expense Reports, Timesheet Entries — hidden when time tracking is off) each link to their detail queue. Below, a unified &quot;Pending Workload&quot; card shows the big-number total + a horizontal bar breakdown per queue, followed by a Review Queues table (Queue badge, Status, Pending count, Review link). Status dot in the header pulses amber when items are waiting and turns green when the queue is clear. A per-queue skeleton covers the pre-fetch window so the cards never flash &quot;0&quot; before counts arrive.

- **Per-type approval pages** — Three new dedicated routes: `/approvals/leave`, `/approvals/expenses`, `/approvals/time`. Each follows a consistent layout: breadcrumb + page header, search + filter dropdowns + export toolbar, a data table with `&lt;colgroup&gt;` column widths, employee avatar cell, colored status / type badges, row-click detail slideover, action dropdown menu per row, reject modal with a dedicated header / body / footer + live character counter + keyboard shortcut hint, and a bottom-pinned pagination footer with rows-per-page selector and prev/next navigation.

- **Reports dashboard overview** — `/reports` is now a dashboard overview. Five edge-joined KPI stat cards (Leave requests, Expenses total, Time hours, Active projects, Scheduled shifts — the last three hidden when time tracking is off) link to their detail pages and surface live numbers fetched in parallel. A two-column chart row shows the Expense Trend (3 or 6 months, area chart with fill) and Leave by Employee (top 5/10/15/20, bar chart rendering compact initials on the x-axis with full names in the hover tooltip — 10-user cap enforced on the API fan-out to prevent chart breakage on large orgs). A three-column chart row below (gated on time tracking) shows Hours Tracked over the last 6 months, Project Hours as a stacked area chart where each project is rendered in its own color (configurable top 3/5/7/10), and Scheduled Shifts by month. Each chart has a settings gear with contextual options (period, metric, max items) and a primary-colored &quot;Done&quot; button. An &quot;Available Reports&quot; table (responsive: desktop table, mobile card list) links to each sub-page.

- **Per-type report pages** — Five new dedicated routes: `/reports/leave`, `/reports/expenses`, `/reports/time`, `/reports/projects`, `/reports/scheduling`. Each wraps the existing tab component inside a consistent shell (breadcrumb + page header). Permission gates and time-tracking redirects preserved.

- **Tab → query-param navigation** — Hash-based tab navigation on `/approvals` and `/reports` (e.g. `#leave`) replaced with query params (`?tab=leave`). URLs are shareable, round-trip through Vue Router, and cooperate with existing drill-down query params (e.g. `?tab=time&amp;userId=…`). A shared `useTabParam` composable handles the state, URL sync, and the async-validation edge case where `validTabs` depends on settings (e.g. `isTimeTrackingEnabled`) that load after the initial render.

- **Shared UI primitives for approvals and reports** — New `components/common/` directory: `PageHeader`, `PageTabs`, `PageToolbar`, `StatCard`, `StatusBadge`, `SearchInput`, `FilterSelect`, `FilterBar`, `SlideOver`, `ActionMenu`. The stat card uses an edge-joined `first:rounded-l-lg last:rounded-r-lg` strip pattern so a row of cards reads as a single unit. The action menu teleports its dropdown to `&lt;body&gt;` with fixed positioning so it escapes any clipping ancestor (table wrappers, slideovers). The slideover is a right-aligned 400px drawer with backdrop click / Esc to close. All built in raw Tailwind against the existing CSS variables so they match the rest of the product&apos;s design system.

- **Cost flow fix in time reports** — The Reports Time tab was dropping `cost`, `totalCost`, and `entriesMissingRate` between the API response and the chart/card render paths on the previous `by_employee` merge. Refactored the merge logic out into `utils/time-report-shape.ts` with proper types. The &quot;(N unpriced)&quot; hint now renders correctly on the Total Cost summary card when entries lack effective compensation, and per-employee cost flows through to the table column.

- **Full-width page treatment** — `/approvals`, `/reports`, and all 8 sub-pages drop the `max-w-7xl` cap and stretch to the full content-area width, matching the `/schedules` layout so wide tables don&apos;t leave empty side margins on large monitors.

- **Pass-through of avatar role colour + badges** — Every new approval/report surface uses the existing `&lt;UserAvatar&gt;` component, so an employee&apos;s initials circle, role-tinted colour, and Administrator/Executive crown/star badge render identically across `/users`, `/calendar`, `/approvals`, and `/reports`. No new palette, no drift.

#### Settings Search

- **Global settings search bar in the top header** — On every `/settings/*` route, the top toolbar renders a compact Stripe-style search input (left-aligned with the page H1). Press `/` anywhere on a settings page to focus it. Hidden on mobile to keep the toolbar usable.

- **Deep-linkable individual settings** — Search results resolve to `path#anchor` (e.g. &quot;time zone&quot; → `/settings/general#time-zone`, &quot;auto clock out&quot; → `/settings/timetracking#auto-clock-out`). Anchor IDs added across ~30 settings components covering General, Time Tracking, Expenses, Carry Forward, Leave Types, Departments, Holidays, Email, Policies, Documents, Training, Performance, Onboarding/Offboarding, Company Directory, SSO, Integrations, QuickBooks, Branding, Security, Support, Danger Zone, Password, 2FA, Notifications, Connected Apps, Guided Tours, and Trusted Devices. Landing on a deep link smooth-scrolls to the target element and paints a soft primary-colored focus ring that fades after ~2.6s.

- **Hand-curated search index with keyword aliases** — `composables/useSettingsSearch.ts` defines a static index of ~75 entries (one per settings page + one per prominent sub-setting) with label, description, parent-page, icon, hash, and keyword aliases. Scoring prioritizes exact label match (1000) &gt; label prefix (500) &gt; keyword exact (400) &gt; label substring (300) &gt; keyword prefix (200) &gt; keyword substring (150) &gt; description match (75) &gt; multi-term all-match (100). Case-insensitive; multi-word queries require every term to appear somewhere in label/description/keywords.

- **Billing-aware lock badges in results** — Each result carries `locked`, `planLabel`, `isAddOn`. Locked entries render a `🔒 Pro` / `🔒 Business` / `🔒 Enterprise` / `🔒 Add-on` pill matching the badge style on `/settings` overview cards — so users can see a gated feature exists and know which plan unlocks it before they click. Locked rows stay in the list (for discovery) but rank lower via a `-25` score penalty. Uses the same `isFeatureLocked` + `getLockedPlanLabel` helpers as `/billing` so the labels stay consistent across the product. The bar calls `loadSubscription()` on mount to ensure badges reflect the org&apos;s actual plan.

- **Role-aware visibility** — The search only indexes `visibleItems` from `useSettingsNavigation`, so an employee searching for &quot;audit logs&quot; gets no result (the page is admin/exec only), while an administrator does. Department heads see onboarding/offboarding entries.

- **Tabbed-page auto-switch** — On pages with tabs (Security, Connected Apps), navigating to `#audit-logs` / `#personal-webhooks` / etc. now auto-selects the matching tab via a `watch(route.hash)` wired to a static anchor-to-tab map, so a result click lands on actual content rather than the default tab.

- **Keyboard navigation** — Arrow keys move the active row, Enter commits, Esc closes, `/` global shortcut focuses the input (ignored when the user is already typing in another field).

- **First-paint layout stability** — The authenticated layout&apos;s outer wrapper animated `lg:pl-[68px]` ↔ `lg:pl-[260px]` when the sidebar collapsed state hydrated from localStorage, dragging the header — including the search bar — left/right for a split second on every refresh. Suppressed the transition on the very first paint via a `layoutReady` flag so the layout snaps instantly; sidebar-toggle animation still works for later user interactions.

#### Guided Tours Overhaul

- **Redesigned popover** — Each tour step now leads with an icon chip, a clearer title, and a short body. Optional &quot;Tip&quot; strips surface pro moves and shortcuts; optional keyboard-shortcut chips (e.g. `/`, `A`, `R`) appear where relevant. Subtle entrance animation, a gentle pulse on the highlighted element, full dark-mode parity, and a viewport-aware width so the popover never overflows on small screens (respects `prefers-reduced-motion`).

- **Rewritten tour copy across the app** — Every tour — Welcome, Calendar, Time Tracking, Timesheets, Schedules, Expenses, Approvals, Reports, Users, Documents, Billing — replaces the old label-style descriptions (&quot;Click here&quot;, &quot;View data&quot;) with outcome-led coaching that names the actual job (&quot;One tap to clock in&quot;, &quot;Find anyone, fast&quot;, &quot;Select many, change once&quot;). Welcome ends with a concrete next action.

- **Five new tours** — Geofencing, Projects, Profile, Onboarding, Training. Each 3–4 steps, auto-opens once per user on first visit to the matching page, replayable any time from Settings → Guided Tours. The Geofencing tour walks through the map editor, the Google / OSM provider switch, and the assignments step that most admins miss.

- **&quot;Don&apos;t show tours&quot; opt-out inside the popover** — A subtle text link on step 1 of every tour lets a user dismiss every tour they haven&apos;t seen yet, without navigating to Settings. Marks them all complete server-side and locally; individual tours can still be replayed later.

- **Smarter placement** — Tours now scroll the highlighted element into view only when it&apos;s actually off-screen (with a 64px top margin for sticky headers), anchor the popover directly next to the target instead of drifting to the bottom of the page, and size themselves to the viewport so narrow phones don&apos;t get a clipped card. Fixed a positioning regression where the popover could drift hundreds of pixels from its target on tour start.

#### Page Redesigns &amp; Data Export

- **Clean flat list view for timesheets** — New admin-audit-log-style table replaces the day-grouped list view. Shows all entries across the selected range in a single flat table with columns: Date, Employee (UserAvatar + department), Project (color dot + task), Description, Time (in→out), Duration, Status (CommonStatusBadge), and Actions (CommonActionMenu). Server-side pagination (50 rows/page default) keeps the API efficient. Checkbox multi-select supports bulk edit and bulk delete. The entries API endpoint now returns summary aggregates (approved/pending/rejected minutes via `groupBy`) alongside the page so header stats stay accurate across pagination. View mode (calendar/list) persists in the URL query param (`?view=calendar` / `?view=list`) — no flash on refresh.

- **AG Grid export page for timesheets** — Clicking the export button navigates to `/time-tracking/timesheets/export` with the active date range and filters as query params. The page uses AG Grid Community (`ag-grid-vue3`) with: four theme variants (Quartz / Alpine / Balham / Material) auto-switching to dark mode, custom Excel-style checkbox set filter per column (Select All / Deselect All with search — replaces the Enterprise-only Set Filter), Columns dropdown to show/hide columns with live column re-fit, quick filter search across all columns, pinned bottom totals row that recalculates on every filter change, ResizeObserver for responsive column sizing on window resize, and CSV export that respects current filters and visible columns. All data loads in a single infinite-scroll grid — no pagination.

- **PDF preview in new tab** — PDF export now opens in a new browser tab instead of auto-downloading, so users can review before saving. The PDF also now respects the date range filter (was previously always the current week). Logo alignment in the PDF header is fixed — vertically centered with the brand name text using proper pdf-lib baseline math.

- **List view + export for schedules** — All timesheet list-view features ported to `/schedules`: flat table (Date, Employee, Department, Shift Type badge, Time, Break, Duration, Notes, Actions), calendar/list toggle persisted in URL, AG Grid export page at `/schedules/export` with the same tooling, Export CSV and PDF buttons in the top bar, sidebar and date range hidden based on view mode, stat chips updated to uniform neutral style, scrollbar auto-hide in list view. Client-side pagination since the schedules API returns all shifts at once.

- **Users page redesign** — `/users` redesigned to match the admin dashboard&apos;s users table pattern. Modal-based filter replaced with inline filter dropdowns (Department, Role, Status) always visible in the toolbar. Table upgraded from a 12-column grid layout to a proper `&lt;table&gt;` with 8 columns: Name+Email (UserAvatar cell), Department, Role (StatusBadge), Job Title, Status (StatusBadge with Offboarded variant), Last Login, Joined, Actions (CommonActionMenu preserving all existing actions). Client-side pagination with rows-per-page selector (10/20/50). CSV export of filtered users. Full-width layout matching `/approvals`. AG Grid export at `/users-export`.

- **Uniform stat chip styling** — Timesheet and schedule top bars use consistent neutral-tone stat chips (`bg-muted/60 ring-1 ring-border`) instead of rainbow-colored pills, matching the admin dashboard pattern across all pages.

- **Responsive top bar wrapping** — Both timesheet and schedule top bars use `flex-wrap gap-y-2` so stat chips, view toggle, and action buttons wrap gracefully on narrow viewports instead of overflowing.

- **Sidebar visibility gating** — Employee sidebar toggle button hidden in list view on both timesheets and schedules (sidebar is only relevant for the calendar grid).

- **Date range visibility gating** — Date range filter row hidden in calendar view on both timesheets and schedules (calendar is fixed at 7-day columns).

- **Unified Export dropdown** — New `CommonExportDropdown` component replaces separate CSV/PDF/Excel buttons with a single &quot;Export&quot; button + dropdown menu showing &quot;Export in Excel&quot;, &quot;Export in PDF&quot;, and &quot;Export as CSV&quot;. Applied across all pages: timesheets, schedules, all 3 approval pages, users, expenses.

- **AG Grid export pages for approvals** — Three new export pages: `/approvals/leave-export`, `/approvals/expense-export`, `/approvals/time-export` — each with the full AG Grid tooling (theme picker, column visibility, custom set filters, quick filter, pinned totals).

- **Client-side branded PDF export** — New shared utility `utils/export-pdf.ts` generates branded PDFs client-side using pdf-lib. Fetches org logo + company name from `/api/branding` (which now falls back to `SMTP_LOGO_URL` env var). Logo + brand name header on page 1, proper page breaks, footers with page numbers. Used by all approval pages, users, and expenses for PDF export.

- **Manage Departments modal redesign** — Compact header/body/footer sections matching the approvals reject modal pattern. Contextual icon badges per department (primary when active, muted when inactive). Clickable status badges. Inline add form with 2-column grid.

- **Expenses page redesign** — Full-width layout, admin-style table, inline filter dropdowns (status, sort). Nav tabs removed — Reports and Approvals moved to toolbar action buttons with pending badge. ExpenseTableRow actions replaced with CommonActionMenu (3-dot ellipsis). AG Grid export at `/expenses-export`.

- **Expense approvals redesign** — Admin-style table replacing grid-cols-12 layout. CommonActionMenu per row. Reject modal with header/body/footer sections, contextual chip, character counter. Pagination footer.

- **Expense reports redesign** — Admin-style table, CommonPageToolbar with inline filters, edge-joined CommonStatCard strip (Total Claims, Purchases, Per Diem, Travel, Grand Total), pagination, branded PDF via shared utility.

- **Reports overview fixes** — All 5 charts use settings gear overlay with period options (3 months / 6 months / YTD). Period badge next to gear button. Fixed expense chart month bucketing (departureDate not createdAt). Fixed schedule chart date range. Fixed leave count (org-wide via leaves-data endpoint). Stat card labels updated to &quot;total&quot; instead of &quot;this month&quot;.

- **Leave report tab redesign** — Transformed from &quot;report generator&quot; (download cards) into a data dashboard. Admin-style table showing actual leave requests with UserAvatar, leave type badges, status badges, CommonActionMenu. Server-side pagination with aggregate stats. Leave distribution section preserved.

- **Expense report tab redesign** — CommonPageToolbar with search and inline filters. Edge-joined CommonStatCard strip. Admin-style table with CommonActionMenu and CommonStatusBadge. Client-side search. Pagination. PDF export via shared utility.

- **Time report tab redesign** — Removed all charts (Area, Bar, Line, Donut). Admin-style data table with individual time entries, server-side pagination, CommonStatusBadge, CommonActionMenu. Stats use server aggregates.

- **Projects report tab redesign** — Stat card strip, CommonPageToolbar with search and inline filters, admin-style table with project stats and progress bars, CommonActionMenu, pagination, export.

- **Scheduling report tab redesign** — Stat card strip, CommonPageToolbar, per-shift detail table with shift type badges (REGULAR=primary, FLEXIBLE=info, ON_CALL=warning, HOLIDAY=success, WEEKEND=neutral, OVERNIGHT=error), pagination, export.

- **Projects list page redesign** — Full-width, admin-style table with project color dots, status badges, progress bars, CommonActionMenu, pagination footer, export dropdown.

- **Documents page redesign** — Full-width, admin-style table with CommonActionMenu and CommonStatusBadge. New `CommonSegmentedTabs` component replaces underline tab bar — pill-shaped toggle group with sliding primary-color indicator, ResizeObserver for responsive positioning. URL sync changed from `#hash` to `?view=` query params.

### Improvements &amp; Fixes

#### UX Refinements

- **Org chart list view matches the /users table styling** — The `/users/orgchart?view=list` People page has been realigned with the admin-dashboard `&lt;table&gt;` treatment used on `/users`: a single shared `CommonPageToolbar` with search + Department / Employment Type / Status inline filters, a proper `&lt;table&gt;` with `&lt;colgroup&gt;` column widths and rounded header cells, inline `UserAvatar` cells, `CommonStatusBadge` pills for the employment-type status (Full-time / Part-time / Contract / Intern / Temporary / Seasonal), and the standard rows-per-page pagination footer (10 / 20 / 50). Employment-type tones are mapped through the shared StatusBadge palette so colors stay consistent with the rest of the product. Column visibility (Employee # / Department / Location) is preserved as a trailing toolbar action. Mobile switches to a card layout.

- **Current-session indicator on /settings/trusted-devices** — The trusted devices page now shows a dedicated &quot;Current session&quot; card at the top with your parsed browser + IP (e.g. &quot;Chrome on macOS · 192.168.1.10&quot;) so you always know which device you&apos;re looking at — even when none of the stored trusted-device rows match. Per-row matching uses two signals: a cookie-based hash match flags &quot;This device&quot; with high confidence, and a heuristic fallback (single trusted row whose stored user-agent *and* IP both equal the current request) flags &quot;Likely this device&quot;. Ambiguous matches are intentionally left unlabeled rather than guessed. The matched row is sorted to the top of the list so the device you&apos;re on is always the first thing you see.

- **Persisted day-row heights on the schedule grid** — When a user drags the row-resize handle on `/schedules` to make a day taller or shorter, the new height now survives page reloads instead of snapping back to the 80px default. Heights are keyed by day index (Mon → Sun), clamped to the same 60–400px range the drag handle enforces, and written only when the drag ends (not during every mouse-move tick). Double-clicking a handle still resets that row, and when every row has been reset the storage entry is cleared entirely.

- **Leave history no longer shows phantom -1 day deductions for non-deducting types** — The History table on `/users/:id?tab=timeoff` was rendering &quot;-1.0&quot; for every leave regardless of whether the leave type actually drew from a balance bucket. Work-from-home, Meeting, Training, and other tracking-only types were reporting balance hits that contradicted the Leave Balance card on `/calendar/:id`. A new shared `utils/leaveBucket.ts` helper mirrors the same ANNUAL / SICK / NONE classification used server-side (including the legacy fallback for rows that predate the `deductionBucket` column), and the History cell now shows &quot;—&quot; with an explanatory tooltip for leaves that don&apos;t deduct.

- **Mark all tours completed in one click** — `/settings/tours` gains a &quot;Mark All as Completed&quot; button next to &quot;Reset All Tours&quot;. Admins and returning users who aren&apos;t interested in replaying the onboarding walkthroughs can now dismiss every visible tour at once instead of triggering each one to collect its completion flag. The button disables itself when every visible tour is already marked complete, so it can&apos;t be accidentally re-run. `useGuidedTour.completeTours(ids)` is the underlying helper for any future flow that needs to mark tours complete in bulk.

#### Bug Fixes

- **Notification settings (`/settings/notifications`) crashed for orgs with legacy defaults** — When an organization&apos;s saved notification defaults were stored in an older shape, the page would throw `Cannot read properties of undefined (reading &apos;enabled&apos;)` instead of rendering. The server endpoint now normalises partial payloads through the shared `resolveNotificationPreferences` helper, and the client merges fetched values over the form&apos;s defaults so a missing nested key can no longer blow up the view.

- **Password manager hints on settings** — Added the right `autocomplete` attributes to every password / client-secret input across settings (change password, SMTP password, SSO client secret). Browsers no longer warn in the console, and password managers can now offer the correct suggestion for each field.

- **Due-date calculation ignored BEFORE/AFTER direction** — Template tasks configured as &quot;7 days before hire date&quot; were being created with due dates *after* the hire date (e.g. hire May 1 → laptop task due May 8 instead of Apr 24). The frontend import path in `pages/users/[id]/index.vue` was always adding the offset; it now defers to the server which honors `dueDaysDirection: &apos;BEFORE&apos; | &apos;AFTER&apos;` with UTC date arithmetic.

- **&quot;Start Onboarding&quot; silently picked the first template** — Clicking Start Onboarding auto-selected whichever template was alphabetically first with no way to choose. Added a picker modal that lists every eligible task list (or &quot;Start with no tasks (add later)&quot;) before the instance is created.

- **&quot;Import Task List&quot; merged into an existing list** — Selecting IT Setup when HR was already attached appended IT tasks into the HR card, erasing the grouping. Import now calls `POST /api/onboarding/instances` with the template ID, creating a separate `OnboardingInstance` with its own `templateName`/`templateIcon` snapshots so each imported list renders as its own card.

- **Already-imported templates were re-selectable** — The Import and Start modals showed every template every time, allowing duplicate imports of the same list onto one user. Both modals now use `availableTemplatesForType` / `availableTemplatesForStart` computeds that filter out templates already present in the user&apos;s instances.

- **Employees could mark their own onboarding tasks complete** — The subject user (the employee being onboarded) was able to tick off their own checklist items, including completing compliance tasks that require admin/HR review. Completion is now restricted to administrators, executives, the department head of the employee&apos;s department, or the explicit task assignee. Employees keep read access to see what&apos;s coming up.

- **Signed documents did not auto-complete their linked tasks** — When an employee signed a document attached to an onboarding task, the task stayed in `PENDING` status until someone manually ticked it. Added `autoCompleteTasksForSignedDocument` which fires from the document sign handler, matches tasks by `(documentId, instance.userId)`, flips status to `COMPLETED`, rolls up instance status, and dispatches the task-completed notification. Works for both the direct per-user clone and the source-template document cases.

- **Task list modal was too small and cut off the icon grid** — The &quot;New Task List&quot; modal was `max-width=&quot;sm&quot;` which made picking an icon require scrolling a 47-item grid inside a 256px container. Bumped to `max-width=&quot;2xl&quot;` with a two-column layout (Name + Department side-by-side) and the icon picker given full breathing room below.

- **Shrine icon rendered as a blank square** — `lucide:shrine` is not a valid Lucide icon name and showed empty in the picker. Removed it. Added ~85 additional icons covering HR &amp; onboarding (user-plus, id-card, handshake, badge-check), IT &amp; equipment (laptop, headphones, server, wifi, printer), access &amp; security (key, lock, fingerprint, shield-check), finance &amp; payroll (banknote, calculator, receipt), communication (mail, phone, video, megaphone), documents (file-signature, file-check, folder), facilities (building-2, factory, truck), sales &amp; analytics (target, trophy, rocket, pie-chart), and common actions (check-circle, bell, settings).

- **Department heads could not manage their own team&apos;s task lists** — Only ADMINISTRATOR and EXECUTIVE could CRUD onboarding templates, forcing every HR/IT/Sales lead to route changes through an admin. Added `OnboardingTemplate.departmentId` (nullable). Department heads can now create, edit, delete, and manage task lists scoped to their own department. Templates with `departmentId: null` stay admin/exec only. Enforced via the new `server/utils/onboarding-access.ts` helper across all template, taskdef, instance, and per-user-task endpoints.

- **Department heads could not see Onboarding / Offboarding in /settings** — The settings sidebar and page wrappers had hard `adminOnly` gates. Introduced a `deptHeadAllowed` flag on `SettingsNavItem` and `SettingsPageWrapper`. Onboarding and Offboarding now opt in; department heads see both entries in their settings sidebar and can open either page.

- **DH saw all templates on the settings page** — After unlocking the page for DH, they were seeing org-wide (admin-only) task lists they couldn&apos;t edit. Added `?manageableOnly=true` to `GET /api/onboarding/templates`. The settings page passes this flag, so a DH only sees their own department&apos;s templates. The user-page Import/Start flow still fetches the full visible set (org-wide + dept) because DHs should be able to import admin-built lists for their team.

- **403 on /api/onboarding/packets for department heads** — Opening `/settings/onboarding-templates` as a DH crashed the data load because the packets endpoint is admin-only. `loadData()` now skips the packets fetch entirely for non-admins and hides the &quot;New Hire Packet Templates&quot; tab. If a DH lands on `?tab=packets` directly, it coerces to `tasks`.

- **Misleading &quot;All departments (admin-only)&quot; dropdown label** — The department selector in the New/Edit Task List modal didn&apos;t make clear which *roles* could manage the list. Replaced with &quot;Who can manage this list&quot; — &quot;Administrators &amp; Executives only&quot; for no-department, and &quot;{Dept name} department — Administrators, Executives &amp; {Dept name} Head&quot; for each option. Plus explanatory helper text below: &quot;Administrators and Executives can always manage any list. Picking a department additionally grants that department&apos;s head manage access. Employees and department heads of other departments cannot edit the list.&quot; For DH callers, the dropdown is auto-pinned to their own department and disabled.

- **Task list cards had no spacing between them** — Multiple onboarding/offboarding instances rendered flush against each other with no gap. Added `mb-4 last:mb-0` to each instance card on both the Onboarding and Offboarding tabs.

- **Add Task button disappeared from the user&apos;s onboarding tab** — When the flow was restructured to support multiple task lists per user, the header-level &quot;Add Task&quot; button (which ambiguously targeted the first instance) was replaced with a tiny `+` icon that was easy to miss. Each task list card now shows a clearly labeled &quot;+ Add Task&quot; button next to Remove, targeting that specific list unambiguously.

- **Per-user Add Task modal missed fields that existed in the template modal** — The modal was missing Task List selector (required now that multiple lists exist per user), attached-document picker, and &quot;Require signature before complete&quot; option. Rebuilt to match the settings &quot;Edit Task&quot; layout: Task Name, Task List, Assign to, Category, Due Date, Description, Attach Document + signature gate. Intentionally omits the template-only &quot;Import this task when onboarding (All/Some)&quot; and &quot;Update existing employee tasks&quot; fields because per-user tasks only ever apply to one user.

- **Assigned Role dropdown in the per-user Add Task modal was redundant** — The modal showed both an &quot;Assign to&quot; employee picker AND an &quot;Assigned Role&quot; fallback dropdown, which was confusing for per-user tasks. Removed — the server still defaults to `&apos;HR&apos;` when not provided, and the template flow keeps the full role picker since template tasks may be authored without a specific user in mind.

- **Task completion emails only went to the assignee** — When a task was marked complete (or auto-completed by a document signing), no one in HR/management learned about it. Added `sendOnboardingTaskCompletedNotification` which emails administrators, executives, AND the task assignee (deduped). Includes the employee name in the subject line and body.

- **Due-date reminders only went to one person** — The 1-day-before / 3-day / 7-day reminder cron sent to the assignee if one existed, otherwise to the employee. Now fans out to all administrators + executives + the task assignee (deduped). Subject line includes the employee name so admins know whose onboarding it belongs to. The employee being onboarded is intentionally *not* reminded because they can&apos;t mark their own tasks complete.

- **Task removed → no notification** — Deleting a task from an active instance silently disappeared the row. Admins/execs/DH now receive an email + in-app notification with the employee name, task title, assignee, and who performed the removal. Sent synchronously before the delete so details can still be read.

- **Instance removed → no notification** — Same for removing an entire task list from a user&apos;s profile. Admins/execs/DH are now notified with the list name, task count deleted, and who removed it.

- **No audit trail for onboarding/offboarding settings changes** — Template and task mutations were not appearing in `/settings/security → Audit Logs`. Added `logOnboardingAudit` helper that writes `AuditLog` entries with IP + user-agent for every CREATE/UPDATE/DELETE on `ONBOARDING_TEMPLATE`, `ONBOARDING_TASK_DEF`, `ONBOARDING_INSTANCE`, and `ONBOARDING_TASK`. UPDATEs include before/after snapshots. Task PATCHes distinguish `reason: STATUS` (marking complete/incomplete) from `reason: EDIT` (field change) so the audit feed is actionable.

- **No way to reorder tasks within a task list** — Once a task was added, its sort order was locked unless you deleted and recreated it. Each task row in `/settings/onboarding-templates` and `/settings/offboarding-templates` now has a grip handle and is `draggable=&quot;true&quot;`. Drag to reorder; `sortOrder` is renumbered locally and each changed row is PATCHed. Optimistic UI — reverts on error.

- **Email CTA buttons used a hardcoded purple** — All onboarding/offboarding email action buttons (&quot;View My Tasks&quot;, &quot;View Task&quot;, &quot;View Onboarding&quot;, &quot;View Profile&quot;) rendered `#4f46e5` regardless of the organization&apos;s white-label branding. Added `primaryColor` to `EmailConfig` which reads `CustomDomain.primaryColor` (falling back to `#3B82F6`). All eight CTA buttons across the onboarding email templates now render the organization&apos;s brand color.

- **`OnboardingInstance` lost its identity if the template was edited or deleted** — When an admin renamed or deleted a template, every instance using it suddenly showed &quot;Onboarding&quot; as its card title or crashed on dereference. Added `templateName` + `templateIcon` snapshots on `OnboardingInstance`. Each imported/started list keeps its own identity even after the source template changes. The UI prefers the snapshot (`inst.templateName`) over the live relation.

- **`canCompleteTask` in the frontend allowed the instance owner to complete their own tasks** — Mirrored the backend fix in the `taskDetail` completion gate. The modal&apos;s &quot;Mark Complete&quot; button now requires admin/exec, the explicit assignee, or a matching department head — not just &quot;is this your own instance&quot;.

- **Saving a time-tracking setting could fail with a 400 after the page was reloaded** — Toggling any switch on `/settings/timetracking` (for example &quot;Require Location&quot;) sometimes responded with &quot;autoApproveAfterDays must be a number&quot; and rolled the UI back to the previous state. The page hydrates its form by merging the full GET response into local state, so nullable numeric columns were being echoed back as `null` on save — which a strict type check was then rejecting. The save handler now treats `null` the same as an omitted field (skip), so the toggle-and-save flow works regardless of which optional settings happen to be unset on the row. Real type errors (strings in numeric fields, out-of-range numbers, invalid dates, unknown enum values) still fail with 400 as before.

#### Security &amp; Compliance

- **Department-head scope enforcement** — A department head cannot use a template scoped to another department (enforced on `POST /api/onboarding/instances` when they try to pass a `templateId` belonging to a different department). They also cannot re-scope a template between departments via PATCH.

- **Template-move authorization** — Moving a task definition between templates (via `PATCH /api/onboarding/templates/[id]/tasks/[taskDefId]` with a new `templateId`) now re-runs `assertCanManageTemplate` against the target template&apos;s department. A DH cannot move a task into a template they don&apos;t own.

- **Document auto-complete cross-user safety** — `autoCompleteTasksForSignedDocument` filters by `instance.userId === signerUserId`, so signing a document only completes the signer&apos;s own tasks — never another user&apos;s task that happens to reference the same source document.

- **DH departmentId self-pin on create** — When a department head creates a new task list, the backend always pins `departmentId` to their own department regardless of what the request sent, closing the gap if the UI-level dropdown is manipulated.

- **Tenant isolation on time-entry and project mutations** — Foreign-key fields written on time-entry create/edit (`projectId`, `taskId`) and project create/edit (`managerId`) are validated against the caller&apos;s organization at every write path.

- **Department-head scope on timesheet PDF export** — When a department head runs the timesheet PDF, results are constrained to their department&apos;s users on every code path; an out-of-department `userId` filter returns 403 instead of an empty report so the caller knows the request was denied.

- **Project financials visibility** — Hourly rates, budget amounts, and billed-amount stats on projects are restricted to Administrators, Executives, and Department Heads. Regular employees can still see hours and the hours budget on projects they&apos;re working on; the monetary values are stripped from the API response entirely for non-privileged callers.

- **Lockdown-override audit trail** — Every admin/exec edit, create, or delete that bypasses the pay-period lockdown is recorded in the audit log with the entry&apos;s clock-in and the lockdown cutoff. Audit writes are fire-and-forget so a failed log never rolls back the user-visible action — the override itself still happens, but compliance always sees it.

- **Hardened external fetch in PDF generator** — The optional org-logo embed in PDF reports validates the URL through the same SSRF guard used by webhook delivery (HTTPS only, blocks private and link-local addresses), with a fetch timeout and response-size cap. A broken or missing logo never fails the report.

- **Stricter input validation on time-entry edits** — Break duration must be a non-negative finite number and cannot exceed the entry&apos;s total span. Invalid clock-in / clock-out ranges are rejected up front so downstream billing math never sees a negative duration.

- **Strengthened input validation across all time-entry endpoints** — All mutation endpoints (create, edit, bulk update, duplicate, clock) now enforce stricter type checks, length limits on free-text fields, and range constraints on numeric settings. Invalid or out-of-range values are rejected early with clear error messages.

- **Improved multi-tenant isolation on write paths** — Foreign-key references passed during create and update operations are now validated against the caller&apos;s organization before persistence, closing potential data-integrity gaps in multi-tenant environments.

- **Tighter scoping for department-level roles** — Department heads are now consistently constrained to their own department&apos;s data across reports, PDF exports, and list endpoints. Org-scoped lookups ensure role-based filtering cannot be bypassed via direct API calls.

- **Hardened settings update endpoint** — Boolean, numeric, and enum fields on the time-tracking settings endpoint are validated by type and range before persistence. Numeric settings enforce documented min/max bounds.

- **Soft-deleted entries excluded from aggregations** — Report endpoints and project statistics queries now consistently exclude soft-deleted records, ensuring accurate totals and preventing stale data from surfacing in dashboards.

- **Sanitized custom CSS in branding** — The branding endpoint strips potentially dangerous CSS constructs (dynamic URLs, imports, expressions, script bindings) from custom CSS before serving it to clients.

- **Bumped vulnerable transitive dependencies** — Updated `follow-redirects` (1.15.11 → 1.16.0), `protocol-buffers-schema` (3.6.0 → 3.6.1), `dompurify` (3.3.3 → 3.4.0), and `hono` (4.12.12 → 4.12.14) via npm overrides to resolve Dependabot security advisories.

#### Performance

- **Search debounce (300ms)** — `CommonSearchInput` now debounces emit by 300ms, preventing re-filtering on every keystroke across all pages. Single fix, global impact.

- **Leaves endpoint server-side pagination** — `GET /api/reports/leaves-data` now supports `page`/`limit` params. Returns `pagination` metadata + `summary` aggregates (approved/pending/rejected counts + totalDays via `groupBy`). Runs `count`, `groupBy`, and `findMany` in `Promise.all` for zero extra latency.

- **LeaveTab server-side pagination** — Stats show real totals from server aggregates (accurate across ALL data, not just current page). Page changes trigger re-fetch. Filters reset to page 1.

- **Projects N+1 query eliminated** — Replaced per-project `Promise.all(projects.map(aggregate))` (N individual queries) with a single `timeEntry.groupBy({ by: [&apos;projectId&apos;] })` query mapped back by project ID. O(N) → O(1).

- **TimeTab server-side pagination** — Uses `serverTotal` for real entry count and `serverSummary` for accurate hours across all pages (not just current page of 50).

- **Branding endpoint SMTP fallback** — `/api/branding` now falls back to `SMTP_LOGO_URL` env var when no white-label logo is configured, ensuring PDF exports always have a logo.

- **Reports overview now loads in one pass** — `/reports` was firing roughly seventy requests on mount to paint five stat cards and six charts. The summary strip now calls a single new `GET /api/reports/summary-stats` endpoint that returns all five KPI numbers via DB aggregates; the leave-by-employee chart reads the existing `/api/reports/leaves-data` endpoint once and groups clients-side instead of fanning out per user; the hours-tracked chart fetches its six monthly buckets in parallel instead of awaiting each in turn. Typical admin loads drop from double-digit seconds to sub-2s on a 50-user org, and the fan-out no longer scales with team size.

- **Approvals overview uses one counts endpoint** — The `/approvals` page used to mount three hidden tab components purely to compute the &quot;N pending&quot; numbers on its stat cards — three full queue fetches for three integers. A new `GET /api/approvals/counts` endpoint returns `{ leave, expense, time }` via DB counts in one hop; the hidden tabs are gone. Drill-down pages still own their own detailed fetches when the user actually clicks through.

- **Faster time approvals** — Approving or rejecting a timesheet entry on `/approvals/time` used to re-fetch the whole queue just to see the row disappear. It now removes the row locally on success and only reverts on error, so the click feels instant regardless of how many pending entries there are. `/approvals/leave` and `/approvals/expenses` already worked this way; this brings timesheets in line.

- **Dashboard reads in parallel** — The home dashboard&apos;s user-row query used to walk through five independent reads in sequence (leaves for the visible range, the year-to-date balance, previous-year leaves for carry-forward, holiday overrides, org holidays). They now run in a single `Promise.all`. No query shape changes — the cold-render latency on large orgs drops proportionally to the slowest query instead of the sum.

- **Schedule auto-generation cut from hundreds of queries to one** — When a team has the default-schedule feature turned on, loading `/schedules` was doing a per-employee-per-day `findFirst` to decide whether to create a shift. A typical 50-person, 5-day week ran 250+ individual queries. A single `findMany` now covers the whole range and the existence check happens against an in-memory `Map`. Unrelated but in the same file: three other sequential reads (leaves, public holidays, schedule publications) now run alongside the main shifts query, and a duplicate org lookup further down the handler has been merged with the one at the top.

- **Leave balance handler parallelizes lookups** — The three independent reads at the top of `GET /api/leaves/balance` (current user, organization settings, target user) now fire together. Permission checks still gate access to the target user&apos;s data for non-self callers.

- **People grid on `/time-tracking/people` uses DB aggregates** — The endpoint was pulling every time entry for the week and for today and then looping in memory to compute per-user totals. It now uses `prisma.timeEntry.groupBy` for the week and day sums plus one narrow fetch for the handful of live active timers, which is all the UI needs for the running-clock badge. Wire payload drops from &quot;all closed entries for the week&quot; to &quot;one sum per user&quot;.

- **Department filter on time reports pushed to the DB** — The `/time-tracking/reports` endpoint had the same department filter expressed both in the `where` clause and again as an in-memory `Array.filter` after the fetch. The redundant in-memory pass is gone; admin-supplied `?departmentId=…` now goes to the DB too so it doesn&apos;t scan rows just to throw them away.

- **Composable fetches in parallel** — Department-head paths in `useTimesheetCalendar` and `useScheduleCalendar` used to `await /api/users` and then `await /api/users/{id}` in sequence when both can start immediately. Same on the cold-boot `useDashboard` call for departments + leave types. All three now fire in parallel via `Promise.all`. The tour/timesheet calendar also gets a microtask-level debounce around `fetchEntries()` so the cascade of watchers that wake up together when you toggle a range filter coalesces into one request instead of 2-3 races. Preferences load once per session instead of refetching `/api/users/{id}` on every calendar navigation.

- **Cross-tab notification dedup** — The unread-count poller in `useNotifications` runs in every open tab. Each tab still polls (so a backgrounded tab can&apos;t go stale), but the result is now broadcast over a `BroadcastChannel` so sibling tabs update their local unread ref from the broadcast instead of all hitting the server independently. User with three tabs open → same load on the server as one.

- **Domain middleware merged into a single query** — `server/middleware/domain.ts` used to find the `CustomDomain` row and then, on a hit, do a second `findUnique` on the owning `Organization` to check plan/features. The org is now loaded via a relation `include` on the first call, so the cache-miss path is a single DB round-trip per unique host.

- **Request-scoped plan cache in feature-gate** — Endpoints that run two or more feature checks in a single request (e.g. an expense-create that checks `checkReceiptLimit` and `checkFeatureAccess`) used to re-query the organization row for each check. A new internal `getOrgBasicCached(event, organizationId)` helper stashes the plan/features/limits shape on `event.context` for the duration of the request, so subsequent checks in the same handler are free. Callers that don&apos;t pass `event` keep the old behaviour — nothing breaks.

- **Reports charts consolidated** — The `/reports` page&apos;s four chart fetchers (expenses, time, project, schedule) now all hit a single `/api/reports/chart-data` endpoint that runs everything as Postgres `date_trunc` GROUP BYs. The wire carries ~6 rows per chart no matter how much underlying data exists. On mount the four charts share one call; each chart&apos;s settings gear still refetches independently when its period changes.

- **Reports stats explainer** — A single &quot;?&quot; icon in the `/reports` page header reveals a short card explaining what each stat card measures (Leave/Expense/Time are all-time, Projects is ACTIVE-only, Scheduling is current calendar year) and that charts default to six months. No per-card clutter.

- **Admin home dashboard** — A new `/api/admin/summary` endpoint returns the platform-wide KPI strip (organizations, users, MRR, etc.) via Postgres aggregates in one call instead of a handful of per-metric reads. Caches in Redis for 60s; charts paint in tens of milliseconds.

- **Admin list endpoints** — `/api/admin/organizations`, `/api/admin/refund-requests`, and `/api/admin/audit-logs` now Redis-cache their list responses for 30s. The `status` filter on refunds is allow-list validated (unknown values used to silently return the full list); the org search string is length-capped at 100 characters.

- **Users list** — `/api/users` now accepts `page`, `pageSize`, `search`, `departmentId`, `role`, `status`, and `sortBy` query params. All filtering, sorting, and pagination is pushed to Postgres. The response includes a `total` count alongside the page of users. DEPARTMENT_HEAD callers are forced to their own department server-side even if they pass a different `departmentId` (gate preserved). Role-aware `select` — employees never receive HR-sensitive fields. Two new composite indexes (`(organizationId, isActive, firstName)` and `(organizationId, departmentId, isActive)`) back the common sort/filter paths.

- **Documents list** — `/api/documents` now uses Prisma `_count` relation aggregates for per-document signer counts instead of looping. Server-side pagination, filter, and sort. Response is Redis-cached for 30s keyed by `(organizationId, userId, role, params)` so an admin&apos;s cached view never serves an employee&apos;s scoped view. Two new composite indexes back the common filter combinations.

- **Calendar list endpoint** — `/api/time-tracking/entries` (used by the timesheets calendar + flat list) now has a short-lived Redis cache scoped by organization + role + department/user and the date window. The `avatar` field was dropped from the user `select` since the calendar never renders it — one less join, one less field to serialize. Date-range validation added to reject malformed inputs early.

- **Approvals detail pages** — `/api/leaves/pending`, `/api/expenses/approvals`, and `/api/time-tracking/approvals/index` all got: Redis-cached list responses, slim selects, server-side pagination bounds, and count + list + summary aggregated in one `Promise.all` (expenses queue). The `status` filter on time-tracking approvals is now allow-list validated.

- **QuickBooks dashboards** — `/api/integrations/quickbooks/status`, `/api/integrations/quickbooks/employees/mappings`, and `/api/integrations/quickbooks/sync/history` all got: Redis-cached responses with conservative TTL (10-60s), `groupBy`-based status summaries instead of looped counts, and explicit exclusion of OAuth credentials + raw QBO request/response payload blobs from the cached response. Admins see fresh status without every poll hitting the DB.

- **Cache-Control headers everywhere** — Every new read endpoint sets `Cache-Control: private, max-age=10-30` and an `X-Cache: HIT|MISS` telemetry header so ops can see cache effectiveness in DevTools.

- **Home dashboard cache** — `/api/dashboard/users` (the endpoint every user hits on login) now Redis-caches its full response for 30 seconds. The cache key scopes by organization, role, and — for dept heads and employees — the caller&apos;s department / user ID, so an admin&apos;s cached org-wide view can never be served to someone who should see less. The external Nager.Date public-holiday lookup that ran on every dashboard load is now memoized per `(country, year)` in Redis for 7 days — same holidays for every tenant with users in that country, fetched once per week.

- **Expenses list pagination** — `/expenses` used to request a thousand expense reports with full line-item / per-diem / mileage / receipt relations on page mount, even though the table only renders a page of ~50 rows. The endpoint now takes `page` / `pageSize` / `search` / `status` / `reportType` / `userId` / `sort` / `startDate` / `endDate` query params and does all pagination / filtering / sorting in Postgres. Heavy relations are opt-in via `includeItems=true`. Optional `includeStats=true` adds a count + total aggregate in two parallel queries. Response is Redis-cached for 30s with role + viewer-scoped keys.

- **Reverse-geocode cache** — `/api/maps/geocode` is hit on every location-aware clock-in / clock-out. External geocoding calls (~900ms each) are now cached in Redis for 7 days, keyed by coordinates bucketed to 3 decimal places (~111m cells). Clock-ins from the same office share a cache entry; clock-ins from different neighborhoods don&apos;t. No tenant prefix on the key — reverse-geocode responses contain only public address strings with no per-user data. Rate limiting and auth checks still run before every lookup; null results are intentionally not cached to avoid pinning a transient provider outage.

- **Billing subscription dedupe** — Every component that called `useBilling()` used to get its own local state and fire its own `/api/billing/subscription` request, so the `/billing` page was making three or more parallel identical requests on mount. `useBilling()` now shares module-level state + an in-flight promise (same pattern as `useBootstrap`), so concurrent callers all await the same single request. One network round-trip per page load instead of three.
</description>
    </item>
    <item>
      <title>v1.0.9</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.9</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.9</guid>
      <pubDate>Thu, 09 Apr 2026 19:15:10 GMT</pubDate>
      <description>### Major HR Modules

This release rounds out the core employee experience with new modules for Performance, Benefits, Training, Onboarding/Offboarding, Assets, Certifications, and more.

### New Features — Profile &amp; Personal Data

- **Profile page redesign** — Two-column layout with sidebar vitals (phone, email, LinkedIn, location, status, department, employee #, hire date, tenure, manager, direct reports), tabbed main content, and inline section editing. Each section has its own Edit button that swaps the read view for an inline form with sticky save/cancel footer.

- **Inline editing** — Replaces the old modal-based edit flow on the profile page. Per-section edits keep changes scoped (basic info, social links, address, contact, emergency contact, employment, leave allowance, holidays).

- **Profile completeness indicator** — Auto-calculated progress bar in the sidebar based on 13 key fields. Color-coded (red/amber/green) and hidden once complete. Recalculated on every read so it stays accurate.

- **Employees can view their own profile** — Employees now have access to `/users/{theirOwnId}` to see and edit personal sections. View Files and Documents tabs are hidden for employees.

- **My Profile navigation** — Replaced the old modal with a direct link from the user menu to the profile page.

- **Education** — Add multiple education entries with institution, degree (10 types), major, GPA, and date range.

- **Languages** — Track spoken languages with separate reading/writing and speaking proficiency levels.

- **Certifications** — Add certificates with name, issuing body, credential ID, issued and expiry dates. Auto-marks as expired when past the expiry date. Daily reminder cron sends 30/14/7/0-day notifications + email to the employee and their manager.

- **Visa / Work Authorization** — Track visa type, country, dates, status, and notes. Auto-expires past-due visas. Daily cron sends 30/14/7/0-day expiry reminders to employee + manager.

- **Assets** — Track assigned company assets (laptop, badge, phone, etc.) with category, serial number, assigned date, return date, and condition. Searchable category dropdown with custom-category support.

- **Compensation history** — Salary changes over time with effective date, type, amount, and reason.

- **Bonuses** — One-off bonus records with date, amount, type, and notes.

- **Job history** — Position changes (title, department, manager) tracked over time.

- **Employment status history** — Status changes (Full-time, Part-time, Contract, etc.) over time.

- **Notes (HR)** — Per-employee notes with three visibility levels: HR Only, Managers, Shared with Employee. Color-coded badges and full audit logging.

- **Termination tracking** — Termination code, notice given date, projected termination date, ROE/SAT completed date. Inline editable on the Job tab (admin-only).

- **Marital status, nationality, shirt size** — New fields on the personal tab.

- **Citizenship Certificate # and Benefit ID** — Encrypted-at-rest fields, masked display, admin-only.

- **Home email, phone extension, home phone** — Separate from work email and landline.

- **Social links** — LinkedIn, GitHub, Twitter/X, Facebook with their own profile section.

- **Emergency contact enhancements** — Full address, email, dropdown for relationship type.

### New Features — Org Chart &amp; People Directory

- **Org Chart page** at `/users/orgchart` with three views: list (sortable table), directory (grouped by letter/department/location), and an interactive org chart tree.

- **People navigation link** — Top-level nav for admin, executive, and department head roles.

- **Directory search** — Search by name, title, email, or employee ID across all three views.

- **Division and Work Location fields** — Added to user profile, API, and org chart.

### New Features — Performance Management

- **Performance Settings** at `/settings/performance` — Configure goal users (none / all / specific), cascading goals toggle, and 1:1 meeting enablement.

- **Goals** — Per-employee goal cards with progress slider, status, due date, and category. Expandable cards show a comments section for collaboration.

- **Goal Comments** — Threaded comments on goals with timestamps and author avatars.

- **1:1 Meetings** — Recurring 1:1 series with frequency (Weekly/Biweekly/Monthly/One-time) and first meeting date. Inline view on the profile page with agenda items, side-by-side notes, and private note filtering. Creation/cancellation emails to participants. Daily reminder cron sends meeting reminders with current agenda.

### New Features — Training

- **Training Settings** at `/settings/training` — Define training requirements with frequency (One-time, Annual, Every 2/3/5 years), categories, due-from-hire days, required-for filter (All / Department / Role / Specific Employees), URL field, and &quot;allow self-complete&quot; toggle.

- **Training auto-assign** — Required training is automatically assigned to targeted users when created or updated, with calculated due dates from their hire date.

- **Profile Training tab** — Category-grouped view with inline edit, mark complete, and dismiss actions.

- **Training reminders cron** — 7/3/1 day reminder emails before due. Notifies employee and manager.

- **Training overdue cron** — Detects past-due training, updates status, and notifies the employee + manager.

### New Features — Benefits Administration

- **Benefits CRUD** — Track benefit plans (medical, dental, vision, life, disability, retirement, etc.) with provider, policy number, coverage, premium, and effective dates.

- **Profile Benefits tab** — View enrolled benefits with dependents, premiums, and effective dates.

### New Features — Onboarding &amp; Offboarding

- **Onboarding Settings** at `/settings/onboarding-templates` — Two tabs: task lists (with icons, drag-to-reorder, per-task assignee, due date type, notification timing, target scope) and New Hire Packet Templates.

- **Offboarding Settings** at `/settings/offboarding-templates` — Parallel page for offboarding task lists. Type-aware copy throughout (&quot;On Last Day&quot; vs &quot;On Hire Date&quot;, &quot;before/after last day&quot; vs &quot;before/after hire date&quot;).

- **New Hire Packet Templates** — Configure arrival time, location, contact person, instructions, &quot;Get to Know You&quot; questions, and linked task lists.

- **Onboarding profile tab** — Per-employee onboarding/offboarding instances with progress bar, task list, assignee names, color-coded due dates, and category badges. Add Task and Import Task List buttons for admins.

- **Auto-trigger on hire** — When a new user is created, the default onboarding template auto-creates an instance with all tasks.

- **Auto-trigger on termination** — When `isActive` flips to false, the default offboarding template auto-creates an instance.

- **Standalone /onboarding page** — Active/Completed/Templates tabs with progress tracking, task completion, and a stats bar.

- **Template categories** — Tasks can be tagged Documents, Equipment, Access, Training, or Other with color-coded badges.

- **Update existing employee tasks** — When admin adds a new task to a template, optionally apply it retroactively to all employees with active onboarding for that template.

- **Document attachment to tasks** — Admins can attach a document (employee handbook, NDA, policy) to any onboarding task and require it be signed before the task can be completed.

- **Per-user document copies** — When a sign-required document is attached to an onboarding task, each new hire gets their own personal copy of the document. Each employee signs their own copy independently — no shared multi-signer PDF, no privacy leak between employees. Each employee can re-view their signed copy at any time.

- **Signature gating on task completion** — Tasks with attached signing-required documents cannot be marked complete until the recipient has actually signed their copy. Admins can override.

- **Auto due-date calculation** — Task due dates are computed from the employee&apos;s hire date (or end date for offboarding) using the task definition&apos;s &quot;X days before/after hire date&quot; rule. Falls back to &quot;today in the org&apos;s timezone&quot; for users without an explicit hire date so dates always match the operator&apos;s local calendar.

- **Per-task notifications** — In-app and email notifications fire when:
  - An onboarding instance is created (employee gets the full task list)
  - A task is assigned to a specific user (assignee gets a notification)
  - A task is reassigned (new assignee gets notified)
  - An instance is completed (employee + admins get a completion email)

- **Daily task reminder cron** — Sends 7/3/1/0 day reminders + 1 day overdue for every pending onboarding/offboarding task. Recipient is the assignee or, if none, the employee being onboarded. Skips offboarded users.

- **Task detail modal** — Click any task to open a detail modal showing description, assignee, due date, category, attached document, and Mark as Complete / Mark as Incomplete buttons. The modal also surfaces signature status with a clear &quot;Signature required&quot; or &quot;Signed&quot; badge.

### New Features — User Offboarding Lifecycle

- **Deliberate offboarding flow** — Replaces silent `isActive` toggling with `POST /api/users/:id/offboard`. Required: end date, termination code. Optional: notice date, ROE completed date, notes, replacement department heads. Runs a transactional cleanup across leaves, time entries, expenses, document assignments, direct reports, department heads, 1:1 series, onboarding instances, projects, tasks, benefit enrollments, and future shifts.

- **Offboard preview** — `GET /api/users/:id/offboard-preview` returns counts of everything that will change so the operator sees a &quot;what will happen&quot; summary before clicking.

- **Reactivate offboarded user** — `POST /api/users/:id/reactivate` restores login access (subject to seat limits) without undoing the cleanup.

- **Audit log entry** — Every offboarding writes an OFFBOARD audit entry with the full input + cleanup summary.

- **Inactive user enforcement** — Approval, time-tracking, and expense endpoints now consistently reject actions from deactivated users.

- **Cron filtering** — Reminder crons (training, certification, visa, document, 1:1, onboarding) skip offboarded users so they don&apos;t receive emails after leaving.

- **Hard-delete disabled** — `DELETE /api/users/:id` now returns 410 Gone with a pointer to the offboard endpoint. Hard-deletion would orphan audit logs, leaves, time entries, and reporting chains. GDPR Right-to-Erasure remains available via the privacy data-deletion endpoint.

### New Features — Auth &amp; Sign-In

- **Stripe-inspired auth pages** — Redesigned login, register, forgot-password, and reset-password pages with a modern card layout, brand-aware branding, and consistent footer.

- **Google sign-in / sign-up** — Server endpoints, frontend callback, and route configuration for Google OAuth.

- **Microsoft OAuth fixes** — Removed the consent prompt that was blocking non-admin users.

- **Forced logout toast** — Users see a clear toast notification when their session expires instead of being silently kicked to the login page.

### New Features — Dashboard &amp; Calendar

- **Hire date and work anniversary on dashboard and calendar** — Hire dates show on the calendar grid and in the dashboard&apos;s &quot;Today&quot; view. Work anniversaries (every year after hire) display as a separate badge with the year count.

- **Daily anniversary digest** — Cron sends a daily anniversary email to admins celebrating today&apos;s work anniversaries alongside birthdays.

### Improvements

- **Profile tab navigation** — Tab bar is now horizontally scrollable on all screen sizes with edge fade gradients and (desktop) chevron scroll buttons. Active tab smoothly scrolls into view on click. Works on mobile without the previous &quot;More&quot; dropdown.

- **Settings navigation** — Added Training, Performance, Onboarding, Offboarding, and Company Directory entries.

- **Documents Completed tab** — Now shows a &quot;Signed By&quot; column instead of &quot;From&quot;, so you can see who actually signed each document.

- **Documents list filtering** — Per-user document copies are hidden from the admin&apos;s list view by default to avoid clutter. Each employee still sees their own copies, and admins can opt in to see all copies via a query parameter.

- **Email layout** — Onboarding/offboarding emails include the full task list with assignees and due dates, plus a &quot;View My Tasks&quot; CTA button. All emails use the org&apos;s timezone for date display.

- **Notification deep links** — Onboarding notifications now link to `/onboarding` (which works for everyone — admins, employees, and assignees) instead of profile-page tabs that were admin-only.

- **Inline document badges on tasks** — Tasks with attached documents show a green &quot;Signed&quot; or amber &quot;Signature required&quot; badge directly in the task row, with a click-to-open link.

### Billing &amp; Usage

- **Document signing requests count toward billing** — Each document file (1) plus each signing request (1 per recipient) counts toward the monthly document quota. A handbook shared with 10 new hires = 1 file + 10 signing requests = 11 toward the quota. The billing page shows the breakdown (&quot;X files + Y signing requests&quot;) with a tooltip explaining the math.

- **Per-user usage attribution** — The Usage Breakdown page now credits documents to the file owner and signing requests to the recipient (the employee who has to sign), not the admin who triggered the assignment. So compliance work appears against the right person&apos;s row.

### Security &amp; Compliance

- **PII encryption** — New profile fields (`citizenshipCertificateNo`, `benefitIdNumber`, `phoneHome`, `homeEmail`, `offboardedReason`) are encrypted at rest using AES-256-GCM.

- **Sensitive ID display** — Tax ID, citizenship certificate, and benefit ID display masked (e.g. `XXX-XXXX-1234`) and are visible only to admins.

- **Rate-limited Google OAuth** — Server endpoints harden against brute-force with rate limiting and input validation.

- **Permissions-Policy** — Allowed geolocation for own origin so the in-app location features work in modern browsers.

- **GDPR Right-to-Erasure expansion** — Data anonymizer now clears termination, ROE, and offboarding fields when a user requests deletion.

- **Department head consistency** — A user can only head one department at a time, enforced via a shared helper across all department endpoints.

### Bug Fixes

- **Mobile sidebar scrolling** — Fixed scrolling failure that left the bottom user menu unreachable on production and staging.

- **Guided tour leakage** — Guided tour tooltips no longer appear on the wrong page after navigation.

- **Setup page scrollbar** — Removed the scrollbar from the setup page on laptop screens.

- **Reset-password redirect** — Visiting `/reset-password` without a token now redirects to `/forgot-password` instead of showing an error.

- **iCal feed URL undefined** — Fixed the iCal feed URL returning undefined after a page refresh.

- **Empty-string date crashes** — All API endpoints that accept date strings now safely handle empty strings instead of crashing.

- **Profile data load on tab navigation** — Profile sub-tabs (training, performance, benefits, onboarding) now correctly fetch their data on initial URL visit.

- **Birthday and hire date timezone shift** — Date-only fields use UTC date components throughout, so e.g. &quot;Feb 25&quot; no longer displays as &quot;Feb 24&quot; for users west of UTC.

- **Onboarding due date off-by-one** — Due dates now calculate from &quot;today in the organization&apos;s timezone&quot; with UTC date arithmetic, so &quot;1 day after hire date&quot; correctly resolves to the right calendar day for users in any timezone.

- **Receipt limit reset test flakiness** — Stabilized a flaky test that occasionally failed near month boundaries.

- **Sectional save isolation on the user profile** — Editing one section of the user profile (Job, Personal, Contact, etc.) now reliably leaves the other sections untouched. Comprehensive regression coverage added.

- **Tenure calculation rewritten** — The &quot;Years of service&quot; line on the profile job tab is now calculated through a dedicated utility (`utils/tenure.ts`) covering future hire dates (&quot;Starts in N days/weeks/months&quot;), the first day (&quot;First day today&quot;), short tenures (`Nd`), and longer tenures (years/months). 39 unit tests cover every boundary including new-year rollovers.

- **Training assignment targeting** — The &quot;required for&quot; filter on training courses (All / Department / Role / Specific Employees) is now applied consistently on both create and update paths, so courses only assign to the intended audience. Auto-assignment logic centralized into a shared helper. 39 tests cover the targeting algorithm.

- **Profile training tab now respects course targeting** — The training tab on a user&apos;s profile only displays courses that actually apply to that user.

- **Profile training tab cleanup** — Removed an incomplete inline editor in favor of the canonical training editor under `/settings/training`. Added a read-only details modal so users can review training info directly from their profile.

- **Recording completed training is now instant** — The &quot;Record Completed Training&quot; flow no longer requires a manual page refresh to see the new entry. Optimistic UI update + single-request creation.

- **Reports To picker respects role hierarchy** — The &quot;Reports To&quot; dropdown on the user edit form now only suggests users at or above the employee&apos;s level in the hierarchy, excludes inactive users, and reacts live to in-form role changes. The currently saved manager is preserved even if outside the filtered list.

- **Document links from profile docs tab** — Clicking a document on a user&apos;s profile documents tab now opens the right assignment for the current viewer in all cases, while preserving the existing per-user privacy boundary (non-admins still only see their own assignment).

### Performance &amp; Loading Experience

This release dramatically reduces the &quot;split-second flash&quot; of empty/fallback content that used to appear on first navigation, and replaces every page-level loading spinner with a layout-matching skeleton.

- **Single-request page bootstrap** — Authenticated pages used to need several sequential round trips to load the small set of &quot;always needed&quot; data (org settings, timezone, leave types, departments, etc). These have been folded into a single bootstrap request that uses the existing JWT middleware and is org-scoped on every database query. The response is intentionally minimal — no employee data, no leave or balance information, no per-user-per-year content. Comprehensive regression tests lock the response shape and verify no sensitive data is included.

- **Session-scoped cache** — A reactive cache holds the bootstrap response for the rest of the session, shared across every page. It is dedicated to a single in-flight fetch at a time, refreshed on a short TTL, cleared on logout (so nothing persists across user sessions), and automatically invalidated whenever the user saves a setting that would affect it.

- **Pre-warming on app start** — A client plugin fires the bootstrap fetch right after auth is ready, so the first page the user lands on already has its layout chrome populated.

- **Auto-invalidation on settings mutation** — When an admin saves a new timezone or other org-level setting and clicks another page in the sidebar, the new value is reflected immediately — no manual page refresh required. Implemented as a network-layer hook so individual pages don&apos;t have to remember to invalidate.

- **Calendar, dashboard, users, and approvals refactor** — Each of these pages used to make multiple sequential network round trips in `onMounted` before the layout could render. They now run all initial fetches in parallel. Lookups that aren&apos;t immediately needed (like the department list for the Group Booking modal) are lazy-loaded only when the user actually needs them.

- **Dropped redundant auth-readiness waits** — Several composables were waiting for auth-ready state inside individual fetchers, which added per-fetch latency on the hot path. The auth middleware already guarantees ready state by the time `onMounted` fires, so these calls were dead weight and have been removed.

- **Parallelized leave types load** — Calendar pages now fetch leave types in the same parallel batch as leaves, balances, holidays, and locked dates instead of waiting for the parallel block to finish first.

- **Skeleton component library** — New `components/skeletons/` folder with a `Skeleton` primitive (rect/circle/pill/text shapes) plus 11 layout-matching composites covering list pages, detail pages, form pages, card grids, the calendar header and grid, the dashboard grid, the user profile, the schedule/timesheet board, and the org chart. All fully responsive (mobile-first Tailwind breakpoints). Reusable across the app via props.

- **Loading spinners replaced across the app** — Every centered spinner that hid the page during first load is now a layout-matching skeleton that holds the layout shell. Pages updated: expenses (list + detail + reports + approvals), documents (list + detail), clients (list + detail), projects (list + detail), training, schedules, admin, onboarding, time-tracking timesheets, time-tracking approvals, users profile, users data drive, users orgchart (view-aware: orgchart/list/directory each get the right skeleton), settings overview, billing. Plus the approval tab components, reports tab components, and 20 settings sub-page components.

- **No more &quot;no projects found&quot; flash on `/projects`** — The empty state used to flash for one frame on every navigation because the loading flag started as false. The initial value was flipped so the skeleton renders from the very first frame.

- **Org chart card and connector redesign** — Larger node cards, bigger avatars, outlined role badge, bottom-right reports/collapse toggle, dot-grid card background, smoother bezier connector curves, search input with match dimming, expand-all/collapse-all buttons, and per-node collapse toggles.

### Browser Compatibility

- **PDF rendering on older browsers** — The document signing flow could fail on browsers released before early 2025 due to a JavaScript syntax feature used by the modern PDF.js build. Switched the application to PDF.js&apos;s officially supported legacy build, which targets ES2020 and works on every browser from 2021 forward (Chrome 88+, Firefox 78+, Safari 14+). The legacy build is built from the same source as the modern build and receives the same security patches in lockstep from Mozilla.

- **PDF.js version pinning** — Tightened the dependency range so future patch releases land but a minor version bump (which could re-raise the minimum browser target) requires an explicit, reviewed upgrade.

</description>
    </item>
    <item>
      <title>v1.0.8</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.8</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.8</guid>
      <pubDate>Mon, 23 Mar 2026 00:43:10 GMT</pubDate>
      <description>### UI Redesign — Navigation &amp; Settings

This release is a comprehensive redesign of the application&apos;s navigation and settings architecture, modeled after modern dashboard dashboard patterns.

### New Features

- **Sidebar navigation** — Replaced the horizontal header with a fixed left sidebar on desktop. Includes org logo, grouped nav sections (core, apps, management, admin), collapsible width with persisted state, user profile dropdown with logout, and theme toggle.

- **Mobile navigation drawer** — Slide-in drawer from the left with backdrop blur, replacing the old hamburger dropdown. Sticky top bar with org logo, notification bell, and theme toggle on small screens.

- **Sidebar collapse with tooltips** — Sidebar collapses to icon-only mode (68px) with hover tooltips showing labels. Collapsed state persists across sessions via localStorage.

- **Active route indicator** — Sidebar nav items show a colored left accent bar on the active route, matching modern dashboard visual pattern.

- **Settings overview page** — New card grid hub at `/settings` with grouped sections (Personal, Organization, Executive). Each card shows icon, title, description, and feature lock badges. Cards have shadow-on-hover effect with dark mode support.

- **Individual settings routes** — Every settings section now has its own URL (`/settings/password`, `/settings/general`, `/settings/quickbooks`, etc.) instead of query parameters (`?tab=password`). 22 new route pages created.

- **Settings breadcrumb navigation** — Each settings sub-page shows a back arrow linking to the settings overview, plus a page title with icon matching the overview cards.

- **Settings feature gating on sub-pages** — Locked features show an upgrade prompt directly on the sub-page with plan badge and CTA button, consistent across all gated sections.

- **Inline QuickBooks sync history** — The Sync History tab in QuickBooks settings now renders the full audit log inline with filtering and pagination, replacing the placeholder link.

### Improvements

- **Documents page — sidebar removed** — Replaced the left sidebar with horizontal horizontal tabs (My Documents, All Documents, Action Required, Completed, Drafts) with count badges and active underline indicator.

- **Documents quick links relocated** — Templates and Bulk Send links moved from the sidebar to inline buttons in the page header, next to the Start dropdown.

- **QuickBooks sidebar → horizontal tabs** — Converted the vertical sidebar navigation (Overview, Employees, Vendors, etc.) to a horizontal tab bar with a Disconnect button at the right end.

- **QuickBooks sync-history breadcrumbs** — The full-page sync history now shows a breadcrumb trail (Settings → QuickBooks → Sync History) instead of a back-button card.

- **Settings backward compatibility** — Old URLs (`/settings?tab=password`, `?changePassword=true`, `?setup2fa=true`, `?tab=calendar`) automatically redirect to the new path-based routes.

- **Forced password/2FA on sub-routes** — Middleware path matching updated from exact `/settings` to `startsWith(&apos;/settings&apos;)` so users aren&apos;t bounced away from settings sub-pages during forced flows.

- **Duplicate headers removed** — Removed redundant title/description headers from all 20 settings components since the page wrapper now provides the heading.

- **Settings overview dark mode** — Cards use `gray-900` base with `gray-800` hover and stronger shadow in dark mode for visual distinction.</description>
    </item>
    <item>
      <title>v1.0.7</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.7</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.7</guid>
      <pubDate>Fri, 20 Mar 2026 19:59:54 GMT</pubDate>
      <description>### New Features

- **E-Signature Platform** — Complete document signing system with drag-and-drop field placement, sequential and parallel signing workflows, typed or drawn signatures, and multi-signer support.

- **Drag-and-drop field placement** — Place signature, initials, date signed, name, email, company, and title fields directly onto PDF documents. Fields are color-coded per signer.

- **Sequential and parallel signing** — Configure signing order when assigning documents. Sequential mode notifies each signer only when it&apos;s their turn. Multiple signers can share the same order number to sign in parallel.

- **Typed signatures** — Choose from 8 cursive font styles to generate a typed signature, in addition to drawing freehand. Signatures can be saved for reuse across documents.

- **Signature validation** — Canvas signatures are validated for quality: minimum size, ink coverage, and stroke complexity. Trivial scribbles are rejected with a clear error message.

- **Audit trail PDF** — Every signed document can be downloaded with a full audit trail appended, showing all signers&apos; names, emails, timestamps, and signing status.

- **Document sharing without signature** — Documents can be shared for review without requiring a signature. Recipients receive a notification and email.

- **Department head document permissions** — Configurable read and create permissions for department heads. Create access implies read. Bulk Send remains admin/executive only.

- **Breached password detection** — Passwords are checked against the Have I Been Pwned database in real-time as users type during registration and password changes. Breached passwords are blocked from being set. Existing users with breached passwords are notified via in-app notification and email on their next login.

- **Remember Me** — Server-enforced session vs persistent login. Unchecked by default — users must opt in to stay logged in across browser sessions.

- **Leave approval from detail modal** — Approvers can now approve or reject leave requests directly from the leave detail modal without navigating away.

- **Group booking restricted** — Group leave booking is now restricted to administrators and executives only.

### Improvements

- **Documents index redesigned** — Sidebar navigation with My Documents, All Documents (admin), Action Required, Completed, and Drafts views. Admins and executives can see all documents across the organization.

- **Table layout rebuilt** — Documents table uses a proper table layout with status badges, action buttons, and a Recipient column in Action Required view for admins.

- **Browser back button support** — Switching between document views now uses `pushState` so the browser back button works correctly.

- **Signature timestamp on PDF** — Each signature and initials field in the rendered PDF shows the signer&apos;s name and timestamp.

- **Email messaging for shared documents** — Emails for non-signature documents say &quot;shared a document with you&quot; instead of &quot;sent for signing.&quot;

- **Due date timezone handling** — Due dates are now inclusive with a 24-hour buffer. A document due on March 20 is not marked overdue until March 21.

- **Dept head uploader filtering** — When department heads upload documents, the user autocomplete is filtered to their department only.

- **Self-approval prevention** — Users can no longer approve their own leave requests, even if they have approver permissions.

- **Dashboard scroll optimization** — Scrollbar only appears on screens below 1320px width.

### Security

- **Data encryption at rest** — Sensitive personal data (phone numbers, addresses, tax IDs, emergency contacts, bank details, webhook URLs, leave reasons) is now encrypted at the application level using AES-256-GCM, in addition to database-level encryption.

- **HttpOnly cookie authentication** — Refresh tokens are now stored in HttpOnly secure cookies instead of browser-accessible storage, protecting against cross-site scripting (XSS) token theft.

- **Security headers** — Content Security Policy, Strict Transport Security, X-Frame-Options, Referrer-Policy, and Permissions-Policy headers are now set on all responses.

- **SSRF protection** — Webhook URLs (Slack, Teams) are validated against private IP ranges, localhost, and cloud metadata endpoints before making server-side requests.

- **SSO domain verification** — DNS-based domain verification for SSO prevents cross-organization domain hijacking. HMAC-signed state parameters protect against CSRF in SSO flows.

- **Breached password blocking** — New passwords are checked against 900M+ known breached passwords via Have I Been Pwned before being accepted.

- **Auth gate hardening** — Unauthenticated users no longer see a brief flash of authenticated UI. API requests are blocked immediately when no session exists.

- **Guided tour security** — Tours no longer fire for unauthenticated users.

### Privacy &amp; Data Protection

- **Data export** — Users can export all their personal data in machine-readable JSON format from their account settings.

- **Data deletion** — Users can request deletion of their personal data. Data is anonymized to preserve organizational reporting integrity.

- **Data sharing opt-out** — Users can opt out of third-party data sharing.

- **Data retention automation** — Automated cleanup of data beyond the configurable retention period (default 7 years for tax/financial record-keeping).

- **Privacy policy updated** — Added sections for legal basis of processing, international data transfers, data breach notification, children&apos;s privacy, and Do Not Track signals.

- **Cookie policy updated** — Added details for authentication cookies and security cookies.

- **Terms of use updated** — Added sections for data processing, data portability, and service availability.

### Bug Fixes

- **Completed view duplicates** — Fixed documents appearing multiple times when they had multiple signers.

- **Action Required filtering** — Shared documents no longer appear in Action Required. View now only shows documents assigned to the current user.

- **Unassigned fields not rendering** — Legacy fields with null assignment correctly render in the PDF.

- **Billing: immediate charge on upgrade** — Plan upgrades and add-on purchases now charge proration immediately instead of deferring to the next invoice.

- **Settings access** — Fixed /settings being blocked for non-admin users.

- **TOTP login flow** — Fixed 2FA verification being blocked by the API interceptor during login.

- **Email verification resend** — Fixed resend verification endpoint missing auth headers.

- **Password change token refresh** — Fixed token handling after password change to prevent unnecessary logouts.</description>
    </item>
    <item>
      <title>v1.0.6</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.6</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.6</guid>
      <pubDate>Sat, 14 Mar 2026 18:47:35 GMT</pubDate>
      <description>### New Features

- **Hourly / time-slot leave booking** — Employees can now book leave for specific time windows (e.g. 09:00 - 13:00) in addition to full or half days. The system calculates the leave fraction automatically based on the employee&apos;s work schedule.
- **Per-leave-type &quot;Allow hourly booking&quot; toggle** — Admins and executives can enable or disable time-slot booking on each leave type individually from Leave Type settings. Enabled by default for Working from Home and Paid Sick Leave. Shows a warning if no organization schedule is configured, directing admins to Time &amp; Projects settings.
- **Schedule-aware time slots** — When booking hourly leave, the available start/end times are generated from the employee&apos;s assigned shift, personal work schedule, or organization default hours (15-minute intervals).
- **Half-day visual indicators** — Calendar and dashboard views now show a gradient-filled half circle for half-day leaves: morning off shows the left half colored, afternoon off shows the right half colored. Time-based partial leaves show a proportional bottom-up gradient fill.
- **Half-day and hourly leave tooltips** — Tooltips on calendar days and dashboard cells now display &quot;(Morning)&quot;, &quot;(Afternoon)&quot;, or the actual time range (e.g. &quot;09:00 - 13:00&quot;) for partial-day leaves.

### Improvements

- **Leave balance display** — Balance summary values (allowance, used, carried over, remaining) now display rounded to 2 decimal places, supporting fractional day tracking from hourly bookings.
- **Leave request modal** — User avatar and name now always shown in the modal header. Paid/Unpaid status displayed as a colored pill badge (green for paid, amber for unpaid) instead of inline text.
- **View mode for time-based leaves** — Leave detail view now shows start/end times, total hours with day equivalent, and a proportional gradient fill on the leave type badge.

### Bug Fixes

- **Expense tab disappearing** — Fixed an issue where toggling Company Card Expenses or saving any expense setting caused the Expenses tab to disappear from the header navigation until page refresh.
</description>
    </item>
    <item>
      <title>v1.0.5</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.5</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.5</guid>
      <pubDate>Mon, 09 Mar 2026 21:09:29 GMT</pubDate>
      <description>### New Features

#### Introducing MCP for BookYourPTO
- Connect your AI assistant (Claude Code, Cursor, Claude Desktop) to BookYourPTO and manage PTO, expenses, time tracking, and more through natural language
- 28 tools across leave management, expense reports, time tracking, calendar, approvals, org settings, and user profiles
- Secure OAuth 2.0 login — sign in via your browser, passwords never touch the AI
- One-click authorize when already logged in, full login with 2FA support otherwise

#### In-App Support
- Submit bug reports, feature requests, general issues, and security vulnerabilities directly from the app
- Attach files and screenshots to your support tickets
- Rate limiting to prevent spam

#### Bulk Scanning
- Bulk receipt scanning with redesigned scanner UI

#### Company Card Expense Settings
- Enable/disable company card expenses per organization via Expense Settings
- Role-based access control: Admins can allow all roles to create company card reports, or restrict to admins/executives only
- Optional approval workflow: Company card expenses can optionally require approval before being marked as paid. When disabled, admins can mark as paid directly from draft status

#### QuickBooks Bill Payment Sync
- When an expense is marked as paid and a Payment Account is configured, a BillPayment is automatically created so bills show as &quot;Paid&quot; in QuickBooks
- If a bill&apos;s total changes after the initial payment, the amount is automatically updated on re-sync
- Multi-currency support: payment amounts now correctly match the QuickBooks bill total regardless of currency

#### Tax &amp; Gratuity in QBO Bills
- Line item descriptions in QBO now include a tax breakdown and gratuity amounts for full financial visibility

#### Gratuity/Tip Field
- Added gratuity/tip input to the bulk receipt import scanner (desktop and mobile)
- Gratuity field available on individual purchase add/edit forms

### Bug Fixes
- Fix PDF receipts not viewable in purchases tab and receipts tab — PDFs now render inline instead of showing as broken images
- Fix avatar errors cascading across all pages — gracefully falls back to initials when avatar file is missing
- Fix calendar header misalignment on mobile
- Fix dashboard mobile view — stack avatar and name vertically to prevent name overflow onto calendar dates
- Fix email verification failing after registration
- Fix support form not pre-populating when opened from a direct link
- Fix expense data (purchases, per diems, receipts) disappearing after submit, approve, reject, or mark-paid actions
- Fix QuickBooks Payment Account selection not persisting after page refresh
- Fix &quot;Sync All&quot; not updating existing bills in QuickBooks for paid reports
- Fix BillPayment amounts not matching bill totals for multi-currency expenses
- Fix &quot;All&quot; status pill count not matching the number of visible expense rows

### Theming / White-Label
- Replaced all hardcoded purple/violet colors with theme-aware primary colors across Company Card UI elements

### Improvements
- QuickBooks integration now shows official logo in navigation (full color when active, grayscale when inactive)
- Fix QuickBooks connect failing in production due to missing environment variable mappings
</description>
    </item>
    <item>
      <title>v1.0.4</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.4</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.4</guid>
      <pubDate>Thu, 05 Mar 2026 21:12:58 GMT</pubDate>
      <description>## New Features

### QuickBooks Online Integration
BookYourPTO now integrates directly with QuickBooks Online, bringing your leave management, expense tracking, and time tracking into your accounting workflow. Available on **Business** and **Enterprise** plans.

- **OAuth 2.0 Connection:** Securely connect your QuickBooks Online company with a single click. Disconnect at any time — your QBO data is never modified without your explicit action.
- **Employee Sync:** Sync your employee directory between BookYourPTO and QuickBooks Online. Smart conflict detection compares records and highlights differences, so you always know what will change before it happens.
- **Expense Report Push:** When an expense report is approved, it can automatically be pushed to QuickBooks Online as a Bill. Vendors are auto-created for reimbursements, with duplicate name handling built in.
- **Time Entry Push:** Approved time entries are pushed to QuickBooks Online as TimeActivities, keeping your billable hours in sync with your accounting records.
- **Chart of Accounts Mapping:** Map your BookYourPTO expense categories to your QBO chart of accounts. Auto-map suggestions make initial setup quick — just review and confirm.
- **Department &amp; Client Mapping:** Map your BookYourPTO departments, clients, and projects to their corresponding QBO entities for accurate cost allocation.
- **Leave Liability Journal Entries:** Generate and push leave liability journal entries to QBO, helping your finance team track accrued leave obligations.
- **Sync History &amp; Audit Trail:** Every sync operation is logged with full audit history. Filter by sync type, status, and date range. Paginated history view keeps everything accessible.
- **Scheduled Sync:** A configurable cron-based sync keeps your data up to date automatically across all active connections.
- **Settings UI:** A dedicated QuickBooks settings section with a 7-panel sidebar covering connection status, employee mapping, account mapping, department mapping, sync history, leave liability, and payroll — fully mobile responsive.

### Timesheets Redesign with Calendar View
The timesheets module has been completely redesigned. The old time board has been replaced with a modern calendar view that gives you a clear, visual overview of your team&apos;s tracked hours across the week or month. Navigate between days, weeks, and months with ease, and see at a glance who logged what and when.

### Leave &amp; Holiday Integration in Timesheets
Approved leave requests and public holidays now appear directly in your timesheets — no more switching between modules to understand why someone wasn&apos;t logging hours.

- **Calendar view:** A compact leave summary strip sits between day headers and the time grid, showing per-day leave pills. When 4 or more employees are on leave, it collapses to a clean &quot;X on leave&quot; summary with a hover tooltip listing everyone.
- **Calendar view:** Public holidays are highlighted with emerald-colored labels and subtle column tints, so holiday days are instantly recognizable.
- **List view:** Holiday badges appear on day cards, with an emerald banner for selected holidays and an amber leave summary showing employee name pills.
- **Mobile view:** Holiday dots appear on day tabs with a leave count in each day header.
- **Top bar:** New &quot;on leave&quot; and &quot;holiday&quot; summary stat chips give a quick snapshot.
- **CSV export:** Enhanced with a new Type column (Time Entry / Leave / Holiday), leave rows include portion info, a holiday column, and a per-employee summary section at the bottom of the export.

### Scheduling System Redesign &amp; User Detail Page
The scheduling interface has been overhauled with a fresh design. A new `/user/:id` detail page gives managers and admins a dedicated view for any team member, consolidating their schedule, leave history, and profile information in one place.

### Per-Leave-Type Privacy Controls
Leave types can now be marked as **private**, giving organizations control over which leave information is visible to other employees.

- When a leave type is marked private, other employees will see a gray &quot;Private&quot; label with an eye-off icon instead of the leave type name, reason, or notes.
- **Role-based visibility:** Employees see only their own leave details. Department heads see their own department. Admins and executives see everything.
- Annual Leave and Sick Leave default to private during onboarding.
- A new **isPrivate toggle** is available in the leave type create and edit forms.
- Leave balance badges are hidden from unauthorized viewers for private leave types.

### Digest Privacy Filtering
Email digests now respect per-leave-type privacy settings. Private leave types are masked in digest emails using the same role-based rules as the dashboard — employees only see their own private leave details, department heads see their department, and admins/executives see all.

### Smart Digest Scheduling
Daily digests are now smarter about when they send:

- **Business day awareness:** Digests skip non-business days based on your organization&apos;s configured business days (e.g., no digest on Saturday/Sunday if your org runs Mon–Fri).
- **Holiday awareness:** Digests are also skipped on public holidays specific to each user&apos;s assigned holiday calendar.
- **Upcoming holidays:** Daily digests now include an &quot;Upcoming This Week&quot; section with a green-highlighted list of public holidays in the next 7 days, so your team knows what&apos;s coming.

### Redesigned Welcome Email Flow
When admins add new users, the experience is now cleaner and more secure:

- New users receive a **&quot;Set Up Your Account&quot;** email with a secure 24-hour setup link instead of a temporary password.
- A new dedicated **/setup-account** page provides a streamlined onboarding experience — simpler than the standard password reset flow.
- The Add User modal no longer displays or copies passwords. The success state now shows a clear &quot;setup email sent&quot; confirmation.
- Password change and account setup flows now issue fresh session tokens automatically, so users don&apos;t need to log out and back in after completing setup.

### Department Head Leave Allowance Editing
Department heads can now edit leave allowance settings (custom allowance, carry forward, manual carry over) for members within their department, giving them more autonomy over day-to-day team management without needing to involve an admin.

### Expense Submission Notifications
When any expense report is submitted, all administrators and executives in the organization now receive an in-app notification — not just the assigned approver. This ensures visibility across leadership and prevents expense reports from getting stuck in a single approver&apos;s queue.

---

## Bug Fixes

### Fixed: Date of Birth Displaying the Wrong Day
Dates of birth and start dates could appear one day off depending on the user&apos;s timezone (e.g., October 19 showing as October 18). This was caused by the browser interpreting UTC midnight dates in the local timezone. Dates are now displayed in UTC consistently for date-only fields, so the displayed date always matches what was entered.

### Fixed: Department Heads Seeing Their Own Expense Claims in Approvals
Department heads and managers were seeing their own expense claims in the approvals list, inflating pending counts and creating confusion. Their own claims are now excluded from the approvals view — they&apos;ll only see claims from team members they can actually approve.

### Fixed: Expense Approval Counts for Department Heads
The pending approvals badge count on the expenses page was computed from the general expense list, which for department heads included their own pending claims. The count is now derived from the dedicated approvals endpoint with proper role-based scoping.

### Fixed: Expense Report Controls Visibility
Non-owners could see edit and delete controls on draft expense reports. These controls are now properly gated behind submitter or admin role checks.

### Fixed: Expense Reports User Filter for Department Heads
The user dropdown on the expense reports page now correctly scopes to department members for department heads, instead of showing all organization users.

### Fixed: Avatar PNG Upload Failing on Windows
PNG file uploads were failing on Windows because certain browsers report an empty MIME type for PNG files. The upload flow now falls back to file extension detection on the client, and the server uses magic byte detection to confirm the actual file format regardless of what the browser reports.

### Fixed: Avatar Not Updating Immediately After Upload
After uploading a new avatar, the old image would persist until a page refresh. The avatar component now properly invalidates its cache after upload, and all instances across the page refresh immediately with the new image.

### Fixed: Avatars Not Loading Across the App
Avatars were failing to load in various components because they were using raw storage keys as URLs instead of the authenticated API endpoint. All 18 components that render avatars now use the authenticated fetch path, with a shared blob URL cache to avoid redundant network requests.

### Fixed: Avatars in Expense List Views
Expense cards and table rows were rendering broken avatar images. These now use the standard UserAvatar component with proper authenticated loading.

### Fixed: App Randomly Getting Stuck on Loading Spinners
Users were experiencing a frustrating bug where parts of the app would get stuck on infinite loading spinners, requiring a manual page refresh (sometimes twice) to recover. This happened randomly across the entire app — dashboard, settings, documents, time tracking, everywhere.

**What was happening:** When multiple API requests fired simultaneously with an expired authentication token, the first request would successfully refresh the token, but late-arriving responses from other requests would trigger redundant refresh attempts. This cascade left some requests unresolved, causing permanent loading states.

**What changed:** The app now detects when a token has already been refreshed by another concurrent request and skips unnecessary refresh attempts. All pending requests silently retry with the new token. Additionally, authentication headers are now managed in a single place, ensuring retries always use the freshest token.

**Impact:** Pages now load completely and reliably every time. Users can leave the app open, come back after their session token expires, and their next action works seamlessly — no more random loading freezes.

### Fixed: &quot;Takes X Days&quot; Preview Not Counting Business Days Correctly
The leave request modal&apos;s &quot;Takes X days&quot; preview was counting raw calendar days instead of business days. It now uses your organization&apos;s configured business days, timezone, and public holiday calendar to give an accurate count. This also fixes an issue where holidays could shift to the wrong day in western timezones due to UTC date conversion.

### Fixed: Session Becoming Unresponsive After 2FA Setup
After completing two-factor authentication setup, all API calls would fail because the session still carried outdated authentication state. Users had to log out and log back in to get a working session. The system now issues a fresh session immediately after 2FA setup completes.

### Fixed: Department Head User List Showing All Organization Users
The user management page was showing all organization users to department heads instead of only their department members. Additionally, action buttons (edit, etc.) weren&apos;t appearing even when the department head had permission. Both the filtering and permission checks now work correctly.

### Fixed: Email Addresses Getting Truncated in User List
Long email addresses were getting cut off in the user table. The email column has been widened, and a native hover tooltip now reveals the full address. The Add User modal success summary also now shows the full email without overlapping adjacent fields.

### Fixed: Weekly Digest Duration Labels
Weekly digest emails were showing redundant duration information for leave entries that span multiple days. The weekly view now shows the employee name and pending status badge only, since the same leave naturally repeats across multiple days in the weekly layout.

### Fixed: Digest Date Calculations Using Wrong Timezone
Digest date range calculations were using UTC midnight instead of the organization&apos;s configured timezone, which could cause off-by-one errors in which leaves appeared in a given digest. Date calculations now consistently use the organization&apos;s timezone.

### Fixed: Settings Page Not Loading After 2FA Setup
The settings page could fail to load in certain scenarios after completing 2FA setup due to a route matching issue. The route matcher now correctly handles both the settings root and all sub-routes.

### Fixed: Settings Navigation Items Briefly Showing Locked State
Settings navigation items would briefly flash lock icons on page load before the subscription data finished loading. The feature-locked check is now deferred until the subscription data is available, eliminating the visual flicker.

### Fixed: Stale Authentication in Time Tracking and Expense Settings
The time tracking settings and expense settings pages were capturing authentication tokens at call time instead of using the app&apos;s automatic token injection. This meant that after a token refresh, these pages would retry with the old expired token. They now use the standard automatic authentication flow.

---

*For questions or feedback about this release, contact support@anhourtec.com.*
</description>
    </item>
    <item>
      <title>v1.0.3</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.3</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.3</guid>
      <pubDate>Thu, 26 Feb 2026 20:42:47 GMT</pubDate>
      <description>## New Features

#### Per-User Holiday Override Toggle
- Added a &quot;Use custom holidays instead of organization defaults&quot; toggle to the **Edit User &gt; Holiday Overrides** tab
- When enabled, the user no longer follows the organization&apos;s public holidays — admins can configure a custom country, exclude specific holidays, or add custom ones
- When disabled, the toggle clears any previously set custom holiday country/region and the user reverts to organization defaults
- Dashboard calendar, leave requests, public holidays, and email digests all respect the new setting

#### Carry-Over Expiry Date
- The carry-over balance now supports an optional expiry date — expired carry-over days are automatically excluded from balance calculations
- Expiry is evaluated using the organization&apos;s timezone to prevent off-by-one date issues across time zones
- The expiry date is cleared automatically when carry-over balance is set to zero

#### Improved Leave Balance Calculations
- Manual carry-over adjustments are now included on top of automated carry-forward calculations in balance views
- User-specific carry-forward day limits now correctly override the organization-level cap
- Carry-forward eligibility threshold is now exposed in organization settings for accurate frontend display

## Bug Fixes

#### Date of Birth Timezone Handling
- Fixed date of birth shifting by one day in western timezones (e.g., Feb 25 displaying as Feb 24) by using the organization&apos;s timezone instead of UTC
- Prevented selecting future dates in the date of birth picker

#### Department Filter Toggle
- Fixed the users filter modal where unchecking &quot;All departments&quot; did not deselect individual department checkboxes

#### Leave Balance Carry-Forward Edge Case
- Fixed an issue where setting a user&apos;s custom leave allowance to `0` was incorrectly treated as &quot;use organization default&quot; instead of zero

#### Guided Tour Popover Appearing After Logout
- Fixed guided tour popovers occasionally persisting on the login page after signing out
- Tour state is now fully reset on logout, preventing stale tour data from carrying over between sessions

### Improvements

#### Quick Edit via Avatar Click
- Clicking a user&apos;s avatar on the Users page now opens their Edit Profile modal directly
- Available for Administrators, Executives, and Department Heads (restricted to their own department members)


#### Leave Allowance Tab
- Simplified the Edit User leave allowance tab with a cleaner, settings-focused layout

#### SSO Domain Validation
- Added validation to prevent public email domains (e.g., gmail.com, yahoo.com) from being added to SSO allowed domains
- Instant client-side feedback with inline error messages

#### Plan Downgrade Handling
- Paid integrations (notification channels, calendar sync) now gracefully pause when an organization downgrades and automatically resume on re-upgrade without losing configuration
</description>
    </item>
    <item>
      <title>v1.0.2</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.2</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.2</guid>
      <pubDate>Tue, 24 Feb 2026 06:18:13 GMT</pubDate>
      <description>BookYourPTO v1.0.2 — Release Notes                                                                                                                             
                                                                                                                                                                 
  Trusted Devices — Skip 2FA for 30 Days                                                                                                                         
  Employees can now check &quot;Remember this device for 30 days&quot; when logging in with 2FA. Trusted devices can be viewed and revoked anytime from Settings &gt; Trusted
  Devices. Disabling 2FA automatically revokes all trusted devices.

  Slack &amp; Teams Notifications
  Get your BookYourPTO notifications delivered straight to Slack or Microsoft Teams.
  - Personal: Each employee can connect their own webhook in Settings &gt; Connected Apps &gt; Slack &amp; Teams to receive personal notifications (leave approvals,
  rejections, etc.)
  - Organization-wide: Admins can set up a shared channel for team notifications in Settings &gt; Notifications Channel — pick which notification types get posted

  Settings Redesign
  Calendar Integration and Slack &amp; Teams are now combined under a single &quot;Connected Apps&quot; tab with a cleaner tabbed layout.</description>
    </item>
    <item>
      <title>v1.0.1</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.1</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.1</guid>
      <pubDate>Mon, 23 Feb 2026 19:43:06 GMT</pubDate>
      <description>## Birthday Indicators
  - Users with a date of birth now see a 🎂 pink cake icon on their birthday in the `/calendar` yearly view and dashboard calendar grid
  - Hovering shows a &quot;Birthday&quot; tooltip (dashboard shows full name)
  - Birthday cells get a subtle pink border and background highlight

  ## Balance Display Settings
  - **Dashboard badge** — controls which leave balance is shown on each user&apos;s avatar badge (Annual / Sick / Both)
  - **Calendar balance summary** — controls which leave buckets appear in the calendar sidebar (Annual / Sick / Both)
  - Configurable from **Settings &gt; General** by administrators and executives

  ## Birthday Reminder Emails
  - Monthly cron endpoint sends a birthday digest email on the 1st of each month to admins, executives, and department heads
  - Lists all team birthdays sorted by date with name, department, and date
  - Department heads only receive birthdays from their own department
  
  ## Dashboard UX Improvements
  - User names in the dashboard are now clickable links to their `/calendar` page (for admins, executives, and same-department heads)
  - Weekend columns have consistent muted background across the full column height</description>
    </item>
    <item>
      <title>v1.0.0</title>
      <link>https://changelog.bookyourpto.com/releases/v1.0.0</link>
      <guid isPermaLink="true">https://changelog.bookyourpto.com/releases/v1.0.0</guid>
      <pubDate>Fri, 06 Feb 2026 04:12:02 GMT</pubDate>
      <description>We&apos;re excited to announce the first official release of **BookYourPTO** — an all-in-one leave, time tracking, expense, and document management platform for modern teams.

Available as an **open-source community edition** for self-hosting and a **cloud-hosted version** with Pro, Business, and Enterprise plans at [bookyourpto.com](https://bookyourpto.com).

Development began on **December 22, 2025**, and v1.0.0 marks the culmination of six weeks of active development.

---

## Core Platform (All Plans)

### Leave Management
- Submit, approve, reject, and cancel leave requests with full workflow support
- Configurable leave types with custom allowances and accrual rules
- Leave balance tracking with fiscal year awareness
- Leave approvals and policies
- Dashboard calendar with monthly navigation and team-wide visibility
- Leave transaction audit trail

### Time Tracking
- Clock in/out with real-time timer
- Manual time entry creation, editing, and deletion
- Project and task management with client association
- Billable hours tracking
- Work schedules with customizable shift patterns
- Timesheet approvals with individual and bulk actions
- Geolocation capture for clock-in/out events

### Expense Management
- Expense submission with AI-powered receipt scanning
- Mileage and per diem expense types
- Receipt upload with secure access via short-lived Redis tokens
- Expense approval workflow
- Expense reports with filtering and export

### Digital Document Signing
- Upload and assign documents to single or multiple recipients
- ESIGN Act compliant digital signature capture
- Searchable documents with OCR
- Document preview, view, sign, and decline workflows
- Browser timezone capture displayed on signed documents
- Document encryption for sensitive files

### Notifications
- In-app notification system with real-time bell indicator
- Notifications for leave submissions, approvals, rejections, and cancellations
- Notification management page with mark-as-read, clear-all actions
- Pending items widget on dashboard with role-based display

### Reports &amp; Exports
- Leave usage reports with filtering and export
- Timesheet reports with date range selection
- Time tracking billing reports
- Security audit log export (CSV)
- Sign-in log export

### Calendar Integrations
- Google Calendar sync for approved leave events
- Microsoft Outlook calendar integration
- iCal feed support for any calendar application

### Role-Based Access Control
- Four roles: Employee, Department Head, Administrator, Executive
- Department Head role for team-level approvals and oversight
- Role-based permissions across all modules
- Granular permissions system with per-user overrides
- Designate approvers with cross-department approval capabilities
- Locked dates to prevent bookings on specific dates (admin/executive controlled)
- Executive override for booking on locked dates
- Project member roles: Owner, Manager, Member

### Authentication &amp; Security
- JWT-based authentication with refresh token rotation
- Force password change on first login
- Redis rate limiting on authentication endpoints
- Token audit logging
- Sign-in logs with export

---

## Pro Plan Features

- Up to 10 users
- 500 receipts/month
- 1,000 documents with OCR
- Email support

## Business Plan Features

- Up to 30 users
- Unlimited receipts and documents with OCR
- Advanced approval workflows
- Custom reports
- Email digest notification system with daily/weekly scheduling
- Multi-currency expense support with role-based visibility

### White-Labeling
- Branding settings with logo, colors, and theme configuration
- Domain-specific branding (custom domains show org branding)
- Branding API with cache-control headers

### Auth0 Integration (OIDC)
- Enterprise Single Sign-On via Auth0
- Configurable &quot;Enable Auth0&quot; and &quot;Require Auth0 Login&quot; settings
- SSO enforcement option for organizations
- Auto-create users on first SSO login with configurable default role and department

### Audit Logs
- Comprehensive audit logs with entity types for all modules
- Security violations tracking and management
- Time tracking compliance dashboard

### Custom Domains
- Custom domain support with DNS verification
- Single custom domain per organization enforcement
- Public branding endpoint for unauthenticated access

### Priority Support

## Enterprise Plan Features

- Unlimited users
- Everything in Business
- Custom limits
- Dedicated support
- SLA guarantee

---

## Stripe Billing

- Subscription management with plan-based feature gating
- Checkout session creation with discount/coupon support
- Invoice tracking and billing history
- Webhook processing with idempotency protection
- Plan limits enforced across all API endpoints
- Plan-based UI gating in settings
- Refund processing with hardened input validation
- Free plan default for new organizations

## Email System

- Configurable SMTP settings per organization
- Test email functionality for verifying configuration
- Branded email templates with organization logo support
- Fallback to platform SMTP logo when org has no custom logo
- Email notifications for leave workflows, document assignments, and more

## Organization &amp; Multi-Tenancy

- Multi-tenant architecture with organization-scoped data isolation
- Organization onboarding workflow
- Department management (create, update, delete)
- User management with role-based access control (Employee, Department Head, Administrator, Executive)
- Organization statistics dashboard
- Data backup/export endpoint

## Public Holidays

- Country-based public holiday management
- Regional subdivision holiday support
- Per-user holiday override system
- Dashboard calendar displays user-specific holidays

## Infrastructure &amp; Deployment

- Docker containerization with multi-stage builds
- Docker Compose with PostgreSQL, Redis, and application services
- Environment variable configuration for all services (Stripe, SMTP, OAuth)
- Persistent document storage via Docker volumes
- Nuxt 3 full-stack framework
- Prisma ORM with PostgreSQL
- Redis for caching, rate limiting, and session management
- Cloudflare integration for domain management

## UI/UX

- Responsive design across all pages (mobile, tablet, desktop)
- Dark/light mode support
- App Launcher navigation for unified approvals and reports
- Sticky dashboard calendar with team visibility
- Custom modal components with scroll support and mobile optimization
- Area charts for analytics visualization</description>
    </item>
  </channel>
</rss>