All notable changes to Compass land here. Format follows Keep a Changelog and the project loosely follows SemVer.
When something ships to production, move it from Unreleased into
a dated release block. git log is the source of truth for
attribution and commit hashes; this file is the human-readable
summary of what users care about.
[Unreleased]
Added
- Business Lounge (B6b, fifth part): the client's view inside the Business Lounge now shows a contract's signing card exactly as they see it, with every button and field switched off and a note that their buttons do nothing here.
- Business Lounge (B6b, third part): each quote, contract, questionnaire and invoice now has small settings cards at the top: In their Lounge, Reminders, and Activity and notes (with a lock: only you see it). Each shows its state in a word and opens in a box. The Activity and notes box is that item's own log, like the job's Activity log: filter pills with counts, a search, a heading per day, what happened to each email about it (delivered, opened, bounced), and your notes about it in full. Write a note at the top; edit or delete one from its menu (delete asks first). The Internal notes, Email history and Activity cards under the paper are gone; a signed contract keeps its signature evidence there.
- Business Lounge (B6b, fourth part): when your client taps I've paid, a line waits at the top of the invoice ("Kay and Lee say they paid $X by bank transfer, 29 Sept 2026. You got a bell notification and an email. Record it once it clears in your account.") with Record this payment, which opens Record a payment filled in. Nothing is marked paid until you record it.
- Settings, Payment methods (B6b, slice 2): one list of the ways clients pay, card included, in the order they see them after tapping Pay. Drag a row by its handle (mouse, touch or keyboard) or use Move up and Move down; the order saves at once. One method can be the preferred one, with your own callout words, and it stays in its place instead of jumping to the top. One Edit box for every method: the button's name (card's too), preferred and its callout, detail lines each with its own Copy tick, the Reference line with the invoice number, a short note and which currency it shows on; card's Edit holds the Stripe link and the card fee. A live preview beside the list shows what their clients see. Their pay screen, the invoice paper, the PDF and the invoice email all follow this order, and the paper prints each method's note.
- Business Lounge (B6b, first part): an invoice's own page now has a Payment schedule card above the paper, in place of the Payments card. Each payment is a row with its status, due date, last action and amount, sorted by date, with no names. A row paid by card links to Stripe and cannot be changed here; a row paid another way can be changed, receipted or marked unpaid; an unpaid row can take a new date or amount, take a payment, or be removed. Add a payment date and Change ask only for the date and the amount, and the last other unpaid payment balances. A part payment now shows as two lines, the part paid and the rest, due the same day, on the card, the paper and the PDF. Total, Paid and Balance due sit at the card's foot, and on the paper and the PDF the third figure reads Credit when more was paid than owed. The card-payment switch and the saved schedules stay on the card for now.
- Client Lounge (B6a, early access only): an invoice is paid on the client's own page. Pay next payment (when it is split) or Pay full balance shows the ways to pay in the business's order, with its preferred one marked. Card uses today's card payment and brings them back to the invoice with a thank-you. Bank transfer and PayID show each detail with its own Copy button, then I've paid, which tells the business with a bell and an email (a new notification, on by default) and never marks anything paid; their page then says what they told you until you record the payment. Every invoice paper and PDF now prints its payment schedule (Due, Status, Paid on, Amount, by date), with Total, Paid and Balance due at its foot.
- Emails (, second part): Compass now keeps a copy of every email it sends for a business, exactly as sent (subject, the email itself and its plain text, and the names of any attached files, never the files). Owner alerts (bookings cancelled or moved, new online bookings, a bounced email, the automation daily limit) and the contact form's auto-reply now keep theirs too. An owner alert's copy belongs to no client: it never shows as a client's last contact or on their timeline, and if it bounces nothing is paused and no second alert goes out. The auto-reply is a client email, so its bounce now pauses automatic emails to that address like any other. Only the business can read the copies, and no screen shows them yet. Emails that carry sign-in backup codes are never copied. A copy that cannot be saved never stops the email.
- Emails (, first part): the database gains a place to keep what each sent email said (its HTML and plain text, as sent). Nothing writes it yet; the next change starts keeping the copies.
- Client Lounge (, early access only): a questionnaire is answered right on its paper on the client's own page. Every kind of question works (short and long answers, yes or no, one choice, several choices, a date), with the * marks and "N of M answered". Answers save on their own as they type ("Saving…", then "Changes saved", and a small Saved chip at the top). Submit answers checks the required ones in plain words ("Please answer this one."), then shows "Thank you. Your answers are in." with their answers and "Update your answers". An autosave can no longer overwrite answers after they are submitted.
- Client Lounge (, early access only): a contract is signed on the client's own page. Sign contract at the top takes them to a signing card under the paper, which says "Not signed yet. Sign below when you are ready." The "I have read and agree" box unlocks once they reach the end of the agreement; they type their name, which shows as a signature, can add a second signer on the same screen, and sign. Plain error lines say what is missing. After signing, a thank-you box leads to the invoice to pay ("Both signatures are on your contract." when two signed). There is no Decline on a contract. After accepting a quote or signing, the page returns to the top of the item.
- Client Lounge (, early access only): a quote now works on the client's own page. Accept quote and Decline sit above the paper; on a quote with several options they pick one package and any extras right on the paper (extras that are always included are locked in) and their total updates as they pick. Decline asks first ("You can change your mind until
"), then says "You declined this quote." with Undo, which puts it back as it was. A declined quote says "Changed your mind?" with Accept quote while it can still be accepted: until its last day, and only while the job has not been booked and no other quote on it was accepted; otherwise it says it cannot be accepted now. After accepting, a thank-you box leads on to the contract to sign or the invoice to pay. The business can still never reopen a declined quote. A declined quote can no longer be taken back once the business has made or sent another quote on the job. On the quote page too, the running total while picking options no longer reads low when the quote has a discount. - Client Lounge (B2c, early access only): on the client's own page, each quote, contract, questionnaire, invoice, file and note now opens right there, with its paper, their status and line, and their buttons, as the approved design and the Business Lounge's client view show it. A room with a single item opens that item straight away. Their buttons still take them to the item's own page to accept, sign, answer or pay, until the next parts bring each of those here. A file has its Download button. The Business Lounge's client view now shows a note as their page does, its words on a card, and a contract that waits for its quote the same way on both.
- Client Lounge (B2b, early access only): their Home is no longer a list of rooms. It greets them, shows the one thing to do next with its button (Review & accept your quote, Review & sign your contract, Review & pay your invoice, or Answer your questionnaire) and the steps of their booking, then the key facts: their date, what they have paid so far, and what is due next. The Business Lounge's client view shows the same Home.
- Client Lounge (early access): the client's own page, and the Business Lounge's client view, take the business's Lounge colour from Settings, Client Lounge (the setting's default when none is chosen), as today's Lounge does.
- Client Lounge (B2a, early access only): for a business with the Lounge page's early access, the client's link now opens their own page drawn like the approved mock: their cover photo, the business's name and logo, the rooms and lists as the Business Lounge's eye shows them, and a quiet footer with who to ask, the business's email and phone, the private-link note, and 'Powered by getcompass.studio' for businesses on the free plan. A note opens in their Notes room. Documents still open on their own pages for now. Everyone else keeps today's Lounge.
- Invoices (, first part): the database gains a place for an invoice's private notes (never shown to the client). The notes box itself follows in the next change.
- Invoices: a private notes box, like a quote's "Internal notes (not shown to client)", on new invoices, Edit, and the invoice's editor in the Lounge. The Lounge's invoice page shows them in its private Internal notes panel and the older invoice page shows them when there are some. They are never printed, emailed or shown to the client; the client's Lounge drops them the moment it reads an invoice.
- Business Lounge (slice 6d, early access, test business B only): the client's Lounge gains a Notes room and a Deliverables room, in its present look, with the approved design's words. A deliverable reads "Not ready yet. Due
." or "Ready." with a Ready tick; opening a note shows it inside the Notes room and records that they read it. Their Home gains a Deliverables step ("Album and Prints. Not ready yet."). Only notes and deliverables shown in their Lounge appear; a link to a hidden note lands on their Home with the notice. The Business Lounge page's preview of their Lounge, and its "not shown here" line, follow the same rule. Their switches now work, on the Lounge page and on the job page of a business with the Lounge page: a note's in its box (with Save), its row's Show and Hide in the ⋯ menu and their Undo; a deliverable's Show and Hide in its ⋯ menu on the Deliverables card (with Undo) and its eye; and the Add box, where a new note or deliverable can start shown (a new deliverable starts as its Settings template says). An Undo of a note's delete puts it back shown or hidden, as it was. Everywhere else notes and deliverables stay locked as before. - Business Lounge (slice 6c-2, test business B only): a file hidden on a job now refuses that job's links to it, old emailed ones included, and lands the client on their Home with the notice (links with no job are unchanged); its page says so. A receipt for a payment that lands on a hidden invoice still goes, with its PDF, but without its "view your invoice" button. A workflow step whose document is hidden waits, sends nothing, and goes on the first run after it is shown again; the workflow card says "Waiting:
- is hidden from their Lounge." Sending a workflow invoice step by hand shows a hidden invoice first, as every Send does.
- Business Lounge (slice 6c, early access, test business B only): the In their Lounge switch now works for quotes, contracts, questionnaires and invoices, everywhere it shows: the item's own page (at once, with Undo), Show and Hide in the ⋯ menu, the rename box, the editors (saved with Save; "Saved. Hidden from their Lounge.") and the Add box (a new contract or questionnaire can start hidden). Hiding something they accepted, signed or paid asks first ("Hide it?"), on the switch as in the menu. A contract waiting for its quote still follows the quote, and so does one whose quote closed ("It follows
, which closed."). Undo of a show is refused once the item was emailed since ("It was emailed after you showed it, so it stays in their Lounge."); an editor writes the switch only when it was turned there. Sending a hidden item shows it ("Sending shows it in their Lounge." in the Send box; "Sent to
. It shows in their Lounge now."); a typed email that does not go out puts it back. Mark sent does not show it. A hidden document's line reads "They can’t see or open it." and, once emailed, "Links you emailed before stop working too, until you show it again."; its row adds "old email links closed while hidden". Notes and deliverables keep their switches locked until their rooms reach the client's Lounge. - Business Lounge (slice 6b): nothing is emailed or texted about an item hidden from the client's Lounge. A contract's or questionnaire's reminders skip the steps that fall due while it is hidden and carry on from the next one when it is shown again (missed ones are never sent in a burst); an invoice's payment reminders the same; "Send a reminder now" on a hidden invoice says it is hidden; a contract whose quote is accepted while the contract is hidden gets no signing email, and the client is not led to it; Today offers no Remind for a hidden contract or questionnaire. Their Reminders row reads "Paused while hidden." with "Nothing is emailed or texted about it while it is hidden. Show it again and they carry on from there. Missed ones are skipped, never sent in a burst." Nothing is hidden yet, so nothing changes today.
- Business Lounge (slice 6a, early access, test business B only): the client's side now honours "hidden". A quote, contract, questionnaire or invoice the business hid from their Lounge is left out of it (its rooms, Home steps, the count of things needing them, history and Payments totals), and no link opens it, old emailed links included: its page, its PDF, and accepting, declining, signing, saving or submitting answers and paying all refuse. A refused link lands on their Home with one plain line, "This is not available right now. Please ask
about it." (a document with no Lounge shows the line on its own). A contract follows its quote until the quote is accepted. A hidden accepted quote still opens their Contract room, and a payment already under way on a hidden invoice is still recorded when they come back from paying. Nothing can be hidden yet (the switch goes live in a later part), and nothing in production is hidden, so nobody sees a change today. A refused link never creates a Lounge. A contract follows only a quote on its own job, as the business side reads it. - Security (quotes): the client's Accept on a quote's page no longer takes any extra instruction from the browser. It used to accept a third argument meant only for the business's "Accept on the client's behalf", with which anyone holding a quote link could skip the "accept only what your page showed" check and write their own text as the acceptance signature in place of the recorded address and browser. The business's own path now goes through its signed-in action only. Also for clients: their Contract room's "Agreed total" and "Pay deposit" come only from the accepted quote the contract belongs to, never from a later open or a superseded quote.
- Business Lounge page (early access, test business only): Send now opens the email itself, as the mock draws it. "Email
" shows who it goes to (read only), the Subject and the Message, ready to change, then the item's own choices: a contract's sign-by date and reminders, a questionnaire's due date and reminders, an invoice's due date and payment reminders with the PDF line. The Subject starts as the email's own; the Message starts "Hi Sam and Alex," with a line naming the item as the client sees it (and, for a quote with a contract waiting, that the contract comes next). What is typed takes the place of the email's own greeting and paragraph; the button, the PDF and the saved signature stay. An empty Subject or Message says "Add a subject and a message before sending." and a refusal keeps the box open with the words, so nothing typed is lost. A typed email that does not go out leaves the item unsent with no reminders started, and says why. Typed emails are plain text (nothing typed can become HTML or one of the email's own fill-ins), the subject is one line of at most 300 characters, and a business can send at most 20 a minute (one budget with the workflow card's sends). The quote, contract, questionnaire and invoice pages outside the Lounge send exactly as before. - Emails: the questionnaire email now carries the business's saved signature, as the quote, contract and invoice emails do. A line break in a quote email's message no longer shows as "<br>", and a client's name in an email's greeting can no longer become HTML. A quote can now be emailed to a client whose only address is on their contact, as a contract or questionnaire already could (it used to say the client had no email). A questionnaire email whose file link cannot be made now names the file, as the contract's does.
- Business Lounge page (early access, test business only): the eye now shows the page as the client sees it (part 5g-1). A bar across the page says so with a way back, a thin band names everything on the job they cannot see, each with its reason (hidden, void, written off, opens once they accept a quote, not in their Lounge yet), the rail lists only their rooms by their own names (Payments), their rows carry their own words (Ready for you to review, Review, Sign, Pay, Accepted, Signed, Paid, and the date-passed forms), the Payments room shows what they have paid to date, and their Home shows its welcome and no Needs you. In their view an item opens as they see it (part 5g-2): its name, their chip and line, their own buttons shown switched off ("Their buttons. They do nothing here."), a contract that closed with its quote reads "Not needed" throughout, the paper with their words ("Ready for you to sign", "Read it through. When you are ready, press Sign contract at the top.", a lock box when a contract waits for its quote), a thank-you leading to the contract after an accepted quote, and none of your buttons, switches or private cards. An item they cannot open sends them back to its room.
- Business Lounge: the page's room list and rows now say "not in their Lounge" for exactly what the client's own Lounge leaves out (a void or declined contract, a void questionnaire, a written-off invoice, a withdrawn quote), by one rule shared with the "see the new version" message. A room holding only such items no longer says it is in their Lounge. A test holds the rule and the client's Lounge together.
- Contracts: saving a quote no longer puts back old wording over its contract. The quote editor sends the attached contract's wording with every save, so a quote saved from an older tab overwrote edits made in the contract's own editor. Now the wording is written only when it was changed in the quote editor, and only over the version of the contract the page was opened with. If the contract changed somewhere else since the page opened (its wording, or which contract is attached), the save says "This quote's contract was changed a moment ago, so your changes were not saved. Refresh the page to see it." A contract in the Trash is no longer treated as the quote's contract.
- Business Lounge: the editors' sticky edit bar (and the phone's rooms bar) now stays below the "Show all settings" tab when the page is scrolled, instead of half under it. The settings drawer now says how far it reaches below the nav, the way the nav says its own height.
- Formatted editor: pressing Enter in one of the editor's pop-up fields (the link's text or address, a custom colour, the file search) no longer submits the whole form. It inserts the link or uses the colour, and the file search just stays open. It used to save the contract and lose a half-made link.
- Contracts: a contract whose wording has been emptied (only empty lines, spaces or a divider left) can no longer be saved, sent or made. Editing a contract says "The contract has no wording. Add its wording before saving."; a contract template says "Add the contract body before saving…"; a quote with an attached contract says "The attached contract has no wording. Add its wording, or remove the contract." The words now show before anything is sent to the server, so they are not lost and nothing else typed is cleared. Send refuses to email one, and the "ready to sign" email when a quote is accepted, a workflow's contract step and a quote's own contract make or send no contract with no wording. An image counts as wording when the signing page can show it. No stored contract or template was empty.
- Trash: the Undo on the "moved to the Trash" message after deleting a job now brings back its quotes, contracts, questionnaires and invoices too, as the Trash page's Restore does. It used to bring back only the job, leaving its documents in the Trash to be restored one by one. A failed read now says the Undo did not work instead of claiming it did.
- Invoices: an invoice a workflow step makes from an invoice template now keeps each line's own discount (Disc %), so it bills what the template shows and what a hand-made invoice from the same lines bills. It used to drop it: "Album 1 x 500, Disc 10%" billed $500 instead of $450. Both now store lines by one shared rule. No template has a line discount and no invoice has been made this way yet, so nothing stored changes.
- Invoices: the invoice editor and the save now agree on what a line is. A priced line with a quantity of 0 (or none), a line with a price but no description, and a percent discount over 100% are no longer quietly changed or dropped on save: the editor says so under the line ("Line 2 needs a quantity above 0.", "Line 3 has a price but no description. Say what it is for, or clear its price.", "A percent discount can be at most 100%.") and Save will not go until it is fixed: the browser points at the field and shows the same words, so nothing typed is lost. More than 200 lines or 20 discounts, which the save used to drop without a word, are refused the same way. A blank line is still left out, and a free line with no quantity (a "not included" note) still saves at $0. Invoice templates follow the same rule. Nothing stored had any such line, and no stored invoice has an old-style line.
- Invoices: an invoice a workflow step makes from a template now starts where a hand-made new invoice for the client starts: the client's own region, else the business's default region, else no region in the business's own currency. It stores and bills what that invoice's tax field would as it opens (the region's own rate, else the template's rate while it is still active). It used to ignore the client's region and currency, so a client in a tax-free region could be billed the default region's tax. A new invoice opened from a booking, in the booking's currency, now starts in the client's region when it is in that currency. No invoice has been made from a workflow yet, so nothing stored changes.
- Trash safety: nothing on a job in the Trash can be sent or changed from a page left open after the job was trashed. Sending a quote, contract, questionnaire or invoice, marking or recording payments, write-offs, charges, schedules, status changes, deletes, notes, shared files and deliverables, a new quote started for the job, and a workflow step sent from the job page all refuse with "This job is in the Trash. Restore it to …". The Send buttons and the Lounge's Mark sent and Mark paid show those words.
- Invoices: the invoice editor's live total now includes the tip, shown as its own line, exactly as saving adds it (on the edit page, the new-invoice page and the Business Lounge editor). It used to show the total without the tip.
- Tax safety: when Compass cannot read a business's tax rates or a region, it now refuses to save rather than saving the wrong tax. That covers making or editing an invoice or a quote, an invoice made from a template by a workflow step (the step waits and tries again), a client accepting a quote, saving a client's region, setting up the business's home region, and the invoice export. Nothing is saved and the failure is reported. The Business Lounge editors, the quote editor and the client form say so in plain words ("Compass could not read your tax rates, so nothing was saved. Try again."); a client accepting a quote sees "Something went wrong on our end. Please try again in a moment."; the older invoice pages and a new quote show the app's error page. Before, one failed read could store a document with no GST or the default GST in a tax-free region.
- Business Lounge page (early access, test business only): after an edit, "…see the new version in their Lounge now." is said whenever the document is shown in their Lounge and the client can open it, drafts included (clients open drafts too; a contract once a quote on the job is accepted, when their Contract room opens). A job in the Trash can no longer be changed through a Lounge editor or the Add box, the same rule the job page's rename box follows, with the same words.
- Invoices: the invoice editor's live totals now show the tax that saving will charge. An invoice with no rate of its own and no region previewed no tax while saving added the business's default rate, and where the old "GST registered" setting was on without a default rate, it previewed GST that saving never charged. The preview on the edit page, the new-invoice page and the Business Lounge editor now works the rate out the same way saving does, from what the form sends. No saved amount changes.
- Business Lounge page (early access, test business only): Edit on a contract (while it can still change) now opens its editor right there, laid out as the design draws it: a line that the change is for this contract only and the template stays the same (and, once it is sent, that the client will read the change before signing), "Names and who sees it", "This job's wording" with the formatted editor, then when they can sign it, and Internal notes. Save comes back to the contract's page; a save that does not go through says why on the page. A changed client name also changes the name its running reminders use, as a rename does.
- Business Lounge page (early access, test business only): Edit on an invoice (draft, sent or part paid) now opens its editor right there, laid out as the design draws it: "Names and who sees it" (the name only you see and the name your client sees; once the client has paid part of it they are fixed and a line says why), Client (with "These print on this invoice. The client's own record does not change."), Dates (and the extra charge's due date while one is owing), Lines (with the tip before the totals) and Notes. Save comes back to the invoice's page; a save that does not go through says why on the page and keeps everything you typed. In every Lounge editor all fields now share one look, nothing makes the page wider than a phone (each line stacks on a phone as the design draws it), a date picked from the calendar counts as an unsaved change, and "see the new version" is said only when the document is in their Lounge.
- Business Lounge page (early access, test business only): Edit on a quote now opens its editor right there, laid out as the design draws it: an edit bar with Cancel and Save (and "Unsaved changes" once you type), "Names and who sees it" on top (the name only you see and the name your client sees, In their Lounge, the kind, valid until), then Line items (or Packages and extras), Discounts, Contract and payments, Terms, Internal notes and Totals, with Cancel and Save again at the foot. Save comes back to the quote's page with "Saved."; Cancel discards at once; leaving by any other link asks first.
- Business Lounge page (early access, test business only): contracts and questionnaires now have Email history and Activity panels too. Every email about a contract or questionnaire (its send, the signing email sent when its quote is accepted, workflow steps and reminders) is now tied to it, so its history lists them from 27 Sept 2026 on, and a reminder reads "Reminder sent to". Their Activity is built from their own records: made, sent, signed by each person (or signed on paper), started and answered, declined, void, and each reminder set, sent or stopped.
- Business Lounge page (early access, test business only): under each document's paper, the panels only you see, each marked "never client-visible": an invoice's Payments (record what comes in, the payment plan, card payments), Email history and Activity; a signed contract's Signature evidence (typed name, when they agreed, IP address and browser); a quote's Email history and Activity; and Internal notes on quotes and contracts (and on a questionnaire when it has one). Email history shows each email's outcome as a word and an icon (Delivered, Opened, Not opened yet, Bounced), with what each means on hover.
- Business Lounge page (early access, test business only): every quote, contract, questionnaire and invoice page now has a Reminders row, with a chip that says On, Waiting, Paused, None, Off, Stopped, Blocked, Completed or All sent, a line saying what goes out next and why (for example "Gentle nudges: 2 sent. Next one Tue 20 Oct, 7 days before it is due."), and a small line saying what stops them by itself. A contract's or questionnaire's Change menu stops its reminders (it asks first); pausing and sending one now come with the reminders update and are greyed saying so. Quotes say they have no follow-up yet. An invoice keeps its own menu.
- Business Lounge page (early access, test business only): the Status row is a whole sentence with the moment and, where Compass knows it, the place: "Sam and Alex accepted it on Sat 20 June at 7:42 pm, in their Lounge.", "You accepted it for them on …" for a yes you recorded, "Signed by Sam Taylor on Mon 22 June at 8:05 pm, and by Alex Rivera 2 minutes later.", and a sent invoice not paid yet says what is due and when.
- Business Lounge page (early access, test business only): the job page's Client Lounge rows now open each item's own page in the Business Lounge. A business without the page keeps today's links.
- Business Lounge page (early access, test business only): a questionnaire now opens on its own page, on the document paper: its title and dates, your letterhead, then every question with its required mark and the answer so far, "No answer" once it is out, or the kind of answer it asks for before anyone answers. Under the buttons, a line says its questions come from its template, with a link to Settings, Questionnaire templates. The buttons follow the design: Send by email or Re-send (the questionnaire's own send, with its due date and reminders), Save as PDF, and More (Archive, Delete).
- Business Lounge page (early access, test business only): a contract now opens on its own page, on the document paper: its title and dates, your letterhead, who it is between and the event date, its text, and its signatures (who signed and when, "Signed on paper", or what it is waiting for). The buttons follow the design: Edit, Send by email or Re-send (or "Emailed when they accept" while it waits for its quote, since its signing email goes when the quote is accepted), Save as PDF, and More (Move to for the manual overrides, Archive, Mark as void, Delete), each the contract's own action; a status change comes back to the contract's page. A contract waiting for its quote links to that quote, and a signed one lists who signed it and when.
- Business Lounge page (early access, test business only): a quote now opens on its own page, on the same document paper as an invoice: its number, dates and total ("From" the lowest package on a quote with several options), your letterhead, who it is for, its lines and totals or its packages and extras, the payment plan your client sees before accepting, and its terms. The buttons follow the design: Edit while it can change, Send (or Send again), Mark accepted (verbal yes), Save as PDF, and More (Save as template, Undo acceptance, Withdraw or Reactivate, Archive, Delete), each the quote's own action. Once accepted or closed, a line under the buttons says why it can no longer change.
- Business Lounge page (early access, test business only): an invoice now opens on its own page. Its buttons follow the design (Edit, or Add a charge once paid, or Reverse write-off; Send by email; Save as PDF; Print, which prints the invoice alone; Mark sent; Mark paid; More with Save as template, Write off, Archive and Delete), each doing exactly what the invoice page's own button does. Under them: why it is locked once paid or written off, the In their Lounge row, the invoice's Status and Reminders rows (with their Change menu), then the invoice on its paper, with the name your client sees under the number and, when you have no logo, a quiet "Add your logo" link that clients never see.
- Business Lounge page (early access, test business only): a file or a note now opens on its own page. A file's page shows its names (with Rename), its size, Download, the In their Lounge switch (it works at once, with Undo), whether the client has opened it and how often, and the file itself. Remove is greyed with the reason, as taking a file off a job comes later. A note's page shows its words, with Edit and Delete (Delete asks first, then offers Undo in the Notes room).
- Business Lounge page (early access, being built in parts; on for a test business only): the page for everything a job's client can see, at the job's Lounge address. A rail of rooms (Home, Quotes, Contracts, Questionnaires, Invoices, Files, Deliverables, Notes) with counts and one status word each; Home shows what needs you and what the client sees first; each room lists its items with the same menus and Add box as the job page. On a phone the rooms open from a Rooms bar.
- Business Lounge (early access): Rename on the Client Lounge card. A quote, contract, questionnaire, invoice or file on a job has two names, the one only you see and the one your client sees, and Rename changes both until your client acts on it (accepts, signs, starts answering, pays or opens it); after that Rename is greyed and says when that happened. The Add box's Rename link works too, so a new contract, questionnaire or file can get its own names as you add it. Your client sees their name everywhere they meet the item: their Lounge, the document's page and PDF, its emails and its reminders. An invoice keeps its number, with its name under it. Editing a contract says that changes apply to this contract only, not its template.
- Business Lounge (early access): the Client Lounge card's "+ Add" opens a short menu, "Add to this job", in the kit's order (Quote, Contract, Questionnaire, Invoice, File, Deliverable, Note). A contract, questionnaire, file, deliverable or note is now added in a box right on the job page, without leaving it: pick the template (each shows the name your client sees), or your file (or upload one), or type the deliverable or note, and Save. The new item appears in its card with a short message. Quote and invoice still open today's screens.
- Two new fill-ins for emails, texts, workflow steps and contracts: "Client's first name" and "Partner's first name", so a message can say "Hi Danica & Kirk". They use the first word of each person's name and are blank when a person has no name. A text no longer shows a client a fill-in that nothing filled (a typo, for example); like emails, it is removed before sending. The job page's text box offered "business_name", which never filled in; it now offers "studio_name", your business name. Payment and document reminders now fill "Partner's name" too (it printed blank there).
Fixed
- Client Lounge: when a client opens a link to a document outside any job that the business has hidden, and they have one link for all their work, their Lounge now says "This is not available right now. Please ask (the business) about it." Before, they landed on their list with no word why. With only one job, the notice shows on that job's Lounge.
- Trash: restoring a quote from the Trash now brings back only its newest draft contract, and none when the quote already has a contract. Before, a draft deleted by hand and then remade by a Save came back beside its replacement, so the client saw two contracts.
- Trash: restoring a quote's contract from the Trash now checks the quote first. If the quote now uses a different contract template, or already has a contract, the contract stays in the Trash and Compass says why in plain words (this works on the Trash page and on the Undo toast). Before, a contract restored by hand was sent to the Trash again at the quote's next save, and a sent contract that Replace had trashed brought its old client link back to life beside the new contract.
- Sending: after an email that really went out, Compass no longer says it could not be sent. Before, if Compass failed to write down that a contract, questionnaire or invoice was sent, the page said the email could not be sent, which invited a second email to the client. Now it says "Sent. Compass could not record it, so it may still show as not sent. Do not send it again." (for an invoice, it adds "Press Mark sent so its reminders start."), reports the problem, and starts no reminders for it. The Send box's own catch-all words no longer claim the email was not sent either: they say "Something went wrong. Check the item before you send it again." Also, a failed Send in one browser tab can no longer hide, or roll back, a quote, contract, questionnaire or invoice that another tab has just sent: the put-back checks that nothing was sent since. A quote whose email went out is no longer reported as failed when only the page refresh afterwards fails.
- Today: the Send button on a workflow step now does what the job page does. On an email step it opens the email to review and send; on an invoice or text step it takes you to the job with that step brought into view and flashed, so its own Send (with its confirm) is right there; a questionnaire or contract step offers Done, as on the job page. Before, every one of them opened the email panel, which then refused to send anything but an email.
- Workflows: when a workflow's last step is an invoice, sending it now finishes the workflow even if some steps were skipped. Skipped steps already counted as done everywhere else; the invoice step's Send now only counted ticked steps, so such a workflow stayed open forever.
- Today: workflow steps timed from "quote sent" or "quote accepted", and every step chained after them, now appear on the Today page and in the dashboard's Today summary when they are due. Both worked out step dates without the quote dates, so those steps had no date and were left off. The dashboard summary also now counts steps timed from the booking, and no longer lists a step the business skipped.
- Workflows: a workflow's invoice step now emails the invoice's own current address (the person the invoice greets and bills), with their second inbox and the job's loop as the step allows, like every other invoice email. Before, it emailed the job's main contact, so after "Make main contact" on the client or the job the email could reach one person while the invoice named another. Applies to the automatic send and to Send now. No job today has diverged contacts and an invoice step, so no email changes now.
- Client Lounge: the welcome message a business writes in Settings, Client Lounge, now shows under the greeting in each client's Lounge, and in the business's own view of it. Settings promised this, but a job's Lounge always printed a fixed line. With no message written, the Lounge keeps its usual line ("Everything for your booking lives here. Here is where things stand."), and Settings now shows that line as the default instead of an old one the Lounge never used. No business has written a message yet, so nothing visible changes today.
- Client Lounge: a client's Lounge no longer shows the job's own name, which is the business's label (for example "Alex's enquiry"). The browser tab and every place that named the client now use the people on the job ("Kay and Lee"), as the Lounge greeting already did, and fall back to the job's name only when it has no people.
- Calendar: changing a job's status (in the app, or through the AI connector) now updates the business's connected Google Calendar straight away. A cancelled job leaves the Jobs calendar, and a job moved back to upcoming returns. Before, the calendar only caught up at the job's next edit. No business has calendar mirroring switched on today, so nothing visible changes yet.
- Booking emails: the booking confirmation, the reminder and the moved-booking email now name the business's time zone under the time (for example "Australia/Perth time"), in the same words as the booking page. Before, they showed the time in the business's zone without saying so, so a client abroad could read 9:00 am as their own morning. The moved-booking email also now writes its time like the others ("Friday, 9 October 2026 at 9:00 am") instead of "09/10/2026, 9:00:00 am", which a client abroad could read month first. The business's own wording in each email is unchanged, and the Event types note now says the emails name the zone.
- Settings, Event types: the page no longer speaks only to wedding photographers. Its examples read "a first call, a consultation" instead of "chemistry call", and the How it works note now says "A booking creates an enquiry automatically, so it shows on your dashboard." The words "advance-notice" no longer split across two lines.
- Waypoint (security review, LOW): the "email me my results" email no longer prints "undefined" when a figure is missing from the request (the close rate, show rate, number of months or number of jobs). A missing figure's line is left out instead. The calculator itself always sends them, so nobody using it saw this.
- AI connector: updating an enquiry can now clear its next-action date and text (send null or an empty value), so a lost lead or a cancelled call stops showing as due. It can also set or clear the event date, booked or not. Like the app's own edit, the change goes in the record's history, the calendar copy follows, and if another open enquiry or job holds that date the reply says so as a heads-up, never a block. Changing a job's date, name or place through the connector now updates the calendar copy too, which it never did.
- AI connector: attaching a workflow said its automation starts paused, but it has started armed since July, the same as attaching in the app. The description now says so, and names the two guards that still stop a surprise email: the first automated message on a job waits for the business's one-tap approval, and an overdue send step never sends by itself.
- Settings, Event types: the How it works note told businesses that client time zones were not handled and to book international clients by email "until Phase 2 lands". That stopped being true: the booking page names the business's time zone and a client elsewhere can switch the times to their own. The note now says that, and that the confirmation email shows the time in the business's zone without naming it. The same note also loses a dash.
- Workflows: an automatic step set to "At a specific time" now picks a whole hour, from 12:00 am to 10:00 pm. Automatic sends go out on the hour, so a time like 9:30 used to go at 9:00, half an hour early, and a time after 10pm never went at all. A time already saved with minutes now goes at the next hour, never before the time shown. The other two choices now say what they do: "Best time (from 8 am)" (it used to promise a workspace default that does not exist) and "As early as possible (from 7 am)". The AI connector takes whole hours only and says so.
- Payment details written without a colon, such as "BSB 062-000" or "Acct 12345678", now show as copyable lines on their pay screen, labelled as the business wrote them. Only well-known labels count (BSB, account number and name, PayID, reference, SWIFT and the like); anything else stays a note.
- The no-show recovery email now goes as a client booking email with its enquiry, like the confirmation and the reminders: it counts as contact with the client and the business's own copy applies. It was sent under the business's own notification category, which recorded no enquiry. None has ever been sent. Its words lose two dashes: "No worries at all. Things come up." and the subject "We missed you today, from
". - Emails: the notifications Compass sends to a business about its own work (a new enquiry, a signed contract, a payment, the daily digest) no longer count as contact with the client. They used to show as the client's Last contact on the hub and add "Email opened" lines to the client's timeline, and a bounce of the owner's own address paused it. They still send exactly as before. The ones already sent are marked the same way; nothing is deleted.
- Activity log: saving Edit details with nothing changed no longer writes a "Note added" line, so the Notes filter shows only real notes. Older lines stay as they are.
- Client Lounge: a contract that cannot be signed yet (details still to fill in, or its quote is gone) no longer asks them to sign. Its chip says "Not ready", its row says "Not ready yet. Ask
about it.", its page line says "Contract · not ready yet", and a room asks for Sign only when one of its contracts can be signed now. A quote past its last day no longer says Review. - Client Lounge (early access): the client's own page now takes the full page width on a computer (it was narrower than the design) and the design's narrower side margins on a phone.
- Contacts (, again): a long email address, phone or second email now wraps inside the Contact card on a computer and a phone. The July fix did not reach an email shown beside its bounced badge, so a long address could still run past the card's edge.
- Emails: the plain-text part of client emails now shows apostrophes and quotes as characters, not codes like '''. Booking emails use the same rule.
- Header menus: on a short window the account menu and the tools menu fit the screen and scroll, so 'Sign out' can always be reached.
- Payment reminders: a reminder names the business the way the invoice email does (the invoicing business name when set, else the brand name), so one client never sees two names.
- Client tracker: the money-due widget shows what is still owing on each invoice, not its full total.
- Daily summary: 'Overdue invoices' uses the invoice page's own rule: what is still owing on instalments whose date has passed, or the balance once the date it is really due (including a charge's own date) has passed. Part-paid invoices count, and each shows the amount that is late.
- Email fill-ins: {{lead_source}} now fills on automatic workflow emails too, and {{client_phone}} is the main contact's number, else the record's own copy, on every send path (job composer, workflow Send now, automatic sends).
- Workflow Send now: the fill-in menu no longer offers Due date (it only fills on questionnaire and contract steps) or My email signature (the panel already carries the signature, so inserting it made two).
- Reports: 'Where enquiries come from', the conversion funnel and 'Why we lose' were empty for every business, because the page asked for a column dropped on 31 May 2026. They show again, and any section whose data cannot be read now says so instead of looking empty. The build check for dropped columns now works them out from the migrations, per table, so a drop is covered the moment it lands.
- Invoices: sending, marking sent, recording or settling an invoice, and reminder changes now refresh the job's hub and Business Lounge too, so the Status panel no longer says 'Not sent' until a reload.
- Dates: these now use the business's own day, not the server's world-time day: the Reports 12-month window, the dashboard's 'Today' and 'Tomorrow' labels, the in-flight jobs figure, the date on a client-merge note, and sample data. The date check's list drops from 26 to 1 (the workflow sender's date maths, held under ). The other sites are correct world-time arithmetic (including the payment reminders' 10-day window, which the invoice page's 'Next one' date models on purpose), now marked with why.
- Invoices (clean-up): the first 'Add a charge' database step, add_invoice_charge, is removed. Nothing has called it since the charge moved to add_invoice_charge_line.
- Email settings: 'BCC me on every email Compass sends to a client' now works. It showed as ticked for every business while nothing read it; it now starts unticked for everyone (nothing changes until a business ticks it), and once ticked the business gets its own copy of every email to a client at its reply-to address: sent just after, headed 'Your copy of the email sent to …', with the same attachments and no unsubscribe link, and Reply goes to the client. Notifications and digests to the business are not copied. The 'Track opens + clicks' box, which nothing read either, is now 'Show when clients open emails and click links': ticked as before, and unticking it stops Compass recording and showing opens and clicks (and its 'check their Junk folder' hints) for that business. The email service still counts opens, and the settings say so.
- People on a job: removing the partner in Edit details now sticks (they came back on reload). Making someone in the loop the main contact from Edit details now says to use Make main contact on the People card, instead of writing their details over the old main contact and leaving a duplicate. The partner's own loop row is found by who they are first, so two people sharing one inbox are no longer mixed up.
- Contracts: a contract made from a quote, or made on a job, now names the job's own people. After 'Make main contact' swapped the couple on the job, a contract still named the client record's original partner.
- Quotes (words, ): the acceptance screen's words are shorter, with no filler: 'Thank you. Next, Review & sign your contract.', 'Thank you. Next, Review & pay your invoice.', 'Thank you. Your invoice is ready to view.' or 'Thank you. Your quote is accepted.' In the Lounge, a quote no longer promises 'your invoice is ready' when accepting it makes no invoice, and after accepting it offers payments only when an invoice was made and the contract only when there is one.
- Quotes: after a client accepts a quote, the screen no longer promises that the business will send a copy of the invoice (no email goes on acceptance, as ruled). When there is no contract to sign first, it offers 'Review & pay your invoice', which opens the invoice made from the quote; its payment reminders run as before, one per instalment. The same link shows when accepting in the Lounge.
- PDFs: a PDF asked for straight after another no longer fails with 'Could not generate the PDF'. The PDF service allows about one new PDF every 10 seconds, so Compass now waits as long as the service asks (up to about 12 seconds) instead of giving up after 3. Each PDF is also kept by its exact content, so opening an unchanged document again (for example after the receipt email) is instant. Every 'Save as PDF' shows 'Preparing your PDF…' and 'This can take up to 10 seconds.' while it is being made.
- Invoices: saving an edited invoice now lands only if its total, status and the amount paid are still what they were when the edit page opened. If a payment came in, a charge was added or the invoice was settled while the page was open, nothing is saved and the page says to refresh and check it, instead of the edit quietly wiping the charge. Background updates (reminders, the client's details) do not block a save.
- Invoices: Add a charge now adds its line and the change to the totals to what is saved on the invoice, so an edit that moved money between lines at the very same moment is kept. The totals' change is worked out the same way as everywhere else, so a document discount applies to the charge too (10% off a 150 charge adds 135, not 150) and the invoice's total matches what the client's invoice shows.
- Dates (, second part): the Dashboard's upcoming list, month and year counts and overdue marks, the Today card's bookings for today (it ran 8am to 8am in Perth) and its overdue contracts and questionnaires, the Today peek's booking day, a client's 'Reminders paused' state and snooze, and the hub's 'last contact' date past eight weeks now use the business's own day. A new check stops new code taking 'today' from the server's world-time clock.
- Dates (, first part): the dates a client sees now use the business's own day, not the server's world time. Before 8am in Perth a new quote's 'valid until' was a day short, a contract's date and the 'accepted on the client's behalf' date read yesterday, and a workflow's contract, questionnaire or invoice could fall back to yesterday. The contract and questionnaire send dialogs' due-date preview also counts from the business's today.
- Calendar: the client tracker's Calendar view now works on the business's own clock (or the one chosen for travel). Before 8am in Perth it used to show yesterday as today, open on yesterday, place a 7:30am booking on the day before and draw it in the 11:30pm row of the week, and start the 'booked' count from the wrong month.
- Workflows: the Send now panel on a workflow step now shows every fill-in with the value that will actually send. It used to fill only the names, business name and event date, and blanked the rest (client email and phone, event location, business details), and it used the record's title as the client's name where the email uses the people's names. The panel and the send now take their values from one place. The client's phone is the main contact's current number, the lead source fills in, a signature added from the menu takes the saved signature in place (a dollar sign in a signature now comes through as typed, in every email), every copy shows the main client's email address as the panel does, and if the lead source cannot be read the email is not sent.
- Workflows (, Sentry JAVASCRIPT-NEXTJS-16): Send now on a workflow step's email fills its fill-ins on the server, for each recipient, as the job's email composer does. The panel filled them only when it opened, so a fill-in added from its menu afterwards (such as the client's or partner's name) went out blank.
- Invoices: Add a charge now lands in one step in the database: the new line, totals, part-paid status and the charge's date or plan row together or not at all, and only while the invoice is still paid at the total, with the plan and the payments, the charge was worked out from. A second press that raced the first, or a Save plan or payment in between, is refused with "This invoice changed while you were adding the charge. Refresh the page and check it before you add it again." (it used to be able to add the charge twice when the invoice's credit covered it), and a failure can no longer leave the plan short or over. When the connection drops and the charge cannot be seen to have landed, it never says it failed (it may still land, and adding it again would bill it twice); it says "We couldn't confirm the charge was added. Refresh the page before you try again."
- Invoices: Save plan checks the rows before saving. A missing or impossible date says "Pick a date for each payment." and an amount below zero says "Payment amounts can't be below zero."; both used to reach the database and come back as "Could not save the schedule."
- Invoices: after an invoice's total was cut below what was paid and a payment was then refunded or removed, its payment plan could still show an old row as owing, even Overdue, on the client's invoice page and the PDF, though the invoice was paid. What shows owing across the plan, what the pay page offers for "this payment" and what a reminder chases are now exactly the balance; each row reads at what it asks for now, and only money actually received shows as paid. The saved plan is unchanged, and the business's own plan panel and Save plan work from the payments as before.
- Invoices: editing an invoice with a payment plan now changes the plan's amounts in one step in the database, and only against the plan as the edit read it. A Save plan, a payment or a charge landing in between used to leave the plan short of the new total without any error; now the edit works the plan out again from what is there and applies that, or says "Saved the invoice, but couldn't re-balance the payment schedule (...). Open the schedule and adjust it." as before.
- Invoices: reversing a write-off now works the invoice's status and its plan rows' paid marks out again from the payments (a refund while it was written off used to leave them stale), and a failed read of the payments stops the reversal rather than guessing; when payments recorded while it was written off already cover it, it is reversed to paid and says only "Write-off reversed." (no reminders to resume). An edit that cuts more than the last unpaid plan row now takes the rest off the rows before it, latest first, instead of refusing with "The paid installments already exceed the invoice total.", which was not true. A row cut to $0 stays open, so a later increase can land on it again.
- Invoices: Save plan now saves in one step in the database: all of it lands or none of it, and a second save, a payment or a charge that lands while it is being saved makes it refuse ("Could not update the schedule.") instead of doubling the plan. A failure while saving can no longer leave an invoice with part of a plan. Once the plan has saved, a failure in what follows (which template it came from, the paid marks, the page refresh) is reported to us instead of telling the business the save failed. Also: when an added charge is covered by the invoice's credit, the job's timeline says "Invoice #N: charge added, covered by the invoice's credit:
($amount)" instead of "reopened". - Invoices: Save plan keeps a part-paid payment as the plan panel shows it, locked, with its date and what it still has owing; it used to be replaced, which moved that money to the new dates. The rows you edit now cover what is left after it, and the line under them says so ("Unpaid installments add up to the balance due. Deposit still has $300 owing." / "Unpaid installments total $X. $Z is left to plan after Deposit’s $300 owing. Saving balances the last row."). Saving a plan now puts the new rows in before the old ones come out, and takes them back if that fails, so a failure never leaves an invoice with no plan; a save whose plan rows, invoice total or payments change while it is being saved is refused ("Could not update the schedule.") rather than doubled. A "Paid so far" row reopened by a refund folds back to what it holds, and the rest moves to the new rows.
- Invoices: Add a charge on a paid invoice that had a credit (its total cut below what was paid) now uses the credit first. The charge's plan row brings the plan up to the new total instead of adding the whole charge, so reminders chase only what is owed; when the credit covers the charge, no row is owed at all, and the invoice page says "Charge added. The credit on this invoice covers it, so nothing is owing." (its activity: "Charge added, covered by the invoice's credit"). Invoices without a credit, and plans that no longer match their payments, keep the whole charge on its own row as before.
- Invoices: editing an invoice whose payments go beyond its paid plan rows (a part payment on the next row) no longer counts that part payment twice. The unpaid rows now add up to the new total less the rows already paid, so the plan matches the invoice and reminders chase what is really owed; they used to fall short by the part payment. A failed read while re-planning now stops the save instead of passing for "no plan" or "nothing paid". Which rows count as paid comes from the payments themselves, so a row still marked paid after a refund is re-planned like any other.
- The People card: Add person, and changing a person's email, refuse an address already on the job (the main contact's, or another person's), saying "That email is already on this job." Before, the same person could be added twice and showed twice on the card.
- Accepting a quote: when the contract's "ready to sign" email could not go out, the contract is no longer left marked sent. It goes back to how it was, so the business sees it was not sent and can send it; the client can still open and sign it from the acceptance screen.
- Sending an invoice: an email that could not go out no longer marks the invoice sent, starts its reminders or logs it as sent. The invoice page says plainly that it is not marked as sent and offers Print to send it by hand (it stays shown in their Lounge, so a printed copy's pay link works); the Lounge's Send box keeps saying why under its Send, puts back an invoice it had shown, and its other failed actions now show as failures, not successes.
- Sending a questionnaire or contract: an email that could not go out no longer marks it sent or starts its reminders, and the page says so plainly, still offering the link to send by hand. The send box now opens with the due date the document already has, on its own page and in the Lounge, so sending no longer wipes a due date nobody touched.
- Unsaved work: the quote page, New quote, New invoice and Edit invoice now ask "leave without saving?" before another link throws away what was typed (or a line that was added or removed, a date picked from the calendar, or a contract-wording change made with the toolbar alone). Their Cancel still leaves without asking. New quote's Cancel now goes back to where the quote was started from.
- Phones: the quote page, the invoice pages and a quote or invoice template no longer come out wider than the screen. Their line rows now stack as the Lounge mock draws them for a narrow card (the description on its own row, then the price, quantity and remove, then the line's total), the product picker shrinks to fit, and the pinned Cancel / Save bar stays inside the screen, so it now sits at the bottom of a phone's screen as it does on a computer.
- Contracts (, Gonzalo: "refuse to send"): a contract whose wording still has an empty fill-in (for example the date on a job with no date yet) is never sent and cannot be signed, so a client never sees "{{event_date}}". Every send first fills any empty fill-in from the job's current details and writes it into the contract (a detail already filled is never changed), so adding the date to the job and sending again works. While one is still empty: Send, the Send box and Today's Remind say "This contract has details still to fill in: the date and the venue. Add them to this job, then send it."; the contract's page on the business side says the same; the email after a quote is accepted waits and the acceptance screen does not lead to the contract; a workflow step waits ("Waiting:
has details still to fill in (the date)."); reminders do not chase it. The client's Lounge, the signing page and the PDF link show "This contract is not ready yet. Please ask about it." in place of the contract, with no Sign. A fill-in Compass does not know is named so it can be changed in the wording. - Phone width: every on/off switch keeps its slim pill shape on a phone. A rule meant to make small buttons easier to tap stretched the switches into tall square blocks (In their Lounge, the People card's loop switches, the Guided switch, settings). Each switch now keeps its look and gets a larger invisible tap area above and below it instead.
- Deliverables: adding, ticking or removing a deliverable no longer risks wiping the job's other deliverables. If the list cannot be read, nothing is saved and it says "Could not read this job’s deliverables, so nothing was changed. Try again." (before, a failed read counted as an empty list, so Add would have saved only the new one). A refused tick or remove (a job in the Trash, a failed save) now says why in a message instead of ending on the error screen; the tick and × show they are working while they save. "Add from your templates" says why when it cannot add (a failed read, a job in the Trash).
- Connector: create_invoice_record now checks that the enquiry or job it links an invoice to belongs to the business (and is not in the Trash), as create_contract_record does: "No enquiry or job found with that lead_id in this business". It used to store any id it was given. None has ever linked to another business's job.
- Trash: a quote, contract, questionnaire or invoice can no longer be restored on its own while its job is still in the Trash, where it would have sat live on a job nobody can open. Restore says "Restore its job first. This record belongs to a job still in the Trash." (the job's own restore brings back what went with it). The same rule answers the Undo toast and the connector's restore. A refused restore on the Trash page now shows its words as a message, for a contact still in the Trash too, where it used to end on the error screen.
- The notifications bell's count reads clearly in the dark themes: its number was white on a nearly white badge; it now takes the theme's own dark text, as the light themes keep white on blue.
- An invoice recorded through the AI connector (create_invoice_record) now starts in the client's region and currency, as a hand-made new invoice does, keeping the tax it was given. Before, it had no region and the default currency. The invoice made when a quote is accepted keeps the accepted quote's own region, currency and rate, as before.
- The quote editor no longer says "Sending the quote emails it for signing." under its contract: since the contract is emailed when the quote is accepted, both places now say "They get it to sign once they accept the quote.".
- The quote editor now shows and keeps a quote's own tax rate after that rate was archived, and its live total charges what saving bills (a region on an archived rate included). Before, saving the quote quietly dropped the archived rate, and the live total showed no tax for such a region.
- Deliverables: two people (or two tabs) changing a job's deliverables at the same moment no longer overwrite each other; a change made while the list changed is applied to the new list. Accepting a quote fills in the templates only while the job still has no deliverables, so one added a moment before is never replaced.
- A region whose tax rate was archived is now labelled with that rate in every region picker (invoices, quotes, a client's default region), for example "NZ (NZD · Old GST 15%)". Before, it read "No tax" while the preview and the save both charged the rate.
- An invoice editor now opens its live totals in the currency its region will save it in (the region's currency today), so the preview and the save never disagree when a region's currency was changed after the invoice was made.
- A quote's contract when its template is switched: a signed contract is never touched and the quote keeps it; a void or declined one stays as history and a fresh draft is made beside it; an open one from the old template goes to the Trash (restorable for 30 days) instead of being deleted for good, with a note after Save. When the old contract was already sent, the quote first asks "Replace the contract you sent?" (Replace, or Keep it). Choosing no contract counts as a switch. If a contract changed a moment before the Save (signed or sent), nothing is switched and the page asks for a refresh. A quote whose contract template was archived keeps it chosen, so an ordinary Save no longer switches its contract away. Sending a quote no longer makes a duplicate contract when a void one sits beside a fresh one.
- On the older Edit invoice and New invoice pages and on New quote, a save that cannot go through now says why on the page, for example "Add at least one line with a description and a price.", and keeps everything typed. Before, it showed the app's error page.
- The AI connector's create_contract_record now refuses a contract with no wording, as every other way of making a contract does.
- File links: a file now counts as opened only when a person opens it. An email link scanner, a chat app's link preview or a browser's prefetch still gets the file, but no longer marks it "Opened" (which also fixed its names). An open from an older browser may not count, so it errs toward "Not opened", never a false "Opened".
- Editing an invoice whose tax rate has since been archived (on a business with no regions) keeps that rate: the rate picker still offers and picks it, and a business with no active rates at all keeps the saved one. Before, saving even a typo fix quietly re-rated the invoice at the default rate.
- Deleting a booked job now shows the same "moved to the Trash" message with Undo as deleting an enquiry, and Undo brings it back with its documents, the Trash page's way. Deleting several records at once from the client tracker's list now does the same ("3 records moved to the Trash. They stay restorable for 30 days in Settings."). Before, neither offered Undo.
- A file added to a job that went to the Trash (from a page left open), or a new version of a job's own file while its job is in the Trash, is now refused with "This job is in the Trash. Restore it to add files to it." and nothing is kept. Before, the file was still recorded on the job.
- A job or enquiry already in the Trash no longer shows Delete on its page; it offers Restore. Deleting it again (from a page left open, say) changes nothing, where before its live documents went to the Trash at a new moment that restoring the job could not bring back.
- The invoice export: an invoice-wide discount now has its own line, a negative amount named by the discount (or "Discount") carrying its share of the tax (split in two, taxed and untaxed, when the invoice has both), so the line figures add up to the invoice's totals, and a new last column, Invoice discount, makes subtotal minus discount plus tax and tip equal the total; this is how MYOB's own help says to import a discount, and Xero and QuickBooks have no invoice-wide field. Negative numbers now stay numbers in the file (they were marked as text by the formula guard, which still guards text).
- A quote whose contract is already sent now shows that contract's real wording in its editor, read-only, with "This contract is already sent, so its wording changes on the contract itself, not here." and a link to it (signed, declined or void: "its wording can no longer change"). Before, the editor showed the template's wording under a promise that edits would become the contract, and dropped them; a page left open from before the send now says so instead. Saving such a quote also no longer adds a second, draft contract beside the sent one.
- The invoice export (for your accountant) now works each line's tax at the rate the invoice was actually taxed at, read back from the tax it stored (its invoice-wide discounts included). Before, it worked the rate out again from today's settings: an invoice whose region was archived since, or that stored tax with no rate set, exported its lines at the wrong rate or with no tax.
- An invoice marked sent with no send date (one made when a quote was accepted, for example) no longer says just "Sent.", as if an email went out. It says it is in the client's Lounge and that Compass has no record of an email about it.
- Add a charge: adding a charge to a paid invoice is now all-or-nothing in practice: the invoice and its payment schedule change together or not at all (even when an answer from the database is lost), a second click or a retry can no longer bill the charge twice, and a problem after the charge landed no longer shows it as failed.
- A payment receipt email now shows in its invoice's email history (it was sent, but not tied to the invoice).
- A ⋯ menu opened near the bottom of the screen now opens above its button instead of running off the edge, with its lower items out of reach.
- Business Lounge page: a questionnaire's questions are numbered again, as the design draws them, and an item's title no longer shows a focus box when its page opens.
- The contract and questionnaire pages no longer raise an error when your computer's clock is ahead of the server's (Perth is): the Send dialog's due-date preview now counts from the day you open it.
- Reminder chases: a chase now sends the client at most one message a day, so one that resumes after a pause (archived, hidden, or waiting for details) sends what it missed one day at a time instead of one every hour. A client's pause, now called "Pause reminders", covers their questionnaire and contract reminders as well as invoices (paused or snoozed, the steps due meanwhile are skipped, never sent late). (Archiving a job already pauses its chases.)
- The business's invoice page now reads your logo the same way every PDF, email and client page does (it used to read only an older copy of it).
- Payment plans: a plan set up on an invoice that already has payments now starts with a settled "Paid so far" row, so the new rows stay owing and reminders keep chasing the money still due (they used to read Paid). The plan's first date after a charge is the charge's own due date, and never a date already past.
- A part-paid invoice's page no longer offers a Delete button that could only fail. It says "Part-paid invoices can't be deleted", and hovering says why: remove the payment first.
- Business Lounge (early access): a file hidden from the client's Lounge no longer says its old email links are closed. Those links still open it until a later step makes hiding close them.
- Business Lounge page (early access): the Home room's "What your client sees first" card now shows exactly the checklist on the client's own Lounge Home, every step with its own words (including steps not open yet, such as "Your quote will appear here." and the Gallery step), and names the rooms in their Lounge's menu. The card and the client's page now read one shared rule, so they cannot disagree. Nothing the client sees changes.
- A file shared with a client keeps the names it had on that job. Renaming the file later in Settings, Files no longer changes what that client sees; to change it for one job, use Rename on that job's Client Lounge card (early access).
- Quote and invoice templates (, first part): after Save, the template editor keeps what you typed; it used to show the values the page opened with, so the next Save wrote the old prices back into the template.
- Settings dialogs (, second part): editing a package, a region, an event type or a questionnaire template keeps what was typed after Save, and after a refused Save. They used to put their fields back to the values they opened with, so a package's tax treatment, a region's currency, an event type's availability or a question's options could read the old value and be saved back. A New event type or questionnaire still opens with its starting values each time.
- Forms (, third part): a refused save no longer wipes what was typed in the discount, contract template, contract, public profile, Invoicing, sending address, and New quote, questionnaire and contract dialogs. Edit client starts from the client as saved each time it opens, so cancelled text is dropped and a saved region shows. The quote editor keeps its package wording, ticks, auto-invoice, terms and notes when a save is refused or Save & send cannot send. A booking page's custom email with only a subject or only a body is refused ("Add a subject, or use Restore default." / "Add a body, or use Restore default.") instead of reading "Saved." while it was deleted; emptying both still goes back to the default. Invoicing keeps a 0 for "Invoices fall due" (due on the day of issue) and the row says "Due on the day of issue". The calendar picker's Refresh shows a newly found calendar, renaming a deliverable, a lead source or a source category shows the new name while it saves, and a refused category rename says why.
- A greyed item in a ⋯ menu now shows its reason beside the menu, as the design kit draws it, instead of over the menu items above it.
- Dialogs across Compass (settings edits, the guided setup, notes) now look like the design kit's: no rule line under the title, the title a little larger, and a warmer shade behind. Tooltips now show inside a dialog instead of behind it.
- A new enquiry made in Compass for one person no longer creates a client called "Una's enquiry": the client is named from the people ("Una Tester"), as the contact form does. A booking made on your booking page is now named like every other new record ("Sam's enquiry"); the client keeps the full name.
- On the dark themes (Dark, Midnight, Forest, Plum, Espresso), the coloured icon tiles no longer glare. The Client Lounge and Notes rows on a job page, and the template settings pages (their header tile, row tiles, the active tab and the coloured hint), now use a deep wash of each colour with a lighter icon, instead of the pale light-theme wash. Light themes are unchanged.
- "Make main contact" on a couple's partner now swaps the two: the partner becomes the main contact and the old main contact becomes the partner, still kept in the loop. The confirm says so ("Mia will become the partner"). Before, the new main contact also stayed recorded as the partner, so the People card could list them twice and {{partner_name}} printed the main contact's name. On the People card, "Make main contact" is greyed for a person with no email, with the reason: add an email first.
- New records are named the same way however they arrive. An enquiry from your contact form, your website, a CSV import or the sample data is now named from its people like one made in Compass ("Danica & Kirk", or "Danica's enquiry" for one person), and the name keeps following them if you later rename a person. The client keeps their full names. Enquiries made in Compass without typing a name are no longer saved as if you had typed it, so their names follow their people too. Existing records keep their names.
- The People card on a job or enquiry now lists a couple's second person even when they have no email. Before, only the main contact showed, while Edit details listed both. A person with no email has their "keep in the loop" switch off and greyed, with the reason "Add an email to keep them in the loop"; on the People card that line opens Edit details. In Edit details and New enquiry, the switch now reads left to right: the label, the switch, then its note ("always on for the main contact").
- Edit details now shows a record's own name when it came from somewhere else (a contact form, the Compass connector) with full names, instead of a shorter name built from first names, and saving no longer renames it. A name that follows its people changes only when a person's name changes, or when you clear the field; editing someone's email or phone never renames the record.
- Edit details on a job or enquiry now lists each person once. For a couple whose second person was added with an email, it showed that person twice: once as the Partner with no email, and again below with their email. They now appear once, with their name, pronouns, email and "keep in the loop" together, and saving updates both places Compass keeps them.
- In the email composer, after "Save as new" the template list now shows the new template, the one "Save changes to …" will update. Before, it kept showing the template you started from. Choosing "Blank message" now unties the message from its template (your text stays).
- The Client tracker's preview in the centre of the screen shows the record again. Since late June it showed an empty frame with a broken-page icon, because Compass refused to be shown inside any frame, including its own. Compass can now show its own pages in a frame; no other website can.
- The Workflow card on a job or enquiry now keeps up after "Approve and send" and after you send a step by hand: the step shows as done and "Waiting for your go-ahead" goes, without reloading the page. Before, it kept the old view, and pressing Send again logged a second send that never happened. Undoing a ticked step from the Activity log, or ticking a step twice, no longer marks it done again by mistake.
- On a job page, the Texts card now texts the number it shows, the client's current mobile. Before, if the number changed on the record while the page was open, it kept texting the old one. Sending a workflow email to someone who has since been taken off the record now says "Not sent to" that address instead of dropping it without a word. A template you update or save as new in the email composer shows in its template list straight away.
- Saving Edit details on a job or enquiry no longer puts back old values. It now saves only what you changed in the panel, so a change made meanwhile elsewhere (a person taken out of the loop or given a new email in the People card, the stage moved on the board, a new main contact) stays. The People card now keeps up with changes made in Edit details, and its "Edit main contact" starts from the current details. Retrying a save after "That took longer than expected" no longer adds a new person twice. Changing the job type no longer offers to switch to the workflow that is already attached (accepting it restarted that workflow), and the confirm before a second workflow switch now quotes the workflow that is really attached.
- Reopening a minimised Edit details panel you have not changed now shows the record as it is now. Before, it showed the record as it was when you first opened it, and saving could put back values changed elsewhere since. A panel with unsaved changes still keeps them.
- Your client's pages no longer wipe what they typed when something is refused. On a questionnaire, a refused submit used to clear every answer (and the next autosave then saved the empty form); "Update your responses" now reopens with the answers they just sent. Your public enquiry form keeps what was typed when a submission is refused, and the contract signing page keeps the typed name and the "I agree" tick.
- Reopening a minimised panel you have not changed (Edit details, a message) now shows the record as it is now. Before, it showed the record as it was when you first opened it, and saving could put back values changed elsewhere since. A panel with unsaved changes still keeps them.
- The pressed-and-greyed look for a working button (see Changed) did not reach the live site at first: that deploy reused the previous build's stylesheet unchanged. Every production build now starts fresh, so a style change always ships, and after every deploy an automatic check confirms the live stylesheet was built from the version that is live, and fails loudly if not.
- Small slips after a save: re-emailing a sent or paid invoice no longer says "Status flipped to Sent." (only a draft's status changes, and its confirm says so only then); when an invoice cannot be emailed because email is not set up or the address is blocked, the page now gives that reason and says to send it by hand (then press Mark sent, for a draft) instead of "Try again"; a Today reply whose "dealt with" failed comes back instead of staying hidden; custom fields show exactly what was saved, so a row with no name no longer sits next to "Saved"; and the Budget and costs card, a scheduled email's new time, a file link's expiry or revoke, and a reminder set's attach no longer flash the old values for a moment after saving. (The Workflow card's item waits with the held workflow work.)
Changed
- While an invoice's client has no way to pay, its Reminders row says "Paused until a way to pay is on." instead of promising the next one, and Change says how to turn them back on (follow-up).
- No payment reminder goes out while the client has no way to pay the invoice. The automatic run counts it without sending and writes "A payment reminder was not sent: your client has no way to pay this invoice yet. Add one in Settings, Payment methods." in the invoice's log; "Send a reminder now" says the same and sends nothing. The Lounge, the reminders and Send now share one read of how a client can pay.
- An accepted quote shows the schedule of the invoice it made, with its real dates, and no longer says "Exact due dates are set when you accept".
- The owner alert says "says" for one person and "say" for a couple.
- A payment the business records by hand is credited to the person who recorded it in the item's log, never "Compass".
- The Business Lounge's New quote box asks "In their Lounge" first, like every other Add box.
- An invoice with no way to pay: their chip and room say where it stands ("Sent", "Part paid"), never "Pay", and the business's view says "Your client has no way to pay this yet. Add one in Settings, Payment methods.".
- Ways to pay per invoice (Gonzalo, 29 Sep 2026: "I meant for any invoice"): an invoice in the Business Lounge has a fourth settings card, Ways to pay, listing every way to pay set up in Settings with its own switch for that invoice. Anything not switched there follows Settings, Payment methods, for every invoice, past and future; switching one back to what Settings says makes it follow Settings again. The client's pay screen, "I've paid", the card payment, the PDF and the invoice email all honour it. Settings, Payment methods now says "On for every invoice unless you change one on the invoice."
- Adding or changing a payment date never removes another date silently. When the change would take the whole of another date, the box says which date goes and asks first ("Add anyway" or Cancel), and the note afterwards says what happened, including when another date only changed to keep the total.
- Payments now pay the earliest-due payment first (Gonzalo, 29 Sep 2026), not the first in the plan's list, and money already received stays where it landed (coordinator, option B): new money fills the earliest-due unpaid payment, so a charge added later with an earlier date is owed and chased on its own date, while the payments already paid stay paid. A part payment keeps what it holds, a card refund comes back off the payment it refunds, and a new "Paid so far" keeps the money received before the plan. Payments with no date come last. The same rule everywhere: the schedule on the paper and the PDF, the business's schedule card, Pay next payment, the invoice's status line, editing the invoice, Save plan, and payment reminders.
- Client Lounge switch-on preparation (early access only): a client's combined link (all their jobs on one link) now opens in the new Lounge too. It lists their jobs, each opening its own Lounge, then any of their documents that belong to no job, each opening its own page. With one job and nothing else, the link goes straight to that job's Lounge. Every other business keeps the old portal.
- Client Lounge switch-on preparation (early access only): for a business with the new Lounge on, a link to a quote, invoice, contract or questionnaire, from a new email or one already in a client's inbox, opens that document's own page in its room, not the old room. Links that name the old rooms ("payments", "notes" and so on) land in the matching new room. Every other business is unchanged.
- Business Lounge: an invoice's paper in the Lounge (their page and your view of it) no longer prints How to pay; the ways to pay live in the pay flow, each detail with Copy (mock rev 9g). The PDF keeps it, since people pay from a PDF. A contract or questionnaire made before 27 Sep 2026 says at the foot of its activity log that older emails may not show there.
- Tabs and switches: the Settings tabs are now underlined tabs (the chosen one bold with a line under it), as on the Client tracker, and wrap onto a second line on a phone. The calendar's 'Calendar year / Financial year' and 'Year / Month / Week' switches are now the grey switch with the chosen part raised in white, as the tracker's Board / Calendar / List.
- Buttons: a switched-off button now looks clearly switched off everywhere: a grey fill, faint text, a dashed border and a 'not allowed' pointer, instead of fading slightly (it read as live on a white button). Its tooltip still says why.
- Menus: on a phone every menu row is 44 pixels tall, easy to tap, with slightly larger text. Desktop is unchanged.
- Breadcrumbs (, Gonzalo 28 Sep 2026: "They should look like sc1 across the whole of compass"): one trail everywhere, the kit's icon trail from the Business Lounge mock. An icon at every level (Dashboard, Contacts, the person, the job, then the current page in bold with its icon) and chevrons between. It replaces the plain-text trails on the job page, the Business Lounge, the six invoice pages, the template pages and the Vocabulary page, and the person page's "All clients" back link. The invoice trails follow the invoice mock (no plain "Jobs" or "Invoices" level); an edit page ends "Invoice N › Edit". Settings groups carry no icon, as the kit draws them.
- Invoices (, , first part): the database gains one step that adds a charge to a paid invoice whole (its line, totals, part-paid status, the charge's date or plan row, together or not at all), and only while the invoice is still paid at the total, with the plan rows and the payments, the charge was worked out from. Nothing uses it yet; Add a charge switches to it next.
- Client's Lounge (, Gonzalo's ruling): the footer now reads "This is a private link
sent you. Please do not share it."; the line "anyone with the link can see this page" is gone. The same words now close the older combined portal view and the client invoice page (they said "Don't share it publicly", the portal adding "Anyone with the URL can see this page."). - Invoices (, first part): the database gains one step that applies an invoice edit's new payment-plan amounts whole, and only if the plan and the payments are exactly as the edit read them. Nothing uses it yet; the invoice edit switches to it next.
- Invoices (, first part): the database gains one step that saves a payment plan whole (the new rows, the old ones out, and any change to the settled row, together or not at all), refusing if the plan's rows, the invoice total or the payments changed since the plan was worked out. Nothing uses it yet; the plan save switches to it next.
- Reminders (follow-up, the coordinator's words): the client's pause now reads as covering all their reminders. The invoice page's menu says "Pause all of
's reminders…" and "Resume all of 's reminders", its date picker "Pause all of 's reminders until…", its Reminders line "Paused for until …", and its messages "Reminders paused for .", "Reminders are on again for ." and "All of 's reminders are still paused." A contract's or questionnaire's reminder line, on its page and in the Lounge, reads "Paused: this client’s reminders are paused." while the client's pause holds their next reminder back; a set that only nudges the business is unchanged. - Buttons: more hand-made buttons take the kit's shape: white-faced and bordered ones become the normal button (the portal links' Copy and Open, Sign out everywhere, Match my app look, the dashboard's Customise, the send-later presets), and red ones the kit's red delete button (Trash's Delete forever and Empty trash, the danger zone, removing a passkey or an authenticator, Delete all test records, Discard in the unsaved-changes bar).
- Delete buttons: the shared delete style takes the kit's look, a red button with white text (dark text in the dark looks, whose red is lighter), as Gonzalo asked for the whole app in the kit's look. It covers the quote, contract and client pages' Delete, the invoice's delete, Undo acceptance, Settings files' Delete, and Remove on a business logo and a contact form field. Confirm boxes keep their wording.
- Buttons and fields (stage 3, the plain remainder): the hand-made buttons on the calendar, event bookings, getting started, money, questionnaires, today, the sign-in and set-up pages, the error page and archived products take the kit's shape; booking status buttons too (cancel and no-show in the delete style). Fields that still painted their own grey fill on the element (in Settings lists like deliverables, job types, lead sources and stages, the branding card, the pickers and the text editor's own boxes) take the kit's white face. Filter pills, tabs and buttons in other colours wait for a decision.
- Filter pills: the list pages' filters (quotes, contracts, questionnaires, contacts, event bookings) take the kit's chip look: a small grey pill, and the chosen one in the soft accent colour with a tick, so the choice shows by shape as well as colour.
- Settings, Reminders: the reminder set builder saves from the pinned bar too, with its name on the left and a Cancel that goes back to Reminders without asking. On a phone every pinned bar keeps its buttons on one row; the name shortens first.
- Business Lounge editors (N40, mock rev 9d): Cancel and Save changes move into ONE bar pinned to the bottom of the screen, like New enquiry and Edit details, with the item's name small and grey on the left; on a phone Save changes fills the width. The top of the editor keeps what is being edited and "Unsaved changes", and now scrolls with the form. The quote, invoice and contract editors in the Lounge all use it.
- Edit pages: the long single-Save Settings forms (the Lounge's branding, texting's Connect Twilio, and a contact form's Build, Configure and Style tabs) save from the same pinned bar, on the card or page they sit on. The quote page and a quote or invoice template gain a Cancel beside Save: it discards what was typed and goes back to where the page was opened from. On a page that watches for unsaved changes (the template page), Cancel does not ask "leave without saving?" about its own form; unsaved work in another form on the page still asks.
- Buttons (stage 3, Settings and shared parts): the hand-made buttons across Settings, the email and text composers, the unsaved-changes bar, the guided tour and the create dialogs for quotes, contracts and questionnaires take the kit's shape. Left as they are: the "Show all settings" tab, the Help chip, the workflow screens (held), and the confirm box that the client's pages also use.
- Form fields (, colour correction): fields take the kit's white face, as Gonzalo agreed ("move the whole app to the kit's look"). In the light look a field is white with its firmer edge, like the normal buttons; in the dark and themed looks it takes that look's raised surface, never the page background. This covers the shared field and the 39 business screens that still drew their own grey field.
- Buttons (stage 3, records screens): the hand-made buttons on New enquiry and Edit details, the enquiry and job pages, the hub, contacts, the client tracker, To send and the dashboard take the kit's shape, like the shared button. The workflow screens wait for the held workflow work.
- Buttons (stage 3, first area): the hand-made buttons on the invoice, quote and contract pages take the kit's shape, like the shared button: the main action in the accent colour, the others white with a fine edge, deletes in red text. On the invoice's Payments panel, "Record a payment" is a normal small button, as the Lounge mock draws it.
- Form fields (stage 2): every business-side text box, dropdown and notes box, and the sign-in pages' fields, take the kit's shape (9px corners, 14px text, the accent ring on focus) in the app's own field colours, one height for a text box and a dropdown, and 16px text on a phone. A date field on a business form now matches the fields beside it. The client's own pages keep their look for now. Buttons that shrink when pressed animate again.
- Edit pages: Cancel and Save now stay pinned to the bottom of the screen while the form scrolls, the same bar as New enquiry and Edit details, with the record's name on the left: New invoice, Edit invoice, the quote page, and a quote or invoice template in Settings. Their buttons take the kit's shape. Pop-up editors already kept their buttons in view and are unchanged.
- Invoices: an invoice with a client now shows the client's address exactly as the client has it, blank included. Before, clearing a client's address left the last one on its invoices. Only an invoice with no client keeps an address of its own.
- Buttons (stage 1, Gonzalo: "Agreed"): the shared button takes the design kit's shape (13px semibold, 9px corners, a surface face with a line; the small one 12px with 7px corners; the main one in the accent colour) in the app's own colours, so every theme keeps working. Hand-made buttons follow area by area.
- Enquiry and job names (Gonzalo, 28 Sep 2026: "Agreed"): a record's name is set once, when it is made ("Danica & Kirk"), and nothing renames it afterwards. Renaming, adding or removing a person in Edit details no longer changes it, and neither does Make main contact. It changes only when someone types a new name, or empties the name field to make one from the people again. The panel's line under the name says so.
- Invoices (Gonzalo, 28 Sep 2026): an invoice's client details are its contact's, as they are now. The invoice editors show the name and email read-only, with "Change them on the contact"; the business's invoice page and Lounge, the client's invoice page, every PDF made from now on, and every email about the invoice (the invoice, reminders, receipts) use the contact's current name and email. There is no frozen copy any more: fixing a typo on the contact and sending again sends the fix. The address is the client's current address too (the invoice's own only when the client has none), read-only the same way. The "as issued" label is gone.
- Emails (, the coordinator's ruling 28 Sep 2026): every send box now names who the email copies, so nobody is copied without the business seeing it. The job page's email box reads "Copy: Noah Tester (noah@...)" under its To line; the Business Lounge's Send box for quotes, contracts, questionnaires and invoices gains a Copy field; the older contract, questionnaire and invoice send confirms, and the receipt tick when recording a payment, say "A copy goes to...". The list is built by the same rule the send uses (the main person's second inbox, then everyone kept in the loop).
- Settings, Quote & invoice templates (, Gonzalo: "the template list should indicate the GST rate of a template"): each template with its own tax rate shows it beside its lines ("2 lines · GST 10%"), as the list you start a new invoice from already does.
- Connector (, Gonzalo: "Agreed"): create_enquiry turns a couple given as "Danica Delaporte & Kirk Mason" (or "Sam and Alex") into two people on the record, the main person with the email and phone and the partner, split the way the CSV import splits names. The record is named from its people with the shared rule ("Danica & Kirk", or "Wes's enquiry" for one person) and keeps following them, as every other way a record is made. The client keeps the full name given. A name that is not plainly one or two people (a business such as "Smith & Sons", three people, a comma, an email) is kept whole as one person and the record keeps it, as before. Records made before are unchanged.
- Emails (, Gonzalo: "all emails, manual or not, should include all the people in the loop"): every email to a client about a job now copies everyone kept in the loop on that job, as well as the main contact's second inbox: hand-written and scheduled emails, quotes, contracts, questionnaires and invoices (Send and Remind), the contract email after a quote is accepted, payment reminders, contract and questionnaire reminders, and payment receipts (which copied no one before). Workflow emails already did. Each copy is checked on its own: an address that unsubscribed is left off general emails, and one that hard-bounced is left off automatic ones, without stopping the main email. "Anyone kept in the loop is copied on the emails you send" is now true everywhere.
- Invoices (, Gonzalo: "Perhaps the template list should indicate the GST rate of a template"): an invoice started from a template with its own tax rate now bills that rate, even when the client's region has another one (the region still sets the currency); before, the region's rate quietly replaced it, although the page said the template's rate was used. The template list shows each template's rate beside its name ("Balance payment · GST 10%"), and under the region the page says "Tax from the template: GST 10%. Picking a region uses the region's tax instead." Editing an invoice keeps its own rate the same way until a region is picked. A workflow's invoice from a template follows the same rule. An archived template rate is never started on a new invoice. No invoice has a region and no invoice template has a rate today, so nothing existing changes.
- Business Lounge: the Business Lounge page is switched on for Gonzalo Novoa Photography (its early access), as Gonzalo ruled on 27 Sep 2026. Nothing any of its clients sees changes: none of its documents is hidden and none of its notes or deliverables is shown.
- People card and people panels (part 2b, Gonzalo: "All as steered"): each person opens on the role the record says; only the main person is the Client; one Partner; the person added when there is no partner starts as Partner. The card's chips are the kit's: a star "Main contact" chip, and a plain chip with everyone else's label ("Partner", their own label, or "Contact"). "Make main contact" comes first in each person's menu, works in one click and says what changed in a message with Undo. A partner with no email explains their switch: once an email is added they are copied on emails to the client, and they already fill the partner details in emails and contracts.
- The job page's cards have a slimmer title row, as the design shows: the fold arrow and the small icon buttons no longer make it taller, so a card with no button in its title row is 48px high instead of 55px.
- Quotes, invoices, contracts, questionnaires, files, deliverables and notes each have one colour and one icon, the same everywhere: the settings menu, the settings pages, search, the job page's cards and the Client Lounge. Contracts now show a document icon and questionnaires a clipboard list, as the Lounge does; files and deliverables are cyan, notes a warm grey. Deliverable icons on the job page take the cyan.
- A greyed item in any ⋯ menu now says why in a small label when you point at it, move to it with the keyboard, or tap it on a phone, instead of a line printed under it. The menus are shorter.
- Early access (your studio and test business B only, while the Business Lounge is built): the job page's Client Lounge card lists every quote, contract, questionnaire, invoice and file on its own row, with an eye saying whether your client sees it, its status, and a ⋯ menu for what you can do with it. Each row's icon takes its settings colour: quotes and invoices amber, contracts violet, questionnaires indigo. The job's notes move into their own Notes card, where each note opens to be changed; Edit details no longer holds the notes.
- Compass takes the design kit's colours and text size on the light theme: warm solid grey lines instead of see-through grey, a warmer near-black for text, the kit's red and brand dot (the green stays as it was), body text at 15px instead of 16px, and group labels in a firmer weight. Spacing is unchanged. The dark and coloured themes keep their own colours, and so do your client's pages (their text follows the new size where it had none of its own).
- On the five dark themes (Dark, Espresso, Midnight, Forest, Plum), a working button now looks pressed into the page: near-black with grey text. Before, it turned the same pale cream it uses on light themes, which looked almost like a normal button there. Light themes are unchanged, and your client's pages, which always stay light, keep the light look.
- Your client's Lounge no longer shows an empty band across the top when you have not uploaded a cover photo; the page starts with its content. With a cover photo it looks as before.
- A message with an Undo button now stays on screen until you close it, go to another page, or a newer Undo message replaces it (only one shows at a time). Before, it disappeared after ten seconds, sometimes before you had read it. Messages without Undo keep their timing.
- While a send, save or similar action runs, its button now looks pressed and greyed out ("unavailable"), instead of fading slightly, across the app and on your client's pages (pay, sign, accept). Only the button you pressed changes: before, declining a contract or a quote on the client's page also relabelled the Sign or Accept button ("Signing…"), and a few screens in the app did the same to a neighbouring button. A build check keeps every new working button on this look.
- The open quotes left on jobs that were already booked before the rule above are now closed the same way (3 quotes across 2 jobs; a quote made after its job was booked stays open). Nobody is emailed.
- When a job is booked, its other open quotes now close, so your client can no longer accept a second quote on a job that is already booked. This happens however the job is booked: a quote accepted, a contract signed, a payment (by card, or recorded by you or the AI connector), or Mark as booked. The quote behind the contract or invoice that booked it stays open. Mark as booked now asks first and lists the quotes it will close. Your client sees "Closed, booking confirmed" on those quotes (on the Lounge, the quote page and the PDF), and "Your booking is confirmed, so this quote is closed." if they try to accept one; you see "Closed when the job was booked". One line in the activity log names them. Nobody is emailed.
- An archived record now leaves every list of live work: its workflow steps and next action leave Today and the dashboard, it no longer counts as an active enquiry (Enquiry value, Enquiry drop-off, the Contacts Active filter, the contact page), it raises no date clash, its unpaid invoice leaves the Client tracker's Money due (as it already did on the Money page), and an archived enquiry's date leaves your Compass Leads calendar. A client's unanswered text on it still shows on Today, and now so does one on a lost enquiry, which Today used to leave out. Booked history, revenue and reports still count it.
- A cancelled job, or a lost or not-yet-booked enquiry, that holds a signed contract can now be archived. It can't be deleted (a signed contract is kept as a legal record), so before this it could be neither deleted nor put away. The Delete button and its message now say "Archive it instead" for these, and "once the job is completed" only for a booked job still in progress. If such a record is booked later (your client accepts a quote, signs or pays), it comes back from the archive by itself and the activity log says so. An archived record no longer takes a returning client's new enquiry, and a client's text only lands on it when it answers a text you sent from that record. Reminders about its contract or questionnaire pause while it is archived and carry on if it comes back, as invoice reminders already did.
- On the New enquiry page, Cancel and Create now stay in view at the bottom of the screen while you fill in the form, as they already did in Edit details.
- The Test record tick now sits at the top of the New enquiry form and of Edit details, in larger type, so it is hard to miss. It works as before.
- A contract that comes with a quote is signed only after the quote is accepted, as in Studio Ninja. Your client can read it straight away; its button says "Accept the quote first" and opens the quote. Sending the quote no longer emails the contract separately: the contract's "ready to sign" email goes when the quote is accepted, and the acceptance screen takes your client straight to the contract. A contract sent on its own works as before.
- Panels you minimise with changes in them (a message, Edit details) now say "unsaved changes", and closing one asks "Discard your unsaved changes?".
- A job or enquiry that holds a signed contract can no longer be deleted, one at a time or in bulk: a signed contract is kept as a legal record, so archive the job instead. The Delete button says so up front. A contact holding a signed contract, even one already in the Trash or archived, can't be deleted either, and neither Empty Trash, Delete forever nor the 30-day clean-up ever destroys a signed contract or its contact. Test data clean-up reports records it kept for this reason.
- A saved quote, contract, questionnaire or invoice is already in the client's Lounge, and Send only emails it, so Compass no longer calls it unfinished anywhere. In the app, one not emailed yet reads "Not emailed yet" (the Money filter, search results, Today, the invoice page, help articles, the CSV export option), and the New quote button says "Create quote". The client sees a saved document exactly as if it had been emailed, on the Lounge (including the Payments room's Pay badge), the online invoice and every PDF, so the first email of an invoice saved without sending no longer attaches a PDF that says it is unfinished. On the client's copies an open document now says what it is waiting for: a quote "Pending your review" (as its Lounge room already said), a contract "Awaiting your signature", a questionnaire "To fill in", an invoice "Awaiting payment" ("Unpaid" on its PDF), and a replaced quote "Replaced by a newer quote" instead of "Superseded". The CSV export's Status column uses the same words as the app. The AI connector is told what the status means and to say "not emailed yet". A build check keeps the old word off every screen, including the Waypoint calculator, where a month not saved yet now reads "Not saved".
- The AI connector can now list part-paid invoices and withdrawn quotes by status.
- Payment reminders link to the invoice and no longer attach a PDF copy. The first invoice email, a re-send, invoice workflow steps and receipts still attach it.
- Job and enquiry page cards take the design kit's card look: squarer corners, a thin line under each title, no shadow.
- Compass now runs on version 16.3.6 of Next.js, the framework it is built on (it was 16.2.10). The new version includes the framework's own fix for the crash that most likely caused , where a missing record's page turned blank about a minute after it opened. Compass's own guard against that crash stays in place. Nothing else should look or work differently.
Fixed
- A cancelled job that is booked again (by a payment, a signed contract or Mark as booked) no longer keeps its old cancelled date and reason, as a quote acceptance already did.
- When Mark as booked will close a quote that has an unsigned contract, it now names that contract too, since it can never be signed afterwards.
- A contract's page no longer says Compass will mark contracts Sent and Signed "once the public signing surface ships". It shipped long ago: emailing a contract marks it Sent and the client's signature marks it Signed. The buttons under Move to are for a contract signed on paper.
- A quote's, contract's or questionnaire's internal notes no longer print on its PDF. The forms always said only you can see them, but the PDF your client saves, and the one you download, printed them under "Notes". The online quote page no longer carries them hidden in the page's data either. No live quote, contract or questionnaire has notes today. An invoice's notes still print on the invoice, as their field says. The AI connector no longer suggests putting a "migrated from" reference in an invoice's notes, which your client sees; it points to the client's own notes instead.
- A contract you have already emailed can still be changed until the client signs it; it locks once signed. The edit window tells you the client already has it. Your client always signs the words they read: if the contract changed after they opened it, signing asks them to refresh and read the new version first. Accepting a quote works the same way, so a client can never accept a price or terms that changed after they opened the page. Accepting on the client's behalf is not affected.
- On a phone, the New enquiry page no longer shifts sideways by a hair now that Cancel and Create stay pinned at the bottom.
- A signed contract stays signed. On a contract's page it can now only be voided, and voiding keeps its signature and signing time; nothing moves a contract back to not emailed or sent any more (a declined or void one is replaced by a new contract from a template). If the client signed after you opened the page, your click changes nothing and the page shows where the contract stands now.
- A signed, declined or void contract, and a completed or void questionnaire, is never emailed as ready to sign or fill in again: not from its page, not from Today's Remind, and not when an automatic workflow step retries after the client already signed. The client can no longer decline a contract the business voided. Today's Remind now keeps the due date already set (it used to erase it), and its email names that date.
- A contract can only be made from one of your contract templates. The New contract window no longer offers a blank contract (one used to be saved reading "Add the contract body here.", already in the client's Lounge and ready to sign), and with no templates it points you to Settings, Contract templates. An archived template, or one with no text, can no longer be used, and the same goes for questionnaire templates. A new contract or questionnaire must belong to your own client and job, and each client's Lounge only ever shows its own business's documents.
- The AI connector's contract tool now only records contracts already signed in another system, on your own jobs. A contract a client still needs to sign is made from a template in the app.
- The Lounge card on a job page no longer calls a quote or contract unfinished when every quote was declined, expired or replaced, or when the only contract was declined or void. It now says how the newest one closed, and a closed contract no longer shows a due date.
- A quote accepted before 8 am (Perth time) now creates its invoice dated today, not yesterday. The invoice's payment dates, such as a deposit due on acceptance, count from the same day, so the deposit is no longer overdue the moment the couple says yes, and the job's deliverables timed from the booking count from that day too. The payment plan on the quote page, and in your own quote editor, now shows the dates the invoice will get, including a balance due before the shoot. A new invoice's issue date, and invoice numbers based on the date, use your own date as well.
- Sending a quote again no longer marks its contract as sent when the client has already signed it. A signed, declined or void contract now keeps its status and is not emailed as ready to sign again; an unsigned one is re-sent as before, and a contract in the Trash is no longer re-used (a fresh one is made).
- Choosing a workflow in a job's or enquiry's Edit details and pressing Save no longer makes the Workflow list jump back to "No workflow" (or to the old workflow) while the details save. The list shows the workflow you picked as the current one, and if the details cannot be saved, pressing Save again does not switch the workflow a second time.
- Workflow steps on the dashboard's Today list and in the daily "tasks due" email are now due on your business's own day, not the server's. Before, a business in Perth saw a step due today as "in 1 day" until 8 am. Sending a questionnaire or contract from its own page now counts its due date and its reminders from your own today too. On the Client tracker, Next job, Needs doing and Money due now count from your own today as well, so a booking today stays the next job, money due today says "today" and money due yesterday shows as overdue, and "Booked value, this year" starts the new year on your own New Year's Day.
- Text message steps can now be added to and changed on a job's workflow. The step window offered them, but saving one failed with "Pick a real step type."
- Pressing Send twice on a job's email, invoice or text step no longer sends the client two copies. Each manual send now reserves its place in the send log before it goes, as automatic sends already did, and a send that fails frees that place so trying again works.
- Editing a questionnaire or contract step on a job no longer deletes the email that sends it. An automatic step with no email to send now shows "Needs setup" on the job, as it already did in Settings, and an automatic email with an empty message no longer goes out with only a signature.
- A charge added to a paid invoice now needs its own due date, and reminders chase that date. The date starts empty and must be today or later. While the charge is owing, the invoice's Edit page shows it as "Extra charge due" so it can be moved.
- When an invoice email or a receipt goes out without its PDF (the PDF could not be made, or was too big to attach), Compass now reports it instead of staying silent, and every sent email records which files it carried.
- On a phone, the "Add Compass to your home screen" prompt now steps aside while a panel, sheet or picker is open, so it never covers buttons such as Save changes. It comes back when that closes.
- The Board stages help article now matches the page: the right name and buttons (Settings, Board stages, New stage), the three kinds of stage, which four stages stay, and when a stage can be archived or deleted. It no longer promises that logging a call moves a record, and it no longer shows internal codes.
- The daily digest email can now be sent. It looked for enquiries by statuses that do not exist, so the database refused the request and every business was skipped without a word. It now finds open enquiries the same way the board does. The digest is still off unless a business turns it on.
- When several messages pop up at once, the three newest now show, so the message about what you just did is never the one left waiting out of sight. Older messages wait their turn and come back as the newer ones close; nothing is lost.
- A job or enquiry page no longer reloads itself a moment after it opens when your device and Compass's server disagree about what day it is (every morning before 8 am in Perth, for a record with a workflow). The due tags on workflow steps, such as "Due today" and "Overdue 3 days", now appear as soon as the page has loaded instead.
- On a phone or tablet, tapping a small icon button (such as the pencil for Edit details) no longer leaves its hover label stuck over the page. Hover labels now appear only for a mouse, or when you move to a button with the keyboard.
- Adding the sample data to a new business works again. It used to stop with an error part-way, after adding the sample enquiries but before the sample opening hours, because a business created since 26 June 2026 has no hours schedule to put them in. It now uses the business's default schedule, and creates one called "General" when there is none.
- On a phone, the Edit details panel (and the email panels) now fill the screen's width and no longer scroll sideways, so field labels and the Save changes button are never cut off. A strip of the job page used to show beside the panel, and a hidden help bubble pushed the form wider than the screen. The small "i" help bubbles also stay on screen when opened near the right edge.
- On a phone, the date picker (and every other small menu that opens from a button, such as the snooze, icon and colour pickers) now always fits on the screen. When there is no room under or over its button it moves up onto the screen, and when it is taller than the screen it scrolls. It used to run off the bottom edge, so later weeks and its buttons could not be reached. Menus also no longer open underneath the navigation bar.
- A quote, contract, questionnaire, contact, invoice, payout or settings item that does not exist shows the "Off the map" page and stays there too, instead of turning into a blank "This page couldn't load" screen a minute later or when you open the notifications bell.
- Opening a job or enquiry that does not exist (a deleted record's old link, or a mistyped address) shows the "Off the map" page and stays there. About a minute after it opened, or as soon as you opened the notifications bell, it used to turn into a blank "This page couldn't load" screen.
- On an invoice page, "Keep sending" and "Pause this invoice" now change only that invoice. They used to lift a pause on all of the client's invoices as well. While all of a client's invoices are paused, the Reminders menu offers "Resume all of
's invoices" in place of "Pause all", and the message after each choice says exactly what changed and what is still paused. - On the invoice your client sees, online and as a PDF, a payment on the schedule whose date has passed now reads Overdue, in amber with an alert sign. It used to read "Upcoming".
- The automatic reply a new enquiry gets from your contact form is now headed by your business's name. It used to be headed by the word "Compass".
- The Money page and a client's page show invoice numbers in their short form (20260918 or 20260918-02), the same as the invoice itself and everything your client sees. They used to show the long stored number.
- Opening an enquiry that does not exist shows the same Not found page as a missing job, instead of one that still said "Lead not found".
- A quote, contract, questionnaire or invoice that is not part of a job now stays on its own page, where your client can always see it. Links to it, including the payment receipt's link, used to open your client's Lounge, which only shows documents inside a job, so the document was missing there. Documents on a job still open in the Lounge. (, first part)
- An invoice page now knows when the client's email address has bounced. The status reads Bounced instead of "Not opened yet", the Reminders line says reminders cannot reach the address instead of promising the next one, and "Send a reminder now" warns you before it sends (it still lets you).
- An invoice on a payment schedule with more than one late payment now says how many are late and the whole late amount, not just the oldest payment.
- An invoice's status line uses the invoice's own amounts, the same ones the job page, the client's page and the client's Lounge show, and shows times in the same time zone as the email history and activity on the same page.
- An invoice for $0 no longer says "Stopped. The invoice is paid." under Reminders; it says nothing is owed.
- The invoice your client sees, online and as a PDF, names the job once in its Event box. It used to print the name twice, one line under the other.
- The plain-text copy of the invoice, quote and contract emails, which some mail apps show instead of the formatted one, now carries your signature as ordinary text. It used to show the signature's raw code. The same goes for emails sent through a connected AI assistant.
- Setting up "Send from your own address" no longer tells you to add a DMARC record when your domain already has one. Compass checks your domain, and if one is there it says to keep it and leaves it off the list of records to add, because two DMARC records make inboxes ignore both.
- Pressing "Check my records" now explains in plain words why your domain is not verified yet, such as how many records are still not visible, instead of showing the email service's own technical sentence.
- Checking your records no longer files a false error report each time.
- Opening a job or enquiry through an old link (an address starting /jobs/ or /enquiries/) now goes straight to the record, with no background error. An old link with a mistyped id says Not found.
- Removing a passkey that no longer exists says so plainly instead of showing a technical error.
- A payment reminder now says what is true on the day it arrives. A reminder that went out the day after a payment was due used to say it "is due today"; it now says the payment is overdue.
- A client gets at most one payment reminder a day. Pressing "Send a reminder now" counts as that day's reminder, so the automatic one does not follow it minutes later, and pressing it after the morning's automatic reminder, or twice at once, is refused with a note to try again tomorrow. If either kind of reminder fails to send, the day is given back, so a failed automatic reminder never blocks "Send a reminder now".
- "Send a reminder now" is refused for an invoice whose job is archived or in the Trash, the same as the automatic reminders, and the automatic reminders now also skip an invoice whose job is in the Trash.
- Recording or removing a payment, changing a payment schedule or adding a charge no longer ends a "Pause this invoice until" date you set, and no longer sends the client an extra overdue reminder the next morning. Reminders carry on from where they were, and start fresh only when the payment they chase moves to a new due date. The same applies to payments recorded through a connected AI assistant.
- Writing an invoice off and then reversing the write-off keeps the invoice's reminder pause exactly as it was before. It used to switch reminders back on even if you had paused them before the write-off.
- The Money page and a client's page now show each invoice's status exactly as the invoice itself does, as a word with an icon: Not sent, Sent, Opened, Part paid, Overdue, Paid or Written off. An invoice with a payment that is late now reads Overdue in amber there too, even when part of it is paid or it is on a payment schedule, and "late" is judged by your own date rather than the server's. It used to read "Part paid" in green, a colour people with red-green colour blindness cannot tell from red. A client's page shows the issue date beside it.
- Emails your clients receive no longer carry Compass's red. The red full stop after your business's name is gone from the invoice, quote, contract, questionnaire, payment reminder, enquiry auto-reply and booking emails, and the contract email's due date and the booking reminder's "Join the meeting" button are no longer red.
- The client's online invoice and the invoice PDF show the invoice's status as a word with an icon, in blue for Paid and amber for Part paid, instead of green against brown, a pair that people with red-green colour blindness cannot tell apart. The payment schedule's rows, the Paid so far figure and the thank-you note after paying follow the same colours.
- Deleting a job or an enquiry through a connected AI assistant now works exactly like the Delete button: its quotes, contracts, questionnaires and invoices go to the Trash with it and come back with it, and a record with a card payment is refused until the payment is refunded. It used to trash only the record and leave its invoices live, where payment reminders could keep reaching the client.
- A connected AI assistant that sends a yes or no as text ("true" or "false") is now understood everywhere: making a workflow the default, archiving one, marking a questionnaire question as required, adding the signature to an email template, and pausing a workflow's automation when it is attached. It used to be read as no.
- The invoice email now lists any discount on the whole invoice, between the subtotal and the tax, so its rows add up to the total the way the invoice and the PDF already do.
- The invoice email now says when the invoice is due, and has a "View your invoice" button that opens it online, in the client's Lounge where they have one. The client's online invoice shows its due date too.
- An invoice's number now reads the same everywhere a client sees it: the invoice email's subject and heading, the PDF, the payment receipt email and the card checkout page all show the short number (20260918) that the app and the PDF's file name already used, instead of the long stored one (2026091801).
Added
- An invoice now says in one word where it stands, with an icon: Not sent, Sent, Opened, Part paid, Overdue, Paid or Written off, and a line of detail such as when it was sent, when the client opened it, and what is still owing. Sending an invoice changes the word straight away.
- "Send a reminder now" on an invoice emails the client one payment reminder straight away, the same email the automatic reminders send. The automatic schedule carries on as before.
Changed
- An invoice has one Reminders line instead of two controls. It says whether reminders are on and when the next one goes, or what has paused them, and one Change button pauses this invoice, pauses all of the client's invoices, or turns them back on. The pause choices are the same ones the job page uses to snooze, plus "Until I resume them". Every pause already set stays as it was.
- The invoice itself is drawn on the design kit's document paper: the business stays top right beside the dates instead of dropping below them when an invoice has a due date and a service date, the invoice number is no longer in a typewriter font, amounts line up digit for digit, the paper stays white in dark themes and prints cleanly, and a business with no business name shows its workspace name instead of a dash. The "as issued" tag, the payment-method warning and the email history no longer print.
- Payment reminders now appear in an invoice's email history, so you can see each one was delivered and opened.
Removed
- On a phone, pulling down at the top of a page no longer shows Compass's compass dial or slides the page down.
Changed
- The Activity log is now the first card in the middle column of a job page, for anyone who has not arranged their own layout and for anyone who presses Reset layout. Layouts people have already arranged stay exactly as they are.
Fixed
- An invoice your client opens now sits in the same place on the page whether it is long or short. On computers that show a scroll bar, a longer invoice used to shift slightly to the left.
- A job page address that has been mistyped or damaged now shows the "page not found" screen instead of "Something snapped".
- Sending from your own address now shows every DNS record the email service asks for, and the screen states the real number instead of always saying three. "Check my records" now reads the records back from the email service, so a list that came back incomplete fills in. A domain only counts as verified when every record, including the DKIM signing record, has been seen.
- A part payment now counts towards what a client has paid. The Payments room in the client's Lounge, the Lounge card on a job, and a contact's money summary used to show "$0.00 paid" until an invoice was paid in full. They now add up the payments actually received, the same way the invoice page does.
- File links in emails now work, or the email stops and tells you why. A file linked in your email signature used to reach the client as a dead link on quote, invoice, contract and reminder emails, and on emails sent through a connected AI assistant. It is now a real link. If a linked file has been deleted, the email does not go, and you are told which file to fix. Clicking a link while you write an email no longer takes you off the page.
- The Activity log on a record now opens collapsed every time. Opening it used to be remembered, so one click on "View log" left the log open on every record, on every device, until someone pressed "Hide log". It still opens when you ask, for as long as you stay on the page.
- Pop-ups now open below the navigation bar instead of sliding underneath it. On a phone they start where the bar ends, and a pop-up you drag stops at the bar. This covers the email and edit panels, the Client Tracker peek, the Today peek, the People dialogs, and the workflow step editors.
Security
- Content security policy, report-only: every page now carries a full content security policy in report-only mode. It blocks nothing. Browsers report what it WOULD have blocked to a new collector, which keeps only short, safe words (the rule, an origin or a keyword like "inline", and the page's shape with ids and private links blanked) and counts them in a capped table. The list is reviewed before anything is enforced. The enforced policy is unchanged (frame-ancestors only).
- Sign-in limits: Supabase only ever sees Compass's own server addresses, so its per-address sign-in limits never see a visitor, and its email allowance is shared by the whole project. Compass's own limits were kept in each server's memory, so spreading requests across servers walked past them. They are now counted in the database across every server: sign-in emails (magic link, sign-up, password reset) at most 10 per visitor in 10 minutes, and at most 5 of each kind to one inbox in 15 minutes; sign-in link redemptions at most 30 per visitor in 10 minutes; passkey sign-ins at most 10 per visitor in 5 minutes, counted only once a real sign-in challenge is in hand. An IPv6 visitor is counted by their /64 network. A blocked magic link says "Check your inbox for the newest one, or try again in a few minutes"; a blocked link redemption lands on the sign-in page with "Too many sign-in attempts from here." Password reset still answers the same way whether or not an account exists.
- Error reports (, security review): a client's private link is a working key, and it sits in the address of their Lounge, quote, invoice, contract, questionnaire, file, unsubscribe and booking pages, and in the database calls those pages make. Error and performance reports sent to Sentry, from the server, the edge and the browser, now blank it wherever an address appears in the report (the page address, the Referer, the trace data, the navigation trail, network calls and the server's own request details). Session recordings are never made on those pages. Record ids, trace ids and ordinary pages are kept for debugging.
- Rate limits on the public pages a client acts on without signing in: the booking page's free-time calculation and its Book button, and accepting or declining a quote and signing or declining a contract, from the Lounge or the old pages. The limits sit far above anything a person does; a script that meets them gets a plain sentence to wait a few minutes.
- Contact forms (, security): the address a form sends people to after they submit must start with https:// or http://. It is checked when the form is saved and again when the form sends someone there, so an address that could run code is never followed; the thank-you message shows instead. The form's colours must be colours and its font link a Google Fonts address, checked on save and where the form is drawn, and the new-enquiry email address must be an email address.
- Sign-in (, security): every page that sends someone on to a "next" or "return" address after signing in (the sign-in, two-factor and sign-up steps, the email link, the passkey setup page, the New enquiry return link, and the signed-in bounce away from the sign-in page) now accepts only a path on Compass itself. An address such as /\evil.com or one with a hidden tab in it, which browsers turn into another website, goes to the usual landing page instead.
- Contact forms (, security): the database itself now refuses a form redirect address that is not http:// or https://, whoever writes it, not only the form's own Save.
- CSV downloads: the payouts CSV and the Client tracker's Export CSV now guard any text a spreadsheet would run as a formula (a client's name or a description starting with = + - @), as the invoice export already did. Amounts stay numbers.
- The list of a job's files that a client sees (their Lounge, the business's job page, the Business Lounge's preview) now checks the business on every read itself, so a future page that forgot to check first could still never list another business's files; the client's combined page lists only its own business's jobs the same way. Nothing changes on screen.
- Only one business can send email from a given domain. If another business on Compass already uses a domain, setting it up again is refused with a plain message. Cancelling, or going back to the Compass address, now also removes the domain from the email service, not just from Compass.
Fixed
- Copying anything in Settings now shows the copy straight away, dimmed, with a Saving tag, instead of nothing happening until the page catches up. This covers discounts, reminder sets, deliverables, email templates, packages and add-ons, contract templates, questionnaire templates, and quote and invoice templates. If a copy fails you get an inline message with Retry rather than silence.
Fixed
- The booking alert you get now says where the meeting is in the plain-text copy too, not just the formatted one. Before, a plain-text reader was told when a booking was and never where, including the street address for an in-person meeting.
Fixed
- Copying a workflow now shows the copy straight away, dimmed, with a Saving tag, instead of nothing happening until the page catches up. If the copy fails you get an inline message with Retry, rather than silence.
Changed
- Client emails and texts now link straight to the Client Lounge instead of to a page that redirects there. The old document links keep working, so mail already sitting in inboxes is unaffected.
- A payment receipt no longer links to a Lounge that will not open. It checks the client's Lounge is switched on before including the link.
- The quotes list now opens on All, and All is the first filter. It used to open on Open, which showed only drafts and sent quotes and hid everything accepted, declined, expired, superseded or withdrawn.
Fixed
The document preview shows the right heading for businesses whose tax comes from the older setting. If your tax rate came from the legacy registered-for-GST setting rather than a rate you set up, the preview in your settings said "Invoice" while your actual invoices said "Tax Invoice". It now asks the same question your documents ask.
The Client Lounge help article is titled Client Lounge. It had moved to the right address but was still headed "The client portal" inside.
Changed
The assistant can see which records are test ones, and respects the rule about them. Every list and lookup it makes now tells it whether a record is a test fixture or real work, so it stops treating the two the same. It follows exactly the rule your own forms follow: it can turn a test record into a real one, it can never turn a real record into a test one, and if it tries you get the reason back rather than a silent refusal. Changes it makes to a contact are now written into that record's history as well, which they never were before.
Three more settings pages now live at the address they are named after. Event types, Products and Client types were reachable only at older addresses, with the friendly name forwarding onto them. That is now the other way round: the page lives at the name you would type, and the old address forwards there forever, so nothing you have bookmarked breaks. Text messages is deliberately left where it is for now, because that address is included in the notification emails Compass has already sent you.
The Client Lounge help article moved to match its name too. It was titled "Client Lounge" while sitting at the old client-portal address, the same mismatch the settings page had. The old address forwards to the new one, so any link you have saved still works.
When something goes wrong, it now looks like it. Four messages that reported a failure were styled as ordinary information, so they faded away like a success: a layout that would not save, a text that could not be marked as handled, and booked jobs that a bulk move skipped. They are now shown as errors, which also means they wait for you to close them instead of disappearing while you are looking elsewhere.
The record history says what changed and how. A record being turned from a test one into a real one used to be logged as "No longer a test record", which reads like a field being edited rather than the deliberate step it is. It now reads "Changed from a test record to a real one, so it now counts in reports", and says the same thing whether you are looking at the enquiry or the contact. Clearing a contact's notes is also now logged as cleared rather than updated, which is what an enquiry already said.
Your documents are headed the way your country heads them. An invoice that charged tax was called a "Tax Invoice" everywhere, which is the Australian term. If you invoice in pounds or euros it now reads "VAT Invoice"; in US or Canadian dollars it is simply "Invoice", because sales tax does not make a document a different kind of document. South African and UAE invoices keep "Tax Invoice", because that is what their own VAT rules ask for even though the tax line says VAT. An invoice with no tax on it is still just an "Invoice", as before.
Fixed
A quote always shows the tax it charged. If your business had a tax rate set up but an older "registered for GST" tickbox was off, a quote could add tax into the total without ever showing the tax line, so your client saw a total they could not reconcile. The line now appears whenever tax was actually charged, which is the same question your invoices and PDFs already ask. Checked against your live records first: only one business has quotes carrying tax and its line was already showing, so no client has received a quote with tax hidden.
Your quotes call the tax by its right name. The tax line on a quote said "GST" whatever currency you invoice in, so a business working in pounds read GST beside a VAT amount, on both the quote page and the quote PDF. It now follows the currency, the way your invoices already did: GST, VAT or Sales tax.
Changed
Your chosen voice now reaches most of your confirmation messages. Picking a different voice used to change about one message in seven, because nearly all of the wording was written out separately in each part of the app rather than coming from the voice you picked. The everyday confirmations now come from it: something saved, sent, logged, moved, added, removed, deleted, archived, merged or copied, and a booking. Whichever voice you choose, the message still tells you exactly the same thing about what happened; only the way it is said changes. Messages about something going wrong stay plain in every voice, on purpose.
A real record can no longer be turned into a test one. Marking something as a test record takes it out of your reports and puts it in range of "delete all test records", so a real enquiry or contact cannot be flipped that way any more. The tick is still there and still shows you the state, greyed out with the reason. It works the other way round: a test record can be made real, because someone ticking Test out of habit before a real client arrives needs a way back. That direction asks you to confirm first and is written into the record's history, and it cannot be undone. The assistant can still mark a record as a test one when it creates it, but it can no longer change the flag afterwards, since it cannot ask you first.
Fixed
- Your paperwork only calls itself a tax invoice when you actually charged tax. If your business is not registered for GST, three places still headed your documents "Tax Invoice": the invoice page you read, the document colour preview in your settings, and the invoice email your client receives. The client-facing invoice page and the PDF already got this right. All of them now say plain "Invoice" when no tax was charged, and every one of them asks the same question: was any tax actually charged on this document. That last part matters on a mixed invoice. If most of your lines carry no tax and one does, the tax can work out to a fraction of a percent of the total, and the first version of this fix read that as no tax at all: your client would have seen "Tax Invoice" on the web page and plain "Invoice" on the PDF and email in the same message.
Changed
Confirmation messages stay long enough to read, and errors wait for you. Anything telling you what just happened now stays for at least ten seconds instead of six, with a thin bar along the bottom showing the time left. The bar pauses while your mouse is over the message, while you are tabbed into it, and while you are off in another browser tab, so a message can no longer run out while you are not looking. Anything that went wrong does not disappear at all: it waits until you close it. The quiet green tick that confirms a setting saved is unchanged and still brief, because it is a reassurance rather than something to read. If several arrive at once only three show and the rest queue, the same message arriving over and over becomes one line with a count instead of a pile, and a "Dismiss all" button appears as soon as there is more than one. Messages also no longer collide with the cookie notice, the "add to home screen" prompt or the unsaved-changes bar: they now sit clear of whatever else is along the bottom of the screen.
The Client tracker board now starts near the left edge of the screen. On a wide monitor the first column used to begin a long way in, lined up with the page heading, which made it look like the whole board fitted on screen when in fact it scrolls sideways. The columns now start close to the edge, so it is obvious there is more to the right. On a laptop, tablet or phone nothing moves.
The settings page for the Client Lounge is now called Client Lounge, and its web address matches. It was listed as "Client portal" while the thing it controls is called the Lounge everywhere else, which made it hard to find. The settings entry, the page title, the search result and the help link all say Client Lounge now, and the page itself has moved to an address that says the same thing. Your existing links and bookmarks to the old address still work, and always will: they now take you straight to the new one.
Added
- Quick settings, in your account menu. Under "Account & password" there is now a "Quick settings…" row that opens a panel over whatever you were doing, holding the handful of settings people actually reach for: theme, accent colour and voice, your document colour, guided mode, which timezone you are viewing times in, hiding things on screen for a screen-share, and the daily digest email. Each group says which settings page it belongs to and links straight there, so this is a shortcut rather than a second place a setting lives. Nothing moved out of the account menu.
Added
- You can make a workflow your default from its own row. The "…" menu on each workflow now starts with "Set as default", so choosing the one new enquiries begin on no longer means opening the workflow to find the setting. The workflow that already holds it says "Default workflow" instead of offering the move again.
Changed
- All four kinds of client are offered from the start. "Group". families, wedding parties, a team. used to be switched off until you went looking for it, so a business that photographs families every week had to find a setting before the shape it works with appeared. All four now come switched on. If you have already turned one off in Client types, your choice stands.
Changed
- A person's email and phone are now the only ones Compass reads. Records used to keep their own copy of a client's address and number, and a few screens and sends still fell back to that copy. Correct someone's details once, on their person, and every screen and every message uses them. Checked against your live records first: none of the 51 would lose an address or a number by this.
Changed
- A record's name follows its people until you name it yourself. Add or rename the people on a record and its name keeps up on its own. The moment you type a name of your own, it is yours and Compass stops touching it, for good; clear the field and it goes back to following the people. Every record that already exists keeps exactly the name it has. nothing was renamed.
Fixed
The Client tracker heading has its red dot again. Every other page title in Compass ends with the small red dot from the Compass mark. The Client tracker was the one that did not, because its heading had been written out by hand instead of using the shared one.
Clicking "Couple" then typing two names now names the record after both of them. The second person card that chip adds was arriving with no role, and only a Client or a Partner helps name a record, so the enquiry quietly ended up named after one person. Opening the form already on Couple was always right; the chip now does the same thing. Adding a person by hand still starts them as "Other", which is what you want for a planner or a parent.
Changed
- A booking now shows who the person turned out to be, and still keeps what they typed. When someone books a call they may not be anyone in your Compass yet, so the name, email and phone they filled in are kept exactly as submitted. Once they become a person on a record, the booking list shows that person's current details, with the original submission underneath, labelled. Nothing is overwritten.
Fixed
- Emails and texts greet the people, not the record's title. A record you named "Rebeca & Caleb's Wedding" used to put that whole phrase where the client's name belonged, so the greeting read as the job rather than the couple. Every message now composes the name from the people actually on the record. "Rebeca & Caleb", or just "Rebeca" where that is your business's style. and falls back to the record's title only when nobody is linked. Nobody has to type an "&".
Added
- Contacts now has three ways to look at the same people. People is the everyday view, with a search box and a sort that remembers whether you like newest-first or by name. Businesses groups everyone who works for a company under that company, with its registered number. Records is the old client list, unchanged, for when you think in terms of a job rather than a person. Adding a person is one button: type an email or phone you already have on file and Compass opens that person instead of making a second copy, while a repeated name is treated as the coincidence it usually is.
Added
- Every person now has a page of their own. Open anyone from Contacts → People to see their details, every enquiry and job they are on, and how they are attached to each. Client and Partner name the record, a planner or a parent are simply on it. Fixing a detail here fixes it everywhere, because every live screen reads a person's email and phone from this one place. Merge only ever lists people who share this person's exact email or phone, and says so plainly when nobody does; deleting is tucked behind the "…" menu and refuses while they are still on a record.
Added
- A contacts check that finds the two real problems with your people. Under Contacts, a new page shows details that disagree. where a record and the person it points at hold different addresses or numbers. and lays both side by side so you pick, because guessing could send mail to an address nobody reads. Underneath it lists everyone who is in your contacts but on no enquiry or job at all, which is where the missing halves of couples turn out to be hiding. Merging is only ever offered where two people share an email or a phone; where they share nothing but a name, the row says so and offers no merge. Nothing changes until you choose.
Changed
- A draft invoice bills the client as they are today; a sent one keeps what it was sent with. While an invoice is still a draft its Bill to shows the person's current name and address, so fixing a contact fixes the invoice about to go out. The moment it is sent, those details are frozen onto the invoice and the screen marks them "as issued". an issued tax invoice has to stay reproducible exactly as the client received it. The emailed copy now goes to the address resolved at that moment, not to whatever was typed when the draft was made.
Fixed
- A corrected phone number now shows and sends everywhere. The email address on a record already came from the person; the number did not, so a mobile you fixed on the contact still read as the old one on the record's People card and in the tracker preview, and a text could print one number while going to another. Both now read the person, exactly as the address does.
Added
- A CSV import can start each row on its workflow. One checkbox in the import options, off by default: tick it and every imported record begins on the workflow its job type uses, exactly as a new enquiry would. Left off, an import of past work stays quiet, which is what importing history should do.
Changed
- Setting up now asks what kind of work you do, not which wedding trade. The first question offers eight kinds of business. Neutral, Weddings & Events, Fitness & Health, Beauty & Aesthetics, Design & Creative, Freelance & Professional Services, Trades & Home Services, and Care & Support. each showing the words it starts you on. Only Weddings & Events goes on to a second question about the trade, where photography and videography are now one card and media freelancers finally have one of their own. A third page then shows exactly what your answer sets up: your words, how records get their names, a sample workflow and a sample job type, all editable later. "Other" no longer quietly hands out wedding words.
Added
- Compass now keeps a plain record of which parts of it get used. the workspace, the name of the screen or feature, and the time. That is all: no client names, no amounts, nothing anyone typed, and not even which person did it. It is written as the app is used and can only be read by Compass staff, so decisions about what to improve or retire stop being guesswork. (, first slice)
Added
- Hover tips across the app. Every icon-only button now says what it does on hover, from the label it already carried for screen readers, and a name or line that is cut off shows itself in full. while one that fits stays quiet. On a record's People card, hovering a person's name brings up a small card with their email, phone and how they are labelled, so you can check a detail without opening anything. One bubble does all of it, so tips cannot drift apart between screens.
Changed
- Settings uses real icons everywhere instead of stray text symbols. The close crosses, drag handles, chevrons, move-up/down arrows and card badges across every settings page were typographic characters that rendered differently on each machine and at each font. They are now icons from the same set the rest of Compass uses, checked name by name against the icon font that ships.
Changed
- Settings is one place again, not seven islands. Payment methods, Tax rates, Regions and Payment schedules now have their own entries in the settings drawer instead of hiding behind Invoicing. Each group carries one tab bar across its pages: Personal (Profile, Business profile, Sign-in & security, Appearance, Notifications), Templates (now including Deliverables), Money (Invoicing, Payment methods, Tax rates, Regions, Payment schedules, Billing) and Connections (Calendars, Integrations, Text messages, Connect to AI). Workflows sits under Templates, where its tabs and breadcrumb already said it belonged. Where a page's address and its title disagreed, the address stays and the name you would actually type now takes you there: /settings/event-types, /settings/text-messages, /settings/products and /settings/client-types.
Added
- Today can be grouped, filtered, and no longer buried by one record. Overdue now shows one row per record. the step that has waited longest. with a "+N more overdue on this record" pill that opens the rest in place, so nine late steps on one job cannot hide eight other jobs. A Group by switch flips the whole list between Record and Date (earliest first), and "Only mine" narrows it to records assigned to you plus anything nobody has claimed, saying how many it hid. Both are view settings; a reload starts fresh.
- Three more dashboard cards carry a real number. "Waiting for your OK" counts from the same loader the Today section uses, so the card and the section cannot disagree; Contacts and Quotes each count their own rows. Money still shows no number on purpose: what belongs there is money outstanding, and a count of invoices would read as dollars.
Changed
- A record's workflow is changed in one place now. The Workflow card no longer attaches or detaches; Edit details (the pencil beside the name) is the single place, so two screens can never disagree about what is running. The card says where to go when a record has none. Change a record's job type and, if that type usually starts on a different workflow, Compass offers the swap in a line you can accept or wave away. it never re-plumbs a record silently. Dropping the workflow now reads "None, I will handle this one by hand", last in the list and never pre-selected.
Added
- Every job type can start its own workflow. Open a job type and pick the workflow its enquiries begin on: "Use the workspace default" (the safe first option), any of your workflows, or "None, start bare" for work you drive by hand. A new enquiry asks its job type first and only falls back to the workspace default when the type has no opinion. The list now says, per type, which workflow it starts and how many records carry it, and the "…" menu offers Set as default, Archive, and Delete for a type nothing has used yet, each saying why when it does not apply.
Changed
- Payment schedules read like sentences now. Each schedule in the list says the plan in the same plain English a client sees ("50% of the order due the moment the quote is accepted. 100% of what's left due 14 days before the main event date."), with the number of payments beside it, and the editor shows that same sentence as a live preview while you build the plan, so it is proof-read before saving rather than after. The "…" menu gained Set as default, and Delete for a schedule nothing has used yet; anything with history is archived and keeps its payments.
Changed
- Tax rates now live inside the region that charges them. GST only exists because it is one of Australia's rates, so adding a region for the US no longer offers it: you type the rates that region actually charges, one of them marked Default. The Tax rates screen becomes a read-only summary grouped by region, with an "Edit in the region" link on every group, so there is never a second screen that thinks it owns the number. Existing rates were attached to your default region, and nothing on an issued document changed. A region that has never been used can be deleted outright; one with history can only be archived, and the menu says which and why before you click.
Fixed
Form fields look like fields again. On the new enquiry form the boxes were the same colour as the card behind them, so only a hairline told you where to type, and the dropdowns sat shorter than the text boxes beside them. Fields now sit a step off the card with a firmer edge, and every input and dropdown shares one height. Checked in all nine themes.
The Activity log keeps its quick-entry strip when you fold the card. Folding it hid the whole thing, so the email, text, note and call buttons went with it. Only the history folds now.
Connecting Twilio no longer wipes what you typed when it complains. If the opt-out line was missing, the error appeared and your Account SID, token and Sender ID vanished with it. Everything you typed stays; only the token box clears, and only after a save that worked.
Text messages and Sign-in security use proper icons instead of emoji, like the rest of your settings.
Nav links and settings chips can no longer be dragged around by accident, which used to leave a ghost image and a URL tooltip stuck to the cursor.
Two hover states in the pricing calculator flashed a light panel on the dark themes. They now use your theme's own colour, like everything around them.
Four places that turned white-on-white in the dark themes. The Getting Started group headers ("Before your first enquiry"), the hover state on its rows and on the welcome card's shortcuts, the Today preview panel, and the hover state on activity rows all painted a fixed off-white background under theme-coloured text. On a dark theme that meant near-white text on a near-white panel. They now use the theme's own colour.
Changed
Today and To send are one list. Held automated sends and texts from numbers Compass could not place now sit at the top of Today under "Waiting for your OK", where nothing sends and nothing is lost until you act. The old To send page takes you straight there, so old links and bookmarks keep working, and the dashboard card and text notifications point at the same place.
The Getting Started list opens as a side panel instead of sitting on the dashboard. Your dashboard keeps the progress bar and a "Finish setup" button; the full list slides in beside it, so you can work through setup without losing the page you were on. The same panel opens from the settings drawer's setup card.
Added
A business client's number prints on their invoices. Set it when you create the record as a Business and it appears under their address, labelled the way your own is (ABN, VAT or EIN, following your settings).
Every person on a new enquiry has a role instead of a star. The first person is the main contact because their role says Client, so there is nothing extra to tick. Change a role and the record's name follows, because only Client and Partner make up the name. Planner, Parent or guardian and Billing contact are there too, and the role you pick is kept on the record instead of vanishing when you save. A business record uses Main contact and Billing contact, since the business names the record.
Fields that come from your settings now say so. The Job type and Workflow labels on a new enquiry carry a small explainer: hover it or tab to it and it tells you where that default comes from, with a link straight to the setting. The date section, which is named from your own vocabulary, carries the same thing with your word on it.
A new enquiry starts as a Solo client, rather than assuming a couple. One click switches it.
You can choose the workflow while creating an enquiry. It used to attach your default silently. Now the list is there with your default already picked and labelled as such, so you are told the automatic answer at the moment you change it, and "None, I will handle this one by hand" sits last and is never pre-selected. Enquiries arriving from your form, website, a booking or an import keep attaching your default as before.
A record can start as a Business. Alongside Solo client and Couple, picking Business gives you a card of its own for the business name and its business number (the ABN in Australia), above the people who are its contacts. The record takes the business's name, and the number is kept for the invoices you send them.
The public roadmap is current again. The Tree of Compass now lists everything shipped since mid-July, in plain language: texting, the activity log, Today, the Getting Started list, your home location and regions, default job types, the help centre, and the rest. A couple of stale entries that said "coming soon" for things already live have been corrected.
Your deliverable templates now reach records that already exist, and the quick-add chips are your own words. Adding a template in Settings only ever affected jobs created afterwards, so a template you added today could not be put on a record from last week. The Deliverables card now offers "Add from your templates" whenever something is missing, and it adds only what is missing however many times you press it. The quick-add chips read your own template names instead of the built-in Gallery, Album and Prints, which were three photography words on a product that also serves copywriters, DJs and trainers.
A sample that already suits you can be kept, without pretending to edit it. Starter records arrive with a "Sample" badge and do not count toward Getting Started until you change them, which was silly if the sample was already right. the 10% GST rate, say. Every sample now has a "Keep it" beside its badge: one click adopts it as yours, the badge goes, and Getting Started counts it.
A new account gets its home region instead of being told it has none. Existing accounts that had already confirmed their home location and had no regions got theirs in the same change, so nobody is left on "0 regions" waiting for a prompt that may never come again. Regions pair a currency with the tax that applies there, and a brand-new workspace had zero of them, so a business trading happily in one country was told it had no regions at all. Compass now creates your home region from the currency and tax rate you already set, at signup and when you confirm your home location. If you already have any region, nothing is created. The Regions wording also stops using the United Kingdom as its example.
You can pick a default job type, and every new enquiry starts on it. (Shipped, then fixed the same afternoon: the setting saved but the Default badge and the pre-filled picker did not appear, because the list that feeds those screens was not reading the new setting.) Enquiries used to arrive with no job type at all, whichever way they came in, and you set it by hand every time. Settings › Job types now lets you mark one as the default (and un-mark it), and it is applied by the new-enquiry form, your contact form, the website webhook, an online booking, a CSV import and the AI assistant alike. "Pick a default job type" joins the Getting Started list. Archiving a type clears it as the default, so nothing new lands on work you have retired.
The help centre stops leaving big holes in the page. The search box used to take one half of the first row, so the first category sat awkwardly beside it, and a category with eleven articles ran on next to one with two. Search now spans the full width above the categories, and each category shows four articles with a "Show N more" for the rest.
The Getting Started list stays on your dashboard until setup is finished. Once you had your first enquiry, the checklist beside the welcome card disappeared and all that was left was a progress bar telling you how far along you were, with no way to see what was actually next. The step list now sits beside that bar, and both go once setup is complete.
Every record now has a Texts card, whether or not you text yet. The "Set up texting" button sits in the card's header, so you can see and click it without opening the card first. It used to appear only once a record already had a text, so if you had never set texting up you would never find out it was there. It now sits on every record, closed, with a "Set up texting" button that takes you straight to the setting. Once texting is connected it opens as the conversation.
The record's Activity card is now the Activity log, and it opens as just its composer. The full history was taking so much of the page that the workflow underneath could be missed entirely. You still get the email, text, note and call strip at the top of the card, always one click away; the history itself sits behind "View log", and once you open it Compass remembers that for you on every record.
The Custom fields card on a record opens closed. Most records have no custom fields, and the card's explanation and add form were taking up a screenful above the cards you actually came for. One click still opens it.
The Vocabulary preview no longer shows a menu that does not exist. Renaming a word used to preview it as a top-menu item, but enquiries, jobs and the calendar share one Client tracker menu item now, so there was no such entry to change. The preview shows only the places your word really appears.
The back link on the New enquiry page calls the page it goes to by its real name. It said "Enquiries" and landed on Client tracker. It now says Client tracker, and goes straight there.
A brand-new record no longer opens on a step that is "overdue 192 days". If you attach a workflow whose steps are timed well before the event to an enquiry whose event is sooner than that, several steps used to compute to dates months in the past, so a record created this morning greeted you with nine overdue steps and a next action you could never have done. Those steps are now due on the day the record was created, and the "Next action" banner names the first step in your workflow's own order that is actually due, instead of whichever one happened to compute furthest into the past. The same applies on Today and to the automation hold notice. Automatic sends are unchanged: a step whose timing predates the record still never sends by itself.
Card surcharges end for Australian businesses on 1 October 2026, and Compass handles it for you. From that date, Australian businesses may no longer add a card surcharge. Compass stops adding the "Card processing fee" to any card payment made on or after 1 October, including payments against invoices you sent in September, and the setting switches itself off. Whether it applies is decided by the country of your connected Stripe account, which is the business the rule actually binds, not by where your workspace says you are. Buy Now Pay Later is unaffected. Your payment settings page carries a heads-up until the date arrives.
The setup progress bar's stripes are actually visible on the dark themes. The first fix gave each theme its own stripe colour, but the five dark ones came out barely a shade off the bar itself. They are now clearly darker, at the same visible difference the light theme has always had. If you have picked your own accent colour, the stripe now follows it too, instead of staying on the theme's default and disappearing. (follow-up)
The setup progress bar has its stripes back. The moving barber-pole bar on your dashboard and setup card was drawing its stripes in a colour almost identical to the bar itself, so it looked like a plain solid block. On the darker themes it had the opposite problem and looked like hazard tape. It now uses a colour picked for each theme, so it reads the way it was designed to.
Every remaining place where a save could fail silently now speaks up. This finishes the job: from 295 such places when it was first counted, down to none. Three were deliberately left to report rather than stop, because stopping would have been worse: after a text or an email has already gone out, Compass records it and tells you if the record failed, instead of pretending the message never sent. The overnight reminder and scheduled-email jobs also used to treat a database hiccup exactly like "another run already did this" and skip quietly; they now say something.
Another 50 places where a save could fail without telling you now fail loudly. This round covers the ones that matter most: new enquiries arriving from your website, the scheduled-email and reminder jobs that run overnight, a client accepting a quote, sending a client email, uploading a file, and your calendar sync. Where Compass used to carry on as if a save had worked, it now stops and reports it. That is 117 such places down to 67 across the whole app.
The Texts card now finds your client's mobile. It was looking in the wrong place, so a client who had just texted you showed as "No mobile on file" and the reply box was switched off, which is precisely when you most want it. It also greeted you with "ZZTEST's's phone" when a record's name already ended in an apostrophe-s. Both fixed.
Six settings pages that were showing nothing now work again. Products & services, Discounts, Tax rates, Regions, Payment schedules and Invoicing had been opening as an empty page for everyone since 2 September. They loaded their menus and then simply stopped, with no error and no explanation. The cause was a change on 2 September that made the tab strip along the top of those pages read your own words for quotes and invoices; the way it was wired made the page fail before it drew anything. Fixed, and a new build check now refuses to ship that mistake again.
Another 55 places where a save could fail without telling you now fail loudly. If the database hiccups while saving a job type, a tax rate, a region, a payment schedule, a workflow, a file, a contract, a questionnaire, your sample data or an onboarding answer, Compass used to carry on as if it had worked and the change simply vanished. Now it stops and says so. That is 172 such places down to 117 across the whole app. ()
Texts on a record now read like a phone conversation. A new Texts card on the job hub shows the whole thread the way a phone does: bubbles, day headings, replies on the left and yours on the right, grouped when they came one after another. A text a workflow sent carries an Auto tag, one that failed says so and can be sent again with a tap, and one held because the client opted out says that too. There is a toggle to see the same thread as your client's phone shows it, which deliberately hides anything that never reached them, so you can tell what they have actually read before you write the next message. Underneath, compose a text with your saved templates and fill-ins, with the character and segment count as you type. Pictures they texted you are marked as saved on the record.
The record's Activity log now shows the money, folds the noise, and explains itself. Quotes, invoices and payments are read from your actual money records rather than guessed at from wording, so the log carries the moments that matter: a quote sent, accepted or declined, an invoice sent, money in with how it arrived, and a refund read as a refund. A save that changed six things is one line saying "6 changes" that opens to show all six, and the same line happening three times shows once with an x3, so a busy afternoon no longer buries the day. Anything Compass did as a knock-on (dates recalculated, a workflow attached) tucks under the action that caused it behind a "Why", instead of scattering through the feed. Ticking a workflow step off now appears in the log at all, which it never did before, and a step you just ticked carries an Undo for ten minutes. ()
Texting, slice two, part three: STOP is respected and pictures are kept. When a client texts STOP, Twilio stops delivering on its side and Compass now mirrors it into your own opt-out list, so it never queues a text it already knows will be refused. A quiet line on their record explains why that number went silent, and the bell tells you it happened; a later START clears it and says so. Pictures a client texts you are pulled off Twilio and saved as files on the record, so they survive Twilio deleting them, and the record's Activity says how many are there. ()
Texting, slice two, part two: a reply now asks for your attention. A client's answer shows on Today as a row with their actual words under it, above everything else on that record, because someone waiting on you outranks anything scheduled: Reply opens the record's Text pane, or mark it as handled and it leaves the list. The one-line summary at the top says how many replies are waiting. Texts from numbers Compass does not recognise, which is most first contacts, wait in their own list on To send with three ways out: attach it to someone already on your list, start an enquiry with the number already filled in, or dismiss it, which deletes nothing. The bell carries both kinds and each opens the right place, a known client's record or the holding list. Three new notification settings let you choose how you hear about replies, unknown texts and opt-outs. ()
Texting, slice two, part one: a client's reply now comes back into Compass. If you text through a dedicated number, their answer lands on the right record instead of disappearing into Twilio. Compass points your number at itself when you save your Text messages settings, and if it cannot (the number sits on another Twilio account) the address to paste in by hand is right there on the page. A Sender ID cannot receive at all, and the page now says so plainly instead of leaving you wondering. Every incoming message is checked against your own Twilio signature before Compass touches it, so nobody else can post fake replies into your account. The reply is filed on the record you last texted that number from, or failing that their most recently active open record; a number two people share is filed under the first person and says so. It shows on the record's Activity as "Mary Tan replied by text", attributed to the client, and their words are never quoted in the log. The holding list for numbers Compass does not recognise, the Today row and the bell come next. ()
The help articles stopped calling your business a studio too. The main copy sweep missed the Help centre, so six lines there still said "studio": how texts are sent (they come from your business, and the Sender ID shows your business name), the sample opt-out address, the client-portal recommendation, and two billing-region examples. They now say "business", matching the rest of the app. The Help centre's industry examples ("A copywriter says project. A DJ says gig.") are deliberate and unchanged, as is the getcompass.studio address. (residual)
The back link on the New enquiry page no longer reads "Enquirys". It printed your singular word with an "s" stuck on the end, so "enquiry" became "Enquirys" and any renamed word came out equally wrong. It now prints the plural you actually set. A build guard fails from now on if any screen tries to make a plural that way again.
The Workflows page says so when nothing is the default. If you have workflows but none of them is marked as the default, one line now sits above the list: "No default yet. New enquiries arrive without a workflow. Pick one." Until now that gap was silent, and every new enquiry quietly arrived with no workflow attached. The line uses your own words for enquiries and workflows, and disappears the moment you set one.
The job hub's Activity is now the whole record's log, in the main column. One list of everything that happened: emails (sent, delivered, opened, bounced), texts, workflow steps and calls, money, edits to the people and the record, notes, and the quiet things Compass did on its own. Every row carries a coloured type chip, says what happened in plain words, names who did it (you by name, Compass, a connected assistant, or the client) and when. Filter pills with live counts, a search box, a who-did-it picker, and a "Show system events" switch that keeps housekeeping out of the way until you ask. The composer strip has four modes: email, text, log a note, log a call. Rows load twenty at a time, the list says how far back it goes, and the record's Created row is pinned at the foot so where it came from is always in reach. Notes are never quoted in the log. (; the expandable "why", folded bursts and Undo follow in 4b)
Today opens the thing itself. Clicking a row on the Today view now opens what that row is about in a card over the list, so you never lose your place: a workflow email shows its preview with the real recipients and a Send now button; a text step shows the message and the mobile it will go to, with Send now; a contract step shows the contract's status (not sent, awaiting signature, signed) and when it was sent; a questionnaire step shows how many answers are in and the first few; a next-action note opens in a box you can edit and save; a booked appointment shows its time, length and who it is with. Rows with nothing to preview still open the record as before. ()
Texting, slice one: workflows and reminders can text your clients, and texts get fill-ins. A new "Send a text" step in the workflow builder (and in a job's own workflow) works like the email step: start from one of your text templates or write it here, drop in fill-ins (the same ones as email, minus the signature and your business address), see the character and segment count, and choose manual or automatic sending. Automatic texts are OFF until you allow them in Settings > Text messages; until then every text step waits for you to press Send it. When they are on, the same first-send gate applies as for email (the first automated message on each job waits for your one-tap go-ahead), a step with no mobile number waits until one is added, an overdue step flips to manual, and reminder sets with a text step start texting too. Fill-ins also work in the Text button on an enquiry and in your text templates. Texts still go through your own Twilio account and skip opted-out numbers. Replies coming back into Compass are the next slice.
A brand-new dashboard now shows the way in. The old four-path welcome card (two of them stale) is three paths that each lead to an Essential setup step: add your first enquiry, bring in your existing clients, connect your website. Beside it sits the real Getting Started checklist as a rail, same steps and groups as the standalone page, with "Start here" on the next step, "Set up" on the rest, and "Done · Open" on finished rows so a completed step still has a way back in. A step whose screen holds only a starter sample says so and carries the Sample chip. When everything is done the rail folds to one line with "Reopen setup". On a phone the rail collapses under its header. The progress bar is the new locked one: thicker, striped, gently moving, reading "41% · 7 of 17 done", and the same bar now sits on the dashboard's setup card and on the settings drawer's "Finish setting up your studio" card.
Your document words reach the job hub and the Client Lounge too. The hub's Lounge rows, the cockpit's quick-add chips, the tracker peek's Lounge counters, and the client-facing Lounge (room names, headings, empty states, the Accept and Sign buttons) now print your Vocabulary terms for quotes, invoices, contracts and questionnaires. Document numbers keep their "Quote #12" form. Part two of two. ()
Your words for quotes, invoices, contracts, questionnaires, workflows and reminders now show up where you look for them. The Vocabulary terms you can already edit were stored but not yet printed. Now the top nav's Quotes item, the Templates and Invoicing tab bars, the settings sidebar, the breadcrumb, the six template pages (titles, "Your …" labels, empty states, the + New buttons), the Quotes, Contracts and Questionnaires pages, the shared New quote / contract / questionnaire dialogs, the Today view's step labels and the trash toasts all use them. Part one of two; the job hub, cockpit and Client Lounge rows follow. ()
A new workspace is asked where home is, not treated as a traveller. A brand-new account used to be greeted with "You seem to be in Perth right now. Show times in Perth while you travel?", because every workspace starts on a default timezone the studio never chose. Now, until you have chosen one, the strip asks instead: "You seem to be in Perth. Is that home for your studio?" with "Set Perth as home" and "Choose another location". Once home is set (or your browser already agrees with the default) it never asks again, and the travel offer only appears when you really are somewhere else.
Clients can unsubscribe from your general emails. Every general email now carries an unsubscribe link in its footer, plus the header mail apps read, so Gmail and Outlook show their own one-click unsubscribe button too. Clicking it stops general emails to that address from your studio, and the page says which studio it is. Your documents are deliberately unaffected: quotes, contracts, invoices, questionnaires and reminders still reach the client, because those are the work they hired you for, not marketing. This was the missing half of the unsubscribe system, which could already record an unsubscribe but gave nobody a way to ask for one.
Edit the next action without hunting for it. The Next action bar now has its own "…" menu carrying "Edit step", which opens the same step editor the workflow list uses. Previously the bar could only do it or snooze it, and changing anything meant finding the step again down in the Workflow card.
Skip a step, or delete it outright. A step's "…" menu now separates the two things you actually mean. Skip this step is for "decided not to do this one": it stays on the list, crossed out and marked Skipped, and Un-skip brings it back if you change your mind (this is the old "Stop automation", renamed to say what it does). Delete this step is for a step that was never relevant to this client: it goes. Both touch this client's workflow only, never the template in Settings. Deleting asks first, and if other steps were timed off the one you're removing, it says so up front (those steps keep their place and simply ask for a new timing rather than being quietly moved to a new date).
Change a record's workflow without losing its story. The Edit panel's Workflow field is now live: pick a different workflow (or none) and save. Finished steps stay on the record as history, the old workflow's unfinished steps are cancelled along with their upcoming automatic sends, and the new workflow's steps land timed off the record's own dates. Nothing fires behind your back: the new steps arrive held until you give the go-ahead, and anything already past its date waits for you to decide. Before it happens, a confirmation spells out the exact numbers ("2 done stay · 5 pending cancelled incl. 1 scheduled send · 8 new planned"). Detaching from the Workflow card now keeps finished steps too, with the same plain-numbers confirmation.
One composer, three ways to reach out. The hub's composer now opens as one panel with Email, Text, and Note tabs: the mail icon starts you on Email, the message icon on Text (replacing the old separate text pop-up), and the Note tab logs a note or a call. Drafts in every tab survive switching tabs, minimising the panel, and navigating away; texts stay plain (SMS carries no formatting) with the character and segment count as you type. The quick inline note box on the Activity card still works as before.
Phone numbers for everyone on a job. Extra people (a partner, a planner, a parent) can now carry a phone number: it shows on their row in the People card with one-tap copy, and the add/edit person dialog has the field. The enquiry form always asked for it; now it actually saves (it used to be quietly dropped for everyone but the main contact).
Arrange the hub your way, and it remembers. Every card on a record's hub now has a grip: drag cards up, down, or into another column and the page keeps your arrangement. A new "+ Add a card" spot at the end of the right column opens a small gallery (Custom fields, Budget & costs) so optional cards only appear when you want them, with a card menu to remove them again (cards holding real data stay put). In the two-column layouts you can drag the divider between the main column and the rail to set the split you like: the main column never squeezes below half the page, and a double-click snaps the default back. All of it, including your three-or-two-column choice, now saves to your account instead of the browser, so your layout follows you to any device.
The Next action bar sees past the first thing. When more than one workflow step is due, the record hub's amber bar now shows a "+N more due" pill; click it and the other due steps unfold as rows you can act on right there, each with its own snooze and do-it buttons. When nothing is due (or no workflow is attached yet), the bar offers "set a next action" instead of disappearing, and saving one on a workflow-less record quietly starts an ad-hoc checklist for it. The bar's main button now wears your accent colour too.
"Last contact" at a glance. The record hub's facts row now says when this client last heard from you ("Last contact 3 days ago (you)", or "(automated)" when a workflow sent it), pulled from your sent emails, texts, and logged calls.
Hub polish, found in first use. One pencil, one job: the little name-only editor next to the record title is gone (the header pencil opens the full Edit panel, which renames too). Scrolling to the end of the Edit panel no longer scrolls the page behind it. And the Client Lounge card's empty rooms are now actionable: click "Quote · Not started" and the new-quote flow opens, same for contracts, questionnaires, invoices and files; the card's footnote now says what rows really do.
One form for creating and editing a record. The pencil on any record (enquiry or job) now opens the same form used to create an enquiry, pre-filled, in a floating panel you can minimise while you check something else. It carries the people, the details, the event, and a new internal-notes field (private to your studio). Money fields deliberately moved OUT of the form: the new Budget & costs card on the hub is money's one home (client budget, job value, direct cost, margin), wearing a "never client-visible" badge because that is exactly what it is. Events can now carry start and end times with an "All day" toggle; timed events land on your Google calendar as real timed blocks instead of all-day banners, and the form warns you inline (softly, never blocking) when the date clashes with another booking. Client Lounge card rows now open your studio-side view of each item (the quote, the contract) rather than the client's copy; the eye icon still previews their view. The old separate edit forms are retired.
The date-clash warning grew a memory. When another enquiry or job shares the event date, the hub shows a calm amber heads-up (it never blocks saving) with links to the clashing records. Allow the clash (say, a second shooter) and it tucks away into a small "Clash OK" pill beside the Event date; dismiss it and a "Date clash" pill keeps the flag visible. Either way, one click on the pill brings the full warning back for review.
One hub for every record, from first enquiry to final delivery. An enquiry and a booked job now share the exact same page: the same header (with the record's board stage as a clickable chip that moves it, including "Booked", Lost with its reason, Cold and On hold), the same cards (Job details, People, Workflow, Activity, Client Lounge, Deliverables), and the same controls. Pre-booked records see their Lounge and Deliverables from day one with friendly empty states. The layout button now cycles three arrangements (three columns, rail on the left, rail on the right), and a new fold button collapses or expands every card at once. Scheduled emails now show inside the Activity card, shared portal files inside the Client Lounge card, and an email-delivery problem shows as a badge on the affected person in the People card.
Pick your accent colour. Settings → Appearance has a new "Accent colour" card: one pick recolours the interactive moments across the whole app (primary buttons, add buttons, highlights, selected states, and the focus ring as you tab around), and it follows you across every theme and device. Compass keeps the pick readable automatically, brightening it on dark themes and deepening it on light ones when needed. "Theme default" hands each theme its own accent back. As part of this, primary buttons now wear the accent (a fresh indigo out of the box) instead of plain black, and the signature red stays where it belongs, on the Compass dot.
Changed
Compass no longer calls your business a "studio". Around 110 customer-facing lines (Getting Started, the setup rail and drawer, onboarding, settings, and the client-facing quote, contract, questionnaire, booking, invoice and Lounge pages) now say "business", or "you" where that reads better, so the app fits a copywriter or a DJ as well as a photographer. Sample company names such as "Driftwood Studio" and the Business profile page's own name are unchanged. The home-location prompt now asks "Is that home for your business?". (, wording)
Edit panels on the job hub (Edit details, the composer, any editor opened from the hub) now open centred on the screen over a dimmed backdrop instead of docked to the right edge. Dragging, Escape to minimise, the dock pills and the full-screen sheet on phones are unchanged.
The Text messages settings no longer promise automatic texts we do not send. The page and its help article said Compass could text booking and invoice reminders and receipts. It cannot yet: today you can only text a client by hand from an enquiry. The copy now says exactly that, so nobody sets up expecting automated texts that never arrive. Automatic reminders and receipts still go by email.
Your emails come from your studio, not from "Compass". Client emails now show your studio name as the sender, and replies go to your own address instead of disappearing into a no-reply mailbox. Your clients hired you, not Compass, and an unfamiliar sender name is what gets a real quote ignored or marked as spam. The sending address behind the scenes stays ours, because that is the part your inbox provider has already been told to trust; changing it would make your email more likely to land in junk, not less.
Both contact lists sort the same way now. Clients used to be ordered by most recent activity while People was alphabetical, so the two halves of Contacts behaved differently. Both are now A to Z. Contacts is where you look someone up, so the order stays put instead of reshuffling as activity lands (the Client tracker is still the place that surfaces what needs doing). Each client still shows its last activity.
Budget & costs is just an optional card now. It used to appear by itself whenever a record happened to carry a budget, value or cost, and you could not remove it while it did. Now it behaves like every other optional card: add it from "+ Add a card" and it stays until you remove it, whatever the record's money says. If a record has money and you want to see it, add the card once and it is there.
More room on the wide screens. The nav bar, the record hub, the client tracker, and the quote and invoice builders now share one wider layout (up to 2000px) so they line up and use the space on a large monitor. On the record hub the three columns are now proportional with sensible caps: the side rails grow a little but stay tidy, and the extra width goes to the middle column where the workflow and activity live. On smaller screens nothing changes.
Retired code swept out. The old separate edit form's save machinery (retired when the one create=edit form shipped) and a leftover rename helper are gone, along with their now-unused plumbing. No behaviour change; the unified panel and its field-scoped saves were already the only live path.
The Edit panel got comfortable. The floating Edit-details panel is wider (the name/pronouns and email/phone rows finally breathe), its Save and Cancel buttons stay pinned at the bottom while the form scrolls (no more scrolling to the end just to save; the title bar was already pinned up top), and the header's "Minimise" word is now a tidy dash icon beside the close ✕.
Snoozing grew names. Moving a workflow step's date is now called Snooze everywhere, with named shortcuts that show their real dates (Tomorrow, Next week, In two weeks, Next month) plus "Pick a date", replacing the old "Change date" menu and its "move N days later" options. The step menu, the Next action bar, and its expanded rows all share the exact same menu, and snoozing now confirms itself with a toast (mentioning when an auto-send is being held).
The homepage loads instantly. The front page is now served as a pre-built static page from the CDN instead of being rendered fresh on every visit (the signed-in redirect to your dashboard still works, it just happens a layer earlier).
The public pages are tidier for Google and for keyboards. Every public page (home, pricing, the Tree, help and its articles, changelog, status, privacy, terms) now tells search engines its one true address, so preview copies of the site stop competing with the real one. Browser-tab titles no longer repeat the Compass name twice, and the "skip to content" link for keyboard and screen-reader visitors now lands properly on every public page.
Security
- A second, signed-in tenant-isolation test now runs in CI: it signs in as a real second test account and checks it can only ever see its own workspace's enquiries, clients and invoices, and never the owner's, even when it knows the other workspace's id. It runs only once the test account's password is stored as a repository secret, and skips quietly until then.
Fixed
63 more database writes fail closed instead of silently continuing: the sample-data seeder and reset, the job workflow actions, booking-page settings, the Brevo email webhook, the calendar lead-push and deliverable settings. A failed write now surfaces (and reports itself) instead of the screen pretending it worked. Unchecked writes: 235 → 172. ()
After a validation error on the public quote, contract and questionnaire forms and on the login page, focus now moves to the field the error is about (or to the message itself), so keyboard and screen-reader users land on the problem instead of at the top of the page. (residual)
Every workspace now has a default workflow, so a new enquiry always picks one up: the sample workflow where it still exists, otherwise the oldest live workflow. (extension)
New enquiries on a new workspace now pick up the sample workflow automatically. The sample was seeded without being the default, so the "attach the default workflow" step had nothing to attach and new customers' enquiries arrived with no workflow at all. The sample is now the workspace default (still labelled Sample until you edit it), and workspaces with a single workflow and no default have it set.
"Add your studio details" no longer ticks itself on a brand-new account. Signup always names the workspace, and the step only checked that a name existed. It now completes when you save your Business profile, when you give the studio a real name (not the signup "…'s workspace"), or when a business address, phone, email or number is filled in.
Accounts that signed up with a magic link now get the inline "Set a password" form in Sign-in & security. They were shown "Change password", which asks for a current password they never had, because the check behind it looked at the sign-in system's stored password, and that system gives every magic-link signup a random one behind the scenes. Compass now keeps its own record of whether you have chosen a password (set, changed, reset, or signed in with one).
Getting Started no longer ticks itself off. Finishing setup seeds sample packages, templates, a payment schedule, a workflow and a tax rate so no screen opens empty, and the checklist was counting those, so a brand-new workspace read "10 of 17 done" seconds after signup. Seeded records are now labelled "Sample" in every list and editor, and a step counts only once you have made something of your own or edited the sample (the label disappears the moment you do). Vocabulary counts once a term differs from your industry's preset, and the pipeline counts once a stage is renamed, reordered, recoloured, archived or added.
The setup wizard counts its steps honestly. After two steps were retired in August the counter still said "Step 1 of 6" and jumped from 3 to 6, and Back on the final step led to a retired page that only bounced you forward again. The counter, progress bar and every Back link now come from the one live step list (four steps), and a test keeps them in step.
Sign out now ends only the browser you clicked it in. It used to revoke every session on every device (the sign-out call defaulted to the global scope), so signing out of Safari also signed you out of Chrome. A new "Sign out everywhere" button in Settings > Sign-in & security keeps the all-devices option for a lost phone or a shared computer.
The tax box on quotes and invoices now says what you will actually be charged. When you had not picked a tax rate on a document, the box could read "Workspace default (no tax)" while the document went on to add tax, because the wording was still driven by an old on/off tax setting the calculation had stopped using. The wording is now worked out from the very same rule that does the sums, so it names your default rate and its percentage (for example "Workspace default (GST 10%)"), and only says "no tax" when no tax will genuinely be added. Fixed on new invoices, invoice editing, quotes, and quote/invoice templates. One user hit this and worked around it by making a 0% rate their default, which is safe to leave in place for now.
Addresses start with the country, and the state picks itself. On a client's address you now choose the country first, and the rest of the form adjusts to match. For Australia, New Zealand, the United States and Canada the state line becomes a dropdown of the real options, so there is no more guessing between WA and W.A. and Western Australia. The labels change too, so a Canadian client is asked for a Province, a New Zealander for a Region, and an American for a ZIP code rather than a Postcode. Anywhere without a fixed list stays a plain text box, because a half-finished list would be worse than none. Every country is in the list, with Australia, New Zealand, the United States, the United Kingdom and Canada at the top.
The privacy policy now explains exactly what Compass does with your Google Calendar. A new section spells out what Compass can see when you connect a calendar (the names of your calendars, when you are busy or free, the bookings Compass itself creates, and the email address of the account you linked), what it uses that for, and what it never does with it. It states plainly that Compass does not read the contents of your personal calendar entries, only when you are busy. It also covers where the connection is stored and how to disconnect, both inside Compass and from your Google account. This is required wording before Google will review Compass, which is the step that opens calendar connecting to everyone instead of a named list of testers.
Payment reminders for a payment plan no longer go quiet for weeks. On an invoice split into instalments, each reminder was counted against the invoice as a whole rather than against the instalment being chased. So once a client paid one instalment, the running total carried over to the next one and silently swallowed its reminders until the count caught up, which took weeks. On one real invoice, an instalment due 19 July did not get its first reminder until 5 August, 17 days late. Each instalment now keeps its own count, so it gets the full run of reminders from the friendly heads-up before the due date onwards. An instalment that is already overdue when Compass catches up gets one reminder at the right stage rather than a burst of catch-up mail. This also covers instalments paid by card, which were the ones slipping through, because the card payment path never reset the count.
A broken merge field can no longer reach your client, and now shows up while you type. Merge fields like the client's name look like neat little tags in the editor, but underneath they are ordinary text, so one stray keystroke could turn one into something misspelt. Nothing flagged it, and the broken tag was then sent to your client exactly as written, so they could receive an email opening with "Hi {{partner_nam}},". Two changes. In the editor, a field that is not one of the real ones is now outlined in red with a wavy underline and explains itself on hover, so you see the break the moment you make it. And as a last line of defence, anything still unrecognised is removed just before the email leaves, so the worst case is a missing word instead of visible gibberish. Real document links (contracts, questionnaires, invoices) are deliberately left alone, because those are filled in at the last moment on purpose.
The invoice PDF now shows card payment, and stops splitting the payment section across pages. Two fixes to the "How to pay" part of the PDF. It used to break across a page boundary and strand one method (PayID) alone at the top of page 2; it now moves down as a whole block if it will not fit. And the PDF only ever listed bank transfer and PayID, even when the same invoice could be paid instantly online by card, Apple Pay or Google Pay, so a client who only opened the attachment never learned the fastest option existed. Card now appears first, with the link to pay online. It only appears when that invoice really can be paid that way, so the PDF never offers something the payment page will not honour.
Server-side crash reporting works again, after being silently off since launch. Compass has two crash alarms, one for the browser and one for the server, and the server one had never actually switched itself on in production. Because the browser half kept reporting normally, the dashboard looked healthy the whole time, so nothing ever pointed at the gap. Crashes on the server side (the parts that save your work, send your emails and build your documents) were happening unseen. The alarm no longer depends on the startup step that was failing: it now switches itself on at the moment it is needed, so a crash gets reported either way. Confirmed working with a real test crash arriving in the dashboard.
Compass now tells us when its own crash alarm is switched off. The alarm that reports server-side crashes could be turned off by a single missing setting, and it went quiet without saying so, which meant faults could go unseen for weeks while the app looked perfectly healthy. It now writes a loud warning into the production logs the moment it starts up without that setting, and there is a new admin-only check that reports, from inside the live site, whether crash reporting is actually running.
A dead CC address no longer blocks the good main address. Invoice reminders and some other emails also copy the contact's second inbox. When that copied address was dead and bounced, Compass was blocking the main (working) address by mistake, and the alert to you named the wrong address. It now blocks only the address that actually bounced, so a bad second inbox can never take out the one that works.
The public booking page works again. Every attempt to book a call or session had been failing with "Something went wrong on our end", and it was wiping everything the person had typed. The cause was a mismatch between the booking code and the database (it was trying to save a field that no longer exists), so no booking ever got through, going back to early June. That is fixed, and a failed attempt now keeps the person's details on screen so they are not made to type it all again.
A quote that fails to send now says so. If the email could not go out, Compass used to mark the quote as sent anyway and tell you it was away, leaving you waiting on a reply to an email that never left. The failure now appears straight away with the reason, the quote goes back to how it was instead of sitting there falsely marked sent, and the problem is logged for us. The contract-ready email is logged the same way.
Error monitoring stopped drowning in one harmless message. If you left a Compass tab open while a new version shipped, that old tab would report an error every time it tried to act, even though nothing was actually broken (the tab just needed a refresh, which it does by itself). One burst of this filled about 65% of the monthly error-reporting allowance, which risks hiding real problems. That specific message is now ignored. Genuine errors still report exactly as before.
A workflow step no longer completes when you click the row. Clicking anywhere on a step (the name, the timing chip, the notes) used to tick it off, so a stray click quietly marked work done. Ticking a step off is now the checkbox's job, or "Mark done" in the step's "…" menu. The rest of the row does nothing.
The "drag cards here" hint only shows on a truly empty column now. In the two-column layouts the side rail stacks two card slots in one column, so an empty slot sitting under a filled one used to draw a stray "Empty column" box beneath your cards, as if it were a separate drop zone. The hint now appears only when a whole column is genuinely empty, and reads as that column's empty state rather than a box under the content.
Dragging got easier to aim. While you drag, the column that will receive the card now wears a soft dashed outline for the whole drag, so you can always tell where it will land even when you have scrolled far from the insertion point. Releasing works anywhere on the page now, not just strictly inside the grid, so drifting a few pixels past a column's edge no longer cancels the drop. And an empty column shows a permanent faint "drag cards here" placeholder instead of one that tried (and on Safari, often failed) to appear mid-drag.
Dragging cards is finally dependable. The root cause of every "sometimes the drop just doesn't take" report was found with a real-input reproduction: browsers cancel a drag if the page re-draws at the exact moment the drag begins, and the hub re-drew itself right then (to dim the card and light up the landing areas). Whether your drop worked was literally a race. The re-draw now waits one tick, so the drag always survives: the card dims, the landing areas appear, and the drop lands, every time, in every layout.
The giant empty gap in the two-column layouts is gone. With a long workflow, the browser was spreading the tall main column's height across BOTH of the side rail's rows, inflating the gap between the rail's upper and lower cards by thousands of pixels. The rail now sizes its first row to its actual content and lets the second row absorb the difference, so the side cards sit snugly again.
Dropping a card lands wherever you let go. Drops used to require your cursor to be exactly inside a column's own box; any dead spot (a gap, the space beside a long column) silently refused them. The whole grid is now one drop surface: wherever you release, the card goes to the nearest column at that height. Together with the gap fix above, dragging between columns should finally feel dependable, however long the workflow.
Dropping a card works at any scroll depth. Columns used to be only as tall as their own cards, so if you scrolled deep into a long workflow and tried to drag something to a shorter column, there was nothing under your cursor to drop onto. While you drag, every column now silently extends to the full height of the page grid (nothing moves visually), and an empty column's dashed "Move it here" target runs the full height too, so it's always in view.
The People card stopped breaking at in-between widths. With the new draggable divider the side column can be almost any width, and at middling widths (a 50/50 or 75/25 split) the People card tried its single-line layout in space where it could never fit: emails truncated to a few letters and the "Always emailed" label collided with the contact icons. The single-line layout now only engages when there is genuinely room for it; anything narrower uses the stacked layout that always fits.
Hub arranging, round two. Three follow-ups found in live testing: a column you emptied by dragging its card away had nothing left to drop onto (while you drag, every column now keeps a landing area and empty ones show a dashed "Move it here" target); clicking the column switcher could set off an endless stream of "Too many changes too quickly" messages until you refreshed (a save was being re-fired by a React quirk on every repaint. saves now fire exactly once per click); and folding the Workflow card no longer hides the Next action banner (folding a card now just hides its body instead of tearing it down, which also means cards remember their internal state when you unfold them).
The hub's columns render properly again. The drag-arrange release shipped with its column widths missing from the built styles, so cards could crush into slivers or pile on top of each other. The widths now ship as a real style rule (render-verified in a browser against the built styles this time), and a new reset button in the hub header restores the default layout (3 columns, default split, default card order) in one click, so a misbehaving saved layout can never strand you again.
Security
An email is never sent when we cannot check the unsubscribe list. If that check hit an error, Compass used to send the email anyway and report success. It now refuses and tells you, so someone who unsubscribed or whose address bounced can never be emailed because of a momentary glitch. Sending a document by hand (a quote, contract, invoice or questionnaire) is the one exception, and only because the unsubscribe list never blocks those in the first place, so refusing them would have stopped your most important sends for no benefit.
Closed a hole where the wrong person could have read your client documents. The database rules that let a client open their own contract or questionnaire from an emailed link were too broad: they granted access to any sent document rather than the one specific link, so someone technical could have listed contracts and questionnaires belonging to other studios, and in the case of contracts, altered them. The same applied to booking availability, booking page locations and intake questions, and your booking email templates, which were readable across every studio. Those blanket rules are gone. Opening and signing a contract, submitting a questionnaire, and the public booking pages all work exactly as before (they never relied on those rules).
[0.7.0]. 2026-07-14
Added
See and stop a running chase, and attach sets from the builder. A questionnaire or contract being chased shows a status line on its page ("Standard chase · 1 sent · next nudge in 4 days · stops when submitted") with a Stop button that halts the nudges without touching the item. The reminder-set builder gains its second tab, "Apply it to a workflow step": your workflows' questionnaire and contract steps listed with one-click attach, showing which set already chases each step and pointing out steps that still need a due date.
Reminders now actually chase. The reminder engine is live: attached sets nudge the client on schedule (counted from the item's due, sent, or event date), during daytime hours in your timezone, and stop by themselves the moment the questionnaire is submitted or the contract is signed. Private steps arrive as notifications to you ("still not done, give them a quick call"), "also notify me when this goes out" gives you a quiet heads-up per nudge, and "when they complete it, notify me" tells you the moment the chase ends because they did the thing. Three new rows appear under Settings, Notifications so you control where each of those lands. Emails to a client who has unsubscribed or hard-bounced are held back automatically, text-message steps wait quietly until SMS is connected, and a chase never sends more than one nudge an hour.
Attach a reminder set to anything you send. The workflow step editor (both in Settings and on a job) gains a "Chase it for you?" picker on questionnaire and contract steps, right under the due date, and the same picker appears in the one-off send dialogs on a questionnaire or contract page. When the item goes out, its chase starts counting from the date the set is built on; a step's saved card shows the attached set next to its due tag. Reminders need a due date, so the picker stays off until you set one. The actual nudge emails start with the next slice.
Reminders: build reusable "chase until it's done" sets. Settings gains a Reminders page in the Templates group: build a named ladder of nudges counted from a date (7 days before it's due, on the day, 3 days after), each step aimed at the client (an email you write, with tokens for their name, the thing being chased, its due date and link; text messages can be saved for when SMS is connected) or privately at you ("still not done, give them a quick call"). Client steps can quietly notify you when they go out, and a set can notify you the moment the client completes the thing. Sets can be archived and restored, and the list shows where each one is attached. Attaching them to what you send, and the sending itself, arrive in the next slices; nothing chases yet.
Reminders foundation (not visible yet). The data model and scheduling core for reusable "chase until it's done" reminder sets landed: sets you'll build under Settings, and the running chases they mint when something goes out with a due date. Nothing sends yet; the pages, the attach controls, and the sender arrive in the next slices.
Due dates on the questionnaires and contracts you send. A questionnaire or contract can now carry a due date, whether it goes out as a workflow step or you send it on its own from its page (where you can also pick a fixed date). Set it a number of days, weeks or months before the event or after it's sent. It resolves to a real date for each job (shown with its weekday) and is saved onto the item when it sends. You can drop a "Due date" token into the step's email, and the client also sees "Due..." on the item in their Client Lounge. On your side it shows on the dashboard's what's-next list and on the job's Client Lounge card, and an unsigned or unfilled item reads as overdue once its due date has passed. Reminders will count from this date. Invoices and quotes keep their own existing dates.
Payment receipts now carry the invoice PDF and a single Client Lounge link. When a client pays, the receipt email attaches a copy of the invoice as a PDF (as it stands after that payment), so they have it in their inbox without clicking through, and it links straight to the Payments section of their Client Lounge. The subject, the summary table, and the "Paid in full. Thank you!" line are unchanged. If the PDF can't be produced for any reason, the receipt still sends without it.
Changed
The Client Tracker loads faster. Its data (your leads, job types, pipeline stages, archived count) now loads in one parallel batch instead of one query after another, cutting the wait to show the page.
Public pages load lighter. Your marketing, sign-in, and shared client links (portals, invoices, quotes, questionnaires, contracts, booking pages) no longer download the ~450KB icon font or the ~550KB session-replay bundle that only the app itself needs, so they start faster, especially on mobile. Nothing changes about how the app or those pages look or behave.
The due-date chooser shows every option's date at once. When picking when a questionnaire or contract is due, each choice now shows the real date it would land on (for example "Before the event" and "After sending" side by side), so you can compare before you pick instead of clicking through them. The little number and unit controls also line up at the same height now.
The due-date choices read the way they were designed. A saved workflow step now shows its due date on the step row (for example "Due 1 month before the event"), the options explain themselves in your own words ("1 month before their wedding day", using your Vocabulary event name; "2 weeks from the day this step fires" on a step, "from today" on a one-off send), and the one-off send dialog notes that the Client Lounge shows the due date too.
Fixed
Money and sending problems now always raise an internal alarm. About thirty spots where a payment follow-up, a workflow send, a reminder nudge, a booking win, or an invoice creation could fail with only a note in the server logs now also alert our error monitoring, so a quiet failure gets noticed and fixed instead of waiting for someone to stumble on it.
Client emails, automated documents, and receipts are protected against behind-the-scenes hiccups. A database stumble can no longer make a composed email send with broken personalisation or a missing attachment (it now holds and says "try again"), can no longer cause an automation step to create a duplicate questionnaire or contract or break a client's existing document link, can no longer create duplicate contact cards, and can no longer send a payment receipt claiming the client still owes money right after they paid (the receipt simply waits). Anything that quietly degrades instead of failing now raises an internal alarm.
Online bookings are protected against behind-the-scenes hiccups. If the database stumbles while a client books a call, the page now says "please try again" instead of quietly skipping your required questions or the location choice, checking the time slot against the wrong timezone, or (worst case) saving a booking that never appears in your pipeline. And after a booking saves, anything that fails to follow it (your calendar event, the confirmation email's custom wording, your "new booking" email) now raises an internal alarm instead of failing silently.
Accepting a quote is now protected against behind-the-scenes hiccups. If the database stumbles at the moment a client accepts a quote, the page now says "please try again" instead of wrongly claiming the quote doesn't exist, quietly skipping safety checks, or (worst case) knocking an in-production job back to just-booked. And after an acceptance goes through, anything that fails to follow it (the invoice's payment installments, the job's updated value, the "you got a booking" alert, retiring the older quotes) now raises an internal alarm instead of failing silently, so nothing is quietly missing from a booking.
The column switcher works on an enquiry page now. The 3-columns / 2-columns toggle at the top of an enquiry used to do nothing; it now switches the layout the same way it does on a job.
Website enquiries now land in your pipeline properly from the moment they arrive. Leads coming in through your website form (or Zapier, Make, and the like) used to be created without a pipeline stage, so they only showed on the board through a fallback and could drift out of place. New website leads now start in your New Enquiry column straight away, and the handful of existing leads that arrived without a stage have been placed in the right column for their status.
Dragging a card somewhere it can't go now explains itself instead of breaking the board. Dropping an enquiry onto a job column used to crash the whole board page; dragging a job backwards used to look like it worked until a reload. Now an invalid drop never moves the card and shows the reason right away ("Book this enquiry first...", "This is a booked job. Use the job page..."), a refused or failed move visibly snaps the card back, and dropping anything on the Booked column explains that booking happens by accepting a quote or marking it booked, rather than silently doing nothing.
Receipts keep their cents. A $2.20 payment emailed a receipt saying "$2"; receipt subjects and amounts now always show exact amounts.
Two small due-date layout fixes. In the narrow workflow side panel, the example date no longer sits on top of the option's wrapped text (it moves to its own line); and a long "due..." tag on the job's Client Lounge card no longer squeezes the row's name out of view (it trims with a hover tooltip instead).
The database stopped re-checking who you are for every single row. The permission rule on most tables re-ran the "which workspace is this user in?" check once per row it returned; it now runs once per query. Together with new indexes on the busiest lookups (contacts on leads and clients, invoices by job, and reminder chases), lists over big datasets get faster and the database works far less per click.
Every save and send got a little quicker, and the dashboard stopped re-checking finished setup. Each action was double-checking your login with a second round-trip that the page had already done; it now reuses the first check. And once your setup checklist reads fully complete, Compass remembers that instead of re-counting your templates, workflows and packages on every single page load.
Money paths no longer trust a failed database read. A handful of payment-critical lookups treated a momentary database error the same as "nothing found", which in the worst cases could have re-marked a paid invoice as unpaid (and then reminded a client who had paid), double-recorded a replayed card payment, or silently dropped a refund so the invoice stayed marked paid. Those paths now stop and retry instead: Stripe's webhook re-delivers, the invoice-reminder run fails loudly (it also now reports its health like every other background job), a website enquiry hitting a database blip gets "try again shortly" instead of "unauthorized", and an email whose do-not-send check can't be read is held rather than sent.
The free tools can now show up on Google, and the embeddable contact form embeds again. The Waypoint calculator and the public roadmap were quietly marked "do not index", so search engines skipped the exact pages meant to bring people in; that flag is gone. And a blanket security header was blocking the contact form from loading inside other websites, breaking its embed feature; the form can now be iframed anywhere while every other page keeps its clickjacking protection.
Pages open much faster. The app's server code now runs in the same region as its database (they were on opposite sides of the Pacific, so every lookup a page made added roughly a quarter of a second, and a questionnaire page took around three seconds to open). The questionnaire and contract pages also fetch their details in one combined trip instead of one after another. Public pages measured 3 to 6 times faster to first byte after the move.
A workflow template now remembers the due dates you set on its steps. Setting "When is it due?" on a questionnaire or contract step in the Settings workflow builder looked saved but was silently dropped when the workflow was stored, so it never reached the steps that send. Due dates set on a job's own workflow were unaffected. Template due dates now save properly.
Long email addresses stay inside the Contact card. On a client's page, a very long email (or any long unbroken value) now wraps within the Contact panel instead of spilling past the card's right edge.
The "Send by email" button explains itself when it can't send. On a questionnaire or contract page with no client email on file, the button used to sit greyed out with only a hover tooltip saying why, which read as broken. It now shows a visible note underneath, "Add a client email first, then you can send", linking straight to the client so you can fix it. And if the client's email lives on their contact card rather than the older client record (as happens for migrated clients), the button and the send now find it there, so it no longer disables when an address actually exists.
The workflow step menu and its Snooze options now open in the right place. On a job's workflow, the per-step "..." menu and the "Snooze" option (from the menu or the what's-next bar) could open offset, overlapping, or too wide. They now use the same anchored popover as the rest of the app, so they open pinned under the button you clicked, stay within the screen, and flip above when there isn't room below.
The board's All tab keeps your stages in phase order. On the All tab, stage columns are now grouped by phase (your enquiry stages first, then your job stages) and ordered within each phase, so an enquiry stage can't appear after a job stage like Delivered. The Enquiries and Jobs tabs are unchanged.
The "Something snapped" page's "Try again" now actually recovers, and moving a card confirms it worked. If your open tab was running an older build after an update, an action could fail with a "Failed to fetch" style error, and the "Try again" button just re-ran the same failing step, so it never recovered (only a manual refresh did). "Try again" now reloads the page properly, which picks up the current version and recovers. Separately, dragging a card to a new column on the board now shows a brief "Moved to..." confirmation, so a move that saved no longer looks like nothing happened.
Moving a booked job through its stages now works from both the board and the job page, and they agree. Dragging a booked job's card from Booked into In production or Delivered used to be rejected ("Could not move that record"), and the job page's "Move to" buttons changed the status but left the card sitting under Booked on the board. Now a single shared rule moves the status and the board column together, whichever way you do it, so the board always reflects where the job actually is. Dragging a booked job back into the enquiry pipeline or an off-ramp is still refused (cancelling or undoing a booking stays a deliberate action on the job page). The job page's "Move to" buttons now read your own stage names (for example "Delivered" instead of a generic "Completed"), so they match the board columns.
Permanently deleting a protected invoice no longer shows an error page. In the Trash, "Delete forever" on an invoice that has a recorded payment now shows a plain message explaining it stays on record (and leaves it in the Trash, still restorable), instead of dropping you on the error screen. Those invoices are financial history and are kept on purpose; the automatic 30-day trash cleanup already skips them.
Archiving a quote now lets you delete the client, like the message says. When a client had an archived quote (or invoice, contract or questionnaire), deleting the client was still blocked even though the on-screen note says to "delete or archive those first". Archiving one now clears it from the block, so the note is true and you are not left stuck with a sent quote that has no delete button of its own. Paid invoices still protect a client from being permanently purged, as before.
Screens update in place instead of waiting for a reload. A handful of spots changed something in the background but left the screen looking the same until you refreshed the page. Now they update straight away: archiving or restoring a discount, adding, deleting, archiving or restoring a board stage (including the Undo), attaching or removing a workflow on an enquiry, and switching the board between the All and Jobs tabs. Removing a payment from an invoice now drops it (and re-figures the balance) on the spot, and the invoice Delete button shows "Deleting…" so you can tell the click landed.
Security
Sign-in attempt limits can no longer be dodged. The caps on wrong-password, two-factor-code, and portal-email attempts now count against the account itself in shared storage, so an attacker can't reset the counter by switching networks. It closes a gap where the limit was tracked per server and per address, which a determined attacker could sidestep.
Abuse throttling now identifies visitors by their true network address. The limits that slow down sign-in and other sensitive endpoints now read the client address from the platform's trusted header instead of one a request could fake, so the throttles can't be sidestepped by spoofing.
Passkey sign-in now always confirms it's really you. Because signing in with a passkey counts as your second factor, it now requires the fingerprint, face, or device PIN check every time (not just presence). Everyday passkeys (Face ID, Touch ID, Windows Hello) already do this, so nothing changes for you; if a key can't do that check, you'll get a clear prompt to sign in with your password and 2FA code instead.
Search terms are cleaned consistently everywhere. The text you (or the AI assistant) type into a search is now scrubbed through one shared routine before it hits the database, so special characters can't skew the results. The assistant's client search had been missing this step; it's fixed, and three slightly different copies of the cleanup were unified into one.
Contracts and signing pages now use a proper allowlist to clean their content. The formatted text in a contract (which is shown on the public signing page and in your client portal) is now filtered through a real, industry-standard HTML sanitizer that keeps only known-safe formatting, links, images and icons and discards everything else, instead of the older pattern-matching approach. Your contracts and emails look exactly the same; the change only hardens the public pages against a crafted body.
Workspace isolation is now enforced by the build, not just by convention. A new automated check makes sure every behind-the-scenes query that skips the usual per-account guardrails still restricts itself to a single account's data. It also added an extra account check to a few internal file and reminder operations as belt-and-braces. No change you'll see; it closes the door on a whole class of "wrong account's data" mistakes before they can ship.
[0.6.0]. 2026-07-08
Added
The enquiry page catches up to the job cockpit's people and workflow controls. The enquiry view now uses the job page's People card (person chips with per-record labels like "Planner" or "Mum", and "Make main contact" right there), the collapse-all-phases control on the workflow card, and the same amber page-level "next up" bar under the header instead of the old blue next-action banner. One more step towards the enquiry and job views feeling like one page.
One address per client record, for its whole life. Every enquiry and job now lives at a single web address (getcompass.studio/hub/...) that stays the same from first enquiry to delivered job. Before, a record's link changed when it got booked (enquiries and jobs had separate addresses), so a saved link could point at the wrong view. Old links and bookmarks still work; they simply forward to the new address. Copy-link buttons, search results, calendar entries, email notifications and the tracker all hand out the new address now.
The enquiry view now rides the same cockpit as your jobs. Opening an enquiry gives you the job page's layout system: the same collapsible section cards (serif titles, one consistent chrome), the 3-column or 2-column toggle in the header, and the running activity journal tucked under the workflow in the centre column instead of floating below the page. Everything you had is still there (details, portal link, recipients, custom fields, quotes, invoices, contracts, questionnaires, scheduled emails, portal files); it just reads like one app whether you are looking at an enquiry or a job. This retires the last of the old page layout.
Your board now follows a job past "Booked", too. Board stages gains a Job stages section: after an enquiry is booked it moves through your job columns, seeded with "In production" and "Delivered", right up to completion. They show under the Jobs tab (and All), each with its own icon, colour and description, and you can add, rename, reorder, archive or delete them just like your enquiry stages. "Won" stays the reserved booked pivot (rename only). "Delivered" is simply a friendly label over the existing Completed status, so your reports, archiving and filters are unchanged. Booked work that used to have nowhere to sit on the board now has a home.
Make your board your own: name, colour and shape your stages. Settings now has a Board stages page where you can add, rename, restyle and reorder the columns of your enquiry board, each with its own icon, colour and a one-line description. Add a stage from the section you want it in, drag the handle to reorder, and archive one you have stopped using (it leaves the board but its history stays in your reports, and you can restore it any time). If a stage still has records in it, Compass asks where to move them first, so nothing gets stranded. The four built-in exits and pivots, Won, Lost, Cold and On hold, can be renamed and restyled but not removed, and you can add your own off-ramps (like "Ghosted" or "Postponed") that count as either Lost or just parked, so your win and loss reporting stays honest. Cold and On hold are now proper, renameable stages too.
Change a workflow step's type without rebuilding it. The Edit step window on a job now has an Action selector, so you can turn a to-do into a send-email (or a questionnaire, contract or invoice) and back, right there. Switch to a send type and its template, recipients and sending options appear; switch away and they clear. No more deleting and re-adding a step just to change what it does.
See your contacts as people, not just client records. A new People view on the Contacts page (the Clients / People toggle by the title) lists every individual person across your enquiries and jobs, each their own contact, with their email, phone, any company, and the work they are linked to (and their role on it). The Clients view is unchanged; this is a second lens on the same data.
Tell Compass who you work with. A new setup step, and a Settings, Client types page, let you say whether you work with solo clients, couples, groups or companies, with a live preview of how a new enquiry will start for each. It sets the defaults only; you can always add or remove people on any enquiry. This is the first piece of the new people-first enquiry form: it is saved and previewed now, and shapes the form as that lands.
Finishing a quote or invoice takes you back to the job. After you build a quote or create an invoice that started from a job, saving now returns you to that job, with the new document's row briefly highlighted in the Client Lounge so you can see it landed, instead of leaving you on the enquiry view or a document detail page. Cancelling or going back does the same. Quotes and invoices that belong to an open enquiry still return to the enquiry, and standalone ones to their list, so nothing loses its way home.
Invoicing from a job stops re-asking who the client is. When you create an invoice from a job, the Client section now shows that client locked in, taken straight from the job, instead of blank-looking editable name, email and address boxes you have to eyeball. Need to bill a company or a different name for this one invoice? An Edit bill-to button reveals the fields. Creating an invoice straight from a client page is unchanged (still fully editable). Its Cancel already returned you to the job, and still does.
Starting a quote from a job no longer sends you on a detour. The Quote quick-add on a job's Client Lounge now opens a small in-context dialog (pick a template, name it) and creates the draft right there, already tied to that client and job, then drops you straight into the builder. No more bouncing to a separate page that asks all over again which client the quote is for, and Cancel simply closes and leaves you on the job instead of dumping you on the quotes list. It now matches how the Contract and Questionnaire buttons already work, one consistent way to create anything from a job.
Make anyone on a job the main contact, and label people your way. A person's menu on the job now has "Make main contact": it moves your automated emails, the client portal, and the default bill-to to them, and the person who used to be main stays on the job and keeps getting emails (nothing goes quiet behind your back). A clear confirmation spells all of that out first. You can also give any extra person a label that fits the job, "Planner", "Partner", "Mum", shown on their chip in place of the plain role; it is remembered per job, so the same person can be "Planner" on one wedding and the couple on their own.
Changed
One consistent "New enquiry" everywhere, and it knows your existing clients. The pop-up box is gone; every "+ New enquiry" button (the enquiries list, the client tracker, and a client's profile) now opens the full people-first page. Starting one from a client's profile arrives pre-filled for that client and tied to them (with a "For
" tag), and Cancel takes you back where you came from. Starting a blank one, as you type the first person's name, Compass suggests matching existing clients (" . · existing client"), and picking one fills them in and links the enquiry to that client, so you never create an accidental duplicate. Two small niggles fixed along the way: switching to a single-client shape now clears an empty second-person card, and turning off your last client type now explains why it can't. Promoting someone to main contact re-titles the record to lead with them. When you make a different person the main contact, an auto-named record like "Alex & Jordan" now reads "Jordan & Alex". A name you typed yourself is left untouched.
Creating a new enquiry is faster and never looks stuck. The New enquiry page now does its checks in parallel, so it saves and opens the new enquiry noticeably quicker. And if the connection hiccups on save, you get a clear "it may already be there, check your list before retrying" message instead of a button that sits on "Creating…" forever (so you never accidentally create a duplicate).
Every person is now their own contact under the hood. Each individual's name, phone and second inbox live on their own contact record across enquiries, jobs and clients, instead of being packed into the old two-names-in-one-record fields. Everything reads and sends exactly as before; this is the groundwork that lets a person be reused across jobs and keeps couples, groups and companies tidy.
A person's second email now works the same on every send. A client's optional second inbox is now taken from their contact for every automated and manual send, quotes, invoices, contracts, questionnaires and payment reminders alike, so the billing side matches the enquiry side. For almost everyone nothing changes; if someone had a second inbox on their enquiry but not their billing record, their billing emails now copy it too, one consistent person, one set of addresses.
Contracts and questionnaires send you back to the job too. Backing out of a contract or questionnaire that belongs to a booked job now returns you to that job's page (not the older enquiry view), matching quotes and invoices, so all four documents behave the same way when you're done with them.
The workflow card now matches its blueprint. Phases wear their proper coloured containers: a soft tinted header with the phase name, an always-visible progress pill ("2 of 3", "3 done"), and a bold colour rail down the left edge. The "what's next" bar turns warm amber (red now only ever means something needs rescuing), reads in two lines with a clear NEXT ACTION eyebrow, and its Snooze became a neat clock button beside the arrow-marked do-it button. Step timing now reads as a tidy chip, and step type markers use one consistent icon language everywhere (contracts amber, invoices as receipts).
The People and Activity cards on the job page now match the cockpit design. People sit in airy rows (name, contact details, loop switch, menu) that adapt to the card's width: a roomy card lays each person out on one line with the switch label visible, a narrow card stacks the details with a short explainer of what the switches do. The Main chip wears its indigo tint, a "+ Add" chip joins the card header, and the "Add person" row anchors the foot of the list. On Activity, the separate Email / Text / Note / Log-a-call buttons became one tidy strip: mail and message icons open the same composers as before, the note icon flips between logging a note and logging a call, and you type straight into the strip and hit the arrow (or Enter) to save. Active filter chips are now outlined rather than filled solid, and a small note under the feed explains that connected tools and AI assistants can post here too.
The job cockpit's client column got a tidy-up. The separate Invoices and Contracts cards folded into the Client Lounge card, so everything the client sees lives in one place; a "+ Add" chip (and friendly quick-add chips when the card is empty) starts a new quote, contract, questionnaire, invoice or file from right there. Deliverables grew up too: each row now shows its type icon, due date with a health dot, and a plain-words status pill (On track, Due soon, Overdue, Done), with the worst case rolled up next to the card title. Both cards greet an empty job with a warm hint instead of a grey sentence, and an event date with no clashes now reads green with a reassuring "No date clashes on this day" tooltip.
The instant-save feel now covers your template and settings screens. The ghost-row treatment that debuted on Discounts (hit Save, the dialog closes, your new item appears immediately with a soft shimmer, then settles with a gentle highlight) now runs on Email templates, Contract templates, Questionnaire templates, Booking pages (event types and availability schedules), Deliverables and SMS message templates. A failed save turns into a clear message with Retry and Dismiss instead of vanishing. Screens that jump you straight into an editor after creating (Quote & invoice templates, Workflows, Contact forms) already give instant feedback by landing you there, so they stay as they are. (Note for the merger: a sibling batch applies the same standard elsewhere, so this entry may need a small merge.)
Instant-create lands on the job page and workflows too. Adding a workflow step on a job now closes the dialog immediately and shows the step softly shimmering in the list while it saves; adding a deliverable does the same on the Deliverables card. Both settle with a gentle highlight when confirmed, and a failed save stays visible with a Retry button.
Adding things in Settings feels instant now, everywhere. The instant-create feel that landed on Discounts now covers the simple settings lists: Tax rates, Regions, Lead sources, Payment methods, Payment schedules, Marketing & business costs, Job types, and Packages & products (add-ons included). Hit Save and the dialog closes straight away, your new entry appears in the list with a soft shimmer while it saves, then settles with a gentle highlight and scrolls into view. On Packages & products the category group even opens itself so you can see the new item land. If a save fails, the row becomes a clear message with Retry and Dismiss instead of quietly vanishing.
Saving something new feels instant now. Creating an item no longer shows a save, a blank list, and then the item popping in seconds later. The moment you hit Save the dialog closes and your new item appears right where it will live, softly shimmering while it saves, then settling with a gentle highlight so your eye lands on it. If the save fails, the row turns into a clear message with a Retry button instead of quietly disappearing. Live on the Discounts page first, rolling out to every create screen. Also fixed there: the Type and Amount boxes now sit at the same height.
The Packages & products page is now tidy. Categories fold up into neat headers with counts (like "Albums (12)"), so the page reads at a glance instead of taking five screens to scroll; click a header to open it. A search box at the top finds any package or add-on instantly by name or description, and archived items now sit out of the way behind a "Show archived" toggle until you want them.
Email drafts now float, minimise, and survive. The "Email client" composer and the workflow step send window open as floating panels you can drag aside, minimise to a pill in the bottom corner (Gmail style), and come back to later: what you typed stays put, even if you visit another page first. Behind the scenes they now share one composer, so templates, tokens, attachments and scheduling behave identically everywhere. Escape minimises instead of throwing your draft away, and closing a draft with real content asks first.
Discounts moved into their own settings page. Your saved discounts now live at Settings, Discounts, alongside the other template types in the Templates group, instead of sharing the Packages & products page. Same library, same one-click apply on quotes and invoices, just easier to find, with each discount on a proper row (name, amount off, the client-visible reason) and archived ones dimmed at the bottom. The Packages & products page is lighter for it.
Workflows now start armed, with a one-tap safety catch. Attaching a workflow (by hand, automatically on a new enquiry, or via a connected AI assistant) no longer parks it paused. Instead, the very first automated client email on each job politely waits for your go-ahead: you get a notification, the job appears under "Waiting for your go-ahead" on the To send page, and the workflow card shows an Approve and send button. One tap (or sending any step yourself) and everything after flows on its own. The pause button stays as a control whenever you want it.
Overdue workflow steps now wait for your decision instead of being quietly skipped. ANY step that goes overdue (to-do tasks included, per your call) holds ALL automatic sending on that job until you deal with every overdue step: tick it off, send it, skip it, or change its date. An overdue automatic send also switches itself to manual so nothing blasts out late. The workflow card explains exactly what is holding things up. And a step that could not send because the contact had no email address now simply waits and sends itself once an email is added, instead of being written off.
Added
The job cockpit is complete. The job page's makeover lands its final pieces. A Client Lounge card shows exactly what your client sees, one row per room (quote, contract, questionnaires, invoices, files) with its live status; the armchair icon copies their Lounge link and the eye opens their view. Deliverables now wear a little health dot per item (green on track, amber due soon, red overdue) with a roll-up dot in the header, plus a shortcut to your Deliverables settings. The workflow's "what's next" bar now sits right under the job title where you land, workflow phases fold up (each on its own, or all at once from the header), and the whole three-column layout is the job page from here on.
The job page gains an Activity card. The running journal now lives on the job cockpit too: every email signal (sent, delivered, opened, clicked, bounced), note, call and system change, grouped by day, exactly as the enquiry view tells it. A filter icon narrows the feed (Emails, Notes, System, Other), a Compact switch shrinks it to one-liners for long histories, and the strip on top acts: Email opens the floating composer, Text sends an SMS when SMS is switched on, and Note or Log a call capture a quick entry without leaving the page.
The job page gains a People card. Everyone on a job now lives in one place in the left rail: your main contact (always emailed, clearly marked) and every extra person, each with a simple switch that keeps them in the loop on client emails. Edit anyone's details, add someone new, or remove a person right from the card, and copy any email or phone with one click. The little people icon in the header copies every in-the-loop address at once, ready to paste into an email.
, tidy link previews for your booking and invoice pages. When you (or a client) share a Compass link, it now unfurls with a clean, studio-branded card instead of a bare URL. Booking pages show the meeting name and your studio; invoice and booking-management links show your studio name with a neutral label. Sensitive details are never in the preview: no amounts, no client names, no document contents, just enough to look professional in a chat or email.
, catch enquiries before they go cold. An open enquiry you haven't touched in two weeks now wears an amber "Going cold" badge on the Client Tracker (board and list), so leads quietly drifting surface before they slip away. Only actively-worked enquiries flag: anything you've deliberately parked (cold, on hold), booked, or lost stays quiet. Hover the badge to see how long it's been silent.
, see why you lose enquiries. Reports gains a "Why we lose" chart: your lost enquiries grouped by the reason you recorded on each, so the pattern (budget, went with another vendor, date unavailable) is finally visible at a glance. The "Why was this lost?" box on a lost enquiry now suggests your own past reasons first, so they stay consistent and the chart stays tidy. Enquiries you marked lost without a reason show honestly as "Not recorded".
(foundation). people become real records. Under the hood, Compass now has a proper Contact for each PERSON: their own name, email, phone and pronouns, instead of two people squeezed into one record's fields. Every existing enquiry has been linked to its main contact, partners are preserved as their own people, and the extra recipients you'd added are matched up too. Nothing changes on screen yet (this is the groundwork slice); the new Contacts surfaces, the who's-in-the-loop wiring, and clientele presets (single, couple, group, company) build on top next. Nothing was removed: the old fields keep working until the final owner-approved switch-over.
, payment receipts, sent for you. When a client pays by card, they now get a warm receipt email straight away: the amount (card fee itemised when there is one), the invoice number, and the balance remaining (or "Paid in full. Thank you!"). Recording a payment by hand offers the same: the Record-a-payment window has an "Email the client a receipt" tick, on by default, easy to untick when you're backfilling old records. A receipt that fails to send never gets in the way of the payment being recorded, and receipts are transactional, so they always reach clients who've opted out of general mail.
, your bank deposits, finally explained. A new Payouts tab under Money lists every deposit Stripe sends to your bank, and clicking one unpacks exactly what's inside: each client, their invoice (linked), the gross amount, the Stripe fee, and the net, footing to the deposit to the cent. Refunds and anything not taken through Compass are shown honestly rather than hidden. Each payout downloads as a CSV for your accountant, and a note on the page shows how to set the wording that appears on your bank statement (that lives in your own Stripe settings, one click away).
(part 3, feature complete). discounts on invoices. Invoices catch up with quotes: add one or several labelled discounts to any invoice, straight from your saved discounts library or typed ad hoc, on top of the per-line percentage that already existed. The client sees each saving itemised on their invoice page and the PDF, right under the subtotal, so the numbers always visibly add up. Tax recomputes on the discounted amount, the combined discount can never push an invoice below zero, and editing a scheduled invoice's discount re-balances the unpaid instalments through the same safe path as any other edit (paid money is never touched). That completes the reusable-discounts feature: library, multi-discount quotes, and invoice discounts.
(part 2). several discounts on one quote, each with its own line. A quote is no longer limited to a single discount: stack as many as apply (say, a returning-client thank-you plus an included-travel reduction), each with its own client-visible label. The client sees every saving itemised on the quote page, the Client Lounge (with the summed "You are saving" flourish intact), and the PDF; the editor previews each row's exact amount live and they always add up to the totals line. Percent discounts each apply to the subtotal (they don't compound), the combined discount can never push a quote below zero, and accepting a quote still carries the full discount onto the auto-invoice exactly as before. Existing quotes with their one discount keep working untouched.
(part 1). a discounts library. Settings > Packages & products gains a Discounts section: save the reductions you reach for often (returning client, included travel, referral thank-you) as named discounts, percent or a fixed amount, each with a default client-visible reason. On any draft quote, "Apply a saved discount" fills the discount in one click, reason and all, instead of retyping it. Editing or archiving a saved discount never changes documents it was already applied to. Coming next in this feature: several labelled discounts on one quote, and discounts on invoices.
Drag and drop in the workflow builder. Steps now carry a grip handle: drag one to reorder it, drop it on another phase's header (or at a phase's end) to move it across phases, and drag a phase's own grip to reorder whole phases. The arrow buttons and the row menu stay for keyboard use. Event-date timing also got friendlier: instead of typing a negative number for after-the-event steps, you now pick days plus a plain "before / after" the event date. And the starter workflow's "Confirm final details" step, which was quietly set to fire a week AFTER the event, now correctly sits a week before (existing seeded copies fixed too).
, archive a finished job, for keeps. A completed job can now be archived from its page: it moves out of your active lists (Client tracker, dashboards, Money, document lists) into a new Archived filter on the Client tracker, together with its quotes, contracts, questionnaires and invoices. Nothing is deleted and nothing expires: unlike the Trash's 30 days, the archive keeps everything forever, for your records, reorders and tax. The job keeps its status, still counts in your Reports history, stops sending any reminders or automated emails, and one click on its page unarchives the lot. Connected AI assistants' list tools skip archived records too (searching still finds them).
, the workflow builder gets a full page of its own. Editing a workflow template no longer squeezes into a small dialog. "Edit" (or "+ New workflow") now opens a proper builder page: your coloured, collapsible phases and steps on the left, and a step editor that opens beside them on desktop (a full-screen sheet on a phone) when you click a step. Steps read at a glance too, each row leads with a little picture matched to what the step is about, says its timing in plain words ("2 days after quote sent", "30 days before event"), and carries a colour-coded marker for what kind of step it is, the same language the job page's workflow card speaks. Also fixed on the way through: a step timed against the event date used to DESCRIBE itself backwards ("70 days after event" when it actually falls 70 days before); the dates it ran on were always right, only the label lied.
Choose who receives any workflow send. Every send step in a workflow (email, questionnaire, contract and invoice alike) now carries a Recipients choice: "Everyone in the loop" (the default, everyone you've included in automation on that job) or "Main contact only" (just your main contact, their second inbox included). Invoices had this already; it now works on all four, in the Settings workflow editor, when editing a step on a job, and for connected AI assistants. Manual sends respect it too: the send dialog pre-ticks only the main contact when that's the step's setting, and you can always tick people back on before sending.
The workflow now leads with "what's next". A highlighted bar at the top of the workflow card names the next step due and when, with two buttons: Snooze (move its date) and a do-it button that matches the step: a to-do ticks off, an email step opens the send dialog, an invoice step sends it (after the usual confirmation). No more scanning the whole list to find where you're up to. Appointment steps have their button too: they carry a date on the plan (deliberately no time, place or calendar invite, they're a marker of a meeting, not the meeting itself), so "Done" simply records it happened.
Add or reshape workflow steps right on the job. The workflow card now has "+ Add step": pick what kind (to-do, appointment, send an email, questionnaire, contract or invoice) and fill in a dialog tailored to that kind, with the step's name, phase, timing (relative to a milestone, or a fixed date), templates, and for sends the auto/manual choice and time of day. Every step's menu also gained "Edit step" with the same dialog. Changes apply to this job only; your workflow template in Settings stays untouched, and new automatic sends go through the same safety gates as everything else (the first-send go-ahead, overdue holds, pause).
Workflow steps now wear icons that tell you what they are. Each step in the workflow card leads with a little picture matched to what the step is about ("First phone call" gets a phone, "Send wedding-day questionnaire" a clipboard, "Sneak peek delivery" a photo), and you can click it to pick any icon you prefer for that step on that job. On the right edge, a colour-coded type marker shows at a glance whether a step is a to-do, an appointment, or sends an email, questionnaire, contract or invoice.
Move a workflow step's date without touching the plan. Every workflow step's menu now has "Change date": push it a day, three days, or a week later, or pick any date. The step keeps its place in its phase, and the moved date holds everywhere at once: the card, the automatic sender, and the reminder emails all follow it. "Back to the planned date" undoes the move. And a step whose email already went to the client now locks its tick: you can't accidentally mark a sent step "not done" (the menu explains why).
(part 2). clear your test data, or start completely fresh. A new Settings page, Test data & reset, with two clean-up actions. "Delete all test records" moves everything wearing the Test badge to the Trash in one click (documents included, restorable for 30 days). "Reset my data" clears every record for a true fresh start: enquiries, jobs, contacts and documents go to the Trash, and upcoming bookings are cancelled with their calendar events removed and nobody emailed. Your setup always survives: templates, workflows, packages, booking pages, branding and settings are never touched. Real money stays protected everywhere: any record holding a card payment is kept and reported until the payment is refunded in Stripe, and the reset asks you to type "reset" before it runs.
(part 1). test records that stay out of your numbers. You can now mark an enquiry or a contact as a test record: a checkbox when you create an enquiry (or later, in its edit form), and the same in a contact's edit dialog. Test records keep working exactly like real ones and stay visible in your lists wearing a vivid "Test" badge, but they never count toward your dashboard numbers, the Reports page, or the metrics a connected AI assistant reads. Creating a test enquiry also marks its brand-new contact as test (an existing contact is never flipped), and connected AI assistants can create and flag test records too. Coming next: one-click "delete all test records" and a full "reset my data", both from Settings.
The workflow now lives on the job page too. The job cockpit's centre column carries the same workflow card as the enquiry view: phases, step ticking, skip, pause, the first-send approval banner, overdue holds, and manual sends, all without hopping to the enquiry view of the same record. First slice of the cockpit workflow centrepiece; the elevated design treatment follows.
Fixed
The payouts page shows the exact cents again. Payout amounts were being rounded to whole dollars on screen (a $1,234.56 payout read $1,235), so the figures didn't match your bank statement; the CSV export was always exact. Both the payouts list and a payout's detail now show the precise amount, cents and all.
Your board stage counts don't double-count lost enquiries. On the Board stages settings page, every "counts as lost" exit (the built-in Lost plus any of your own, like "Ghosted") was showing the same lost enquiries, so a brand-new, never-used stage could read "1 lost" alongside the real Lost column. Each stage now counts only the records actually in it, with stage-less records landing under the built-in default for their status, so the numbers match your board.
A discounted quote now shows the same total everywhere, including the Client Lounge. When a quote had a discount, the quote room inside your client's Lounge quietly re-taxed the discounted amount and printed a total that was lower than the one on the accept page, the PDF, and the confirmation, so a client could see two different prices for the same quote. The Lounge now uses the exact same figures as every other surface (an $880 quote reads $880 there too), and its tax line is labelled with the amount added on top, not a misleading "included".
Accepting a quote keeps every named discount on the invoice. When a client accepted a quote, the invoice it created rolled all of your separate, labelled savings into one unlabelled lump, so the client's invoice no longer showed what each discount was for. The invoice now carries the same itemised discounts the quote did, each on its own line. The accepted-quote summary in your dashboard also lists those savings, so its numbers visibly add up instead of jumping from subtotal to a lower total with nothing to explain the gap.
Tax invoices print the correct GST rate. When an invoice had discounts, the GST line could read the wrong percentage (for example "GST (9%)" on a 10% invoice) because the rate was worked out against the pre-discount amount. The GST amount was always right; only the printed percentage was off. It now reads the rate off the discounted amount the GST was actually charged on, so a 10% invoice always reads 10%, on the invoice page and in the emailed copy.
Typing an existing client's email now offers them, and stray browser autofill is fenced out. On the New enquiry page, the "existing client" suggestions used to appear only while typing the name; they now appear while typing the email too, so pasting a known address links the right client with one click instead of doing nothing. The email and phone boxes also now tell the browser not to autofill them; that stops the browser's own saved-form guesses from dumping text into the name box (the "name and email squashed together" report), which was never Compass writing it.
The To-send page shows your queue again, and calendar sync is back. Two more surfaces were still asking the database for columns retired in the contact-model switch-over, and both failed silently: the To-send page came up empty, and the behind-the-scenes push of enquiry dates to your Google calendar quietly stopped. Both now ask only for current columns, so the send queue lists properly and calendar entries for enquiries sync again. A full sweep (code and database) confirmed no other surface still references the retired columns.
The icon and colour pickers now float cleanly above the settings card. Opening the icon picker (on a Job type or a Deliverable) used to show only a sliver of the grid, the card's rounded edge clipped it, which also made wedding icons look missing. And opening the colour palette pushed the row taller instead of floating over it. Both pickers now open in a small panel pinned right under the button you clicked, above everything else, and click anywhere outside to close. The icon starter set also gained wedding rings and a church.
You can archive a finished job again. When a job finished by its delivery date (rather than by a status change), the Archive button was hidden, so there was no way to tidy it away. Archive now appears for any completed job, whichever way it finished.
Closing an email draft no longer hides the "Discard this draft?" question behind the toolbar. When you closed a composer with unsaved writing, the formatting toolbar could paint over the confirmation, leaving it half-buried mid-panel. The confirmation now sits clearly on top, up near the close button where you just clicked.
The invoice PDF's columns no longer run together. On the invoice PDF the Qty, Unit price, Tax and Amount columns had lost their spacing, so the headers read as "QTYUNIT PRICETAX" and a line like "$5.00" and "10% incl." sat jammed against each other. Each numbered column now has a clear gap, in the header and the figures, so the invoice reads cleanly.
Every button now tells you it's working, a full sweep. A pass over the whole app found the last controls that sat silent for a few seconds after a click and gave each an instant acknowledgement: adding sample data on the dashboard (now reads "Adding sample leads…"), all eight "add a starter…" buttons in Settings (tax rate, packages, payment schedule, contract, questionnaire, workflow and email templates), creating a new quote/invoice template or contact form, saving invoice edits and "Save as template", deleting a contract or questionnaire, restarting the setup wizard, and the client-facing "Open my portal" button on the Client Lounge email gate. Each now disables itself and shows what it's doing the moment you click.
A missing page inside the app no longer wears the website's footer. Hitting a dead link while signed in (say, a record that was deleted) used to show the 404 with the marketing site's menu and footer stacked inside the app, two footers deep. The signed-in 404 now sits properly in the app shell and points you at your Dashboard, Client tracker and Contacts instead of the marketing pages.
The email-tracking webhook now accepts its secret only in the private header. The temporary query-string fallback from the switch-over is gone now that deliveries are confirmed flowing on the header path.
A trashed job's link now takes you to its record with a Restore button. Opening the job view of something sitting in the Trash used to dead-end (a 404, and in some browsers a broken page). It now lands on the enquiry view of the same record, which shows the "this is in the Trash" banner and one-click Restore.
A tab left open across an update now fixes itself. When Compass ships an update, a tab still running the old version could die at load with "This page couldn't load" and needed a manual refresh. The app now detects that failure the moment it happens and quietly reloads itself once to pick up the current version (with guards so a genuine error still shows instead of looping).
Restoring a job from the Trash now brings its documents back with it. Deleting a job sweeps its quotes, contracts, questionnaires, and invoices into the Trash; restoring it used to bring back only the job, stranding all of those in the Trash. Restore now reverses exactly what the delete took (anything you trashed separately stays put), from the Trash page, the record page, and connected AI assistants alike.
The delivery deadline is back on the job page, with honest labels. The deadline (and its health badge) lost its home when the old Jobs list was retired into the Client Tracker; it now shows in the job's details card. The badge also tells the truth: a past deadline reads "Overdue 3 days" instead of the old "Overdue soon".
Adding a deliverable acknowledges the click instantly. The Add button now flips to "Adding…" the moment you click, instead of sitting silent for a few seconds while it saved (which read as the button doing nothing).
Buttons now react to your mouse. Every button across the app shows a pointer cursor and a visible shade shift on hover (and a firmer press when clicked), so it's always clear something is clickable. Works on dark filled buttons and on link-style buttons (like the record peek's Open record) too. One global rule, applied to old and new surfaces alike.
[0.5.0]. 2026-07-03
Client-action notifications, the send-invoice workflow step, universal search, secondary contact emails, the online-booking correctness overhaul (the full calendar audit: server-side slot validation, double-booking protection at the database, timezone-correct day handling, Google sync fixes), the automated test suite gating every deploy, and a long run of correctness and security fixes from the launch-hardening program.
Added
You now hear about it the moment a client acts. Compass tells you (in-app and by email, following your notification preferences) the moment a client accepts a quote and books in, signs a contract, or makes a payment. The line on the client pages that says "the studio has been notified" is now actually true. A returning enquiry (someone who went quiet coming back through your website) pings you too, framed as "Returning enquiry from…", so you can jump on a warm lead.
Workflows can now send invoices. A workflow step can raise an invoice from one of your invoice templates and send it on its due date (or hold it for you to send manually), with an optional amount override and your choice of recipients.
A second email address for a contact. Some clients live in two inboxes. You can now add a secondary email to a contact or enquiry, and every automated email goes to both addresses.
Find anything from anywhere. Press Cmd-K (or click the search bar in the top nav) and type: contacts, jobs, quotes, invoices, pages, settings, and help articles all surface instantly, grouped and highlighted as you type, with full keyboard navigation. Three results per group with a view-all row when there are more, and present-safely mode keeps names and amounts masked in the results while you're screen-sharing.
Workflow phases in your colours. Each phase of a workflow template can now carry its own colour from the shared picker, and the workflow checklist wears it. Pick it right on the phase header in the workflow editor; the enquiry page then groups the checklist under coloured phase headings, so you can see at a glance where a job sits in its journey.
A safety net under the engine room. Compass now runs an automated test suite over its money math (quote totals, invoice discounts and instalments, card-fee gross-up, payment ledger), its job lifecycle rules, and its automation scheduling on every deploy; a failure blocks the release before it can reach you.
(6/6). drop an icon into your documents. The text editor now has an "insert icon" button (the same searchable Tabler picker) on quote and contract documents, so you can add a little visual flourish to what clients read on their web page. It's deliberately off in the email composer and email templates, because icon fonts don't render in email apps (they'd show as an empty box in the recipient's inbox).
(5/6). new jobs start with their deliverables filled in. When a quote is accepted and the enquiry becomes a booked job, its deliverables are now seeded automatically from the job type's template (with each due date worked out from the turnaround, e.g. "gallery, 6 weeks after the event"). If you've already set deliverables on that job, nothing is overwritten. Seeding is best-effort, so it never gets in the way of the booking.
(4/6). reusable deliverable templates per job type. New Settings, Templates, Deliverables page: set up the things you hand over for each kind of work (a Wedding gets Gallery, Album, Prints, Review; a Portrait gets its own set). Each deliverable has an icon, a colour, a turnaround window (e.g. "6 weeks after the event"), and toggles for showing it in the client portal and whether it carries a delivery link. There's an "All job types" group for defaults. New jobs will seed their deliverables from these (next slice), so you stop retyping them.
(2/6). pick an icon for your job types. Job types can now carry an icon, chosen from a searchable picker of the full Tabler icon set (type to search, hover to see a name). The icon shows in the Type column on the Client Tracker, tinted to the job type's colour. The picker is a shared component, reused next by deliverables and lead sources.
(1/6). the colour picker now names each colour. The picker used for Job Type colours is now a shared component, and hovering (or tapping) a swatch shows the colour's name (Indigo, Amber, Teal…). Same vibrant palette and custom-hex field as before, and it's built to slot in your Brand colours later. Reused next by workflow-phase colours.
, a "Re-enquired" badge on returning leads. When someone who went quiet (a parked cold or on-hold enquiry) comes back through your website, Compass already reopens their existing lead to New instead of creating a duplicate. Now that returning lead also wears a vivid orange ↩ Re-enquired badge on the Client Tracker (board card, list row, and record peek) so a strong buying signal stands out at a glance. The badge shows only while the lead is still open, and clears once it's booked or closed.
Changed
The Client tracker opens on the Board. The tracker used to land on the List view every time; it now opens on the Board (the view switch still remembers nothing per visit, it simply defaults to Board, and any view you pick stays in the URL so bookmarks keep working).
Contacts now lives at /contacts. The page's address matches its name, the header counts contacts, and every old /clients link or bookmark forwards automatically.
One name everywhere. The contacts page now matches its place in the navigation (Contacts), new workspaces talk about enquiries rather than leads out of the box, and a sweep of page titles and breadcrumbs now say where you actually are (no more doubled Compass suffixes or wedding-specific wording on neutral surfaces like Workflows and Import).
The job page got its cockpit bones. The job view now lays out as the new three-column cockpit (details and quick facts on the left, documents front and centre, notes and deliverables on the right) with collapsible cards, a column toggle that remembers your choice, a proper breadcrumb trail, and a one-click copy of the job's link. The deeper cockpit cards (workflow, people, activity) arrive next.
Availability schedules read as a tidy list. With more than one schedule, each now shows as a collapsed row (name, Default badge, and a day summary like "Mon, Tue, Wed, Thu, Fri") instead of every schedule's full week-grid being open at once. Click a row to expand and edit it; the only schedule stays open by default.
(part of). vibrant stage colours. The pipeline stage colours on the Client Tracker pills (board, list, record peek, cockpit) are now punchier and more saturated, matching the locked design-elevation direction: New reads as a vivid indigo, In conversation a vivid blue, In production a vivid purple (Won stays green; Completed, Lost, and parked statuses unchanged). The calendar's lead-status dots now read from the same single colour source (
STAGE_PILL_COLOR), so the tracker pills and the calendar can never drift apart.
Fixed
Client portal dates now match your calendar, not the server's. The "Accepted", "Submitted", "shared" and quote issued-on dates in the Client Lounge could show the previous day for late-evening actions (they took the date in UTC). They now show the date in your studio's timezone, the same fix contract signature dates got.
Small hardening tidy-ups. The Waypoint results-email address check now validates a real email shape instead of just looking for an @; and two scheduled jobs now share the standard constant-time secret comparison instead of carrying their own copies.
Moving or cancelling a booking now updates the right Google calendar. When your bookings write into a chosen destination calendar, a client's reschedule or cancellation used to try to update your account's default calendar instead, quietly failing, so the old event kept its old time and kept blocking the freed slot. Compass now remembers which calendar each booking's event was created on and updates that one.
Booking reminder emails can no longer be skipped by a slow scheduler. The 24-hour and 1-hour reminders used to fire only inside a tight 30-minute band; if the scheduled run came late (which happens routinely), the band was missed and that booking's reminder never went out. Reminders now catch up on anything due that hasn't been sent, while bookings made on short notice sensibly skip reminders (the confirmation email just arrived).
No-show follow-up emails now name the session correctly. The "we missed you" recovery email always said "session" because of a lookup against a misspelled table; it now uses the event type's real name.
A multi-day block in your Google or Apple calendar now blocks every day it covers. A Monday-to-Friday "away" event used to block Monday only; clients could book Tuesday through Friday right over your break. Any busy range (or long booking) now removes slots on every day it touches.
Buffer times now respect each event type's own settings. A booking used to be shielded by whatever buffer the event type being booked happened to have, instead of its own. Each booking now claims its own type's before/after buffer, and the gap between two bookings honours the larger of the two claims on it. Personal calendar events also no longer count toward your bookings-per-day cap (three private Google events used to read as "day fully booked"), though they still block their own time.
Booking over an unreadable calendar is now refused. If your connected Google or Apple calendar can't be read at the moment someone confirms a booking (an expired or revoked connection, an outage), the booking is politely refused with a try-again message instead of being taken blind, which could double-book you over an event Compass couldn't see. The slot picker itself still shows times when a calendar hiccups, so your booking page never goes blank.
Daylight-saving switch days no longer scramble the booking window. On the day clocks fall back, the 21-day window used to show the same date twice and silently drop the last day. Days are now walked by calendar date, immune to clock changes.
Cancelling a booking from your dashboard now tells the client and clears your Google Calendar. Marking an event booking cancelled (or deleting it) used to leave the client uninformed, so they showed up to cancelled meetings, and left the event sitting in Google Calendar where it kept blocking the freed slot. Both paths now remove the Google event and send the client the same cancellation email the self-serve cancel link sends (only for bookings that were still upcoming). Failures on these updates are also no longer silently ignored.
A no-show who rebooks is a real booking again. Rebooking from a no-show recovery email used to leave the booking marked no-show, so reminder emails never fired for the new time and your dashboard kept showing it as missed. Any reschedule now re-arms the booking: status back to scheduled, and its reminder emails set to fire fresh for the new time.
Booking pages now say whose timezone they're showing, and can show the visitor's. Both the public booking page and the reschedule page now carry a "Times are shown in Australia/Sydney time" note, and a visitor in another timezone gets a one-tap "Show in my time" toggle that relabels every slot in their own zone (with a weekday hint when their date differs from yours). The manage-booking page also spells out the booked time in the visitor's own timezone. Previously times carried no zone at all, so an overseas client could read your 10am as theirs.
The reschedule page now offers only the hours you actually opened for that event type. It used to mix together every availability schedule in the workspace, so a client moving a booking could be offered times from a different schedule entirely. It now resolves the event type's pinned schedule (or your default), exactly like the booking page.
Slot availability stays accurate for busy studios. The booking and reschedule pages fetched every booking ever taken when working out free slots; past the database's 1,000-row cap the list silently truncated, which would eventually let double bookings through at random. Both pages (and the new server-side gate) now fetch only the window that matters.
Your public booking page now double-checks every booking on the server. Submitting or rescheduling a booking now re-verifies, at the moment of saving, that the chosen time is genuinely one of your offered slots: inside your availability schedule, past your minimum notice, within the 21-day window, on the slot grid, under your per-day cap, clear of other bookings (with buffers) and clear of your connected Google and Apple calendars. Previously a stale page or a hand-crafted request could confirm a time you never offered, complete with calendar event and confirmation emails. Overnight double-booking is also closed at the database itself: two people racing for overlapping times can no longer both get in, and per-day caps and clash checks now count your day in your own timezone instead of UTC (which used to miss morning-hour overlaps for ahead-of-UTC studios like Sydney and Perth).
Contract signatures are now recorded first-come and shown in your timezone. Two people signing at the same moment can no longer overwrite each other, and a late-night signature no longer shows the previous day's date.
The next invoice number setting works again. Set it to 0500 and the next invoice is 0500 (then 0501). It acts as a jump-to number: it never goes backwards and never reuses an existing number, and the settings page now shows the real next number.
A partner's second signature now appears on the signed contract PDF and in your signature evidence, not just the client portal, so your legal record is complete. When a couple both sign in the client portal, the extra signer used to show only in the portal. Now they also appear beneath the primary signature on the downloadable signed PDF and in the studio dashboard's Signature evidence panel, with the same details (typed name, agreed-at, IP, browser).
You can now record a verbal yes on a choose-your-package quote. Soft-accept now lets you pick the package and add-ons the client chose, instead of dead-ending. On a Pick and Choose quote, the "Mark accepted (verbal yes)" dialog shows the same package radio and add-on toggles the client sees on their web page (defaulting to the recommended package, with any mandatory add-ons locked in), so the booking and invoice come out right. Fixed quotes keep the one-tap confirm.
Permanently deleting a contact can no longer destroy invoices that have real payments on them. A contact with paid, part-paid, or written-off invoices (or any invoice carrying a recorded payment) is kept as your financial record instead. This applies wherever a contact is purged: Delete forever in the Trash, Empty trash, and the automatic 30-day cleanup, which now leaves those contacts in the Trash rather than cascading their invoices away.
An accepted quote now titles its calendar event correctly. When a client accepted a quote and the enquiry became a booked job, its calendar event could stay labelled "(LEAD)" because that path skipped the calendar refresh. It now refreshes on acceptance, so the event moves onto the Jobs calendar with the right title straight away.
An extra quote accepted on a booked job now grows the job's value. Accepting an upsell or add-on quote on a job that's already booked used to leave the job's value untouched. The job value is now the sum of the accepted quotes, so the upsell is added on top (the first acceptance still sets the value as before).
The GST exclusive card-fee option now works as it says. The card fee has GST added on top (and remitted), instead of behaving the same as GST inclusive.
Automated emails can never double-send, even on an off day. The workflow auto-send engine now locks in each email before it goes out, so two overlapping runs can no longer both email the same person. Invoice reminders got the same treatment, and a scheduled email whose send hits an unexpected error now shows as failed on the enquiry (with one-click reschedule) instead of silently hanging forever.
Skipped workflow steps stay skipped. The daily reminder digest no longer nags you about steps you deliberately skipped, and it now works out due dates from the same anchors as the send engine (quote sent, quote accepted, event date), so the digest and the actual sends can't disagree. Ticking off the last real step now also finishes the workflow even when other steps were skipped.
Trash keeps the full story. Deleting a draft quote now moves its auto-created draft contract to the Trash alongside it (instead of erasing it outright), and restoring the quote brings that draft contract back too. Detaching a workflow from an enquiry also no longer wipes the record of which emails it already sent. And when a bulk move on the Client Tracker leaves booked jobs untouched, a small message now tells you how many were skipped and why.
Booked jobs can no longer be accidentally un-booked. Dragging a booked job's card on the pipeline board, or sweeping it up in a bulk "Move to" on the Client Tracker list, used to quietly turn a live job back into an open enquiry. Both paths now leave booked jobs alone (the board explains that cancelling or undoing a booking happens on the job page), and the same protection applies to connected AI assistants. Bulk moves also keep the board columns and the lost date in step, the same way a single move does.
Undoing a quote acceptance restores parked enquiries correctly. If the enquiry was Cold or On hold before it was booked, undoing the acceptance now parks it right back where it was instead of dropping it into the middle of the pipeline. And the undo no longer revives old quotes the client should not be able to accept anymore: only the quotes that were closed by that acceptance come back, and never-sent drafts come back as drafts.
Jobs in production stay on the Jobs calendar. Moving a booked job into production (or marking it completed) no longer bounces its date back onto the Leads calendar with a (LEAD) label, and cancelling a job now clears its calendar event the same way losing an enquiry does.
Security
The email-tracking webhook keeps its secret to itself. The webhook that tells Compass an email was delivered, opened, or bounced now identifies itself with a private header instead of a secret in its web address, which keeps the secret out of server logs.
The card-payment recorder now double-checks who's talking. The Stripe webhook that records client card payments and refunds now verifies the event really comes from the Stripe account connected to the studio it claims, that the invoice really belongs to that studio, and that the amount booked never exceeds what the card was actually charged. Closes a narrow but real hole where a payment-enabled studio could have marked another studio's invoice as paid.
Recipients and workflows are now fenced to their own studio. Adding an extra recipient to a job, and attaching a workflow to an enquiry, both verify the record really belongs to your studio before saving; the automated-send engine and the portal's email check now also ignore any recipient row that doesn't belong to the job's own studio; and the database itself now refuses a recipient or workflow row whose job and studio don't match. Closes a hole where a signed-in user of a different studio who learned one of your job IDs could quietly add their own email to your job's recipient list and receive its automated emails. Attaching a workflow from the enquiry page also no longer creates a duplicate on a double-click (which would have sent every automated step twice).
Fixed
Invoices with real payments can never be deleted or purged. The Trash used to protect only fully paid invoices, so a part-paid or written-off invoice (money someone actually handed over) could be trashed and then destroyed by Empty trash or the 30-day cleanup, taking its payment history with it. Now any invoice with a payment recorded against it, or a part-paid or written-off status, is refused everywhere: the one-click delete, the Trash page's delete forever, Empty trash, the nightly purge, and the assistant's trash tool. Your money records stay put.
Restoring a record whose contact is still in the Trash now asks you to restore the contact first. Bringing back an enquiry, quote, contract, questionnaire or invoice while its contact sat in the Trash quietly set it up to be wiped for good when that contact purged. Every restore path (the Trash page, the undo toast, the assistant) now catches this and points you at the contact instead. And a trashed enquiry's own page now says plainly that it's in the Trash, with a one-click Restore right there; the client-facing links for its quotes, contracts and questionnaires stop working while it's trashed.
Trash now really means trash. Putting an enquiry or job in the Trash used to leave its machinery running: its automated workflow emails kept sending for the whole 30-day trash window, its steps kept nagging the daily reminder digest and the To-send queue, and its client portal link kept working. All of that now stops the moment a record is trashed (and resumes if you restore it). Deleting from the enquiry page also now works exactly like deleting from the job page: the record's quotes, contracts, questionnaires and invoices go into the Trash with it, and a record with a real card payment refuses to be deleted until the payment is refunded.
Automated emails go out on the right day in every timezone. For studios west of UTC (the Americas), a workflow step due on, say, July 7 used to become eligible the previous local afternoon, so "3 days before the event" emails landed a day early. Due dates are now judged against the studio's own calendar day.
Accepting a quote now bills exactly what the client agreed to. A batch of fixes to the moment a quote is accepted: a quote's discount now carries onto the automatic invoice and its payment plan (the invoice used to bill full price); on choose-your-package quotes the recorded totals and the job's value now reflect the package and add-ons the client actually picked (they used to stay at the cheapest default); accepting an extra quote on a job that's already underway no longer rewinds the job to "upcoming" or overwrites its value; two people accepting at the same moment can no longer overwrite each other's signature; a quote is now acceptable through the whole of its last valid day in the studio's own timezone (US studios used to lose the final hours); accepting the quote of a deleted enquiry is refused instead of silently booking an invisible job; and a failed automatic invoice is now flagged loudly instead of vanishing without a trace.
Payment reminders now ask for what's actually left owing. A reminder used to quote the invoice's full total even after a client had part-paid it, and on payment plans it could chase a full instalment that was already partly covered. Reminders now read the payments ledger first, so part-payments are subtracted and instalment reminders show the remaining slice that's due, never money the client already sent.
Invoices keep every line item past the twentieth. The invoice editor let you add as many lines as you liked and previewed the full total, but only the first 20 rows were actually saved, so anything after that quietly vanished from the stored invoice (and its PDF). Every submitted line now saves. The same fix covers quote line items, packages, and add-ons, which had their own row ceilings.
Card charges in no-cent currencies like yen now charge the right amount. Stripe amounts for currencies without cents (JPY, KRW, VND and friends) were being multiplied by 100 on the way out and divided by 100 on the way back in, which would have charged a hundred times the invoice. Charges, refunds, and recorded payment amounts now convert per currency. Nothing changes for dollar-style currencies like AUD.
The hosted contact form now welcomes people back the same way your website does. When someone you'd parked as cold or on hold fills in your Compass-hosted form again, their original enquiry reopens to New (with the Re-enquired badge and their history intact) instead of being brushed off as a duplicate. And if their only earlier enquiry was already closed or in the bin, a fresh enquiry is created rather than silently folding into the old one. The owner notification and auto-responder emails are also now guaranteed to go out after a submission, where before they could occasionally be dropped on the way out the door.
Dashboard booking numbers stay in the year the job was won. The "won this period" dashboard metrics (bookings this year/month, booked YTD, booking rate, average booking value, gross profit and run rate) used to count a job by its last-edited date, so a job won in December that you touched in January would re-count in the new year and double-count revenue across years. They now count by the real win date.
The Reports funnel and lead-source breakdown show real numbers again. The conversion funnel was checking pipeline stages that no longer exist, so most rows sat at zero, and the "where leads come from" report read a legacy source field that new enquiries stopped writing. The funnel now follows the real stages (new enquiry, discovery call, consultation, booked), booked jobs keep counting as wins after they move into production or complete, and the source report groups by your workspace's own source list (with older leads falling back to their original source label).
Importing leads no longer chokes on impossible dates. A date like 2026-99-99 in an import file used to slip through the format check and fail the whole import at the database. Impossible dates are now treated as blank instead.
Card refunds are recorded correctly (and at all). Two problems fixed together: newer Stripe events stopped embedding the refund list, so a refund could quietly never be recorded and the invoice stayed "paid"; and when a refund was recorded, it booked the full card charge including the processing fee, so a fully refunded invoice could end up owing more than its total. Refunds are now fetched directly from Stripe and booked at the amount that originally counted toward the invoice, never more.
Re-sending a paid invoice no longer makes it "unpaid". Emailing an invoice again (say, as a receipt) or clicking "Mark as sent" used to force its status back to "sent", which re-armed payment reminders and started chasing a client for money already collected. The status is now re-derived from the payment ledger after either action, so a paid invoice stays paid.
"Save as PDF" on quotes works again. Every quote PDF (the link on the client's quote page and the studio's own download) had been returning "Not found" since the job-and-enquiry merge added a second link between quotes and enquiries, which made the PDF's database lookup ambiguous. The lookup now names the right link explicitly, the same fix the quote pages themselves already carry.
Client-facing pages no longer disguise a hiccup as a dead link. If the database stumbles for a moment, the public quote, contract, and portal pages used to show "not found", the portal's email check said "that email doesn't match", the signing page said "this link is no longer valid", and the contact form said "this form is no longer available", all of which would send a real client away. Each of those surfaces now tells the truth ("something went wrong on our end, try again in a moment"), and the failure is reported to error monitoring instead of being swallowed. A contract that signs but fails to mark the job as booked is now flagged for attention too.
Settings opens cleanly again (no error flash). Clicking Settings could briefly show the browser's "This page couldn't load" error before landing on Business profile.
/settingshad no hub page, just a server redirect that rendered first; it's now an edge redirect (a location header only, nothing to render), so it jumps straight through. Same fix already used for the retired Enquiries/Jobs/Calendar links. Old/leads/<id>links (from historic emails and notifications) now forward the same clean way.Help article contents no longer show doubled numbers. The "On this page" list rendered each item as "1. 1.", "2. 2.". a stray browser list marker sat on top of the styled number, and some headings also carry their own "1." prefix. The marker is suppressed and any baked-in ordinal is stripped from the contents label, so every article reads "1.", "2." with a single number.
Help pages clear the top navigation. The Help home eyebrow and the article breadcrumb tucked under the fixed nav. Help pages now offset by the real navigation height, so nothing hides beneath it.
Help home heading no longer clips under the top bar. On the Help & support page the "HELP & SUPPORT" eyebrow was tucked under the navigation at the top of the page; the hero now has enough top room to clear it.
Contacts page shows your clients again (was stuck on 0). The Contacts/Clients rolodex loaded every client through an embed on a
bookingstable that no longer exists (removed when a job became the enquiry itself), which made the whole query fail and the page render as empty. It now derives each client's Active / Booked / Past bucket straight from the lead's own status, so the real count and rolodex are back. A failed load is now logged and reported to Sentry instead of silently showing "0".Workflow reminders stop piling up in your bell. The daily "N workflow tasks due" reminder used to add a brand-new notification every run, so the bell filled with identical rows. It now keeps a single rolling reminder (each run replaces the previous unread one); read notifications stay as history. (Detaching a workflow already removes its tasks, so once you stop chasing a workflow, the reminder clears on the next run.)
Client Tracker list columns no longer sprawl. The Event (venue) and Last activity columns clamp to a maximum of two lines (a long venue like "St Nikola Macedonian Orthodox Church" no longer pushes a row to three lines).
Stage pills no longer wrap to two lines. On the Client Tracker list, a longer stage name (e.g. "Consultation done", "Discovery call") could break across two lines in the narrow Stage column. The pills (list table, mobile card, and record peek) now stay on one line.
, "This page couldn't load" flash when opening the old Enquiries/Jobs/Calendar URLs. The retirement redirects were in-page (
redirect()from a rendered route), so the browser rendered an intermediate page and Safari briefly flashed its native "This page couldn't load" error before following the redirect. Moved them to edge 308 redirects innext.config.ts(Location header only, no intermediate render), so/enquiries,/enquiries/board,/jobs, and/calendarforward into the Client Tracker with no flash. Detail cockpits (/enquiries/[id],/jobs/[id]) unaffected.HIGH. a new website enquiry could silently fold into a closed or trashed lead. The webhook's 24h duplicate guard matched any lead with the same email regardless of status or trash, so if the studio had marked that person lost/cancelled (or deleted them) within 24h, a genuine new enquiry was absorbed as a "duplicate, ignored" and never appeared. The dedupe now only folds into an open, untrashed enquiry (excludes
PIPELINE_CLOSED_STATUSESand soft-deleted); a submission matching only a closed/trashed lead creates a fresh lead.cold/on_holdstill dedupe (parked-but-open, still visible).CRITICAL. quotes would not open after the E collapse. Every quote detail page (and the public client-facing quote page) 404'd because the collapse added a second
quotes<->leadsforeign key (leads.won_quote_id), making theleadsembed ambiguous (PostgREST PGRST201), which nulled the query. Disambiguated all quote->leads embeds (and the workflow-sends cron's nested one) with the explicitquotes_lead_id_fkey. Verified against the live REST API., a job's invoices could 404 when the enquiry had no client. The
/jobs/[id]/invoices/[id]view derived the expected client from the lead'sclient_idand 404'd on mismatch; a won job whose enquiry has noclient_id(a pre-collapse shape) failed its own invoices. Ownership is already proven by the lead_id match, so the redundant client cross-check is now skipped when the job has no client.
Added
New quotes get a default validity window. New quotes now automatically set their "valid until" date to 30 days out (still editable per quote), so quote expiry actually kicks in without you remembering to set a date. The window is configurable under Settings, Invoicing, "Reminders & timing", "Quotes valid for (days)".
Withdraw a sent quote. A sent quote now has a "Withdraw" action that pulls the offer back: the client can no longer accept it and sees "this quote has been withdrawn, please reach out to the studio" on the quote page. It's a distinct Withdrawn status (not the same as expiring or deleting), kept as history, and reversible with "Reactivate". Complements Archive (which just tidies a quote off your own lists); Withdraw is the client-facing version.
Reverse a written-off invoice. If a bad debt comes good, a written-off invoice now has a "Reverse write-off" action that returns it to part-paid (if anything was paid) or unpaid, resumes reminders, and logs the reversal. Written-off invoices stay un-deletable (kept as a record), Reverse is the way back, so the "reverse the write-off first" prompts on recording a payment now have somewhere to go.
Returning website enquiries re-open the original lead. When someone who went quiet (a Cold or On-hold lead) submits your website form again, Compass now re-opens that same lead to New instead of creating a duplicate, and logs a clear "Re-enquired" note on their timeline (their history stays intact). Closed or trashed leads still start fresh. (The card highlight for re-enquiries follows next.)
Quotes now respect their expiry date. If a quote's "valid until" date has passed, it can no longer be accepted (the client sees "this quote has expired, please ask the studio to renew it"), and a nightly job flips expired sent-quotes to an "Expired" status so the label stays honest everywhere. A quote is still acceptable through its last valid day; the studio can reopen or extend an expired quote.
Job types. Set up the kinds of work you do (Wedding, Portrait, Commercial, whatever fits) in a new Settings → Job types page: add, rename, archive, restore. Tag each enquiry with its job type from the enquiry's edit form, and it shows in the Client Tracker's "Type" column (which used to show the venue). Job types are deliberately separate from your booking event types (the meeting slots clients pick). Each job type also carries a colour you pick from a palette in settings (brights included, yellows and oranges, plus a custom colour by hex), shown as a dot beside it on the Type column. This is the first slice of ; an icon per job type arrives with the shared icon picker, and per-job-type default workflows and onboarding seeding come later.
Archive a quote. Sent quotes can't be deleted (they're kept as commercial history), but a sent quote that's gone cold used to nag on your dashboard forever with no way out. You can now Archive a quote: it stays as history but drops off the dashboard "Today's actions" and out of the active quote lists, into a new "Archived" tab on the Quotes page. Fully reversible (Unarchive). Available on sent, declined, expired, or superseded quotes; drafts are deleted instead, and an accepted quote stays visible because it backs a won job. An archived quote shows a clear "Archived" badge, and the Archive/Unarchive buttons confirm the moment you click.
(part of). Client Tracker, List view + bulk bar: a new unified
/client-trackersurface with URL-driven E3 filter tabs (All / Enquiries / Jobs / Lost) and a Board/Calendar/List view switch. The List view ships first (Client, Stage, Event, Value, Next action, Last activity), with names and amounts honouring the global present-safely toggle. Multi-select adds a bulk bar: move stage, export selected to CSV, and trash. The Board view is a full-bleed kanban over the configurable pipeline stages, drag a card to change its stage, with a board-only off-ramp to park (cold / on hold) or mark lost. The Calendar view embeds the full calendar (Year/Month/Week, financial-year toggle, events coloured by stage plus the dashed meeting bookings), now a shared component so the standalone/calendarand the tracker render the same thing. Condensed operational widgets sit above the views: Next job (with countdown), Needs doing (next actions), and Money due (upcoming/overdue invoices). Clicking a record opens a Notion-style peek with four modes (side summary, centred full cockpit, full page, new tab); the chosen side/center default is remembered per user. The side peek shows the record summary, copyable contact details, latest activity, and the Client Lounge link. On mobile there is no peek, tapping a record navigates to the full cockpit, the board stacks into vertical stage sections, the list becomes stacked cards, and the calendar shows an agenda list. Now live in the nav: Enquiries, Jobs, and Calendar collapse into a single "Client tracker", "Clients" becomes "Contacts", and Reports folds under Money as a tab. The old/enquiries,/enquiries/board,/jobs, and/calendarURLs redirect into the tracker; the record detail pages (/enquiries/[id],/jobs/[id]) are unchanged., Save edited email back to template: edits made in the enquiry email composer can now be saved back to the source template ("Save changes") or kept as a new one ("Save as new"). Tokens are preserved; if an edit drops a merge field entirely, a prompt names it before saving. Built-in templates are save-as-new only.
, Multiple availability schedules: create named schedules (e.g. "Wedding season", "Off season"), set one as the workspace default, and optionally pin individual event types to a specific schedule. Migration backfills a "General" default for all existing workspaces.
- Daily digest email. Opt in via Settings → Notifications and get a 9am email covering: events and shoots happening today, cold leads (no activity in 14+ days), and overdue invoices. Delivered in your workspace timezone. Toggle on or off any time.
- Deliverables checklist on jobs. Each job now has a Deliverables section where you track what needs to be handed to the client: gallery link, album, USB drive, prints, and so on. Add items with an optional due date, toggle each one done (strikethrough with count), or remove them. The header shows "x of y done" at a glance.
- Reporting library at /reports. Four pre-built reports in a new nav section: monthly revenue (paid invoices over the last 12 months), where leads come from (count and win rate by source), conversion funnel (how many leads reach each stage), and busiest months for events. No Excel needed.
- No-show recovery automation. When a scheduled booking passes its end time without being marked completed, Compass automatically marks it no-show and sends the client a warm "we missed you" email with a rebook link. Fires 30 minutes after the booking should have ended, with a 24-hour look-back window to catch gaps.
- Superadmin tier override. Admins listed in
SUPERADMIN_EMAILScan visit/adminto preview the app as any billing tier (Free, Tier 1, Tier 2, Tier 3) without changing the actual workspace plan. Override is stored in a session cookie and cleared on demand.
- Separate before/after booking buffers. Event types now have two buffer settings: "Buffer before" blocks travel time before a booking starts (so the previous slot ends early enough), and "Buffer after" keeps the post-booking gap. Both default to what you had before, no setup needed.
- Review-ask tracking on completed jobs. Each completed job now has a Review card in the sidebar. Record when you sent the review request (timestamps the date), mark it as received, or undo either action. Three clear states: never asked, asked with date shown, review received.
Delivery deadline health badges on the Jobs list. Set a delivery deadline on any job (new date field in the edit form) and the Jobs list shows a colour-coded badge: green for on track, amber for due within 30 days, red for due within 7 days. No badge shown when no deadline is set.
Jobs list now shows upcoming bookings with a time-horizon filter. The Jobs page defaults to "Upcoming" and lets you filter to the next 30, 60, 90 days, or all upcoming. Status filter pills switch between Upcoming, All, In production, Completed, and Cancelled. All filters are URL-driven (shareable, bookmarkable).
- Cold-lead staleness signals on the Enquiries list. Active enquiries with no update in 14 or more days now show a subtle "Cold" badge next to the name. A new "No activity (14d+)" filter in the toolbar surfaces all stale leads at once so you can follow up, mark lost, or close them.
- Lost reasons breakdown on the Enquiries list. When you filter the list to "Lost", a "Why we lose deals" panel now appears above the table showing each recorded reason, how often it appears, and a relative bar. Reasons are sorted most-common first. No new query needed -- the data was already loaded for the list.
- AI connector writes now run the same logic as the app. Every MCP mutation routes through the shared domain core: status changes on jobs call the booking-status handler so the enquiry mirror fires, winning an enquiry via the connector requires the proper booking flow (not a raw status set), and payments go through the payment ledger. An AI-driven change can no longer leave the CRM in an inconsistent state.
- Social link previews now show the right content for every page. Marketing pages (home, feature tree, changelog, pricing, privacy, terms) emit page-specific titles and descriptions when shared on social. Client-facing token pages (quote, portal, contract, questionnaire) show a safe studio-branded card with only the studio name and a generic prompt -- no client name, quote number, or document content is ever exposed.
- A connected AI assistant can now work with the File Library. Five new tools: browse files (
list_files), inspect one with a download link (get_file), upload by URL (upload_file, server-side fetch -- bytes never pass through the model), create a shareable reference link (attach_file), and revoke it (revoke_reference).
- A connected AI assistant can now answer "how is the studio doing?" and look up invoices and jobs directly. Five new read tools:
get_metrics(bookings YTD/MTD, revenue YTD, pipeline value),get_job(one booked job in booking vocabulary),list_invoicesandget_invoice(with all recorded payments and outstanding balance), andsearch(find any client or enquiry by name or email in one call).
- A connected AI assistant can now move enquiries, jobs, and invoices to the Trash and restore them. Four new verbs:
trash_enquiry,trash_job,trash_invoice, andrestore. Each mirrors the app's 30-day Trash exactly, same guards (paid invoices can't be trashed; only booked leads respond totrash_job), and the calendar event is removed/restored alongside a lead.
- A connected AI assistant can now accept a quote on the client's behalf. The third and final MCP verb in the hardening set: "accept this quote" marks it accepted, creates the auto-invoice if configured, moves the enquiry to won, and supersedes any other open quotes, running exactly the same path as doing it in the app. For Pick and Choose quotes, the assistant also passes the chosen package. The full MCP action set (book enquiry, record payment, accept quote) now covers every key job milestone.
Changed
- Privacy mode also masks the signer's name on a signed contract. The "Typed name" in a contract's signature-evidence block now blurs/samples with the names layer, so a signed agreement can be shown on a screen-share without revealing who signed. (The contract body and the IP/device evidence are unchanged, they're the legal record.)
- Privacy mode now masks your costs and margins. With Privacy mode on and the "costs" layer enabled, the gross-profit and margin figures on an enquiry/job (and the package margin) are blurred or swapped for sample numbers, so you can screen-share or present without exposing what a job actually costs you or what you make on it. Previously the costs toggle masked nothing on the enquiry page. Display-only, as always: it never touches stored data and nothing client-facing reads it.
- An enquiry and its job are now one and the same record (E redesign, full collapse). Winning an enquiry no longer creates a separate "booking" record behind the scenes, the enquiry itself becomes the job and carries it through to completion. The Jobs list, the job page, the calendar, client pages, the client portal, contracts, questionnaires, invoices and the AI assistant all read and write that one record, so nothing can ever drift out of sync. Deleting a job now moves the whole thing (and its quotes, contracts, questionnaires and invoices) to the 30-day Trash where you can restore it, keeps the client, and is refused if a card (Stripe) payment was taken (refund it first). A job with only manual/test payments can always be cleared. Your existing data was migrated in place.
- An enquiry and its job are now truly one record (E redesign). A job no longer keeps its own separate copy of the couple's name, event date and venue, those live on the enquiry as the single source of truth, so the two can never fall out of step. Editing them on the job updates the enquiry and vice versa. Everything reads from the enquiry now (the calendar, job pages, client pages, the client portal, contracts, questionnaires, invoices and the AI assistant). Existing records were unaffected. (For the AI assistant: creating a job now links it to an enquiry, matching how the app already works.)
- Fixed: invoices created by the AI assistant showed "NaN" in the Qty, Unit price and Amount columns. When a connected assistant made an invoice from amount-only line items, those columns rendered "NaN" on the invoice (the invoice total was still correct). Assistant-created invoices now use the same line format as the app (quantity 1 at the line price) so they display cleanly, and the line-total calc no longer produces NaN for any older or malformed line.
- Fixed: editing a quote's line items and sending it no longer drops your changes. The quote editor now has a "Save & send" button that saves your current line items first, then emails the client the accept link, so a quote can never go out as the previously-saved (or, on a brand-new draft, an empty) version. The separate "Send quote" button that sent the last saved version is gone, sending a draft always saves it first now. If the client has no email on file, the edits stay saved and you get a clear prompt instead.
- Fixed: a Customisable quote could be accepted without picking a package (E redesign, phase 3). Accepting a "pick one of these" quote with no package selected used to go through and create a $0 booking and invoice. It is now refused (on both the client's accept and the studio's "accept on their behalf") with a prompt to choose a package first.
- AI-assistant (MCP) actions now keep your records in sync, the same as doing them in the app. When a connected AI assistant changes a job's status, the linked enquiry now updates with it (and a job created as completed marks its enquiry completed too), matching what happens when you do it yourself. The assistant also can no longer mark an enquiry "won" out of thin air, that only happens by actually booking it (which creates the job), exactly as in the app. (Part of routing every assistant action through the same rules the app uses, so the two can never drift apart.)
- A job's progress now shows on its enquiry record (E redesign, phase 3). When you move a job to "In production", "Completed" or "Cancelled", the linked enquiry now reflects that same stage, so the one record tells the whole story from first enquiry through to finished job. Existing in-progress and completed jobs were brought into line automatically; your booking counts and revenue totals are unchanged.
- An enquiry and its job now stay in sync (E redesign, phase 3). When a quote is won, the enquiry becomes a job. Until now the job kept its own copy of the name and event date, so renaming the couple or moving the date on one side left the other showing the old details. Now editing either side updates both, so the name and event date always match across your enquiry, your job, and the calendar. (Groundwork toward merging the enquiry and job into one record.)
- Editing an invoice with a payment plan now keeps the schedule in balance, and a settled invoice is locked (E redesign, phase 2). When you add or remove a product on an invoice that already has a payment schedule, the change flows into the unpaid instalments only, so the plan always still adds up to the new total. Payments you have already recorded are never touched. A fully-paid or written-off invoice is read-only: the Edit button is disabled with a note, and the change is refused server-side too. Lowering an invoice below what has already been paid is held back for now (it would leave a credit), with a clear message instead of a broken total.
- You can now reopen a fully-paid invoice to bill more (E redesign, phase 2). A paid invoice shows an "Add a charge" button in place of Edit. You give it a short description, an amount and a due date, and it adds that as a new line, flips the invoice back to part-paid, and shows the new amount as owing. Nothing you have already been paid is touched. If the invoice runs on a payment schedule, the charge is added as a new unpaid instalment so the plan still adds up. A written-off invoice stays locked (no reopen).
- Lowering an invoice below what has already been paid now shows a credit instead of being blocked (E redesign, phase 2). Previously, editing an invoice down past the amount paid was refused. Now it goes through: the invoice reads as fully paid with an "Overpaid by $X" note, and the balance card flips to "Credit (refund due)" so you know to refund the difference (manual refund for now). Money already recorded as paid is never touched, and any unpaid instalments drop to zero since there is nothing left to bill. Clients never see a negative balance, their view simply shows the invoice as paid.
Added
- A connected AI assistant can now book an enquiry and record a payment. Two new assistant actions that do the real thing, exactly as in the app: "book this enquiry" (creates and links the job, moves the enquiry to booked) and "record a payment" on an invoice (updates it toward paid, re-derives its status, and books the enquiry if it is the first payment). Both run the same rules as doing it by hand, so nothing falls out of sync. (Part of the MCP-hardening set; accepting a quote via the assistant follows next.)
- You can now undo a quote acceptance (E redesign, phase 3). If a booking was made by mistake, or the couple changes their mind, open the accepted quote and use "Undo acceptance". It reverses the whole thing: it removes the job and its draft invoice, moves the enquiry back out of Booked (to the exact stage it was at before), reopens the other quote options, and lets the quote be accepted again. It is blocked the moment any payment has been recorded against the booking (refund or write it off first), and once a job is already in production you cancel it from the job instead.
- You can now accept a quote on a client's behalf (E redesign, phase 3). When a couple says yes on a call, open their quote and use "Mark accepted (verbal yes)". It does exactly what happens when the client clicks Accept online: it books the job, creates their invoice, and moves the enquiry to Booked. The acceptance is recorded as made by you on their behalf (rather than from their device), so the trail stays honest.
- Each invoice now keeps an activity trail (E redesign, phase 2). The invoice page has a new "Activity" section showing what has happened to it in time order: created, sent, payments recorded and removed, charges added on reopen, edits, refunds and write-offs, each with a timestamp. It is read-only and gives you (and your accountant) a clear history of every money event on the invoice without digging through the whole client timeline.
- Half-filled forms now show their progress, and finished documents fade into the background (E4). A questionnaire the couple has started part-way through reads "3 of 8 answered" instead of just "Sent", so you can see how far they have got at a glance. And documents that are done with, declined, void, expired, replaced or written off now sit in a quiet grey rather than a loud red. The one thing that still shouts is an overdue invoice, because that is the only one that needs you to act.
- Guided tips now cover the main screens, and stay quiet once you have read them. Inline guided tips reach beyond settings to the dashboard, enquiries, jobs, clients and calendar, each a warm one-liner on what that screen does for you. And "Got it" now sticks: a tip you have dismissed stays gone on that screen instead of returning every reload, while other screens' tips still appear. (Turn tips off entirely any time under Guided mode in your profile menu.)
- Studio-only "back to the record" link in the Client Lounge. When you (the studio) open a client's lounge while signed in, a "Studio view" block at the top of the sidebar (and the mobile rooms sheet) links back to that enquiry or job. Your clients never see it, it shows only to signed-in members of that workspace.
- A contract can now carry a second signature. In the Client Lounge contract room, "+ Add another signature" lets a partner add their typed name alongside the main signer before signing. Both signatures are recorded and shown once the contract is signed. The main signature works exactly as before.
- The contract is now signed right inside the Client Lounge (, slice 3). Once a couple accepts their quote, the Contract room opens with a short summary (who it is between and for, the agreed total and deposit), the full agreement in a tall, readable panel, and a sign block underneath. The "I agree" box stays locked until they have scrolled the agreement to the end, then they type their name (which renders as a script signature, showing who they are signing as and the date) and sign. Signing updates the lounge on the spot: the alert clears, the count drops, and a "Signed, sealed, and set" confirmation points to paying the deposit and downloading the signed PDF. The signing itself is the same trusted flow as before.
- The quote now opens right inside the Client Lounge (, slice 2). A couple can read their full quote as a warm document (who it is from and for, the line items, the totals with the gold "you're saving" amount, and the payment schedule with a gentle "the moment you accept, your invoice is ready" note) and Accept or Decline without leaving the lounge. Accepting updates the page on the spot: the sidebar count drops, the Quote badge turns to "Accepted", and a panel points to paying the deposit and signing the contract. Tailored quotes show this inline document; pick-and-choose quotes (where you select a package) still open on their own page for now.
- The client portal is becoming the Client Lounge, a calmer roomed space (, slice 1). Above a full-width studio cover banner sits a sidebar that holds your rooms (Home, Quote, Contract, Questionnaire, Gallery, Payments, Files), a red "things need your attention" count, and per-room alert dots and action badges so a couple can see at a glance what is waiting on them. The Home room opens with a warm "where things stand" checklist. Rooms appear in the sidebar as they are added to the client (Home always shows), so the nav reflects what actually exists rather than a fixed template; the full journey, including what is still to come, lives in the Home checklist. Rooms also gate by lifecycle (the contract opens once the quote is accepted, the gallery after the day). On mobile the sidebar becomes a sticky "Rooms" button that opens a bottom sheet with the same room list. The accent uses the studio's own colour, never Compass red. The quote opens from its room for now; a later slice brings the full quote and Accept inline. Applies to per-job portals; the combined multi-job view is unchanged for now.
- Contact forms settings now use the shared design language (, slice 5). The forms list is a proper SettingsListRow list with a top-right "New form" button, Edit navigating to the builder, and Preview plus Delete (with an in-app confirm) in the overflow menu. The builder tabs (Build, Style, Configure, Embed) now use the shared Button primitive for all actions, the ds-label type scale for section headings, and design tokens throughout. The font picker (slice 3) and auto-reply Switch with template picker (slice 8) are preserved unchanged.
- New enquiry and workflow reminder emails now respect your Notification preferences (, slice 2). Incoming lead emails (both the hosted contact form and the webhook) and the daily workflow digest are now sent through the emit() engine, so they honour the per-user in-app and email channel settings you configure in Settings, Notifications. The two legacy "Notify me on new lead" and "Daily workflow digest" toggles in Settings, Email have been removed and replaced by a short link pointing to Settings, Notifications, where per-event control lives. A deploy migration backfills any existing opt-outs so no one starts receiving emails they had previously turned off.
Added
- Privacy mode, present and record safely. A new control in your profile menu lets you hide sensitive things on screen so you can share your screen with a client, or screen-record for social content, without exposing anyone's private data. You pick which layers to hide, other clients' names & contacts, money amounts, your costs & margins, and one of two styles: Blur (frosts the values, for presenting live) or Sample data (swaps in realistic fake names and numbers, so a screenshot looks real but is no one's actual data). A chip in the top bar shows when it's on. It's view-only and per-device, your real data is never touched and clients never see any of this. Coverage is now complete across the app: every list, board and calendar, plus all the detail pages (jobs, enquiries, quotes, contracts, clients) and invoices, masks names, money amounts and costs/margins so a real screen-share or recording is safe end to end.
- Travel timezone switch. When you are away from home, you can view all your times in your current location's timezone without changing a thing for your clients. A "Viewing times in" control in your profile menu lets you switch between your home timezone and where you are now (and back), and when a different timezone is detected a one-time strip offers to switch for you. While a switch is active, a small chip in the top bar shows which zone you are viewing in. Crucially, this only changes how times look to you, across every screen (dashboard, calendar, jobs, enquiries, quotes, contracts, clients and settings). Every email, invoice, booking page and reminder your clients receive always stays in your home timezone.
- A little sparkle on the compass menu. Every so often the compass/star menu up top does a gentle one-second amber twinkle, a quiet "come explore" wink, never a nagging badge. It only happens while you're actually looking at the tab, never in the background, and you can turn it off any time with the new "Sparkle" toggle at the bottom of that menu. It respects your reduced-motion setting and stays off if you've asked your system to minimise animation.
- Pause payment reminders for a whole client. A "Payment reminders" card on the client page, and on each of that client's invoices, lets you pause all of a client's automated payment chasing at once, either until you turn it back on or snoozed until a date (then it resumes on its own). A paused client overrides each invoice's own setting, so nothing gets chased while it's on, and reminder-eligible invoices show a "Reminders paused" badge so it is never a mystery why an invoice has gone quiet. Useful for an agreed payment arrangement or a sensitive situation. Scope is payment reminders only.
- Desktop (web push) notifications (, slice 5). An opt-in card at the top of Settings, Notifications lets you enable OS-level banner notifications on your current browser. Enabling the browser switch does not auto-enable any banners; you then choose which events show a banner using the new Desktop column in the notification grid. Push is strictly per-browser and per-event. The push delivery engine fans out to all registered browsers via VAPID web push, prunes gone subscriptions automatically (HTTP 404/410), and degrades gracefully when VAPID keys are not yet configured. A one-time email retry on transient network failures was also added.
- In-app notification bell (, slice 4). A bell icon in the nav shows your unread notification count and opens a panel with your recent notifications. Click any notification to mark it read and go straight to the relevant page. Mark all read in one tap. The badge goes quiet when you are all caught up.
- Notification preferences (, slice 3). You can now choose exactly what Compass tells you about and how, in Settings, Notifications. Toggle in-app and email per event (new enquiries, bookings, payments, invoices, contracts, workflow tasks, and delivery due dates), grouped by area. Changes save automatically with no button to press, a SaveIndicator shows saving, saved, or error inline. SMS and phone push are shown (coming soon) as a visual teaser. Resets to sensible defaults in one click.
- Notifications engine groundwork (, slice 1). The foundation for in-app and email notifications: per-user channel preferences, the notifications feed table, a single server-side emit() engine, and the canonical event catalog (new enquiry, booking, payment, invoice, contract, workflow and delivery events). No settings screen or in-app bell yet, those land in later slices.
- Set a first password inline in Settings (no email round-trip). If you sign in with a magic link and have never set a password, the password card in Sign-in & security now shows an inline "Set a password" form (new and confirm only). It uses your active session, so you set a password and stay signed in, no email needed. Accounts that already have a password keep the current "Change password" flow unchanged, and the inline set is refused server-side for them so it can never overwrite an existing password.
- Set or reset your password from Settings, no current password needed. The Change password card now has an "Email me a link to set a new password" action for when you have forgotten your current password or never set one (magic-link or one-time-code sign-ups). It emails a secure reset link to your own account email and you set the new password without signing out. The current-password change flow is unchanged for everyone who knows their password.
- "Walk me through it" guided walkthrough on Getting started. With guided mode on, a "Walk me through it" button opens a step-by-step overlay that walks you through the whole setup one screen at a time, leading with the payoff of each step (the why, not just the task) and a "Take me there" link to that screen. It is always available while guided mode is on, even if you have turned the checklist or inline tips off.
- The invoice PDF now matches the polished web invoice. Saving an invoice to PDF produces the same clean layout clients see online, your logo, a "Tax Invoice" heading, the event details, the three summary cards (Total / Paid so far / Balance due), and the same payment schedule, rendered on one page. The web invoice gained your logo and the "Tax Invoice" heading to match. Both views now show the event block (the couple, date, and venue) pulled from the linked job or enquiry.
- The card fee now shows on the client's invoice. When a client pays by card and you pass on the surcharge, the invoice now itemises a dated "Card processing fee" line, the total ticks up by the fee, and "paid so far" reflects what their card was actually charged, so the invoice reconciles with their card statement instead of hiding the fee. The fee's GST folds into the GST line. Your balance is unchanged (the fee only ever covers the card processor, never reduces what you're owed). Bank transfer and PayID payers see no fee. (Client invoice first; the studio view and PDF match next.)
- Your own invoice view now matches it. The studio invoice screen (and its payment panel) shows the same dated "Card processing fee" line and surcharge-inclusive Total / Paid, so your records reconcile with what the client was charged.
- The PDF matches too. Saving the invoice to PDF now itemises the same dated "Card processing fee" line with the reconciled totals, covering both the client "Save as PDF" link and the studio internal download.
- Unsaved-changes guard. Compass now warns before you lose edits. If you've changed something and try to leave the page, refresh, or close the tab, you get a heads-up first, plus a small "You have unsaved changes" reminder while a change is pending. Wired into the editors where losing work hurts most: the workflow builder, questionnaire builder, contact-form builder (fields, style, and settings tabs), quote/invoice template editor, email signature, dashboard layout, and pipeline-stage rename.
- Card surcharge & Buy Now Pay Later settings. The Card payments panel now lets you pass the card fee on to clients (separate rates for domestic and international cards, defaulting to Stripe's pricing) so you receive the full invoice amount, with a live example showing exactly what the client pays. You can also choose how GST applies to the surcharge, and switch on Afterpay/Zip so clients can pay over time while you are paid upfront. Settings only; the client-facing card screen that uses them is coming next, and a compliance note reminds you to check local surcharge rules.
- Disconnect Stripe. The Card payments panel now has a Disconnect button (Settings, Invoicing, How clients pay you), so you can unlink Stripe from Compass in one click. It asks you to confirm first, your Stripe account itself is untouched and past payments stay on your records, and the Pay buttons simply stop showing until you reconnect.
- Clients can pay invoices by card. Online card payments are live. Turn card on for an invoice (or flip the "Accept card by default" switch under Settings, Invoicing, How clients pay you) and your client gets a Pay button on their invoice link, "Pay this month" when there's a plan, or "Pay the full balance". They pay on Stripe's secure checkout (Apple Pay and Google Pay included), the money goes straight into your own Stripe account, and the invoice marks itself part paid or paid the moment it clears, with a receipt on the ledger. Refunds you issue in Stripe flow back automatically too. Card is off by default on every invoice, since the studio covers the card fee, so nothing changes until you switch it on.
- Payments on invoices. Every invoice now has a Payments panel with three clear figures, Total, Paid, and Balance due, a status that keeps itself honest (Part paid, Paid), and a "Record a payment" button for money that comes in by bank transfer, PayID, cash, or anything else. Partial payments are handled properly: pay $500 toward a $1,160 month and the plan shows exactly that. Your clients see the same clear summary on their invoice link, with each scheduled payment marked paid, part paid, or upcoming. The Money page's unpaid total now reflects what is genuinely still owed, not the full amount, on part-paid invoices.
- Payment methods library ("How clients pay you"). Settings → Invoicing now has a place to save the ways clients can pay you, a bank transfer, PayID, Wise, anything, each with free-form instructions shown to the client exactly as you type them. Tag a method with a currency so the right account shows on the right invoice (or leave it on "All currencies"), and mark one as the default per currency. Your existing bank transfer and PayID were brought across automatically, so nothing changes on your invoices. (The drill-in row that opens this lives on the redesigned Invoices tab.)
Changed
- Settings, board stages refreshed onto the Compass look. Your pipeline stages now sit in the same tidy list as the rest of settings. Drag the handle to reorder them (no more up and down arrows), and Rename sits right where you expect it. The status mapping each stage powers stays visible underneath, so you always know what feeds your dashboard analytics, and reordering never changes it.
- Settings, Integrations refreshed onto the Compass look. Your connection keys now sit in the same tidy list as the rest of settings, each showing the key name, a masked preview, when it was created, and when it was last used, with an Active status. Revoke moved into the row's "more" menu and still asks you to confirm first. "Create key" is now a button at the top of the list that opens a small dialog, your new key is shown once to copy, exactly as before. How keys are made, stored, and revoked is unchanged.
- Settings, Business profile and Client portal refreshed onto the Compass look. The at-a-glance cards on these pages dropped their decorative corner glyphs for the same clean, calm look as the rest of settings. Every card keeps its title, summary, and the form inside it, nothing about what you can set or how it saves has changed. Invoicing was already on the new look, so it stayed as it was.
- Clearer invoice payment screen. The "Pay this month" button is now "Pay next payment" (it pays your next scheduled instalment, which is clearer when more than one falls in the same month), and the "payment received" confirmation after paying is now much more prominent so it's not missed.
- Unsaved-changes guard now covers the tax-rate, region, and product/service editors. If you start editing one of these and try to refresh or close the tab before saving, Compass warns you first, the same protection the bigger editors already have.
- Captain plan price. Captain is now $25/mo (was $19). Fleet stays $49 and Pilot stays free, and founding members still get 50% off their first year. Nothing charges yet (billing isn't live), this just keeps the pricing page and in-app plan copy correct ahead of launch.
- Tax is now driven by your Regions and Tax rates. Invoices and quotes work out tax from the region you tag (its rate, or zero when the region is tax free), then your default tax rate, instead of a single "GST registered" switch. This fixes a real bug where a "No tax" region still added 10% GST. Nothing changes for existing workspaces (your GST setup carries over as a default 10% rate), so totals stay identical except that overcharge is gone. Set a default under Settings, Invoicing, Tax rates, and tag clients with a region under Regions.
- Invoicing settings redesign. The Invoices tab now reads as clean grouped rows that match the rest of settings: Business details, How clients pay you, Numbering & logo, Payment reminders, and For your accountant, each opening a focused editor. "How clients pay you" drills into your payment methods, and the reminder editor now shows a plain-English example of exactly when reminders would go out ("for an invoice due 14 Mar: nudge 11 Mar, due 14 Mar, then 17 Mar, 24 Mar, weekly until paid"). The business-number label follows your region (ABN, VAT, or EIN). Tax is no longer set here, it lives in the Tax rates and Regions tabs. The old "Create an invoice" card is gone.
- Invoices now show your payment methods. The "How to pay" block on the invoice detail, the client's online invoice, the PDF, and the invoice email now lists the payment methods that match the invoice's currency (default first), so a client billed in pounds sees your GBP account and a client billed in dollars sees your AUD one. Workspaces that haven't set up methods yet keep showing their existing bank/PayID details, so nothing changes until you start using the library.
- Payment schedules on the unified settings design. The Payment schedules list now uses the shared settings row (design language): each schedule shows its name, a Default badge, and where it's used, with a plain-English summary of its payments underneath. Edit opens the payment editor in a dialog, and Archive moved into the row's "more" menu (with its confirm). Archived schedules are dimmed with a one-tap Restore. Same schedules, same behaviour, just tidier and consistent with the rest of settings.
- Tax rates on the unified settings design. The Tax rates list now uses the shared settings row (design language): the percentage sits on the right, Edit opens the rate, and Archive moved into the row's "more" menu (with its confirm). Archived rates are dimmed with a one-tap Restore. Your rates and how they behave are unchanged, this is the look and interaction only.
- Regions on the unified settings design. The Regions (billing profiles) list now uses the same shared settings row: the currency and tax label read underneath the name, Edit opens the region, and Archive moved into the row's "more" menu. Archived regions are dimmed with a one-tap Restore. Logic and data unchanged.
- Quote & invoice templates on the unified settings design. Each template row now uses the shared settings row: a content summary ("3 lines", "2 packages, 4 add-ons") sits on the right, Edit opens the editor, and Duplicate, Archive/Restore and Delete are tidied into the row's "more" menu instead of a spread-out row of buttons. No change to the templates themselves.
- Contract templates on the unified settings design. Contract template rows now use the shared settings row: Edit opens the same rich-text editor, and Duplicate, Archive/Restore and Delete move into the row's "more" menu. The editor and your templates are unchanged.
- Email templates on the unified settings design. Email template rows now use the shared settings row, grouped under their type in one tidy list. Edit opens the same editor; Set as default, Duplicate and Delete move into the row's "more" menu. Templates and sending behaviour are unchanged.
Fixed
- The email composer's alignment buttons now light up for images too. They already showed the active alignment for text, but an aligned image left all four inactive (they were reading the paragraph's alignment, not the image's own). Now align an image and the matching button highlights, like Bold and Italic.
- New-enquiry notification and email links now open the enquiry instead of a 404.
Every push notification and owner email built the link as
/leads/<id>, but the detail page lives at/enquiries/<id>(there is no/leadspage), so clicking a "New enquiry from..." notification landed on a 404. Fixed at every source (the website-lead webhook, the lead-notification email, the contact-form and booking actions, and the workflow-reminders cron), plus a/leads/<id>to/enquiries/<id>redirect so links in already-sent emails still work. The push notification also now shows the crisp Compass icon instead of a generic one.
- Desktop push notifications now actually send. The server read the public
VAPID key from the wrong env var name (
VAPID_PUBLIC_KEY) while the key is set underNEXT_PUBLIC_VAPID_PUBLIC_KEY, so emit() saw the keys as unconfigured and silently skipped every push. It now reads the key the browser and setup actually use, so banners deliver.
- Notification settings are reachable, and the desktop-notifications card now shows. Two fixes: Settings now has a Notifications entry in the hub (it was built but never linked, so there was no way in), and the "Enable desktop notifications" card now renders for first-time users. The card had been stuck invisible because its status check waited on a service worker that does not exist until you first subscribe; it now resolves immediately so the Enable button appears.
- The browser-tab icon now renders reliably (no muddy or generic fallback). The SVG
app icon used heavy SVG filters (paper-grain and ink-edge) that render unpredictably
at favicon size and that Safari can drop entirely, leaving a blank or generic-looking
icon. The icon is now a flat, filter-free version of the same compass mark, so it
shows crisply across browsers, with the
.icoas the universal raster fallback.
- Signing in now lands you on your dashboard, not the enquiries board. After
signing in, confirming an email link, finishing onboarding, completing two-factor,
or resetting your password, Compass drops you on
/dashboardby default instead of the enquiries board. Deep links (an explicit destination you were headed to) are still honored; only the default landing changed. The default now lives in one place (src/lib/routes.ts), so a future route rename is a single edit.
- Card payments can't get stuck "unpaid" anymore. When a client returns to their invoice after paying by card, Compass now double-checks the payment directly with Stripe and records it if it hasn't already, so a delayed or misconfigured webhook can no longer leave an invoice showing as unpaid. It's a safety net (the webhook is still the main path) and never double-counts.
- Workflow editor no longer loses your edits. Clicking outside the workflow editor or pressing Escape while you have unsaved changes no longer silently closes it and throws the edits away, you stay in the editor (with the "unsaved changes" reminder), and Cancel now truly discards so reopening shows the saved version, not your abandoned edits. A name-only change counts as unsaved too.
- Edit dialogs close themselves after saving. Editing a client or a job and clicking Save now closes the dialog once it saves (it used to show "Saved." but stay open until you clicked Cancel). A second consecutive save closes too, and a validation error (like clearing a required name) still keeps the dialog open.
- Attaching a workflow gives instant feedback. On an enquiry, picking a
workflow to attach now shows "Attaching
…" on that row right away (and Detach shows "Removing…"), instead of a few seconds where nothing looked like it happened while the page refreshed.
[0.4.0]. 2026-06-16
Everything shipped since 0.3.0, cut as a release: payment schedules with a running balance due, multi-currency / regions, invoice write-off, native SMS (connect Twilio, manual send, templates, opt-outs), plus the docs/governance cleanup and a batch of fixes.
Added
- Manage who can be texted (opt-outs). Settings, Text messages now lists opted-out numbers and lets you add one by hand, for when a client asks to stop receiving texts (a dedicated number records STOP replies automatically; a Sender ID can't, so you add those here). Any number on the list is never texted, and you can re-allow a number with one click.
- Saved text-message templates. Settings, Text messages now has a Message templates area where you can save your common texts (a session reminder, a thank-you). When you text a client from their enquiry, a "Use a template" dropdown drops the saved message straight into the box, ready to tweak and send.
- Text a client from their enquiry. Once text messaging is switched on, a Text button appears on the enquiry page next to Email. Write a short message, send, and it goes out through your Twilio account. Opted-out numbers are skipped automatically, the opt-out line is added for you when you use a Sender ID, and every text is recorded. (Automatic texts from reminders and workflows come next.)
- Text messages: connect your own Twilio account (setup screen). A new Settings, Connections, Text messages page lets a studio connect its own Twilio account to text clients (your Account SID + Auth Token, the token stored encrypted and checked with Twilio when you save). Choose how texts are sent from, a Sender ID (your studio name, with a required opt-out line) or a dedicated number (two-way, with automatic STOP). Off by default: nothing sends until you connect a validated account and flip the master switch. Comes with a detailed step-by-step help article (including the exact answers to pick during Twilio signup). Sending wires up in the next step.
Changed
- Calendar settings now show your live Compass Leads and Compass Jobs calendars by name. When lead and job push is on, the Lead and job calendar card names the two calendars Compass created, says which Google account they live in, and explains they show up under "Other calendars" in Google's sidebar (where you may need to tick them on). This clears up the "I can see the lead in my calendar but not in Google" confusion.
Added
- Write off an unpaid invoice as bad debt. When you've given up collecting on an invoice, you can now write off the remaining balance from the invoice page (with an optional reason). It stops the automated reminders and stays on record as bad debt (it is never shown as paid), so your books and your accountant see the truth. Written-off invoices get their own filter on the Money page, a "Bad debt" flag in the accountant CSV export, and they drop out of the client portal. Cancelling a whole invoice is still coming separately.
Changed
- Payment reminders now chase the next scheduled payment, not just the whole invoice. When an invoice is on a payment schedule, automated reminders are timed to the next unpaid installment's due date and show that payment's amount plus the balance still remaining, instead of the whole invoice total on a single due date. Part-paid invoices keep getting reminders (they used to be skipped once a payment was recorded), and each reminder amount now shows in the invoice's own currency. Recording a payment, or changing the schedule, re-points the reminders to the next payment automatically.
Added
- Put a payment plan on a quote, and it carries through to the invoice. The quote editor now has a Payment schedule picker: choose one of your saved schedules (or "Pay in full") and you see a live preview of how the total splits. The client sees that dated plan on the quote before they accept, and when they accept, the invoice that's created is automatically split into those dated installments (ready to mark paid as money comes in). Quotes started from a template inherit the template's schedule. You can still add or adjust unpaid payment dates on the invoice afterwards.
- Clients now see the payment schedule on their invoice. When an invoice is split into dated installments, the client-facing invoice page, the client portal, the invoice PDF, and the PDF attached to invoice emails all show the plan (each payment, its due date, amount, and whether it's paid) with a running balance due. A part-paid invoice now also shows correctly in the portal's open invoices (it used to disappear) and reads "Part paid" everywhere its status shows. All amounts render in the invoice's own currency.
- Client, job and portal money totals separate by currency (multi-currency, step 6). A client's and a job's "X paid of Y invoiced" summary, and the client portal's running total, now show one line per currency instead of adding different currencies together, and every invoice amount in those lists shows its own currency. A single-currency client or job reads exactly as before (one line).
- Change a quote's currency from the editor (multi-currency, step 5). When you have regions set up, the quote editor now shows a Region picker just like invoices: pick one and the quote's currency and tax switch together, with the live totals updating as you choose. Quotes still inherit the client's region by default, this just lets you override it on a single quote. Studios with no regions keep the plain tax-rate picker, unchanged.
- Quotes follow the client's region, and Money totals separate by currency (multi-currency, step 4). A quote raised for a client tagged with a region now starts in that region's currency and tax automatically (e.g. a UK client's quotes come out in GBP with VAT). On the Money screen, the Unpaid and Paid totals are shown per currency instead of being added together at a made-up exchange rate, and each invoice in the list shows its own currency. Single-currency studios see no difference.
- Pick a region on an invoice, and set a client's default (multi-currency, step 3). When you have regions set up, the invoice editor shows a "Region" picker: choose one and the invoice's currency and tax follow it (e.g. a UK client billed in GBP with VAT). You can also tag a client with their region on the client's Edit screen, and new invoices for that client start in the right currency automatically. An invoice created from a booking keeps that booking's currency. Studios with no regions see the usual tax-rate picker, unchanged.
- Regions: bill clients in more than one currency (multi-currency, step 2). A new Settings → Regions screen lets a studio set up regions that each pair a currency with the tax that applies there (e.g. "United Kingdom = GBP + VAT" alongside "Australia = AUD + GST"), reusing the tax rates you already defined. Mark one as the default new clients and documents assume. This is the model and management screen; tagging a client with a region and the document currency picker that uses it land next.
- Invoices now carry their own currency (multi-currency, step 1). An invoice created from a quote or job inherits that document's currency, so an accepted GBP quote produces a GBP invoice, and every place the invoice is shown (the invoice page, its payment schedule and balance due, the PDF, the emailed copy, and the client's private link and portal) renders the amounts in that currency instead of always assuming Australian dollars. The tax line is labelled to match the currency too (VAT for GBP/EUR, GST for AUD/NZD, Sales tax for USD/CAD), so a UK invoice no longer reads "GST". Existing invoices keep exactly what they showed before. This is the foundation for full region/currency profiles, per-client defaults, and per-currency reporting landing next.
- Merge a duplicate client from its page ("Duplicate of…"). When a client is a duplicate (e.g. someone who enquired twice under two emails), open it and use "Duplicate of…" to pick the client you want to keep. Any detail the keeper is missing (phone, address, a partner name) is copied across; a different email or phone is saved as a note on the keeper so nothing is lost; then the duplicate moves to the 30-day Trash. If the duplicate still has a live enquiry, booking, or invoice, it can't be removed this way (you'll be told to move or close those first), so real work is never thrown away. Pairs with the new "No enquiry" filter for finding duplicates and the fold_client_into connector tool.
- fold_client_into tool on the Compass connector (de-duplicate clients). An AI assistant can now collapse a duplicate client into the one you keep: it copies any contact detail the keeper is missing (phone, address, a partner name) from the duplicate, preserves a conflicting email or phone as a note on the keeper (never overwrites or discards it), then moves the duplicate to the 30-day Trash. It refuses when the duplicate still has a booking, quote, invoice, contract, questionnaire, or an open enquiry, so real work is never thrown away, and never folds a client into itself. (The in-app version comes next.)
- delete_client tool on the Compass connector. An AI assistant can now move a client to the 30-day Trash through the connector, with the same safety guard as the in-app delete: it refuses when the client still has a booking, quote, invoice, contract, questionnaire, or an open enquiry (it tells you exactly what is blocking), so real work and money are never silently removed. Lost/won or already-trashed enquiries are trashed alongside the client and restored together. The in-app delete and the connector now share one implementation, so they can never drift.
- Find clients with no enquiry ("No enquiry" filter). The Clients list has a new "No enquiry" chip that surfaces clients with no live enquiry and no booking, the ghost rows the everyday views hide (usually a double form submission or a leftover after an enquiry was trashed). The default views stay clean; this is a deliberate filter for tidying up. Open one to merge it into the right client or remove it.
- Payment schedules on invoices. An invoice can now be split into dated installments: pick a saved schedule (or build a custom one), see each payment's due date and amount, mark each one paid as it lands, and watch the balance due update. Only paid installments lock, you can edit, add, or remove the unpaid ones any time, and the plan always adds up to the invoice total. The invoice status moves Unpaid to Part paid to Paid on its own. (Showing the plan on the client portal and PDF, and on quotes, comes next.)
- Invoice emails now carry the invoice PDF. When you email an invoice,
and on the automated due / overdue / paid reminders, the branded invoice
PDF (the same document as "Save as PDF") rides along as an attachment named
Invoice-
.pdf. If the PDF can't be generated, the email still sends without it, so a missing document never holds up a client email.
- Guided mode helps new studios find their way around. New accounts start in guided mode: a slim banner shows it is on with a one-tap switch to turn it off, the getting-started checklist calls out the next step and explains the payoff of each one ("set your prices once and never retype them"), and a short tip appears on each setup screen telling you what to do there and why it helps. You can keep just the parts you want, the checklist, the tips, or both, from a control in the profile menu, which is also the permanent place to switch guided mode back on later. Turn it off and the whole layer vanishes for a plain interface. Same look in light and dark.
Changed
The "+ New" button now sits on the list itself, top-right, on every settings collection. Packages, payment schedules, tax rates, expenses, lead sources, templates (contract, questionnaire, quote and invoice), workflows and contact forms all share one consistent add button instead of it floating in the page header or hiding at the bottom. On a phone it shows a compact "+ New"; on a wider screen the full label ("+ Add package", "+ New workflow"). Same look in light and dark.
On/off settings now use the same toggle switch everywhere. The "I'm GST-registered" setting and the "create the invoice automatically on acceptance" option on a quote template are now the same iOS-style switch used across the rest of Compass, instead of a bare checkbox. Same look in light and dark.
Merge fields now show as chips in every email and template editor. A field like {{name}}, {{studio_name}} or {{event_date}} reads as one tidy chip while you write instead of raw braces, so it's obvious at a glance what gets filled in. The actual field is unchanged, it still fills in with your client's details when the message sends.
Fixed
- The new/edit invoice editor's live total now uses the region's tax rate. When you pick a region (or a tax rate) on an invoice, the running totals box now recalculates tax at that rate as you type, instead of always using the workspace's default rate. Previously the preview could show, say, 10% while the saved invoice correctly used 20%, now they match. The saved invoice was always correct; this fixes only the live preview.
- Compass's own Leads/Jobs calendars can never be mistaken for a bookable calendar. The conflict-check setup now explicitly skips the two calendars Compass creates for the lead/job mirror, so they can't be offered as a "blocks my availability" calendar or auto-picked as a booking destination (previously they were left out only by luck of how Google lists calendars).
- Multi-currency polish on the client page, quotes, and the invoice form. A foreign-currency invoice now shows its own currency symbol in the client page's invoice list (it was showing the workspace symbol), a quote raised for a client tagged with a region now remembers that region in the editor (the picker no longer reads "No region"), and the invoice Tip helper text no longer hardcodes "GST".
The Money "Unpaid total" now counts what's actually still owing on a part-paid invoice. When an invoice is on a payment schedule and some (but not all) installments are paid, the Unpaid total used to ignore it entirely and the Unpaid filter hid it. It now appears under Unpaid, the Unpaid total counts only the balance still due (total minus what's been paid), and the amount already collected counts toward the Paid total, so the two cards add up. Each part-paid row also shows the balance due beneath its total, and its status reads "Part paid". Single-currency studios are unaffected; the per currency split is unchanged.
The invoice PDF attachment is now named to match the invoice. The branded PDF that rides along on invoice emails is named after the invoice's displayed number (Invoice-0002.pdf for sequential numbering, Invoice-20260615.pdf for date-based), instead of the raw internal number (Invoice-2.pdf).
Editor menus no longer get cut off by the body box. The text-colour picker and the Insert from Files panel open downward from the toolbar, and the lower part used to be clipped by the email body. They now show in full.
The Files library help article now describes sharing accurately. It said client sharing was "coming next", but sharing files (links and attachments in emails, and the portal Files tab) has shipped. The article now explains how controlled, revocable sharing works.
Added
Save an invoice as a clean PDF. A "Save as PDF" button on your invoice view and on the client's portal invoice generates an elegant A4 document in your brand type (the Compass serif + sans), with a tinted header band, your logo, line items, totals, and payment details, not a screenshot of the screen. It's titled "Tax Invoice" automatically when you're GST-registered (plain "Invoice" if not), the grand total sits in a matching accent panel, and multi-line item descriptions (a package title with its inclusions beneath) keep their line breaks instead of running together. First of the document PDFs; quotes, contracts, and questionnaires follow.
Choose your document colour, in Settings, Business profile. One accent colour tints every document the same way (the header band, the line beneath it, the total panel, and the brand dot), across quotes, invoices, contracts and questionnaires. Pick from a small palette or any custom colour, with a live preview; the default is the Compass red.
Invoices now show the event, a PayID, and per-line tax. When an invoice is tied to a booking, the PDF shows the event (couple, shoot, date, venue) above the line items. You can add a PayID (mobile, email or ABN) in Settings, Invoicing, Getting paid, and it appears alongside your bank transfer details. Each line also shows its tax treatment (e.g. "10% incl.").
Save a quote as a PDF. A "Save as PDF" button on your quote view and on the client's quote page generates the same elegant branded A4 document as invoices (your colour, the event details, line items, GST, validity date, terms, and an accepted stamp once it's signed). Second of the document PDFs.
Save a contract as a PDF. A "Save as PDF" button on your contract view and on the client's signing page generates a branded A4 copy of the agreement (your colour and logo, the full contract text, and the signature stamp once it's signed). Third of the document PDFs.
Save a completed questionnaire as a PDF. A "Save as PDF" button on the questionnaire view and the client's questionnaire page generates a branded A4 copy with every question and its answer (unanswered questions read "No answer"). Fourth of the document PDFs, the set is now complete: invoices, quotes, contracts, and questionnaires all share one branded look.
Upload your logo once, in Settings, Business profile. It becomes the single source of truth for your mark and shows top-left on your documents, emails, and the client portal. A live preview shows exactly how it appears (or your studio name, if you have no logo yet). Replaces the old buried "paste an image URL" field; your existing logo is carried over.
Attach a file from your library to automated, template, and booking emails. "Insert from Files" now works in workflow email steps, your saved email templates, the manual "send this step" dialog, your email signature, and your booking emails (confirmation, reminder, cancellation, reschedule), not just the one-off composer. Because one template can go to many people, each send mints its own fresh, version-pinned link, so a file in a template is shared safely and stays individually revocable from Settings, Files.
Start a contact form's auto-reply from one of your email templates. On a contact form's Configure tab, the auto-reply now has a "Start from a template" picker that fills the subject and body for you (your enquiry auto-reply templates are listed first). Edit it afterwards as you like. The on/off control is now the standard toggle switch, and "Enquiry auto-reply" is now a category you can give a template so it shows up here.
All four booking emails are now customisable per event type. The set is complete: Confirmation, Reminder, Cancellation and now Reschedule each have their own editor in Settings, Booking pages. Write the message in your words; the time, location, join link and reschedule details are still added automatically where they apply. Leave any untouched and it reads as before.
Booking cancellation emails are now customisable too. Each event type now has a "Cancellation" email editor alongside Confirmation and Reminder, so the note your client gets when a booking is cancelled can be in your own words. Leave it untouched and it reads as before.
You can now customise the reminder email your clients get before a booking, not just the confirmation. Each event type now has separate "Confirmation" and "Reminder" email editors in Settings, Booking pages. Write the message in your own words with merge fields like
{{invitee_first_name}}and{{event_datetime}}; the time, location, join link and reschedule button are still added automatically, so a custom reminder can never accidentally drop the join link. Leave it untouched and reminders read exactly as before.The public roadmap (/tree) now shows Starter content and the Product catalogue. Two capabilities that shipped recently are now reflected on the roadmap: example content for new accounts, and organising packages into categories with archive and duplicate.
Editing settings lists feels more responsive: inline actions, a save highlight, and centered popups. On Packages & products, Edit, Duplicate and Archive now sit right in each row (no need to open the editor first), and every button shows what it's doing the moment you click it (Duplicating, Archiving, Restoring, Saving). When you save an item, its row briefly highlights so with similar names you can see exactly which one changed. The editor popups now open centered on screen instead of tucked in the top-left corner. The same save-highlight and centering apply to tax rates and payment schedules too.
That same button feedback now runs across every Settings list. Contract templates, questionnaire templates, quote and invoice templates, workflows, event types, pipeline stages and lead sources all got the treatment: every archive, restore, duplicate, delete, pause and save button shows what it's doing the moment you click it, and saving an item briefly highlights its row so you can see which one changed. No more wondering whether a click landed.
New accounts start with example content instead of blank screens. When you finish setup, Compass fills your Packages, email templates, contract and questionnaire templates, payment schedule and a follow-up workflow with ready-made examples tailored to your industry, each clearly marked
[Sample]so you know they're starting points. Edit them to make them yours, or delete the ones you don't need. Your tax rate is set to the right default for your currency too. Nothing is locked in, it's just a running start so the app feels alive from day one.Organise packages & products into categories, archive ones you don't sell right now, and duplicate to make variations fast. Give each package or add-on a category (Weddings, Headshots, whatever you like) and the list groups by it, so a long catalogue is easy to scan. Archive an item to hide it from new quotes without losing it (it moves to a new Archived section you can restore from any time), and Duplicate clones an item so you can tweak a copy instead of starting over. The same categories also group the catalogue dropdown when you build quotes and invoices.
A gentle nudge when a new version is ready. If you have Compass open in a tab while we ship an update, you will now see a quiet, dismissible message: "A new version of Compass is ready. Refresh to update," with a Refresh button. Nothing reloads on its own, and it never interrupts what you are doing. This prevents the occasional "something failed to load" hiccup from an out-of-date tab.
Discarding a draft panel now uses an in-app prompt, not a browser pop-up. The floating draft panels ask "Discard this draft?" with Compass's own dialog, the last spot that still used a native browser confirm. Every prompt in the app is now consistent, and a build check keeps it that way.
Logging an expense is a quick dialog now, and that was the last settings page still showing a permanent open form. Across settings, every section now shows a tidy list with an Add button that opens a dialog, instead of a form sitting open on the page. Consistent end to end.
Adding a lead source is a quick dialog now. The "Add a source" box no longer sits open on the page; it is a button in the Your sources header that opens a small dialog. Your existing sources stay exactly as they were (drag to reorder, click a name to rename).
Tax rates and payment schedules are tidy lists now too. Like Packages, each tax rate and payment schedule is a compact row instead of an always-open form. Tax rates edit in a small dialog; payment schedules expand inline to the full payment editor when you want them. "Add tax rate" and "New schedule" are buttons that open a form, not a permanent block on the page.
Packages & products is far easier to scan and edit. Each package and add-on is now a compact row (image, name, price, profit margin) instead of a tall always-open form, so a long list reads at a glance. Editing opens a tidy dialog, and "Add package" / "Add add-on" buttons sit in each section header. You can now upload a package image (drag a real file in) instead of pasting a URL, and prices show a proper currency symbol.
Pull down to refresh on your phone, and pull a little further for a surprise. On a touch device, pulling down from the top of any signed-in page now refreshes it, with a small compass dial that follows your finger. Pull past the refresh point and three faint dots appear: the only hint that you can keep going. Pull all the way and the needle snaps to true north with a little confetti and a one-line note (which speaks in whichever voice you've picked). It is touch-only and never shows on desktop, and it steps aside for anyone who prefers reduced motion.
The Tree of Compass now shows progress at a glance. The public roadmap (
/tree) gained an honest, segmented progress bar under the intro ("29 of 40 shipped", counted live from the roadmap data so it can never drift), a per-category "shipped" mini bar on every branch, and a gentle pulse on whatever is being built right now. Each feature can carry an optional completion figure shown in its detail popup. No numbers are typed by hand; they are all derived from the curated roadmap, which stays the single safe public layer. Every feature description was also rewritten in plainer, friendlier language with a little emoji, so the tree reads like a person wrote it.Hand your accountant a clean spreadsheet in two clicks. Settings, Invoicing has a new "Export for your accountant" card: pick a date range (it starts on your current financial year), choose whether drafts come along, and download a CSV of your invoices. Every invoice line gets its own row with quantity, price, discount, tax name and rate, net, tax and totals, plus the client and dates, so a bookkeeper or any accounting tool (Xero, QuickBooks, MYOB, a spreadsheet) can take it as-is. Trashed invoices stay out. A direct accounting connection is the next stage on the roadmap; the CSV works everywhere today.
Compass now has a voice, and you can change it. All the small feedback moments (the Saved tick, the undo notice when something moves to the Trash, the apology when a save fails) now come from one carefully written voice: calm, clear and on your side. And in Settings, Appearance there is a new Voice section where you can swap it for something less sensible: Ultra-optimistic, Sarcastic, or Unhinged. The extra voices unlock as you finish your setup steps, the same way themes do, and each card shows a sample line so you can hear it before you commit. Whichever voice you pick, the facts stay intact (what happened, what to do next), it applies only to you, and your clients never see it.
Write the email now, send it later. The composer has a new Schedule button: pick a quick option (In 2 hours, Tomorrow 9am, Monday 9am) or an exact date and time, always in your workspace timezone. Queued emails show on the enquiry in a Scheduled emails card where you can cancel or move them any time before they go. Everything resolves when the email actually sends, so merge fields, your signature, attachments and the recipient address use the latest details, and a scheduled email lands in the portal Files tab exactly like one you sent by hand. If a send fails (say the address bounced in the meantime), it shows as failed on the enquiry with the reason, one click away from retrying.
The email composer grew up: text sizes, smarter spacing, recognisable icons, image alignment, and a toolbar that stays put. You can now set text size (Small, Normal, Large, Huge) anywhere in an email or signature. Paragraph spacing finally matches what real email clients show: pressing Enter reads as a normal new line, and a blank line is exactly one blank line, in the editor and in the sent email alike. The alignment and list buttons use standard icons, selected images can be aligned left, centre or right, recently used text colours appear at the top of the colour picker, and the toolbar stays visible while you scroll a long message. What you compose now arrives looking the same (one shared font and size across the message and signature).
Every file link is now visible and controllable from your Files library. Each file row in Settings, Files shows its links: where each one went (emailed or shared to a portal, and to whom), which version it serves, whether the client has opened it and when last. You can revoke any single link (it stops working immediately, nothing else is touched) or give it an expiry date. A new Versions view lets you download any older version and, when you want to, update every live link to the newest version in one click. Deleting a file that is still linked somewhere now warns you first.
Small files now attach to the email itself; big ones become links, automatically. When you insert a file from your library, Compass checks whether it fits email size limits: files that fit travel as real attachments (you'll see them as removable chips under the message), and anything too large is inserted as a secure link instead. The picker tells you which way each file will go before you choose it. Attached files respect the same portal tick as linked ones, so they also land in the client's Files tab.
The client portal now has a Files tab. Files you email with the new "show in their portal" tick appear there automatically once the email sends, and every enquiry now has a Portal files card where you can share (or remove) any library file with one click. Removing a file from the portal never breaks links the client already received by email. Files stay private by default; nothing appears in a portal unless you emailed it with the tick on or shared it deliberately.
Email any file from your Files library. The email composer's toolbar now has an Insert from Files button: pick a file from your workspace library (or upload a new one on the spot, it is filed against that enquiry) and Compass drops a secure download link into your message. Each link keeps serving the exact version you sent, even if you upload newer versions later, and links stop working if the file is moved to the Trash (restore brings them back). No more re-attaching the same PDF to every email.
Fixed
Large files now upload to the Files library. Uploads go straight to storage instead of passing through the app, so files all the way to the 25MB limit work. Before, anything over about 4.5MB failed with a generic "upload failed" (a hosting request-size cap the app could not raise), so a normal pricing-guide PDF would not go up. The upload error message is also more readable now (it was a faint, semi-transparent toast).
Editing the wedding or event date on an enquiry now updates the calendar, date-clash check, and booking. Previously, saving the date from the enquiry detail page only wrote the legacy column the form field uses, while the column the rest of the app reads stayed stale. The two columns are now kept in sync on every save, so a date change is immediately reflected everywhere.
Pages no longer load unstyled when you navigate from a content page. Leaving a page that carries its own large stylesheet (the Help section, Pricing, the Tree, the changelog, docs) into the app could briefly land on an unstyled screen, because the browser occasionally skipped loading the next page's styles. Those pages now do a full reload when you click into the app, so the destination always arrives fully styled. (Same fix already used when leaving the Waypoint calculator, now applied everywhere.)
The Compass icon shows in the browser tab everywhere. The classic
favicon.icowas an old version, so some browsers and contexts showed a stale icon in the tab even though the rest used the compass mark. It's been regenerated from the current compass (16/32/48px), so the tab icon is consistent across pages and browsers.The event-type editor behaves on a phone. Saving an event type now reliably shows "Saving…" then "Saved" before the dialog closes (it matches the booking-email editor exactly). Tapping into the email body no longer makes the phone zoom in (the rich-text editor now uses a tap-safe text size on mobile, like the other fields). And the dialogs freeze the page behind them while open, so dragging inside one doesn't move the page. (Follow-up to the event-types redesign.)
Today's actions line up neatly. The list item titles now start at the same point on every row, instead of shifting left and right depending on how long each status label ("Overdue 2 days" vs "Overdue 18 days") was. The labels keep their natural sizes; only the titles are aligned.
The home-screen launch screen is more reliable (no more black flash). The branded iOS launch image is now pre-built for every iPhone size instead of being generated on the fly. A slow on-the-fly render could take a few seconds, which is exactly when iOS gives up and shows black on launch. Now it's an instant file, so adding Compass to your home screen reliably shows the branded screen while it loads. (Note: iOS caches the launch image when you add the icon, so delete and re-add the icon once to pick up the new images.)
Less code loads up front on the dashboard. The ⌘K command palette, the install banner, pull-to-refresh, and the new-version watcher now load just after the page appears instead of being part of the initial download, so the dashboard becomes usable a little sooner on a cold launch. Nothing changes in how they behave.
The dashboard loads faster, especially the installed home-screen app. Opening the dashboard used to re-check your sign-in and re-fetch your profile and workspace several times in a single load (once in the page frame, again in the page itself, plus a separate check for the email banner). Those are now resolved once and reused, and the dashboard's data queries run together rather than one after another. Fewer round-trips means the dashboard appears noticeably sooner after launch.
The Sign in / Sign up buttons no longer land on an unstyled page. From the Waypoint calculator (including the "you need an account" gate you reach when reopening the signed-out home-screen app), tapping Sign in or Sign up occasionally loaded /login or /signup with no styling until you refreshed. Those pages carry the large standalone calculator stylesheet, and an in-app navigation away from them sometimes failed to load the next page's CSS. The two buttons now do a full page load on Waypoint/Roadmap, so the destination always arrives fully styled. (Extends the earlier full-load fix, which only covered the signed-in nav links.)
The dashboard now shows its loading layout instead of a black screen on a cold launch. Opening the app (especially the installed home-screen version) used to sit on black for several seconds while the dashboard loaded everything before drawing anything. The page shell + a loading skeleton now paint quickly, then your numbers and lists fill in, so you see the app taking shape rather than a black void.
Less black screen when launching the home-screen (installed) app. The branded splash now caches hard so iOS shows it reliably during the cold launch instead of a black screen, there's a catch-all splash for devices that don't exactly match a known size, and the app paints its background the instant it loads rather than flashing black first. (The remaining launch delay is cold start + loading your dashboard; reducing that is a separate performance pass.)
Contact forms: clearer message when you're over your plan's form limit. If you had more forms than your plan allows (after a downgrade), the notice read "you're using all 1 form" even with 2 in use. It now says exactly how many you're over and what to do, and the wording is correct whether you're under, at, or over the limit (singular and plural).
Contact form Preview now has a way back. Previewing a form opened a bare standalone page with no navigation, a dead-end on an installed (home-screen) app where there's no browser back button. The preview now shows a sticky "Back to forms" bar. The live, embeddable form stays completely bare.
Dates and times across the app now show in your timezone, not the server's. Anything with a time on it, "last synced," "created," "cancelled at," booking times, activity timestamps, and the times in booking emails to clients, used to render off the server's UTC clock, so they could read the wrong day or time depending on where you are. They now use your workspace timezone (set in Business profile), and client emails use your business's home timezone so clients always see a consistent time. Plain calendar dates (wedding dates, due dates) are unchanged, those were always correct.
The dashboard greeting now shows the right day after midnight. It used to read the date off the server's clock (UTC), so in the early hours it could still show yesterday's date (e.g. 2am Saturday in Australia showed "Friday"). It now uses your workspace timezone.
The changelog page reads better on a phone. The big title now scales down to fit narrow screens instead of crowding the edges, the page uses the full width on mobile, and long file paths in the text wrap instead of forcing the page to scroll sideways.
The dashboard's "60-second walkthrough" now actually walks you through getting started. It used to link to a recap of the signup steps you'd already finished. It now opens a new "Getting started with Compass" guide: get a lead in, move it across your board, send a quote, turn a yes into a booking, and get paid.
Onboarding now lands you on your dashboard. Finishing setup used to drop you straight onto an empty board; it now opens the dashboard, your home base.
Stopped naming other CRMs in the app, and dropped the "kanban" jargon. The CSV import hint no longer names a specific competitor (Google Sheets and a generic spreadsheet stay), and the places that called your board a "pipeline kanban" now just call it your board, in the dashboard, onboarding, settings labels, help, the pricing page and the public roadmap.
The default funnel stage is now "Discovery Call Done" for everyone. New workspaces were being seeded with a stage named after one studio's own "Chemistry" branding. The default is now the neutral "Discovery Call Done" (the underlying analytics status is unchanged), and existing workspaces still on the old default name are updated too. You can still rename it to anything during setup or in Settings.
Removed the em dashes from the backup-code welcome email. Replaced them with plain punctuation, in line with the house style.
Changed
Picking a font for your contact form is now visual. Instead of typing a CSS font name and pasting a Google Fonts URL, you pick from a grid of fonts, each shown in its own typeface, grouped into System, web-safe (load instantly), and Google Fonts (load from Google, no URL needed). The live preview updates as you choose. Typing a custom font name / URL is still available under "Use a custom font (advanced)". (Design-language slice 3.)
On/off settings get a consistent switch. Introduced one shared iOS-style toggle used for single on/off settings (the client portal's "ask visitors to confirm their email" and "new clients start with a combined portal" settings), so toggles look and behave the same in light and dark across the app. More single-setting checkboxes move onto it next. (Design-language slice 2.)
Signed-out navigation points to Pricing. When you're not signed in, the homepage now shows just a Pricing link (plus Sign in / Sign up), and every other public page shows the app sections (which open the sign-up prompt when tapped) alongside Pricing. The sign-up prompt's second button is now "Show me pricing" (it opens the pricing page) instead of "Maybe later". Signed-in navigation is unchanged.
Event types have a calmer, consistent row. Each event type used to cram Edit, Copy, four email buttons, Pause and Delete onto one line. Now the row shows the name, key details, one Edit button, and a "⋯" menu (Copy link, Pause, Delete). The four booking emails (confirmation, reminder, cancellation, reschedule) move into an "Emails" section inside the Edit dialog, where you set up the rest of that event type. (Design- language rollout, wave 3.)
Lead sources now use the same clean row layout as Packages. Each source keeps its drag handle for reordering, leads with one Rename button, and tucks Archive and Delete behind a single "⋯" menu, so the actions stop crowding the name and slug. Sources are grouped into tidy cards per category, and the Add buttons match the rest of the app. (Design-language rollout, wave 2.)
Packages & products rows have a cleaner, more consistent layout. Each row now leads with one Edit button and tucks the rest (Duplicate, Archive) behind a tidy "⋯" menu, instead of spreading every button across the row. On a phone the row stacks neatly (name and price, then category and margin, then the actions) so nothing gets squashed or cut off. This is the first step of a shared design language: the same row will roll out to the other settings lists so they all look and behave the same.
Onboarding buttons now respond when you click them, and you can step back from the last screen. Continue and "Open my board" show a pending state (and a subtle press) the moment you tap, so a slow save never feels like a dead click, and the final summary screen now has a Back link in case you want to tweak your stages before finishing.
The top navigation now folds away smoothly as you scroll on a phone. When you scroll down, the row of links (Dashboard, Clients, and so on) eases shut instead of vanishing in a snap, and eases back open when you scroll up or reach the top. The compact bar with the logo and your avatar stays put the whole time. It used to disappear and reappear abruptly, which read like a glitch.
Public copy now aims at freelancers, creative professionals, and service-based business owners (was "freelancers and agencies"). Updated the homepage title/eyebrow/hero/features copy, the footer taglines, the pricing product description, and the SEO keywords (dropped "agency CRM", added "CRM for creative professionals", "CRM for service businesses", and "CRM for consultants"). Drops the unbuilt "agencies" framing in favour of audiences the product serves today.
Booking a lead by hand is now one deliberate button, and it always creates the job. You can no longer drag or set an enquiry to "Booked" from the board, the list dropdown, or the enquiry's Status picker (so you can't accidentally mark something booked, and you can't end up with a "booked" lead that has no job behind it). Instead there's a single explicit "Mark as booked" button on the enquiry, for deals you closed without a quote or contract. Booking still happens automatically too when a quote is accepted, a contract is signed, or a payment is recorded.
The "Won" stage is now called "Booked". The default label for a secured enquiry reads "Booked" instead of "Won" across the app (the board, dashboard, reports, help), and the win-rate metric is now "Booking rate". You can still rename the stage to anything you like in Settings. (Wording only for now; how a lead becomes Booked is unchanged, the auto-trigger rewire comes next.)
Homepage and pricing now speak to freelancers and agencies, not just photographers/studios. The hero, the "what you get" section, the pricing intro and the page metadata previously led with "creative professionals" / "creative studio" / "creatives". They now position Compass as a toolkit for freelancers and agencies running any kind of client work, with the creative and event trades used as varied examples rather than the default. The pricing FAQ that asked "What if I'm not a photographer?" now answers what kinds of work Compass fits: it lists the real built-in industry setups and explains that anyone else can pick "Other" and rename everything to match how they work.
Examples across the app are now varied, and no longer photography-first. Business-name and quote placeholders, the onboarding examples, the pricing FAQ, the SEO keywords, and the help and Tree example lists were photography-led. They now spread across trades (design, coaching, DJ, copywriting, celebrancy, florals, planning, hair and makeup, and yes photography) and never lead with photo or video. Added broader search keywords (freelancers, designers, copywriters, agencies). Cleared a few stray em dashes in the quote screens along the way.
The word "Pipeline" is retired from the interface. It now reads in the terms Compass actually uses: the section is "Enquiries", the kanban view's default name is "Board" (still renamable in Settings, Workflow/Funnel/etc.), and the columns are "stages". Updated everywhere it showed: the homepage feature + meta, the OG image, the command palette, the enquiry detail card ("Stage"), the settings labels, pricing, the help articles, onboarding, and the dashboard metrics ("Enquiry value", "Enquiry drop-off"). Searching "pipeline" in the command palette still finds the board. (Internal code names are unchanged; this is the visible wording only.)
Added
The Files library: upload once, reuse everywhere (, part 1). New Settings, Files area for the documents you send often (pricing guides, brochures, checklists). Files are versioned: replacing one makes a new version while anything you already shared keeps the exact version it got, so a sent pricing guide never silently changes. Storage is private (no public links; you download through your account), deleting goes to the 30-day Trash like everything else, and search-friendly names, descriptions and tags keep the library tidy. Coming next on top of this store: pick files in the email composer, share them on client portals, and smart attach-versus-link.
Deleting feels right-sized now: one click + Undo for everyday deletes, type-to-confirm for the irreversible ones (complete). Moving an enquiry, quote, invoice, contract, questionnaire or contact to the Trash no longer interrupts you with a dialog; it happens in one click and a toast with an Undo button appears for ten seconds (Undo puts everything back, including a contact's enquiries). The truly irreversible actions gained friction instead: "Empty trash" and permanently deleting a contact now ask you to type a short phrase before the button unlocks.
Deleting a contact now uses the Trash too, and the whole Trash story is complete. Removing a contact moves them to Settings, Trash for 30 days along with their remaining enquiries; restoring the contact brings back exactly the enquiries that left with them (anything you trashed separately stays in the Trash). A trashed contact disappears from every list and picker, their portal link stops working, and a new enquiry from the same email address creates a fresh contact instead of resurrecting the old one. The existing safety rules still apply: a contact with bookings, live documents or open enquiries can't be deleted at all. Empty trash and the nightly purge cover contacts as well.
Contracts and questionnaires now go to the Trash too (trash complete for documents). Deleting an unsigned contract or a questionnaire moves it to Settings, Trash for 30 days with restore and delete-forever. Trashed documents disappear from their lists, the client portal, public signing and fill links, the dashboard and the AI connector. Signed contracts remain protected and can never be deleted.
Draft quotes now go to the Trash instead of vanishing. Deleting a draft quote moves it to Settings, Trash for 30 days with restore and delete-forever, same as enquiries and invoices. Trashed quotes disappear from the quotes list, client, job and enquiry pages, the portal, public quote links, the dashboard and the AI connector, and a trashed quote can never be superseded or accepted. Quote numbers are not reused while a quote sits in the Trash. Sent and accepted quotes still can't be deleted at all (they are commercial history).
Invoices now go to the Trash instead of vanishing. Deleting an invoice moves it to Settings, Trash for 30 days, where you can restore it or delete it forever; the nightly cleanup purges anything older. While an invoice sits in the Trash its number is never reused, so a restore can never collide. Trashed invoices disappear from Money, the client, job and enquiry pages, the client portal, public links, payment reminders and totals. "Empty trash" now clears trashed invoices too. (Paid invoices are protected records and can never be deleted at all.)
Changed
- Paid invoices and signed contracts can no longer be deleted (protected records). A paid invoice is financial history and a signed contract is a legal record; both now refuse deletion at the server (even from stale buttons) and the Delete control is replaced with a short explanation of why it's gone and what to do instead (for a signed contract that no longer applies, void it so it stays visible with a 'void' label).
Fixed
Activity times now show in your timezone, not the server's. The enquiry Activity feed stamped entries with UTC times (a note logged at 11:37 pm in Perth read "3:37 pm"), and its Today/Yesterday day headers could bucket evening entries under the wrong day. The in-app Calendar's booking time labels and the dashboard's Today list had the same fault. All three now format in your workspace timezone.
Enquiries created through the AI connector now reach your synced calendar. An enquiry created by a connected AI assistant (for example from a screenshot of a text conversation) appeared in Compass and on the in-app Calendar, but never on your own synced calendar: the connector's create and update tools skipped the calendar push that every in-app path performs. Both now push, and status changes made by the assistant move the event between your Leads and Jobs calendars just like in-app changes. Already-created enquiries sync on their next in-app edit.
Added
Empty the trash in one go. The Trash page gains an "Empty trash" button that permanently deletes everything in it right now, instead of waiting out the 30-day window. It asks for confirmation first and tells you how many items are going. (First slice of the safe-deletion work, ; the automatic 30-day purge already ran nightly.)
Undeliverable and unsubscribed contacts now wear a badge, with one-click resume (complete). When an address bounces or a contact unsubscribes or reports spam, the enquiry header and the client profile show a clear badge explaining exactly what still sends and what is held, with a "Resume sending" control that lifts the block once you have fixed the address (the audit trail stays). The enquiry Activity feed also gains a small "?" legend explaining how reliable each email signal is: Sent and Delivered are confirmed, Opened is approximate (mail filters and link previews can trigger it), Clicked is reliable.
Compass now knows what happens to the emails you send (, part 1). Client-facing emails (the composer, workflow sends, quotes, contracts, questionnaires, invoices, payment and booking reminders, booking confirmations, AI-connector sends) are now tracked end to end: the enquiry timeline shows when an email was delivered, opened (marked approximate, since mail filters and previews can trigger opens) and clicked. Problem signals are handled per address: a hard bounce (dead or mistyped address) pauses automated emails to that address and emails you an alert, while emails you send by hand still go through; a spam complaint or unsubscribe blocks only general emails, your documents and payment reminders for active work still send. Soft bounces (full inbox) are transient and change nothing. The "Resume sending" control on the contact and the undeliverable badge land in part 2.
Quote and invoice templates, part 2: Save as template and Start from template (complete). Every quote now has a "Save as template" button (and every invoice one in its action bar) that copies the structure into a new template and drops you in its editor to rename and trim. Creating a new quote offers a "Start from a template" picker (the draft arrives pre-filled with the template's content, terms, tax treatment and attached contract, using the template's quote type), and the new-invoice form gets the same picker (lines, notes and tax rate pre-filled, swappable before you save). Templates carry structure only; client details never travel with them.
Quote and invoice templates: save your standard quote once, reuse it forever (, part 1). New Settings, Templates, Quotes & invoices area: a workspace library of reusable starting points for both quote types (Tailored and Customisable) and for invoices. A template carries the structure (line items, packages and add-ons, prices, tax rate, terms, the attached contract, auto-invoice behaviour), never client details, dates or discounts. Each template has its own full editor (catalog pickers included), plus duplicate, archive and delete from the list. Comes with a help article. The other two entry points (Save as template on a quote/invoice, Start from template when creating one) land next.
Fixed along the way: unticking "Create the invoice automatically when this quote is accepted" now actually saves. The quote editor read the checkbox in a way that meant an unticked box could never persist as off (the same bug class as the email toggles fixed in #144), so auto-invoice was effectively always on. Unticking it now sticks.
Invoices now have due dates, and Compass chases them for you. Set "invoices fall due N days after issue" once in Settings, Invoicing (or pick a due date per invoice) and every sent invoice knows when it's due: the Money list shows "Overdue since..." in red, and the invoice page shows the due date. Automated payment reminders then do the chasing: a friendly nudge before the due date, one on the day, and an overdue sequence that keeps going until the invoice is paid, all timings configurable, sending at 9am your time, linking the client straight to their invoice. Reminders are on by default per your choice, and any single invoice can be paused outright or snoozed until a date (for an agreed arrangement) right from its page.
The client portal gets its own page colour, and one click matches your app's look. Settings, Client portal now has a page-colour picker next to the accent, with a "Match my app look" button that copies your current Compass theme's background and accent onto the portal (a one-time copy, changing your app theme later won't silently restyle what clients see). Cards stay white for legibility. The live preview now paints the real backdrop and shows sample tabs and a sample document card on both the desktop and mobile views, so it reads like the actual portal.
The migration toolkit is complete: contracts, workflow attachment, and job edits via the connector. Three more connector tools: record an already-signed contract from your old system (with the original signer and date, clearly marked as an imported record, never re-signed, never emailed), attach a workflow to an enquiry with the already-done steps pre-ticked and automation starting PAUSED (so no mid-engagement client gets a surprise email), and update a job's details. Together with the earlier tools, a whole client history, contacts, enquiries, jobs, paid invoices, signed contracts, and half-finished workflows, can now move from another CRM in one conversation.
An AI assistant can now build entire workflows in Compass. Six new connector tools behind the new building-blocks switch: list and fetch workflow templates, create a complete workflow (phases, steps with anchors and chained timing, composed per-step emails, questionnaire and contract sends), update one (existing enquiries keep their own copy; pushing changes to them stays a deliberate action in the app), and create the questionnaire and email templates a workflow references. The tools validate everything with specific, fixable error messages (which step, which field, what's allowed), check that referenced templates actually exist, refuse looping step chains, and spell out the timing rules so an AI can't get the date maths backwards. Making a workflow the default stays a deliberate, clearly-warned choice. This is what lets you say "read my old CRM's wedding workflow and rebuild it in Compass" in one conversation.
A third AI safety switch: building blocks. Settings, Connect to AI gains "Allow building blocks (templates & workflows)" alongside the existing changes and sending switches. It governs whether a connected AI can create or edit workflow templates and questionnaire/email templates, the things that shape how future enquiries are handled. Off by default, off until the disclaimer is accepted, and existing AI connections keep working without re-authorising.
Workflows can now anchor on "after job booked". A new timing anchor for workflow steps that fires when the enquiry is booked, whether that happened by quote acceptance, contract signing, or the first payment (the same trinity that books a job automatically). Until now post-acceptance chains could only anchor on "after quote accepted", which never fired for contract-first or payment-first bookings. Available in the workflow editor's timing picker, the due-date badges, and the automated send and reminder schedules.
An optional email check on client portals. Portal links stay friction-light by default (the unguessable link is the key). If you want a second layer, switch on "Ask visitors to confirm their email" in Settings, Client portal: anyone opening a portal first enters the email the link was sent to (the client's address or any extra recipient on the enquiry), no password, and their device stays signed in for 30 days. Wrong guesses get a friendly nudge and reveal nothing, and rapid guessing is throttled.
The form builder shows a live preview. Building or styling a contact form now shows the real thing beside the editor, rendered exactly as visitors will see it (same page background, same card, same fields), updating with every keystroke. You can type into it to feel it out; it never submits. On the Build tab it previews your unsaved fields; on the Style tab, your unsaved colours and fonts.
Contact forms now have plan limits: 1 on Pilot, 3 on Captain, 10 per brand on Fleet. The forms page shows how many you're using; at the limit the New form button makes way for a plain explanation with a link to plans (and the server enforces it regardless). The pricing page's comparison table carries the new row.
The AI connector can now build your client base, jobs, and invoice history. Four new connector tools: create or update clients (re-running an import safely matches existing people by email), create jobs (including completed past work for migrated history), and create invoices as records, including already-paid ones, with your numbering kept sequential or an explicit unused number, and the original system's reference in the notes. Nothing in these tools ever emails a client. Combined with enquiries (already supported), this is the first slice of migrating an old CRM into Compass by just asking your AI assistant.
Every dashboard card can move now, not just the metrics. Today's actions, Next actions, Upcoming events, Recent enquiries and Where they come from all join the same drag-and-resize grid as your metric widgets: hit Edit layout and arrange the whole dashboard exactly how you want it, per person. The standing cards can be moved and resized but not removed (so nothing important can vanish), and your arrangement is remembered like the rest of the layout.
Invoicing settings reorganised into four clear sections. Business details, the GST toggle, Getting paid (bank + terms), and Numbering & logo each show as an at-a-glance summary with edits in a focused window (the GST toggle just saves the moment you flick it). Each section saves on its own, so updating your bank details can never touch your numbering, and every save confirms inline.
Email settings now save in three independent pieces. Sender details (name + reply-to) show as a summary and edit in a focused window; the signature keeps its editor with its own Save; the four preferences (BCC me, tracking, new-lead notifications, daily digest) save the moment you flick them. Each piece saves on its own, so saving one can no longer overwrite another.
Three more settings join the new save patterns. Your name in Profile now saves itself when you leave the field. Calendar preferences (date format, time format, week start) save the moment you pick an option, no more Save button at the bottom. And the Public profile card shows your live page link and welcome message at a glance, with edits in a focused window. All three confirm with the same inline Saving…/Saved feedback. A full audit of every other settings page confirmed the rest already behave correctly for what they are (lists, builders and editors), with two larger conversions (email sender details, invoicing) queued for their own passes.
Business details now edit in a focused window. On Settings, Business profile, your studio name, brand, industry, timezone and currency show as a tidy read-only summary; Edit opens a focused window with one Save, and the card confirms with the same Saved feedback as everywhere else. This is the editing pattern the rest of Settings is moving to: see your settings at a glance, change them in a focused window, one obvious Save.
The new-enquiry window now floats, drags, and follows you around the app. Adding an enquiry no longer locks the page behind a blocking popup: it opens as a floating panel you can drag anywhere, keep using the page underneath, and minimise to a pill in the corner. Your half-typed draft survives navigating to any other page, and restores exactly where you left off. Closing a draft with typed content asks first; pressing Escape just minimises (it never throws your draft away). On phones it opens as a full-screen sheet. This floating-panel system is a new app-wide building block; more windows move onto it over time.
Rearrange your dashboard right on the dashboard. A new "Edit layout" button on the dashboard switches the metric cards into edit mode: drag a card to move it, tap S, M or L to resize it on the grid, give any card its own time window (this month or year-to-date instead of following the financial-year picker, shown as a small tag on the card), or remove it with one tap. Changes save as you go with the same Saving…/Saved feedback as Settings. Your layout is now personal too: it's saved to your account, so when teammates arrive everyone arranges their own dashboard without trampling each other's. The settings page keeps the metric library for adding cards; the old up/down arrows are retired.
Your theme now follows your account, and every theme is editable. Until now your theme choice lived only in the browser, so a new device or a reinstall reset you to Light. Now it's saved to your account and synced: pick a theme on one device and it's waiting on the next (existing devices keep their choice; it becomes the account's automatically). Once you've finished setup you can also edit ANY theme's colours (background, text, accent; the rest of the palette derives to match), reset a theme back to its defaults, and save your mixes as named themes that join the gallery. System gets a proper pair picker too: choose which light theme and which dark theme your device's appearance switch flips between. Changes save with the same Saving…/Saved feedback as the rest of Settings. The red dot stays put.
Refer a friend. Every workspace now has its own referral link, in Settings, Refer a friend (with a help article to match). Share it and the page tracks everyone who signs up through it. The rewards are two-sided: when a referral starts a paid plan they get 10% off, and you stack 10% off your own plan per active referral, so ten active referrals make Compass free. Rewards switch on automatically when paid plans launch; the link and the tracking work today.
A real waitlist for paid plans, with a founding-member deal. "Join the waitlist" on the pricing page no longer opens your email app; it takes you through the free signup, and inside the app a slim bar (and a card in Settings, Billing) lets you join with one click. Joining locks in the founding-member rate: 50% off your first year when Captain and Fleet launch. The bar only shows for free workspaces, disappears the moment you join (the Billing page then shows you're on the list and since when), and goes away for everyone when paid plans go live.
Templates now have their own home in Settings. A new Templates section in the settings sidebar and on the settings home groups everything you reuse: Packages & products (renamed from Packages), Contracts, Questionnaires, and Emails, each as its own page, with quick tabs across the top of every one so you can hop between them. Packages sit alongside the other templates because they're the reusable building blocks your quotes are made from.
Slow settings saves now say what they're doing. Changing your financial year used to quietly grey out for a few seconds with no confirmation. It now shows "Saving…" then "Saved" right next to the setting (and a clear message if it couldn't save). First step of a consistent save-feedback pattern rolling out across Settings.
The enquiry page is redesigned around your workflow. On desktop it's now three columns: the workflow sits front and centre in a wide middle column (with the activity feed below it), the client portal link, enquiry details and recipients live in a left rail, and quotes, jobs, invoices, contracts and questionnaires live in a right rail. Both rails stay frozen on screen while you scroll a long workflow, and each rail scrolls on its own when it's taller than the window, so the documents you're referencing never disappear off the top. On phones and tablets everything stacks in one column as before, with document cards above the activity feed.
New enquiries now pick up your default workflow automatically. If you've marked one workflow as the default, every new enquiry gets it attached the moment it's created, whether you add it yourself, an AI assistant creates it over the Compass connector, a client submits your contact form, or it arrives from your website as an inbound lead. The workflow comes in held: nothing sends on its own until you open the enquiry and arm its automation, so an overnight enquiry never fires an email before you've looked at it. Before this, the workflow engine sat idle until you attached a workflow to each enquiry by hand. (Safe by design: the attach never blocks creating the enquiry, and a held workflow is skipped by the send engine.)
Invoices now show the same dated lifecycle line as your other documents, finishing "drop the badge, keep the facts". On the Money list, the Status column now reads "Created...", "Issued..." or "Paid..." with the date and time (in your workspace timezone) instead of an Unpaid/Paid tag, so you can see at a glance how long an unpaid invoice has been outstanding, and paid ones turn green. (The Unpaid / Paid / Draft filter buttons are unchanged.) On an invoice's own page, a paid invoice now clearly shows "Paid 5 Jun 2026, 2:39 pm" under the total (and the total reads "Total" rather than "Total due"); before this a paid invoice looked identical to an unpaid one. And the quote page drops its redundant "Status" line, the dated heading and the Sent/Accepted/Declined rows already say everything.
The Waypoint pricing calculator now covers freelancers, professional services, and trades. The "What kind of work do you do?" picker has two new groups: Freelance & Professional Services (consulting, bookkeeping & accounting, marketing & social, virtual assistant) and Trades & Home Services (cleaning, handyman & trades, gardening & landscaping). Each new trade has its own tailored business and per-job cost starting points (the trades use a vehicle/tools/materials cost shape rather than the desk-work one). So a consultant, bookkeeper, cleaner or landscaper sees their own work instead of only weddings, fitness, beauty and design. (More sub-types can still follow.)
A signed contract or a recorded payment now books the job automatically. Until now only accepting a quote turned an enquiry into a booked job. Now when a client signs a contract, or you mark an invoice paid, the enquiry is booked and its job is created too (named after the enquiry), if it isn't already. Whichever happens first creates the one job; the others quietly do nothing. (If the booking ever fails it's logged and the sign/payment still goes through.)
Every document now shows when it last moved, with the time. On the Quotes, Contracts and Questionnaires lists, each one now shows a plain dated line in place of the old status tag, "Created 5 Jun 2026, 2:39 pm", then "Sent...", "Accepted...", "Signed...", "Submitted..." as it progresses, so a brand-new one reads "Created..." instead of looking blank, and a finished one tells you exactly when it happened. Times show in your workspace timezone. Now on the lists, on each document's own page, and on the document cards down the side of an enquiry, a job, and a client. (The invoice pages and the client portal follow next.)
Contracts and questionnaires now show in the client portal the moment you create them. Before, a quote or invoice appeared in the client's portal as soon as you saved it, but a contract or questionnaire only appeared once you pressed Send, so a freshly attached contract was invisible to the client. Now all four behave the same: the moment you create one it shows in the portal, with its open action ready (review a quote, read and sign a contract, fill a questionnaire, view an invoice). The client still needs the private portal link, which only you can share. (Each document quietly gets its own private link the moment it's created.)
A brand-new document just exists, no "Draft" label anywhere. Following on from hiding the draft pill on the document lists and detail pages, the same rule now applies on the enquiry, job, and client pages (the Quotes, Invoices, Contracts, and Questionnaires cards in the sidebar) and on the client portal. A just-created quote, invoice, contract, or questionnaire shows no status label until something meaningful happens to it (sent, accepted, signed, paid, completed), which still shows as before. On the client portal this means your clients never see an internal "Draft" word on a quote or invoice. (Step 2 of "drop the badge, keep the facts".)
Mark a date clash as intentional. Sometimes two events on the same day are on purpose (you shoot one wedding, a second shooter covers another). Open either the enquiry or the job, click "This is intentional, hide it", and the clash warning clears for that date (with a "show the warning again" link to undo). A genuinely accidental third booking on that date would still flag, so you only silence the ones you mean to.
Date clashes are flagged automatically. When two enquiries (or an enquiry and a booked job) fall on the same event date, Compass now warns you: a "Date clash" tag appears next to the date in the Enquiries list and board, and opening an enquiry shows a banner listing the other enquiries/jobs on that date, with links. So a double-booking risk is evident the moment two land on the same day. (Lost enquiries and cancelled jobs are ignored.)
Edit a contract's wording right from the quote, before you save. Attach a contract to a quote and an "Edit contract wording" section appears immediately (no need to save first): tweak the text with the same formatting toolbar, and those edits become the contract when you save the quote. No detour to the contract's own page. Switching the attached template re-loads that template's wording. (Names and dates fill in automatically when you save.)
Contract bodies can now be formatted. The contract body editor (when you create or edit a template in Settings, and when you edit a contract on a job) is now a proper rich-text editor: bold, italic, underline, bullet and numbered lists, alignment, and text colour, instead of plain text. The formatting shows through on the client's signing page and on your own contract view. Existing plain-text templates and contracts keep working untouched, and pick up the new editor with their wording intact the next time you open them. (Images aren't included, contracts don't need them.)
Clients can update a submitted questionnaire. After submitting, there's now an "update your responses" option to change an answer and re-submit. Each submission is kept as a version (the previous answers are archived), so nothing is lost.
Questionnaires save as your client types. A client filling out a questionnaire now has their answers auto-saved as they go (with a "Changes saved" note), so they can stop and pick up later, even on another device, without losing anything. Submitting still finalises it as before.
Clients can open their invoice from the portal. The portal's invoice was text-only with no way to see the detail. Now each invoice has a private link to a clean invoice view (line items, totals, and how to pay). Online card payment is still coming; for now it shows your payment instructions.
Quotes are usable the moment you save them. A saved quote is now live and shareable straight away: copy its link from the quote page and send it however you like, or hit Send to email it. The client can review and accept from that link without you having to "send" first. Saved quotes also stay editable until the client accepts (after that they lock, and trying to save shows a notice). ("Draft" now reads as "Ready", a saved quote isn't an unfinished draft.) This is step 1 of a larger quote revamp.
Attach a contract to a quote and it appears right away. When a quote has a contract template attached, the contract is now created the moment you save (as a draft, on the enquiry), instead of only when you send the quote. Sending the quote still emails the contract for signing. Change the attached template and the old draft is cleaned up; delete the draft quote and its draft contract goes too. (Step 2 of the quote revamp.)
Quote discounts can now say what they're for. When you add a discount to a quote, there's a "What's this discount for?" field, and the reason shows to the client on the quote (e.g. "Returning client"). (Per-line and itemised discounts are coming in a follow-up.)
The client portal now has tabs. A job's portal shows Home plus a tab for each document type it has, Quote, Contract, Invoice, Questionnaire, each with its own shareable URL. A small red badge on a tab counts what's waiting on the client (a quote to review, a contract to sign, an unpaid invoice, a questionnaire to fill), so they can see at a glance what needs them. (Combined portals keep their grouped-by-job overview.)
Each job now has its own client portal link, ready to share. Open an enquiry and the "Client portal" card at the top of the sidebar has a private link. Send it to the client and they see one page with everything for that job, the quotes, invoices, contracts, questionnaires, and bookings, all in one place. The link is created automatically (no setup) and you can copy it or open it to preview exactly what the client sees. (The older per-client portal link on the client page has been removed in favour of this per-job link.)
Optional "combined" portal for repeat clients. On a client's page there's now a "Combined portal" toggle. Leave it off (the default) and each job keeps its own link. Turn it on for a client who has more than one job with you and they get a single link that lists every job, grouped by job, with that job's own quotes, invoices, contracts, questionnaires, and bookings under each. Every job shows its own section (one with nothing outstanding says so), and finished items collect in a History section at the bottom. Copy or open the combined link right from the toggle.
Brand your client portal. Settings → Client portal now has a Branding section where you set an accent colour, a custom welcome message, and a header banner image (recommended 1600 × 400px, a 4:1 strip), with a live desktop and mobile preview as you go. Your accent shows on the portal, the banner runs full width across the top, and the welcome message replaces the default intro. (Fonts and full palettes will come later with the brand kit.)
Set a workspace-wide default for new client portals. A new Settings → Client portal page lets you choose what new clients start with: one link per job (the default) or a combined link. It only affects clients created from then on, and you can still switch any individual client on their page.
New workspaces start with a ready-to-use email template for each type. Brand-new accounts are seeded with a friendly starter template set as the default for General, Quote sent, Invoice sent, Payment reminder, Contract sent, and Questionnaire sent, so you have something to send (and tweak) from day one instead of a blank list. (Existing accounts keep their own templates, nothing is overwritten.)
The same merge variables now work in automated workflow emails. Workflow send-steps offer (and fill in) the same grouped set as the composer, client phone and email, event location, and your business email / phone / address, not just name and date. Automated emails resolve them through the same shared logic as your hand-written ones, so they stay consistent.
"Lead source" variable in the composer. When you write an email by hand, you can insert the lead's source (how they found you). It isn't offered in workflow steps for now (it would need a per-workspace lookup the automated sender doesn't do yet), so it can't come out blank there.
More merge variables in client emails, grouped by type. The "Insert variable" menu in the email composer now offers client phone and email, event location, and your business email / phone / address (pulled from your Invoicing settings), alongside the existing client name, partner, studio name, and event date, organised under Client / Job / Business headings. Every variable listed actually fills in when the email sends (nothing that would come out blank is offered). The quote/invoice link tags are temporarily not listed while the client portal they'll point into is being built.
Link text to a Compass merge link (quote link, invoice link). The email editor's link button now opens a small panel where you set the display words and the destination, and you can pick a merge link (like Quote link or Invoice link) as that destination with one click. So "view your quote" can link straight to the client's quote, with the real link filled in when the email sends. Makes migrating templates that use link variables straightforward.
Every settings page now has a Help article. Filled the remaining gaps (Lead sources, Tax rates, Marketing & business costs, Trash, and the contact form builder, which had a Help link pointing at an article that never existed). From now on this is a rule the build enforces: a settings page can't ship without a Help article behind its "?" link.
Help articles for everything shipped recently. The Help centre gained new sections and guides covering Quotes, Contracts & e-signatures, Questionnaires, Invoices, Workflows (including automatic sending and its safety limits), emailing clients, booking pages & event types, connecting Google/iCloud calendars, and Appearance & themes, so the newer parts of Compass are actually documented.
A fuller email formatting toolbar. The rich-text editor used for emails and templates now has underline, clear-formatting, paragraph alignment (left, centre, right, justify), and a text-colour picker, on top of the existing bold, italic, link, lists, and inline image. All formatting is written inline so it survives in the recipient's email client. (Text size in px is a small follow-up.)
Email templates are now grouped by purpose, with a default for each. Settings, Email lists your templates under clear headings (General, Quotes, Invoices, Payment reminders, Contracts, Questionnaires), and you can mark one template as the default for a purpose using "Set as default" (a "Default" badge shows which one is set). Defaults are remembered per specific purpose (for example "Invoice sent" separately from "Invoice reminder"). This is the groundwork so the "Email this client" composer can soon show only the relevant templates and pre-pick your default. (Part of the email-templates-by-type work.)
Push a workflow edit to the leads already using it. Editing a workflow used to only affect new leads (each lead keeps its own copy from when it was attached). Now, in Settings, Workflows, a workflow that's on active leads shows "on N active leads" and a "Push to N leads" button that updates them all to the current steps in one go. Their progress (done / stopped) is kept, and finished workflows are left alone.
One-tap reminders for unanswered questionnaires and contracts. When a sent questionnaire or contract is still waiting on the client, it shows in Today's actions with a "Remind" button, one tap re-sends it, no need to open the document. It disappears on its own once the client fills it in or signs (the list only shows ones still outstanding).
Workflows can auto-send questionnaires and contracts, not just emails. A workflow step set to Send questionnaire or Send contract and to "Send automatically on the due date" now creates the document from its template, drops a live link into the step's email (where you put the link variable), and sends it to the included recipients, all on its own, with the same guardrails as automatic emails (daily cap, civil hour, no double-sends, per-lead pause). The document is created once per step, so a failed send never makes a duplicate contract. Stays off until you arm such a step.
A "To send" list across all your enquiries. A new page (linked from the dashboard's Today's actions) gathers every workflow email that's due, overdue, today, or coming up soon, across all your couples in one place, so you can work down the list instead of hunting enquiry by enquiry. Each row opens its enquiry, where you review and send. Steps that send themselves are tagged "Auto"; stopped and paused ones are left out.
"Send now" opens the email so you can review before it goes. Clicking Send now on a workflow step now opens the email pre-filled exactly as it will send (the step's own message, with your details and signature merged in). Tweak anything, tick which saved recipients should get it (the couple, a planner, etc.), and send. It goes out the same audited way as the automatic sends, so manual and automatic are finally identical, and it works for steps you built in the composer (no template needed).
Control automation right on the enquiry. The workflow card now shows an "Auto" tag on steps that send by themselves, a per-step "..." menu (mark done, send now, or Stop automation), and a struck-through "Stopped" look for steps you've halted (different from done). There's also a Pause automation switch for the whole lead, when paused, no automatic emails go out for that enquiry until you resume, though you can still send manually. Ticking, stopping, and pausing are all instant now.
A daily limit on automatic emails per job, so no one gets blasted. A job's workflow will send at most a few automatic emails per day (default 4, set per workspace). If more come due the same day, the extras are held and go out the next day on their own, or you can send them now from the enquiry. When that happens you get a heads-up email naming the job, so you are never surprised.
Workflows can now send emails on their own. A workflow step set to Send email and to "Send automatically on the due date" is emailed to the job's included recipients when it falls due, at a civil hour in your timezone. Every auto-send is recorded, no one is emailed twice, steps armed long after they were due are flagged for review rather than blasted late, and you can pause automation per job. It stays dormant until a step is explicitly armed, with nothing armed it sends nothing. For now this covers email steps; auto-sending questionnaires and contracts comes next.
Rename an enquiry from its title. A pencil next to the enquiry name lets you rename it inline (Enter to save, Esc to cancel). The new name shows straight away. Clear the name to fall back to the couple's names. Until now the enquiry title was fixed at creation and editing the couple fields did not change it.
Quotes is back in the top nav. The full quotes list now has its own nav entry (next to Money), so you can reach every quote without needing the URL.
Jobs: choose who automated emails go to. Every enquiry now has a Recipients panel. The primary client (the one who signs) sits at the top, and you can add secondary clients and third parties like a planner, each with their own email address. A tickbox next to each person decides whether they are included in automated workflow emails: clients are ticked by default, a newly added third party starts unticked so an outsider is never auto-emailed by accident. Colour labels (Primary, Secondary, Third party) show each person's status at a glance. Signing is unchanged, only the primary client signs a contract; the tickboxes only affect who gets emails. Add and edit people behind an Edit control in the panel header, and every tick, add, edit, and remove updates instantly (no page reload wait).
Workflows: write the email each send step sends, and choose manual or automatic. A workflow step set to Send email, Send questionnaire, or the new Send contract now carries its own subject and message, composed right in the workflow editor (start from a template or write from scratch, with client merge fields and, for questionnaire and contract steps, a link variable to drop in). Each send step also chooses how it goes out: wait for you to send it (manual, the default), or send automatically on its due date at your best time, as early as possible, or a specific time. Nothing sends on its own yet, the background engine that acts on the automatic setting is next; until then automatic steps simply show an "Auto" badge.
Workflows: "Send now" on a lead's email steps. When a workflow step is set to Send email with a template bound, the lead's workflow card shows a "Send now" button. One tap sends that template to the client (always to their stored email address), drops your signature in, logs it in the enquiry history, and ticks the step off. You stay in control, nothing sends on its own yet.
Workflows: say what each step does. A workflow step can now be set to Task, Send email, Send questionnaire, or Appointment. For the send actions you pick which template it uses, and the step shows a warning if no template is chosen yet. Steps display a small action chip so a workflow reads at a glance. (Sending still happens when you choose; the automatic scheduler is a later step.)
Workflows: phases you can collapse, rename, and reorder. The workflow editor now groups steps into phases (new workflows start with Lead, Production, and Post). Collapse a phase to tidy a long workflow, rename phases to suit your process, reorder or add and remove them, and move steps between them. Steps show as compact one-line rows now (name plus when it is due), click one to expand and edit it. Existing workflows keep working and tuck their steps into a single phase you can split up.
Per-template signature control. Each email template now has an "Include my signature" switch (on by default). When you start a message from a template, the composer follows that template's preference, and you can still change it for the one send. Turning it off removes the signature (and any {{signature}} marker) for that template.
Email a client straight from their enquiry. The enquiry detail page now has an "Email client" button that opens a composer: start from one of your email templates or a blank message, write with the same rich-text editor (inline images and merge fields like the client's name), and send. The email always goes to the address stored on the enquiry, never one typed in by hand. Your signature is shown exactly as it will appear and added automatically, and you can tweak it for this one send (or drop a {{signature}} marker in the body to place it yourself) without changing your saved signature. Every send is recorded in the enquiry's activity history.
Calendar Year view: starts in January, with a Financial-year toggle. The Year view now opens on the current calendar year (January to December) instead of rolling twelve months forward from today. A new toggle in the calendar header switches between "Calendar year" and "Financial year" (your workspace's financial year, e.g. July to June), and Compass remembers which you prefer on that device.
Faster-feeling navigation (loading skeletons). Opening Clients, Contracts, Quotes, Jobs, Money, Questionnaires, Event bookings, or any of their detail pages now shows an instant, correctly-shaped skeleton while the page loads, instead of a generic placeholder or a frozen screen. The page swaps in as soon as its data is ready.
Duplicate a template. Email, contract, and questionnaire templates each have a Duplicate button now, it makes a copy named "... (copy)" you can then tweak, so you can spin a variant off an existing template without rebuilding it.
Rich email signature (, slice 2). Your email signature is now edited with the same rich-text editor as the rest of Compass's email tooling, so you can format it and drop in a logo or photo, and it matches the emails it is appended to. Existing plain-text signatures keep working (detected and rendered with their line breaks, migrating to the rich format the next time you save). The signature now renders consistently across every outbound email (quote, invoice, contract sends, and AI-sent client emails).
Inline images and GIFs in the email editor (, slice 1). The rich-text editor now has an "Insert image or GIF" button: pick a file, it uploads to storage and embeds by URL (never base64, which hurts deliverability), so emails can carry inline photos and animated GIFs. Live in the event-type email editor now; rolls out to the main Email Templates editor and a new "Email this client" composer next.
Smarter enquiry naming (derived, not baked). New enquiries now build their display name from the structured contact fields per the workspace's rule, instead of trusting whatever single name a form sent. Couples land as "Keely & Alex" automatically, and solo or company-based industries get a sensible single name. Each industry preset ships a default rule (weddings show both partners; hair & makeup shows the first contact), with a Vocabulary override ("How a new enquiry's name is shown"). Applied to both intake paths, the website webhook and the hosted contact form, plus the owner notification and auto-responder.
Workflows: "after a specific step" timing. A workflow step can now be timed relative to any other named step, not just the five fixed anchors (lead created, quote sent, quote accepted, event date, previous step). Pick "after a specific step" and choose which one; the due date resolves off that step's own date (with a cycle guard). First slice of the larger workflow-builder rework. No migration (steps are stored as JSON).
MCP connector, Phase 5: hardening, audit visibility, and help. Closes out the connector. The "Connect to AI" page now shows a Recent AI activity log (every change and send, with status), and warns when both changes and sending are armed together. The MCP endpoint re-checks paid-plan entitlement on every call, so a downgrade cuts off existing connections, not just new ones. Adds a "Connect your CRM to an AI assistant" help article and an AI-connector section to the deploy smoke test.
MCP connector, Phase 4: write and send tools. With the arming toggles on, a connected AI can now act, not just read. Write tools (
create_enquiry,update_enquiry,add_enquiry_note) create and update leads; the send tool (send_client_email) emails a client. Heavily guarded: every write/send call re-checks the per-workspace arming flag (off by default), is rate-limited per workspace (sends tighter), runs as the connected user through RLS, and is recorded in a new audit log. Wrong-recipient protection: the send tool only ever emails the address stored on the named client record, never an address the AI supplies. Tools the connection's scope does not grant are hidden from its tool list.MCP connector, Phase 3: Settings "Connect to AI" + arming toggles. A new Settings page (Connections, Connect to AI) shows the connection address to paste into Claude or ChatGPT, a plain-English how-to, the list of connected apps with one-tap disconnect (revokes that app's tokens), and the tiered permission controls. Reading is always on once connected. "Allow changes (safe writes)" and a separate, louder "Allow sending to clients" are off by default and only arm after the user accepts a warning and liability disclaimer. The flags are stored per workspace and will be re-checked on every write/send (Phase 4). Gated to paid plans.
MCP connector, Phase 2: read tools. The MCP endpoint is live at
/api/mcp(Streamable HTTP, built on @vercel/mcp-adapter), bearer authenticated by the Phase 1 OAuth tokens. It exposes read-only tools across the client-facing surface: leads and enquiries (list_enquiries,get_enquiry), clients (list_clients,get_client), quotes and invoices (list_quotes,get_quote,list_bookings), contracts (list_contracts,get_contract), and calendar (list_meetings,get_availability). Every tool runs as the connected user through their RLS (a real per-user session is minted server-side, never the service role), so an AI only ever sees what that user could see in the app. No write or send tools yet (Phase 4).MCP connector, Phase 1: OAuth 2.1 gateway. Compass is now its own lightweight OAuth 2.1 Authorization Server so paid workspaces can connect their CRM to an LLM (Claude, ChatGPT) over the Model Context Protocol. This phase ships the auth plumbing only (no tools yet): dynamic client registration (RFC 7591), the discovery documents at
/.well-known/oauth-authorization-server(RFC 8414) and/.well-known/oauth-protected-resource(RFC 9728), the/oauth/authorizeconsent screen behind full login plus 2FA, and the/api/oauth/mcp/tokenendpoint with mandatory PKCE S256 and rotating refresh tokens (with reuse detection: replaying a rotated token revokes the whole connection). Tokens are Compass-issued, workspace-scoped, hashed at rest, and validated on every call. The feature is gated to paid plans (open to everyone until billing goes live, so it is testable now).{{partner_name}}contract placeholder for the second partner. Resolves from the client's stored Partner 2, so couples' contracts fill in both names instead of leaving a dead token (and Compass never has to block a send the way Studio Ninja does for single-contact couples). Listed in the template-editor placeholder hint.
Changed
A just-created quote, contract, questionnaire or invoice no longer shows a status badge. A brand-new document is simply editable and "just exists", so the "Draft"/"Ready" pill is gone from the lists and detail pages. The meaningful states stay as the at-a-glance fact (Sent, Accepted, Signed, Completed, Unpaid, Paid, Declined, Void, etc.). (Step 1 of dropping the redundant status badges; the sidebar cards and client portal follow.)
Saving a quote takes you back to the enquiry. The quote editor's button now reads "Save quote" (was "Save draft"), and saving returns you to the enquiry the quote belongs to instead of leaving you on the quote. The attached contract no longer appears to clear after saving (the dropdown used to reset visually even though the contract was saved correctly).
A saved contract reads "Ready", not "Draft". A contract you've set up but not yet sent now shows the status "Ready" (matching how a saved quote reads), since it's editable and ready to send, not an unfinished draft. It's still the same editable, not-yet-sent state.
The settings menu closes when you move to another page. If you open "Show all settings" without pinning it, navigating to a different settings page now starts with it closed again. Pin it (the "Keep open" toggle) to have it stay open across pages as before.
Tidier "Use for" menu on email templates. When choosing what a template is for, the menu no longer offers the three categories with nothing behind them yet (Welcome, Quote declined, and Enquiry auto-reply, the real auto-reply lives on your contact form). Existing templates already set to those still show fine.
"Start from a template" is grouped by type everywhere. Both the "Email this client" composer and a workflow Send-email step now group your templates under the same headings as Settings (General, Quotes, Invoices, Payment reminders, Contracts, Questionnaires), General first, so you can find the right one fast instead of scrolling a flat list. Nothing is hidden (a Send-email step is still the catch-all until dedicated quote/invoice send actions arrive).
Accessible text-colour picker (colourblind-friendly). The email editor's text-colour control no longer opens the operating system's colour wheel. It now opens a list of named colours (Black, Red, Green, Blue, Navy, Purple, and so on) shown as readable labels next to each swatch, so you can pick by name instead of by sight. Includes an "Automatic" (default colour) option and a typed hex field, and the toolbar button's tooltip shows the current colour's name.
Signature preview is tucked away by default in the email composer. The signature used to take up a big chunk of the "Email this client" window. It's now collapsed by default ("Show preview" reveals it, and the per-send edit lives inside), so you get the full room to write your message.
Friendlier merge-variable names. The Insert-variable menu now reads "Client's name", "Client's phone", "My business name", "My business address", "My email signature", etc., under Client / Event / My business headings, clearer than a generic field list.
Cleaner Waypoint/Roadmap headers. Tightened the spacing (less empty room above the eyebrow and between the intro and the first step), shrank the big slash titles (Business / Costs, The / Numbers, Each / Month) so each step takes less vertical space, and made the two pages consistent. The industry button moved below the "Photography pricing" label and now reads "Switch industry" so its purpose is clear.
Warmer "free forever" pricing. The free Pilot plan now reads "Free forever" with a green badge, and the page copy leads with backing creatives while they find their feet and grow at their own pace (no card, no countdown), instead of feature-speak. Hero, FAQ, and meta description updated to match.
Help links open in a new tab and lead back. The "? Help" link on a settings page now opens the article in a new tab, so you keep your place in settings, and each article that documents a setting shows a "Back to
" link at the top for the return trip. The Help link was also added to the pages that were missing it (Workflows, Contract templates, Questionnaire templates, Booking pages, Calendars, Appearance, Email, Invoicing, Packages, Payment schedules, Vocabulary, Dashboard layout). A fresh, more distinct set of appearance themes. The theme gallery (Settings, Appearance) swaps the near-identical older palettes for ones that actually look different from each other: Sage, Apricot, and Ocean (light), plus Midnight, Forest, and Plum (dark), alongside the existing Light, Dark, Espresso, and Build your own. If you were on one of the retired themes it moves you to the closest new one automatically (Sand to Apricot, Slate to Ocean, Noir to Dark), so nothing resets to plain Light.
Faster dashboard, enquiries, and calendar loads. These screens now fetch their independent data in parallel instead of one query after another, so they appear sooner. Every workspace list also carries a safety limit so an unusually large account can never stall a page with an unbounded query.
Quote types renamed for clarity (and to stop echoing Studio Ninja's terms): "Fixed" is now Tailored, "Pick & Choose" is now Customisable. Updated across the new-quote picker, quote list, quote detail, client detail, and the packages copy. Display labels only; the underlying
fixed/pick_choosetype values are unchanged.Packages "Direct cost" relabelled "Your cost", with a hover tooltip explaining it is your cost to deliver (second shooter, prints, travel), and that it is not GST. Same field, clearer label.
Noir and Espresso themes unlock earlier, at more than half the Recommended setup steps (5 of 9) rather than all of them. Build-your-own stays the final, all-steps unlock.
Quote breadcrumb now shows a person icon (Client) and a flag icon (Lead) so the two same-named crumbs are distinguishable.
Fixed
Video-call reminder emails now include the meeting link. The 24-hour and 1-hour booking reminders showed only "Google Meet" with no way to join, the exact moment a client needs the link most. Reminders now show a prominent "Join the meeting" button, matching the confirmation email.
The "Invoices live at /invoices" link on the Invoicing settings page went nowhere. It now points to Money, where invoices actually live.
Three email preference toggles (tracking, new-lead notifications, daily digest) were impossible to turn off. Unticking the box saved nothing, the form read an unchecked box as "leave it on", so the off state was silently ignored. Fixed as part of the email-settings split; if you tried to turn one of these off before and it didn't stick, it will now.
Adding an enquiry now confirms it. Creating an enquiry gave no feedback, the dialog just closed and the new row showed up a moment later, so it felt like nothing happened. You now get an "Enquiry added" confirmation the instant you save.
Contracts read "Ready" everywhere now. The contract list and contract page still showed "Draft" (each kept its own copy of the status labels); both now match the rest of Compass ("Ready" for a saved, unsent contract).
Clearer wording on the quote's auto-invoice option. It now says it creates the invoice (ready for the client to pay) when the quote is accepted, instead of calling it a "draft invoice" (it was never a draft, it's live and payable).
No em dash in the auto-created contract name. A contract created from a quote was named "<Template>. <Client>" with an em dash; it now reads "<Template> for <Client>" (matching the other contract name defaults).
Deleting a contract now shows progress and takes you back to the job. Confirming a delete shows "Deleting…" on the button (it used to look like nothing happened), and afterwards you land back on the enquiry or job the contract belonged to, instead of the flat contracts list. (The progress cue now applies to every confirm-to-delete across Compass.)
The booking "Move to…" buttons now respond instantly. Clicking a status (upcoming, in production, completed, cancelled) used to give no feedback until the page refreshed; the button now shows "Moving…" immediately.
Accepting a quote now creates a live, payable invoice (not a draft). When a client accepts a quote, the invoice it generates is live straight away so they can see and pay it, instead of sitting as a draft. The resulting booking is now named after the enquiry (the couple), not the quote's label.
Clients can get back to their portal after acting, and see the signature right away. After accepting a quote, signing a contract, or submitting a questionnaire, the confirmation now has a "Back to your portal" link. And on signing a contract, the "Signature on file" detail shows immediately on the success screen instead of only after a reload.
Contract "Agreed at" time now shows your timezone. The signed-contract timestamp rendered in UTC; it now uses the studio's timezone, like the rest of the app.
Contracts and questionnaires now link back to their enquiry. The top link on a contract or questionnaire used to say "All contracts/questionnaires" and go to a page you can't otherwise reach. It now reads "Back to
" (or the client) and takes you there, the same as quotes. Booking confirmation emails now show the right time and a join link. The confirmation (and the owner's notification) showed the meeting time in UTC instead of your workspace timezone (e.g. 1:15am rather than 9:15am), now fixed in both. And for video meetings, the email now includes the "Join the meeting" link instead of just the label. (A
{{meeting_link}}variable is also now available for custom booking templates.)Public client links no longer demand a Compass login. The booking page (
/book/...), booking confirmation (/booking/...), contract e-sign (/contract/...), questionnaire (/questionnaire/...), and public studio profile (/p/...) were being bounced to a "needs an account" page for logged out visitors, so clients couldn't book, sign, or fill anything you sent them. They're now correctly public (each is still protected by its own unguessable token/id in the link, the same way quote and portal links already worked).Double-clicking a word no longer secretly makes it bold. In the email editor (signature, composer, templates, workflow steps), double-clicking or triple-clicking to select text could silently apply bold to the selection. The toolbar buttons now act on press rather than on click, so a stray click from selecting text can't trigger Bold by accident. Keyboard use of the toolbar is unchanged.
Email editor: text cursor + toolbar no longer steals your selection. The editing area now shows a proper text (I-beam) cursor, and clicking a toolbar button (Bold, etc.) keeps your highlighted text selected, so a format applies to exactly what you selected instead of the button grabbing focus first.
Bullet and numbered lists show their markers in the email editor again. In the email composer and template editors, list items had lost their bullets/numbers (the underlying list structure was there, just no visible dot or number). They render correctly again.
Waypoint/Roadmap header is frosted again, as one seamless bar. The frosted-glass blur behind the page header had silently stopped rendering (a build-time CSS minifier was dropping the standard property in Chrome/Edge, and an earlier scroll fix disabled it in Safari), so content scrolled under it as sharp text. It is back, and the switcher pill, progress bar, and step row now sit on a single continuous frosted surface with no gap or seam between them on either page.
Waypoint steps no longer creep down the page. Clicking through the steps used to scroll a little further down each time. Now the first step opens at the top and every other step opens with its "Step X of N" heading just under the header, and clicking around holds its place.
Tidier pricing pre-launch badges. The "Coming soon" tag is now uniform on the paid plans and the call-to-action buttons line up across all three cards.
No more unstyled page after leaving Waypoint. Navigating from Waypoint (or Roadmap) into the app sometimes landed on a page with no styling until you refreshed. Those two pages carry a large standalone stylesheet, and the in-app (single-page) navigation away from them occasionally failed to load the next page's styles. Leaving Waypoint/Roadmap now does a full page load, so the destination always arrives fully styled.
Mouse-wheel scrolling works on Waypoint in Chrome. The page set its horizontal-overflow clip on both the page and document elements, which made Chrome create two scroll layers and ignore the mouse wheel (the scrollbar still worked, and Safari was fine). Clipping on one element only restores normal wheel scrolling.
Help articles read better. The expandable sections inside a help article were accidentally inheriting the big card styling from the help home page, which made each collapsed heading a tall, mostly-empty box with a tiny, hard- to-spot triangle. They're now compact rows with a clear round expand button, and the first section opens by default so it's obvious the headings expand.
The phone menu gets out of the way as you scroll. On a phone, the row of menu links now collapses when you scroll down (leaving the compact bar with the logo, tools, and your avatar) and slides back when you scroll up or reach the top, so it stops eating screen space while you read. Inspired by the novoaweddings.com.au header.
The "Show all settings" bar stays glued to the top menu. Pulling the page down past the top no longer bounces and detaches the settings bar from the nav (the elastic overscroll that caused the gap is turned off).
A loading screen when you open Compass from your home screen. Launching the installed app used to show a blank (black) screen for a few seconds with no sign anything was happening (the home-screen app has no address or progress bar). It now shows a branded Compass loading frame that matches your theme and clears itself once the app is ready. iOS also now shows a brand launch image during the very first moments of a cold start (the home-screen app has no progress bar), so the screen is filled from the instant you tap the icon, before any page has loaded.
The top menu is readable on phones now. Instead of cramming every menu item into one shrinking line (which cut off labels), the wordmark, tools, and your avatar stay on the top row, and the menu links (Dashboard, Clients, Enquiries, Jobs, Calendar, Money) drop to their own row underneath at a comfortable, tappable size, wrapping onto a second or third line as needed.
Tapping a field no longer zooms the page on iPhone. Form fields now use a 16px text size on phones, which stops iOS from auto-zooming when you tap into them.
Buttons tell you they're working. Creating a new quote draft now shows "Creating…" instead of sitting silent until the page changes, and saving a payment schedule shows "Saving…" then a brief "Saved", instead of just greying out. (The currency and contract-template saves already had this.)
Quotes send you back where you started. When you begin a quote from an enquiry or a client profile, the back link and deleting the draft now return you to that enquiry or client (named on the link), instead of dropping you on the global quotes list with no way back through the nav.
Quote line items: deleting a row no longer scrambles another row's price. A quote starts with one blank line. If you added a product (so you had the blank line plus the product) and then removed the blank line, the product's price was being replaced with the blank line's 0, both on screen and when saved. Each line now keeps its own identity, so removing one never touches another. Also, adding the first item from the catalog now replaces the starting blank line instead of leaving an empty row above it.
Website enquiries no longer lose their owner notification. When two enquiries arrived at nearly the same moment, both leads were saved but only one "new enquiry" email reached you, and a failed send left no trace. The notification now runs reliably after the response (so it isn't cut short), checks whether it actually sent, retries a transient hiccup, and reports a genuine miss so it can never go silent again.
Passkey sign-in works again. The pre-login passkey endpoints were being blocked by the auth gate before they could run, so "Sign in with a passkey" failed with "Could not start passkey sign-in" in every browser even with a passkey registered. The login passkey endpoints are now reachable while signed out (the rest of the passkey routes stay protected).
Password sign-in works again. Entering your email and password and clicking Sign in wrongly reported "Password is required" and cleared the fields. The form was carrying a hidden, empty copy of the email field that masked the one you typed; it's removed, so password sign-in goes through.
Rich-text editor cursor + image-upload feedback. Three fixes: the caret no longer vanishes on Return / Backspace (the editor was re-syncing its content on every keystroke and resetting the selection); pasted or dropped images now show an "Uploading image…" hint while they upload; and an uploaded image lands where you dropped or pasted it, not wherever the caret happens to be when the upload finishes.
Email template merge fields now show email variables, not scheduler ones. The Email templates editor was reusing the booking editor's variable list (Invitee, Event time, Reschedule link). It now offers client-email fields (Client name, Partner name, Studio name, Event date, Quote link, Invoice number, Invoice link). The editor's variable list is configurable per surface.
Pasted and dropped images in the email editor. Copying an image and pasting it, or dragging an image file onto the editor, now uploads it to storage and embeds the real URL, instead of doing nothing or leaving a broken icon. Images pasted from apps like macOS Mail that arrive as unresolvable references (cid: attachment links) are stripped on paste, so the text comes through clean with no broken image placeholders. (Bulk-copying from Mail still cannot carry the image bytes themselves, those are attachment references, not real image data; use the image button or copy an image on its own to bring it across.)
Email templates can be managed again. Settings, Email had no way to view, edit, or create templates: the only control was a one-time "Add starter templates" button that hid itself the moment any template existed, so seeding left a dead end. There is now a full template manager (list, create, edit, delete) with the rich body editor (formatting, inline images, merge fields). Compass-seeded templates can be edited but not deleted.
Navigation progress bar restored. The top loading bar never showed because its "finish" step was triggered the instant it appeared (it keyed on becoming visible, not on the route changing). It now rides up on click and completes only when the new route lands.
Sentry browser noise filtered. Three benign client-side errors were cluttering the issue list with zero user impact:
AbortError: Transition was skipped(an interrupted page navigation),Failed to fetch(a Server Action torn down mid-navigation, already handled by Next's router), and transientnetwork errorblips. Added them to the existingignoreErrorslist ininstrumentation-client.tsalongside the matching Firefox/Safari wordings, so real issues stay visible. Nothing in app behaviour changed. (Sentry JAVASCRIPT-NEXTJS-4, -6, -7.)Contract-templates settings copy no longer says e-signature arrives "when the quote is sent (coming next)". Quote-send and the client signing link are live, so the copy now reads in the present tense.
Quote line-item amount fields now select on focus. The qty and unit-price inputs default to
1/0; clicking in and typing used to prepend to that default (typing3900into a0field produced39000, a silent 10x quote error). Focusing a field now selects its contents so a typed value replaces the default.Waypoint calculator no longer throws on stray document clicks. The delete-popover's document-level
clicklistener (andclosePopover, reachable from the Escape key listener) readpopover.hiddenwithout a null check, so once those listeners were attached they could crash withCannot read properties of null (reading 'hidden')on pages where the popover element is absent. Added the sameif (!pop) returnguard the file's other handlers already use. (Sentry JAVASCRIPT-NEXTJS-1, 27 occurrences.)Hydration mismatch on Settings, Calendars. The Google and Apple connection cards rendered
new Date(last_synced_at).toLocaleString()directly, so the server (UTC) and browser (local timezone) produced different "Last refreshed" text and React flagged a hydration error. The timestamp now renders in its ownsuppressHydrationWarningspan, keeping the user's local time while silencing the mismatch. (Sentry JAVASCRIPT-NEXTJS-5, 12 occurrences.)Em dash removed from quote-name placeholder. The new-quote and quote-editor name fields used "e.g. Wedding photography, full day" with an em dash, against the no-em-dash copy rule. Now a comma.
[0.3.0]. 2026-06-02
Added
- Unlockable themes (Appearance settings). A new
/settings/appearancepage with a theme gallery: Light, System and Dark are always on; Sand and Slate unlock once the Essential setup steps are done, Noir and Espresso once every step is. Locked swatches show why. Themes shift mood + surface tones only, the brand red dot stays constant. Generalised the no-flash theme script + picker to named themes (was light/dark/system only); the old toggle on Sign-in & security moved here. Ties the wizard's progress to a tangible reward. - Starter content for setup steps. Instead of a blank page, the Tax rates and Packages settings now offer a one-click starter: the common tax rate for your currency (AUD GST 10%, NZD 15%, GBP VAT 20%,...) and a set of example packages + add-ons for your industry (photography, videography, celebrancy, florals, planning, hair & makeup, catering, with a generic fallback). Prices are placeholders to edit. Now also covers a starter contract template, a starter questionnaire, three email templates (enquiry auto-reply, quote-sent, invoice-reminder, used as send-time defaults), a payment schedule (30% deposit, balance before the date), and a follow-up workflow. Every starter is guarded (no-op if content already exists) and surfaced as a one-click button on the empty state of each settings page.
- Setup checklist celebration. Completing a step now pops a toast ("Add your packages, done") next time you open Getting started, and finishing every step fires a one-time confetti burst. Detected via a per-device snapshot of seen steps; first visit seeds silently.
- Getting-started setup checklist (first draft). A new
/getting-startedpage walks a studio through Essential steps (studio details, lead capture, packages, invoicing) and Recommended steps (profile photo, vocabulary, tax rates, payment schedules, templates, workflows, calendars, passkey, public profile), with a progress bar, tier badges, tick states, a "ready to take enquiries" marker, and a completion celebration. Each step deep-links to its settings page; completion is read from live data, so ticks never drift. A compact "Studio readiness" card on the dashboard links in and auto-hides once everything's done. (Reward unlocks, themes, the reciprocal-backlink step, and per-step toasts are the next passes.) - Error reporting is automatic, with optional detail. Every error is reported to us the moment it happens (captureException + an error-session replay), no action needed. The error page now says so, and offers a prominent "Add a note or screenshot" button (any file, not just images) to attach extra context to that same report.
Fixed
Tax-"inclusive" products no longer overcharge. Quotes and invoices added GST on top of inclusive-priced items, inflating the total (a $3,900 inclusive quote billed $4,290). The quote and invoice calcs now branch per line on the product's tax treatment via a shared helper (
src/lib/tax.ts): inclusive backs the tax out (total stays $3,900, GST shown as $354.55, subtotal-ex $3,545.45), exclusive adds on top (unchanged), none is untaxed.tax_inclusionis now carried from the catalog through the quote line items / packages / add-ons (and onto the auto-created draft invoice), so a quote and its invoice always agree, and quotes can mix inclusive and exclusive lines.Public pages no longer demand a sign-up. Clicking Pricing (or any public marketing link) while signed out wrongly popped the "that feature lives behind a free account" modal. The tease now only fires on protected CRM links; public links navigate normally.
Errors now actually reach Sentry. The dashboard error boundary only logged to the console; a render throw isn't a window error, so Sentry never captured it (issues dashboard sat empty). It now calls captureException, and the captured id is attached to any user report.
Error page recovers from stale-deploy "Failed to fetch" too. Previously only chunk errors hard-reloaded; a Server Action whose id changed in a redeploy throws "Failed to fetch" and a client re-render can't recover it. "Try again" now hard-reloads on those as well.
Empty clients no longer linger. A client with no live leads and no bookings (the ghost left behind when its only enquiry is trashed) is now hidden from every clients view. It reappears if a lead/booking attaches again (restore from Trash, or a re-enquiry).
Deleting a client can no longer silently wipe money/work. The delete cascaded to invoices, quotes, contracts and bookings with no guard. It's now blocked (with a reason) whenever a booking, quote, invoice, contract, questionnaire, or open enquiry is attached; the Delete button shows disabled + why. To delete, a live enquiry must first be marked lost or trashed. Clients whose only leads are lost/won or trashed can be deleted, and those leads' pushed calendar events are cleaned up first.
Currency (and other workspace fields) no longer snap back on Save. The business-profile form's fields were uncontrolled, so React 19's post-submit form reset reverted them to the stale prop even though the save succeeded (only visible after a reload). Made the fields controlled.
Error page recovers from stale-deploy chunk errors. "Try again" now shows a Retrying state and hard-reloads on a ChunkLoadError (a client re-render can't recover a missing chunk); the "Back to…" button is a real navigation so it works even when the client router is wedged.
Trashed leads no longer linger. Soft-deleted leads were still counted in dashboard metrics + "recent enquiries" and kept their client showing as Active. Both now exclude
deleted_at.Footer "Pipeline" → "Enquiries" (the nav rename reached the footer link).
Changed
The brand dot is now a page-title design language. The red dot from the "Compass." wordmark trails every top-level page title across the signed-in app: the dashboard greeting, the nav sections, every settings page, the feature lists (Quotes, Contracts, Questionnaires, Event bookings, New/Edit invoice...) and the detail pages (a quote, client, job, contract, questionnaire or enquiry's name). One shared
(decorative, aria-hidden). Deliberately not on card/section sub-headers, client-facing pages (portal/quote/contract links your clients see), marketing/auth pages, or error screens, so the accent keeps its weight. Settings drawer labels now match their page headings. Several settings entries read one way in the drawer and another on the page. Aligned: Business profile, Sign-in & security, Integrations, Dashboard layout, Packages, Contact forms, Calendars (heading follows the drawer), and Event types & availability + Marketing & business costs (drawer follows the heading). The enquiry-stages drawer label now follows the studio's own pipeline term (Vocabulary), matching its page heading on any wording.
Settings left the nav bar; the drawer is everywhere now. The "Settings" nav item is gone. The collapsible "Show all settings" drawer (mounted globally) hangs from the nav on every signed-in screen, so settings are one tap away from anywhere, not just from inside the settings section.
Settings drawer sits flush with the nav and collapses on scroll sooner. It hung 6px below the nav bar (stuck at 64px while the nav is 58px tall); now flush. Scroll-collapse fired only after 120px of scroll with a 1.5s post-open grace, so on short settings pages it felt stuck open and an immediate scroll did nothing. Now collapses after a 24px scroll with a 350ms grace.
/settingsopens the workspace profile; nav is the drawer. The standalone settings cards hub is gone./settingsredirects to Business profile and the collapsible drawer is the only nav. The drawer tab reads "Show all settings" (no count).Settings navigation is now a collapsible drawer. Replaced the Sidebar/Cards toggle (and the left rail) with a single TWTM-style drawer: a sticky "Show all N settings" tab hangs below the top nav, expands into grouped pills (Personal / Sales / Customisation / Money / Connections / Workspace), has a Pin to keep it open, and auto-collapses (one-way) when you scroll down unless pinned. Open / pinned / per-group state persists per-device in localStorage. Desktop shows a 2-column group grid; mobile is a per-group accordion. (
settings-drawer.tsx.)
Security
- Closed an anon RLS exposure on
event_bookingsand pinned trigger search_path (2026-05-30). Dropped two vestigial anon policies. The public booking flow runs entirely through the service-role admin client and guards the manage page with an unguessablemanage_token, so the anon policies were unused, andevent_bookings_public_read (USING true)exposed every workspace's booking PII (name, email, phone, answers) to anyone holding the public anon key. Authenticated dashboard access is unchanged (event_bookings_select/event_bookings_modify, both workspace-scoped); RLS stays enabled. Also setsearch_path = ''on four trigger helper functions (advisor lint 0011). Applied live via the Supabase MCP, recorded in migration20260530030000_harden_event_bookings_rls_and_fn_search_path.sql.
Added
Lead sources are grouped by category. The source list now groups under Search / Social / Referral / Directory / Direct / Other headers instead of a flat wall, with a "Change my name" example at the top signalling the list is editable. The default set new workspaces get is leaner (drops the long tail like Pinterest / LinkedIn / Reddit / EasyWeddings / etc.) while keeping the paid-vs-organic split for Google, Facebook, and Instagram. Reorder now works within a category. Migration 20260531130000 adds the category column + backfills existing rows.
Lead sources are fully manageable + filterable. Settings -> Lead sources now supports rename (label only; the slug stays stable so webhook matching keeps working), reorder (up/down), and delete (guarded: refuses with an "Archive instead" nudge if any lead still uses the source), on top of the existing add/archive. The /enquiries source filter now matches on source_id, so filtering by a granular source ("Google Paid") or a custom source actually returns results instead of nothing. The legacy per-lead
leads.sourceenum column was retired (dropped in migration 20260531120000) now that source_id -> workspace_lead_sources is the sole model; the lead_source enum type stays for expenses, clients, and the inbound-matching bridge.Calendar conflict picker groups Calendars, Shared, and Reminders, and opens on connect. Settings → Calendar's per-account picker now splits calendars into sections: your own Calendars, Shared calendars (calendars others shared with you, Google only), and Reminders (Apple Reminders lists). Reminders default to OFF and only block a bookable time when the reminder has a specific time; all-day reminders are ignored. The picker now opens automatically the moment an account connects (Google via the OAuth return, iCloud via the connect action) so you choose which calendars block conflicts right away instead of hunting for a link. Every toggle autosaves and shows the standard "Saved" tick. Note: iCloud can't tell shared calendars from your own (Apple doesn't expose ownership over CalDAV), so iCloud shared calendars stay in the Calendars group. Also fixes a bug where refreshing the calendar list silently re-ticked calendars you had unticked.
Sentry Cron Monitors on all 3 scheduled routes. New
src/lib/cron-monitor.tswraps each cron with an in_progress check-in at start and ok/error check-in on exit. Schedules registered inline (0 3 * * * cleanup-trash, 0 9 * * * workflow-reminders, */15 * * * * booking-reminders). Sentry alerts when a scheduled check-in doesn't arrive within the checkinMargin, regardless of cause (Vercel didn't fire, bad secret, route threw, hung past maxRuntime). Closes the 17-day silent-failure trap that bit between 2026-05-09 and 2026-05-26. Auth failures with a Bearer attempted are also reported as error-level captureMessage events; bare unauthenticated probes stay silent.Lead source enum:
direct+email. Two new values cover attributions that the Novoa enquiry form sends as "Direct" (no referrer / direct nav) and "Email" (newsletter, personal email referral). Both previously collapsed to "Other". Migration20260530000000_lead_source_add_direct_email.sql.Per-workspace customisable lead sources. Lead source is no longer a hard-coded enum; each workspace gets its own list at Settings → Lead sources. Default seed includes the granular paid/organic split (Google Paid + Google Organic, Facebook Paid + Facebook Organic, Instagram Paid + Instagram Organic) so paid-ad attribution lands cleanly in the pipeline + reports without custom config. Users can add custom labels ("Wedshed inquiry", "Walk-in") from Settings. Inbound source strings from the webhook, hosted form, CSV import, and +Lead dialog are matched against the workspace's sources (exact slug → substring → legacy enum bridge) with "Other" as the fallback. The lead-detail edit picker now reads from the workspace source list. Migration
20260530020000_workspace_lead_sources.sqladds the table + seeds every existing workspace + backfillsleads.source_idfrom the oldleads.sourceenum. The legacy enum column stays in place during the dual-write transition; both columns get populated on every write. Service layer atsrc/lib/lead-sources.ts.Deferred to a follow-up commit: source picker swap on the +Lead dialog (it still sends the legacy enum, which gets bridged to a source_id via legacy_enum_value), source filter dropdown on the /enquiries list, edit / reorder / delete actions on the Settings page (only Add + Archive shipped tonight).
Lead and job event dates can mirror to Google Calendar. New Settings → Calendar → "Lead and job calendar" card flips on a one-way Compass → Google push. Compass creates two calendars in the user's Google account ("Compass Leads", "Compass Jobs") and writes one all-day event per lead with an event date. Title is "(LEAD)
" for active leads; on transition to Won the event moves to Compass Jobs with the "(LEAD) " prefix dropped. Updates + deletes propagate. Google-only (Apple's CalDAV API is read-only for this path). Compass uses the narrower calendar.app.createdOAuth scope so it can only touch the two calendars it created itself, never the user's personal calendars. Existing Google connections need to reconnect once to get the new scope; the toggle surfaces a reconnect nudge if a stale connection is hit.Touches: migration
20260530010000_lead_calendar_push.sql,src/lib/calendar/lead-push.ts(enable/disable/sync/cleanup),src/lib/calendar/google.ts(createCalendar, createAllDayEvent, updateAllDayEvent), and syncLead hooks across every lead write path (webhook intake, hosted form, CSV importer, +Lead dialog, board status drag, lead edit, bulk ops, soft delete, restore, hard delete, cleanup-trash cron).
Changed
parseSource()smart matching (Phase 2 of Novoa → Compass). The inbound lead source normalizer now resolves messy attribution strings to the right channel instead of falling through to "Other". Three passes: exact enum match, channel-keyword substring ("Google Paid" → google, "Facebook Organic" → facebook, "vendor_referral_xyz" → vendor_referral), then a token-level alias scan for Meta CAPI's short forms ("ig_paid_social" → instagram, "fb_organic" → facebook, bare "gads" → google). Paid-vs-organic granularity stays preserved inleads.custom_fields(utm_source + utm_medium captured by the Novoa form's Phase 1 attribution layer), so reports that need the split read from there. The enum stays clean for solo creators who don't run paid ads.
Removed
/api/sentry-checkprobe route. One-shot Sentry-activation probe. Retired 2026-05-29 now that the cron monitors send check-ins on every scheduled run (a live liveness signal that doesn't need a manually-curled endpoint). The route was also unreachable from outside sincesrc/proxy.tsnever had it on the public-route allowlist, so production curls would 401 at the proxy before reaching the route.
[0.2.0]. 2026-05-29
Added
Per-calendar conflict toggles + single bookings destination (Wave 12). The Calendar settings page now matches Calendly's model: connect an account, get a list of every calendar on it, tick which ones should block your Compass bookable slots. A single "Add new bookings to" dropdown across all your connected accounts picks the one calendar Compass writes booking events into.
New table
workspace_calendar_subscriptions(one row per individual calendar inside a connected identity, with blocks_availability + is_default_destination toggles, a partial unique index guaranteeing exactly one default per workspace). Backfill happens lazily: the Calendar settings page fetches each connected account's calendar list on first render after this deploy and persists one subscription row per calendar. No reconnect required.Updated wiring:
- external-busy.ts reads every blocking subscription rather than just the identity's primary calendar. Google freeBusy is batched across calendars in one API call via new getBusyRangesMulti.
- submitBooking writes the Google event to whichever subscription is flagged is_default_destination=true, falling back to the legacy primary for unmigrated workspaces.
- New helpers: src/lib/calendar/subscriptions.ts (refreshSubscriptionsForIdentity); listCalendars on both google.ts and apple.ts.
New Settings → Calendar pieces:
- "Checking N calendars" link on each connected identity card that opens a modal listing every calendar with a checkbox. Toggles persist instantly via server action.
- "Add new bookings to" card with a single dropdown of every writable subscription across all connected accounts.
- "Refresh calendar list" inside the modal pulls fresh data from the provider so newly-added shared calendars show up without disconnect/reconnect.
Migration: 20260528000000_workspace_calendar_subscriptions.sql.
Calendar Month and Week views. /calendar now has a Year / Month / Week view switcher with prev / today / next navigation. Year stays the default. Month renders a 6-row x 7-day grid with up to 3 entries per cell; Week renders a 7-day hour grid (12am to 11pm) with an all-day band, positioning event_bookings by their scheduled_at and duration_minutes. View and anchor date are URL-driven (?view=, ?date=YYYY-MM-DD) so the page stays a Server Component and links are shareable. Week start day and weekday labels come from the workspace calendar_settings.
Previously undocumented
Backfilled 2026-05-29 from a verify-the-code pass. These items
shipped to production before 0.2.0 was cut but never made it into
[Unreleased] (one of the failure modes the AGENTS.md release-cut
hygiene rule now prevents). Verification source noted on each line.
- Two-level Waypoint industry picker. The flat list of 9
industries became 4 group cards (Weddings & Events, Fitness &
Health, Beauty & Aesthetics, Design & Creative) that drill into
per-group job-type cards. Returning users with an active
industry land at the GROUP level, not the type level. Verified
in
public/waypoint/calculator.js(INDUSTRY_GROUPS at line 761,_pickerLevelstate machine). - Five new Waypoint industries: Marriage Celebrant (celebrant), Yoga & Pilates instructor (yoga), Makeup Artist (mua), Hair Stylist (hair), Nail Artist (nails). Each seeded with its own Business Costs and Job Costs defaults. Verified at calculator.js lines 535, 582, 625, 671, 716.
- "Type 'I understand' to continue" gate on the industry
switcher. When switching active industry on a workspace that
already has non-zero values, the user must type "I understand"
(case-insensitive) before the Switch button enables, then
Business Costs / Job Costs reseed with the new industry's
defaults. Life & Admin, goals and roadmap are untouched.
Same-industry repicks with empty values skip the gate.
Verified in
src/app/waypoint/calculator-body.html:790-791andpublic/waypoint/calculator.js:3636. - "Return to pipeline" unhold action on lead cards. Lead cards
in the on-hold lane expose a "Return to pipeline" button that
clears the hold and restores the lead to its original stage.
Verified in
src/app/(dashboard)/enquiries/board/lead-card.tsx:137-139. - Custom-fields editor overflow fix on lead detail. Each row's
CSS grid switched from
grid-cols-[1fr_2fr_auto]togrid-cols-[minmax(0,1fr)_minmax(0,2fr)_auto], so long field names and values stay inside the column instead of pushing the card wider than the right-hand stack. Verified insrc/app/(dashboard)/enquiries/[id]/custom-fields.tsx:92, diff in commit 3436ac8.
Removed
- /invoices route family retired. Phase 3B completed the move: /invoices/[id], /invoices/[id]/edit, /invoices/new, and the /invoices listing all gone. The shared detail / edit / new view components live under src/app/(dashboard)/_invoice-views/ and the thin route wrappers at /jobs/[id]/invoices/* and /clients/[id]/invoices/* are the only entry points. The legacy redirects from /invoices/* (added in Phase 3) were also dropped since the app is pre-public-launch and external links to old paths don't exist yet.
Changed
New + Edit invoice flows now live under their parent. Two canonical "new invoice" URLs: /jobs/[id]/invoices/new (creates an invoice tied to a job) /clients/[id]/invoices/new (creates a standalone invoice) Same shape for edit: /jobs/[id]/invoices/[invoiceId]/edit /clients/[id]/invoices/[invoiceId]/edit All four routes render the same shared form component (_invoice-views/new-view.tsx or edit-view.tsx) and propagate breadcrumbs from the parent. The "Edit" button on the invoice detail page now receives its canonical edit URL via prop rather than building one itself, so the action bar doesn't need to know about the route structure.
/invoices server actions redirect to canonical URLs. Create, update, and the lifecycle actions (mark sent / mark paid) now use the invoiceViewPath helper after looking up the invoice's parent ids. Delete redirects to /money. revalidatePath calls target the canonical URLs too, so cache invalidation works on the new routes.
Invoices moved under their canonical parent. An invoice's URL now reflects the relationship to its job (or its client when standalone). Canonical URLs: /jobs/[jobId]/invoices/[invoiceId] (job-attached) /clients/[clientId]/invoices/[invoiceId] (standalone) The legacy /invoices/[id] URL still resolves: it now permanently redirects to the canonical path after a DB lookup, so sent invoice emails and bookmarks keep working forever. The /invoices listing page also redirects (to /money, which replaced it). The invoice detail itself extracted into a shared server component (src/app/(dashboard)/_invoice-views/detail-view.tsx) so both canonical routes render from one source. A breadcrumb above each invoice spells out Dashboard > Clients > [Client] > Jobs > [Job]
Invoices > Invoice #X (or the shorter chain without Jobs for standalone invoices). Edit + new invoice flows still live at the legacy /invoices/[id]/edit and /invoices/new URLs; moving those is a follow-up commit.
Added
/components/breadcrumbs.tsx. small generic Breadcrumbs row. Last item rendered as plain text (current page); earlier items link when an href is supplied.
/lib/invoice-urls.ts. invoiceViewPath / invoiceEditPath / invoiceNewPath helpers. Every internal invoice link should go through these so the next URL change touches one file rather than twenty.
Changed
- Top nav restructured around 7 essential items. Old nav (Dashboard, Pipeline, Leads, Clients, Calendar, Invoices, Settings) replaced by Dashboard, Clients, Enquiries, Jobs, Calendar, Money, Settings. Quotes, Contracts, Questionnaires and individual invoices are now reachable from their parent Client / Job pages rather than crowding the top bar. Lead list + pipeline board merged behind a single "Enquiries" item with List / Board tabs at /enquiries and /enquiries/board (the original /leads and /pipeline routes were renamed and redirect). /bookings renamed to /jobs (booking detail pages now live at /jobs/[id]).
Added
/jobs landing page. Lists every confirmed Booking for the workspace with name, client, event date, status, and total value. Replaces the previous "/bookings had no list view" gap.
/money landing page. A single payments tracker over every invoice, filterable by status (All / Unpaid / Paid / Draft) and date range (This month, last month, this/last quarter, this/last financial year). Summary cards at the top show count + unpaid + paid totals for the current filter. Due-date filtering and paid-on date filtering will come once invoice schema gets due_on / paid_at columns.
Changed
Settings rework, phase 1. Final shape of the rework that landed in the previous commit: 6 themed groups (Personal, Sales, Customisation, Money, Connections, Workspace), URL slugs renamed to match labels, icon next to every item in the sidebar, and a new cards-grid landing page at /settings. URLs renamed: /settings/account -> /settings/sign-in-security, /settings/workspace -> /settings/business-profile, /settings/pipeline -> /settings/enquiry-stages, /settings/event-types -> /settings/booking-pages, /settings/costs -> /settings/expenses, /settings/dashboard -> /settings/dashboard-layout, /settings/calendar -> /settings/calendars. All seven old URLs redirect permanently to their new paths via next.config.ts so existing bookmarks keep working. Label changes since the previous cut: Pipeline -> Enquiry stages, Lead capture -> Contact forms, Wording -> Vocabulary, Calendar -> Calendars. Brand group merged into Personal (Business profile moved). Client-facing group retired (Packages + Templates moved to Customisation).
Settings reorganised into seven themed groups. The 22-item flat sidebar at
/settingsis now grouped under Personal, Brand, Sales, Client-facing, Money, Connections, and Workspace headings. A search box at the top of the sidebar filters items as you type (matches against labels and synonyms, so "vocabulary", "contact forms", "costs", etc. still find the renamed items). Renames: Account -> Sign-in & security, Workspace -> Business profile, Vocabulary -> Wording, Contact Forms -> Lead capture, Online booking -> Booking pages, Products & packages -> Packages, Dashboard -> Dashboard layout, Costs -> Expenses.Templates pages tab-grouped. Contracts, questionnaires, and email-template settings now share a tab bar at the top so they feel like one "Templates" surface. Same treatment for Invoicing, which now hosts Tax rates and Payment schedules as tabs.
Added
- WebAuthn conditional UI on the login form. Registered passkeys
now surface as autocomplete suggestions directly inside the email
field on
/login, alongside saved emails. Tapping the suggestion triggers biometric verification and signs the user in with zero modal prompts. The explicit "Sign in with a passkey" button stays as a fallback for discoverability and for users without a saved passkey. RequiresPublicKeyCredential.isConditionalMediationAvailable(Chrome 108+, Safari 16+, recent Firefox); gracefully no-ops on older browsers.
Changed
- Login rebuilt around passkey + magic link + 2FA gate. The login
page now opens with "Sign in with a passkey" as the primary CTA,
followed by an email field with "Send sign-in link" and a small
"Sign in with password instead" link. The old email > OTP code >
password three-step flow has been removed. Magic-link clicks land
on
/auth/confirmas before, and the new/login/totpchallenge page enforces a second factor for any user who has TOTP enrolled (whether they signed in via magic link or password). Passkey sign-ins satisfy AAL2 on their own and skip the TOTP prompt.
Security
- Two-factor enforcement at the proxy. Added an AAL2 gate to
src/proxy.ts: any signed-in user with TOTP enrolled must present a valid AAL2 cookie before reaching protected routes. The cookie is HMAC-signed (cannot be forged), expires after 12 hours, and is cleared on sign-out.user.app_metadata.has_totpis now written on enrollment/disable so the gate runs from JWT data with no DB hit; users enrolled before this change fall back to a one-time DB lookup. Closes the gap where the previous login flow silently bypassed 2FA after magic-link verification.
Added
Google Calendar sync (two-way). Hosts can now connect their Google Calendar at Settings > Calendar. Once connected, busy events from Google block availability on every event-type booking page, so a client can't book a slot when the host has a shoot or personal appointment already scheduled. Bookings made via Compass also write back to Google Calendar as events. Connection uses OAuth (the host clicks Allow on Google's consent screen, never types a password). Refresh tokens are AES-256-GCM-encrypted with the
CALENDAR_ENCRYPTION_KEYenv var before being stored. Status card surfaces the connected email, last-sync timestamp, and a Disconnect button.iCloud Calendar sync (read-only via CalDAV). Hosts using Apple Calendar can connect by entering their Apple ID + an app-specific password (Apple does not offer OAuth for CalDAV). Busy times block availability on event-type booking pages, but Compass does not write back to iCloud (Apple's CalDAV is read-friendly but write-unreliable for our use case). Credential encrypted at rest with the same
CALENDAR_ENCRYPTION_KEY.Per-event-type locations. Each event type can now offer multiple meeting locations (phone, video, in-person address, free-form other). The invitee picks one at booking time. Replaces the single per-event-type location field. Existing event types auto-migrate their old location into a single-item list on first load.
Per-event-type custom questions. Hosts can add structured questions to any event type (short text, long text, single select, multi select, checkbox). Invitees answer at booking time. Answers travel with the booking and surface on the /event-bookings admin page and inside the auto-spawned lead.
Per-event-type email overrides. Each event type can override the confirmation email subject and body with a TipTap rich-text editor. Falls back to the workspace default when no override is active. Schema also supports cancellation, reminder, and follow-up template kinds (UI for those ships separately).
Per-event-type reminder toggles + cancellation policy. Each event type now has 24h reminder + 1h reminder boolean switches and a free-form cancellation policy textarea that renders as a subdued footer in every transactional email this type sends. Note: the reminder cron is not currently scheduled (Vercel Hobby limit on sub-daily crons); the route is wired and a TODO is filed to add an external scheduler. Toggles + policy still ship and apply when the cron eventually runs.
Public profile page at /p/{handle}. Hosts can claim a handle (3-40 chars, [a-z0-9-]) and an optional welcome blurb at Settings > Workspace. The public page lists every active event type with one-click booking links. Calendly-equivalent of calendly.com/{username}.
Timezone-aware booking slot computation. Slot picker now honours the workspace's IANA timezone (e.g. Australia/Perth) end-to-end: wall-clock times in availability settings, slot generation, busy-time merging from connected calendars, and rendered labels on the booking page. Replaces the previous UTC-anchored math.
Changed
Database types extended for Wave 11 tables. Hand-maintained
src/lib/database.types.tsnow includesEventTypeLocation,EventTypeQuestion,EventTypeEmailTemplate,EventBookingAnswers,WorkspaceCalendarIdentity, plus thepublic_handle/public_blurbcolumns onWorkspaceand the newselected_location_id,answers,reminder_*_sent_at,external_event_idcolumns onEventBooking.Default placeholder text de-personalised. Form placeholders that referenced the maintainer's family names (Margarita Novoa, Javiera Hair Styling, Gonzalo Novoa Photography) replaced with neutral studio names (Aurora Lane Photography, Alex Morgan, River Stone Celebrant) across invoices, onboarding, email settings, and invoicing.
Tax-rate row layout tightened. Grid column widths adjusted so the "Default for new quotes & invoices" label sits on one line at narrower viewports.
Removed
- Vercel-scheduled
booking-reminderscron. Removed fromvercel.jsonbecause Vercel Hobby limits crons to daily cadence (the reminder cron needs every-15-minutes to land 1h reminders within their window). Route atsrc/app/api/cron/booking-reminders/route.tsstill works; an external scheduler (GitHub Actions recommended) will poke it. Tracked as TODO 19.4.c.
Security
- AES-256-GCM encryption for calendar credentials at rest.
Both Google refresh tokens and Apple app-specific passwords are
wrapped with a 32-byte key from the
CALENDAR_ENCRYPTION_KEYenv var before being stored inworkspace_calendar_identities.secret_ciphertext. The database never sees plaintext credentials. Decryption happens at use-time only.
Added
One-tap passkey sign-in (discoverable credentials). The "Sign in with a passkey" button now works without typing an email first. The browser shows whichever passkeys are stored for the site and the user picks one with their biometric. The server resolves the user from the returned credential id. The email-targeted path still works when an email is filled in, which keeps the helpful "no passkey for this account" message for first-time users.
Clients can reschedule + cancel their own event bookings. Confirmation email now ends with a "Reschedule or cancel" button pointing at a private
/booking/[id]?token=…page. From there the client can pick a fresh slot (same picker as the original booking flow, with the current booking excluded from clash detection) or cancel with an optional reason. Both paths email the studio owner + send the client a confirmation. Token is 32 bytes of randomness stored atevent_bookings.manage_token, validated in constant-time on every request. Migration:20260521000600_event_booking_manage_token.sql./event-bookings admin list. Dedicated page for every online booking the workspace has received. Upcoming / Past / Cancelled / All filter chips with counts. Each row shows the client name, start time, duration, email, phone, and any notes. Status changers (Mark completed / no-show / cancel / re-schedule), an "Open lead" link to the auto-spawned lead, and a delete button that keeps the lead intact.
Online bookings now show on the calendar. When a prospect picks a chemistry-call slot via
/book/[event_type_id], the resultingevent_bookinglands on/calendaralongside bookings and leads. Status label shows the start time and duration; click-through lands on the auto-spawned lead. Past event bookings roll into the past list as expected.Wave 10 Online Booking. public slot picker. SN-style scheduling. Three new tables (
workspace_event_types,workspace_availability,event_bookings, migration20260521000500_online_booking.sql). Settings, Online booking lets the user define event types (Chemistry call, Consultation with duration, buffer, advance-notice, max-per-day, phone / video / in-person location) and a weekly availability grid (Mon-Sun, up to 6 slots per day). Each event type ships with its own public URL at/book/[event_type_id]; a prospect picks a date, sees free slots computed live from availability + existing bookings + buffers, leaves their contact info, and the submit creates both anevent_bookingrow AND a new Lead in the workspace. Confirmation email fires to the client; notification email fires to the studio owner. Slot-conflict re-check on submit guards against races. Phase 2 (timezone resolution, Google Calendar sync, reschedule links) sits in the backlog.Wave 9 Phase 2.1: daily workflow digest email. New cron at
/api/cron/workflow-remindersruns once a day (09:00 UTC, wired up invercel.json) and emails each workspace owner a digest of every overdue and due-today workflow step across all their leads. Reminders only. never auto-ticks; you stay in control. Per-workspace opt-out lives in Settings, Email under "Daily workflow digest" (default on). Email body lists the steps with overdue / today badges and a one-click "Open dashboard" link; each row deep-links to its lead."Today's actions" dashboard widget. New section at the top of
/dashboardthat pulls together everything needing attention into a single punch list. Surfaces overdue + due-today workflow steps (anchored to each lead's real dates), sent contracts unsigned for 3+ days, sent quotes awaiting response for 5+ days, sent questionnaires unfilled for 5+ days, and sent invoices unpaid for 7+ days. Sorted most-urgent first; each row links straight to its surface. Shows "You're all clear" empty state when nothing's flagged.Sample data now seeds a contract / questionnaire / workflow. Clicking "Add sample data" on the dashboard now also drops in one starter contract template ("Main wedding contract" with placeholder substitution baked in), one questionnaire ("Wedding day details", 8 questions across every field type), and one workflow ("Wedding workflow", 9 steps with realistic anchor + offset combinations). Idempotent: re-seeding wipes prior seeded templates by
[seed_sample]marker without touching anything the user authored.Workflow step badges: "Due today", "Overdue 3 days", "In 12 days". Each unchecked step on a lead's workflow card now shows a badge computed from its anchor + offset_days against the real lead / quote / event dates. Overdue badges paint in the warning red; "today" picks up the new accent; "soon" (within 3 days) goes amber; future steps stay quiet. Helpers live in
src/lib/workflow-dates.tsso other surfaces can reuse them. Still fully manual. Phase 2.1 cron + email reminders is the next step once you've seen the visual cue.Client Portal: contracts to sign + questionnaires to fill. The
/portal/[token]page now surfaces two more sections so a client can find everything from a single URL: "Contracts to sign" (deep-links to/contract/[token]) and "Questionnaires to fill" (deep-links to/questionnaire/[token]). Signed contracts and completed questionnaires roll into the history collapse with their submission/signing date.Wave 9 Workflows, Phase 1: templated lead checklists. Build repeatable step-by-step checklists in Settings, Workflows. Each step carries a label, an optional notes line, and a "days after" marker tied to an anchor (lead created, quote sent, quote accepted, before event date, after previous step). Attach a workflow to a lead from the lead detail's new Workflow card and tick steps off as you go; ticking the last one stamps a Complete badge. Editor supports reorder, duplicate prevention, and an "is default" flag for the workspace's go-to workflow. Snapshot model: editing a template later doesn't retroactively rewrite running instances. Migration:
20260521000400_workflows_phase_1.sql. Phase 2 (cron-driven auto-completion / auto-email at the trigger date) is the next iteration; today everything is manual progression.Wave 8 Questionnaires. Whole loop in one go. New tables
workspace_questionnaire_templates(reusable forms with a fields builder for text / textarea / date / pick-one / pick-many / yes-no question types) andquestionnaires(per-client instances with a responses jsonb). Settings, Questionnaire templates page lets the user build forms with an inline drag-free field editor. Lead detail now has a Questionnaires card with "+ New questionnaire" template-picker. Each questionnaire has a /questionnaires/[id] dashboard page (responses view + send-by-email + delete) and a public /questionnaire/[token] surface where the client fills it out. Submissions flip status to Completed and the responses surface back on the dashboard. Brevo-powered email delivery via the existing wrapper. Top-level "Questionnaires" link in the SiteNav. Migration:20260521000300_questionnaires.sql.Date-formatted invoice numbers (optional). Settings, Invoicing now has a "Number format" radio: Sequential (0001, 0002,...) or Date-based (20260521, 20260521-02 for same-day duplicates). Switching applies to future invoices only; existing rows keep their original number. New
formatInvoiceNumber()helper renders either format consistently across the list page, detail page, edit page, lead profile, client portal, and emails. Studio Ninja defaults to the date-based pattern; many studios use it because it doubles as a record-keeping date stamp.Calendar settings now thread through to display. Workspace's
calendar_settings.date_format(DD/MM/YY, MM/DD/YY, YYYY-MM-DD),time_format(12h, 24h), andweek_start(monday, sunday, saturday) get respected on the calendar's past-events list. New shared helpers insrc/lib/calendar-format.ts(formatWorkspaceDate,formatWorkspaceTime,formatWorkspaceDateTime,weekStartDay,workspaceWeekdayLabels) so any future surface that needs a workspace-aware date can reach for the same function.Tax rate picker on quotes and invoices. New nullable
tax_rate_idcolumn on bothquotesandinvoices(migration20260521000200_tax_rate_id_on_quotes_invoices.sql) lets a single quote or invoice override the workspace-level GST flag with any named workspace tax rate (GST, VAT, exempt, etc). Quote editor and invoice new + edit forms now show a "Tax rate" dropdown when the workspace has tax rates set up. Quote editor live-totals update against the picked rate. Display labels switch from "GST (10%)" to the rate's actual name + percentage. NULL falls back to the existing workspace.invoice_settings.gst_registered behaviour, so existing data renders identically.Wave 7 Contracts, Phase 3: public signing surface + email. Contracts are now a complete loop. New public page at
/contract/[token]renders the contract body in serif type with a typed-name signature form at the bottom; on submit, Compass captures the typed name, the client's IP (fromx-forwarded-for), the user-agent, and the timestamp into thesignature_datajsonb column. Decline button does the same but sets status todeclined. Bothsignedanddeclinedend-states render their own confirmation panel so the client knows they're done. "Send by email" button on the contract detail page mints the public token (if missing), sends a "contract ready to sign" email through Brevo, and flips status to Sent. Sending a quote with an attached contract template now auto-spawns the contract instance for the client and fires the signing-link email alongside the quote email. Re-send is idempotent (re-uses the existing token). Added anon RLS policies on contracts so the public page can read- update by token without service-role for defense in depth
(migration
20260521000100_contracts_phase_3_public_policy.sql).
- update by token without service-role for defense in depth
(migration
Wave 7 Contracts, Phase 2: instances + surfaces. Contracts are now real first-class entities in the app. Top-level
/contractslist with Open/All/Signed/Past filter chips, per-contract detail page at/contracts/[id]with edit modal, status changers (manual overrides for paper-signed flows), and linked-entity rail. New "+ New contract" floating dialog (template picker + custom name + notes) on the lead detail page Contracts card, plus a Contracts section on the booking detail page. Quote editor now has an "Attach a contract" dropdown that references workspace contract templates. Phase 3 will wire the public signing surface at/contract/[token].Wave 7 Contracts, Phase 1: template editor. New
workspace_contract_templatesandcontractstables (see migration20260521000000_contracts_phase_1.sql). Settings → Contract Templates page with full CRUD: list, create, edit, archive, restore, delete. Templates support placeholders ({{client_name}},{{event_date}},{{event_location}},{{total_value}},{{studio_name}},{{contract_date}}) that get filled in when attached to a client. New-template flow ships with a starter wedding-photography body so the user has a working example to edit instead of staring at a blank textarea. Thequotestable also gained a nullablecontract_template_idso a quote can carry an attached contract; the create/edit wiring ships in Phase 2.Send invoice by email. New "Send by email" CTA on the invoice detail page. Renders the full invoice inline (line items with discounts, GST, tip, total, bank-transfer instructions) so the client reads it directly in their inbox without clicking through anywhere. Status flips to Sent on click. Reuses the existing Brevo wrapper that already powers quote-send and lead emails. Disabled when the invoice has no client email on file (tooltip explains how to fix it). If Brevo isn't configured the action still flips status and explains "send manually from your inbox" so the workspace's records stay accurate.
Fixed
- Sample-data seeder redirected to the retired
/pipelineroute.seedSampleData()insrc/app/(dashboard)/dashboard/sample-data-action.tsredirected to/pipeline?seeded=1after inserting the five sample leads. The nav rework retired/pipeline(enquiries pipeline now lives at/enquiries/board), so the user landed on the 404 "Off the map" page and never saw the "Five sample leads added" toast. Now redirects to/enquiries/board?seeded=1. Toast watcher already allow-listed/enquiries/boardfor theseededflag, so the success toast fires at the new path. Same class of bug as delete-lead (commit 09b7b09, 2026-05-30). Verified by file read (toast watcher pathnames + new redirect target), not by browser repro. - Delete-lead redirected to the retired
/pipelineroute.deleteLead()insrc/app/(dashboard)/enquiries/[id]/actions.tsredirected to/pipeline?deleted=1after soft-deleting. The nav rework retired/pipeline(enquiries pipeline now lives at/enquiries/board), so the user landed on the 404 "Off the map" page and never saw the "moved to Trash" toast. Now redirects to/enquiries/board?deleted=1. Toast watcher already allow-listed/enquiries/boardfor thedeletedflag, so the success toast fires at the new path. Verified by file read (toast watcher pathnames + new redirect target), not by browser repro. - Settings layout went stale across client-side navigation.
After landing on
/settingsand then clicking into an inner page (e.g. Profile), the sidebar and Cards/Sidebar toggle would silently disappear because the layout'sheaders()-based "which chrome do I render" decision was cached from the first visit. The Settings tree is now split into two route groups.(landing)for the cards hub and(inner)for every other page. so the right chrome mounts for the right route every time, no stale state possible. URLs are unchanged. - Phantom-error after invoice create. The user could see a
"Something snapped" page even though the invoice had been saved.
Root cause: post-insert chores (bumping client activity timestamp,
cache revalidation) ran unguarded, so any transient throw between
the successful insert and the redirect bubbled up to the error
boundary. Best-effort try/catch now wraps the post-insert work
and logs failures to Sentry without making the user re-submit.
Same hardening applied to
updateInvoice.
Fixed
- iCloud-synced passkeys no longer break on repeat use. Apple synced passkeys always return signCount = 0, which can collide with our replay-detection counter when the user also has a hardware authenticator. The verify route now preserves the highest counter we have ever seen for a credential, so a YubiKey asserting after an Apple passkey keeps benefiting from replay detection while the synced passkey keeps working.
Changed
Palette revision: red is now an accent, not just decoration. Reassigned
--accentfrom ink to the brand red#e8423a, and--accent-softfrom a cream wash to a warm-red washrgba(232, 66, 58, 0.08). Every "highlight" surface across the app (status pills, callout panels, active-state cards, settings card chrome) picks this up without per-component edits. Primary CTAs stay on ink so the surface stays calm. Focus rings already used the brand red, so they're unchanged. Added--accent-ringtoken for any future ring/glow styling that wants the warm red.New app icon: hand-painted bearing star. Replaced the C-arc glyph with a north-pointing bearing star on cream paper, framed by a single letterpress ring. Four cardinal points (warm red north, ink east / south / west) sit over four faint diagonal kites for chart-like depth on close inspection. Source SVG includes a paper-grain filter and an ink-edge irregularity filter; both render in the browser favicon (
icon.svg) but are dropped from the iOS apple-touch and PWA-manifest PNGs because Satori doesn't supportfeTurbulence/feDisplacementMap. Updated the inline mark in the PWA install prompt too so the "Add to home screen" banner shows the new glyph.
Added
- "Add to home screen" floating prompt. Small banner that
appears at the bottom of the dashboard on iOS Safari and Android
Chrome, modelled after the PickyEater Pal style. iOS gets the
manual "Tap [share icon] then Add to Home Screen" instruction;
Android with
beforeinstallpromptgets a one-tap Install button. Self-hides in dev, on desktop, in standalone mode (the app is already installed), and for 14 days after the user dismisses it. PWA manifest + icons were already wired; this is the discoverability piece.
Changed
Error screen looks like Compass again. The "Something snapped" page was rendering in the wrong font stack because the global-error boundary replaces the whole document, which means the next/font CSS from the root layout never loaded. Now imports Fraunces + Inter directly, bumps the brand mark to 64px serif and the headline to 32px serif, and matches the dashboard error page's heading size (text-3xl/4xl). Also removed two em dashes from the dashboard error copy.
Confirmation dialogs are now in-app. The native browser
confirm()prompt (the chunky one with system Cancel / OK buttons) is gone. Replaced with a native<dialog>styled to match the rest of Compass: serif title, body copy, Cancel + Confirm buttons with a "danger" tone for destructive actions. Touched every destructive flow: delete client, delete booking, delete lead, delete forever (Trash), delete draft quote, send quote, delete invoice, revoke portal link, revoke API key, and the public-facing decline-quote button. Two reusable components:<ConfirmSubmitForm>for form-action flows and<ConfirmButton>for in-clientuseTransitionflows.
Fixed
- Em dashes removed from destructive-action copy. Two user-facing strings on the client detail page had stray em dashes (delete-client warning + the "No invoices yet" empty state). Replaced with commas per the project copy rule.
Added
Per-workspace logo on invoices (URL-based). New "Logo URL" field on Settings, Invoicing. Paste a link to any public image (PNG / SVG / JPG); it renders top-right of every invoice header above the business name. Stored on the existing
invoice_settingsjsonb, so no migration. Uses a plain<img>(not Next/Image) so the user can host on any CDN without whitelisting domains. Full file-upload pipeline is a follow-up.Per-line discount on invoice line items. Each line carries an optional
discount_pct(0..100) applied before GST. New "Disc %" column on the line editor; the invoice detail view renders "Discount NN% off" beneath the description when set. No schema migration (line_items is jsonb). Matches Studio Ninja's per-line discount behaviour for seasonal-sale studios.Invoice polish batch (five SN-gap fillers).
- Edit existing invoice. New
/invoices/[id]/editpage. The invoice number + status + sent_at + paid_at are owned by the lifecycle actions and stay untouched; everything else (client, dates, lines, tip, notes) is editable. Closes "fix a typo without delete + recreate" workflow. - Service date separate from issue date. New
invoices.service_datenullable column. Surfaced on both the new + edit forms; rendered on the invoice header beneath the issue date when different. Used for tax records where income is recognised on the service date. - Multi-line descriptions on line items. Description input
swapped from
<input>to a resizable<textarea>, rendered withwhitespace-pre-lineso the user can list inclusions inside one line item (matches SN). - Big total above the fold. Total amount now sits in the invoice header at 3xl–4xl, alongside the invoice number. The most important number on the page is no longer buried under the line table.
- "+ New invoice" on lead + booking pages. Lead detail now
shows an Invoices card (when status is won or invoices exist)
with a one-click "+ New invoice" button. Booking detail's
button now passes
booking_idso the new-invoice form prefills the service date from the booking's event_date.
- Edit existing invoice. New
/clientsfilter chips. Four chips above the rolodex: Active (open leads or upcoming / in_production bookings), All (everyone), Booked (has any booking), Past (all bookings done or cancelled, or stalled stragglers with no leads or bookings). Default view is Active so the first paint shows the relationships actually demanding attention; the full rolodex stays one click away. Counts shown next to each chip.Booking detail page at
/bookings/[id]. Bookings now have their own home (instead of routing the user back to the source lead). Shows the booking name, status, event date + location, notes, invoices on this booking with totals (paid of invoiced), and a right rail linking to the parent Client, source Lead, and source Quote. One-click status changers expose the three most-likely next transitions (upcoming, in_production, completed, cancelled). Edit modal mirrors the same native<dialog>pattern as client + lead edit. Calendar entries, client profile bookings list, and lead profile bookings card all now link here.Backlog batch: three small SN-gap fillers.
- Tipping line on invoices. New
invoices.tipcolumn. The new-invoice form has an optional Tip input; the invoice detail page renders a "Tip" row beneath GST when non-zero; the rendered total carries the tip on top. SN's longest-standing unaddressed feature request (Capterra Jun 2019). - Custom submit-button label on hosted contact forms. New
contact_forms.submit_labelcolumn. Surface on the Build tab with examples ("Request a quote", "Get in touch", "Tell us about your day"). Null falls back to "Send enquiry" in the public renderer. Was hard-coded before. - Webhook double-email opt-out. New
workspaces.email_settings.notify_on_intaketoggle, default true. When off, the webhook + hosted-form-submit paths skip the owner notification email. Surfaced on Settings → Email. Fixes the scenario where a studio's website already sends its own notification and Compass would otherwise double-up.
- Tipping line on invoices. New
Fixed
- Phase C build was failing on Turbopack.
src/app/(dashboard)/quotes/actions.tsended withexport type { Quote }. same rule that bit us with the earlier*_INITIAL_STATEconsts, a'use server'file can only exportasync functions. Turbopack rejected the type re-export and the whole Phase C deploy went toERROR(which is why the live invoice page kept showing "Something snapped" against the older deploy). Removed the re-export; callers importQuotedirectly from@/lib/database.types. - GDPR account-export route was querying the dropped
jobstable. Wave 4 retiredpublic.jobs; the export at/api/account/exportwas still pulling from it and would have 500'd the first time anyone requested their data dump. Swapped to the Path B equivalents: clients, leads, quotes, bookings, invoices, plus the existing pipeline_stages and lead_activities. Now the export is a complete snapshot of everything the customer has under their workspace.
Added
- Wave 4: calendar reads from bookings + leads-with-dates. /calendar's monthly grid now unions Path B's bookings table with the legacy lead-with-event_date rows. Bookings render in bold (with their own status colours. upcoming green, in-production amber, completed grey); unbooked leads-with-proposed-dates render in regular weight with the lead's status colour. A booking on a lead always wins over the same lead's date so accepted-quote rows display once. Lost / cancelled rows are still excluded. Past view (collapsible at the bottom) unions both sources the same way.
- Wave 4: Settings → Calendar. New sub-page at /settings/calendar.
Per-workspace date format (DD/MM/YY, MM/DD/YY, ISO), time format
(12h / 24h), and week-start (Monday / Sunday / Saturday). Stored
in
workspaces.calendar_settingsjsonb. Powered formatters get threaded through every date display in a follow-up pass; the schema is in place now. - Wave 5: unified Client Portal. New public surface at
/portal/[token] showing one client every open quote, invoice, and
booking they have, plus a "history" disclosure with accepted /
paid / past items. Branded with the studio name, no app chrome,
no auth. the token in the URL is the access boundary (matching
the /quote/[token] pattern). On the dashboard's Client profile
there's a new "Client portal" card with a Generate / Copy /
Rotate / Revoke surface. Token is generated lazily on first
Generate click and lives in
clients.portal_token(unique partial index). Fixes SN's biggest UX complaint: returning clients no longer juggle a different URL per job.
Removed
- Legacy
jobstable dropped. Vestigial from an earlier session, never wired into the UI, empty in production (verified before drop). Path B'sbookingstable is the canonical accepted-job surface from here on. Drop is covered by20260519000500_path_b_wave_4_5_settings.sql.
Added
- Settings extensions for Quote-builder ergonomics (Path B Wave 3,
Phase C). UIs to populate the Wave 3a tables that the quote
flow relies on.
- Settings → Products & packages now surfaces description, kind (package vs add-on), tax treatment (inclusive / exclusive / none), image URL, "recommended" flag (highlighted on Pick & Choose), and "mandatory" flag (client cannot deselect). The list splits into two cards: Packages and Add-ons. Settings sidebar label renamed to "Products & packages".
- Quote editor: From-catalog picker. Each list (line items, packages, add-ons) gains a "From catalog" dropdown next to its "+ Add" button. Picking a row drops it into the quote with name + description + price + flags pre-filled from the workspace catalog. Line items on a Fixed quote can pull from any catalog row (the description gets a "Package name. description" tag).
- Settings → Tax rates. New page. Define every tax rate the studio charges (GST 10%, GST 0%, sales tax, VAT, etc.). One rate per workspace can be marked default; setting a new default auto-unsets the old one. Rates are decimal-stored, percent-displayed. Archive instead of delete so historical references stay valid.
- Settings → Payment schedules. New page. SN-style reusable deposit-and-balance patterns. Each schedule has a name, applies to either Quotes & Invoices or Online Booking, and contains N payments. Each payment is a fixed amount, a percent of order, or a percent of the remaining balance, due N days / weeks / months relative to "after quote accepted", "on invoice created", "before main shoot date", or "on date of your choice". Edit the whole payment array inline; archive instead of delete.
- Settings → Email. New page. Per-workspace sender name,
reply-to email, multi-line signature, BCC-self toggle, opens +
clicks tracking toggle. Stored in
workspaces.email_settingsjsonb. The signature field is already consumed bysendQuote; sender-name / reply-to / BCC will flow through to subsequent send paths (invoice sends, contact-form autoresponders) as they're wired in.
Added
- Quotes, end to end (Path B Wave 3b + 3c, Phase A). Build a
quote, send it to a client, they accept from a public URL,
Compass spawns a Booking (and optionally a draft Invoice) and
flips the source Lead to won. The full loop, on top of the Wave 3
schema applied earlier.
- /quotes lists every quote with status badge, total, client name, and type (Fixed or Pick & Choose).
- /quotes/new picks the Client (and optional Lead) the quote is for, then chooses the type. Creates a draft and redirects into the editor.
- /quotes/[id] is the live editor for drafts (Fixed: line items table; Pick & Choose: packages + add-ons with mandatory / recommended flags) with totals computed live from the same calculator the server uses on save. Sent / accepted / declined / superseded quotes render read-only.
- Send quote action emails the client a magic-link to
/quote/[token](256-bit public token, branded email template, workspace signature appended if set), supersedes any other sent quote on the same Lead, and timestamps the send. - /quote/[token] is the public accept page (no auth, no app chrome). Fixed quotes show line items; Pick & Choose lets the client pick one package + optional add-ons (mandatory ones locked in) with a live total. Accept / Decline buttons fire server actions via the admin client (RLS-bypassing, token is the access boundary).
- Accept lifecycle does everything in one transaction-ish
flow: marks quote accepted with IP + UA signature, creates a
Booking (snapshotting the total and pulling event_date /
event_location from the originating Lead), creates a draft
Invoice if
auto_invoiceis on (copying line items or the chosen package+addons), moves the Lead to status='won' with the right stage_id, supersedes other sent quotes on the same Lead, and bumps the Client's last_activity_at. - Quotes section on Client profile lists every quote for the
Client with status badge and total; "+ New quote" links to
the new-quote picker with
?client_id=…prefilled. - Site nav gains a Quotes link between Calendar and Invoices.
- Proxy allowlist opens
/quote/*to unauthenticated visitors, alongside/form/*.
Added
- /clients rebuilt as the Client umbrella (Path A Wave 2). The
page used to show won-leads-only. Now it lists every Client the
workspace has ever touched, sorted by most-recent activity
(
last_activity_at desc), which naturally floats currently- active relationships to the top while leaving the rolodex one scroll away. Each row links to the new Client profile. - /clients/[id] Client profile page. Two columns: left card
with contact details, partner names, pronouns, structured
address, and any client-level notes; right column with two
surfaces of activity:
- {Leads}: every Lead this Client has filed, with status badge and event date. "+ New {lead}" opens the New-Lead dialog pre-bound to the Client (skips find-or-create) and pre-fills contact info from the freshest Lead so a returning enquiry is one-tap.
- Invoices: every Invoice issued to this Client, with status, issue date, and total. Footer line summarises paid vs invoiced so the relationship's financial state is glanceable. "+ New invoice" links to /invoices/new?client_id=…
- Edit-client modal. Same native-
- deleteClient server action (ON DELETE CASCADE removes every Lead and Invoice under the Client. no soft-delete for clients yet, the confirm dialog is explicit about that).
- Lead detail page surfaces the parent Client up top. A small "Part of {Client Name} →" link sits above the lead title when the Client's name differs from the lead's, or a "View {client} profile →" link sits underneath when they're the same string. Either way, drilling from a Lead to the Client (other enquiries, invoices, all-in-one history) is one click.
- Invoice creation hub on the Client profile.
/invoices/new?client_id=… now pre-fills client name, email, and
multi-line address from the Client's structured address fields.
/leads/[id] → "Create invoice" continues to work; it resolves the
Client via the lead's
client_idand writes bothclient_idandlead_idon the invoice row so the surface keeps both kinds of attribution.
Changed
- NewLeadDialog accepts
clientId+clientPrefillprops. When the dialog is opened from a Client profile, it renders a soft banner ("Adding this enquiry under {name}") and submits a hiddenclient_idfield.createQuickLeadresolves the parent Client in two paths: explicit hidden field (workspace-scoped lookup + activity bump) or the default find-or-create-by-email. Both paths land at the same Lead-insert with the right client_id. - createInvoice server action now writes
invoices.client_id. Either taken from the explicitclient_idform field or resolved via the lead row'sclient_id. Touches the parent Client'slast_activity_atso the new invoice nudges them up /clients's sort.
Added
- Client as a top-level entity (Path A, Studio Ninja-style umbrella).
New
clientstable introduced via20260519000200_path_a_clients.sql. Every Lead now belongs to a Client (leads.client_id NOT NULL); Invoices gain an optionalclient_idFK (NOT NULL coming in a follow-up once any pre-Path-A invoices are re-homed). Backfill creates one Client per existing Lead, reusing the Lead's UUID as the new Client's UUID so the 1:1 mapping is trivial and lookup-free. Duplicate Clients (Sarah enquired twice as two Leads) are merged manually via a future merge UI. findOrCreateClientByEmailshared helper atsrc/lib/clients.ts. Case-insensitive email match against the workspace; matches bumplast_activity_atso /clients's recent-first sort floats them. Phone-only enquiries always create a fresh Client (recycled numbers / shared lines make phone-match risky). The new-lead dialog, the webhook intake, the public hosted-form submit, the CSV bulk import, and the seed-sample-data action all route through this helper, so every Lead is born with the right umbrella.
Added
- New-lead dialog reachable from every list surface. A single
shared
NewLeadDialogcomponent now mounts in the header of the Pipeline, Leads, Clients, and Calendar pages, opening a native modal with a proper labelled form: primary contact, secondary contact, email, phone, event date, source picker (every recognised source), and notes. Closes Esc, closes on backdrop click, restores focus on close. The cramped inline quick-create on the Pipeline header has been removed.- Clients mounts it with
initialStatus="won", so adding a booked client there lands the lead in the won column without a second step. - The server action allowlists
initial_status(onlynew_enquiry / won / on_hold / cold) so a tampered hidden field can't push leads into terminal states likelost. - On successful create the action revalidates Pipeline, Leads,
Clients, Calendar, and Dashboard, and the dialog calls
router.refresh()so the new row appears wherever the user opened it from. No more redirect-to-lead-detail interruption.
- Clients mounts it with
Changed
- Default pipeline-stage label renamed Chemistry → Discovery.
The seeded
chemistry_call_donestage now reads "Discovery call" everywhere user-facing copy renders it: status badges on Leads, status filter on the Leads toolbar, "Move to …" bulk action, onboarding wizard stage-hint examples, and the Pipeline help article. The internal enum valuechemistry_call_doneis kept unchanged so existing rows and analytics queries continue to work; only the display label moved. (The migration that renamed the seeded stage name was already in20260519000100; this finishes the rename in the application layer.) - Empty states on Pipeline and Leads lead with the hosted contact
form. Both pages used to suggest "Set up a webhook" as the
secondary path for getting leads in. After the integrations
rewrite the hosted contact form is the recommended path for
non-technical studios, so the empty state now leads with
"Set up a contact form" →
/settings/contact-formsand demotes Import CSV and Zapier to secondary options. - Dashboard error page is route-aware.
(dashboard)/error.tsxnow readsusePathname()and routes its "Back to …" link to the section the error came from (Pipeline, Leads, Clients, Calendar, Invoices, Settings) rather than always sending the user to the Dashboard. The body copy reflects the same section.
Fixed
- Every Settings Save / Submit was returning 500. Next.js 16 /
React 19 tightened the rule that a
'use server'file can only exportasync functions; anyconstvalue or sync function on the same module rejects the whole action import at runtime. Four modules were re-exporting their*_INITIAL_STATEconstants alongside the actions, which broke:Settings → Workspace Save,Vocabulary Save,Pipeline rename + reorder,Invoicing Save,Integrations Generate key.- The onboarding wizard's
TerminologyandStagessubmit steps. - The public hosted contact form submit at
/form/[id], which would have 500'd on the first real visitor enquiry. Each offender was split into a siblingstate.tsmodule that exports the type + initial value. Consumers now import the action from./actionsand the state shape from./state. No behavioural change.
/settings/dashboardwas throwing "Functions cannot be passed directly to Client Components". The page was passing the fullMetricDefinitionobjects (each carrying acomputecallback) into theCustomiseDashboardclient component. Added a serializable view type,MetricDefinitionView, plus ametricDefinitionView(def)projector that stripscomputebefore the boundary. The compute itself still runs server-side, so the displayed status is unchanged.- Manual lead creation crashed with a
display_name NOT NULLviolation.createQuickLeadwas insertingpartner_1_name,partner_2_name,email,wedding_datewithout the requireddisplay_name. The action now routes its inputs throughnormalizeLead()(the same normalizer the webhook + public form paths use), so the display name is always derived and partner_1 parses cleanly when the user types a full name.
Added
- Invoices in the top nav. Was reachable only by URL or from a lead detail page. Now sits between Calendar and Settings in the primary nav so it has parity with the other feature surfaces.
Changed
- Settings → Integrations rewritten for plain-English UX. The
page used to lead with "Webhook endpoint", "Workspace ID",
"Sample request" (curl), and "Shared secret (legacy)" cards, all
of which assumed the reader knew what a bearer token was. The
rewrite leads with three "pick your path" tiles, hosted contact
form (recommended), Zapier / Make / Typeform, or custom-built
website, and pushes the technical surface (webhook URL, sample
curl, field reference) behind a collapsed disclosure on a single
"Connection details" card. API keys are reframed as "Connection
keys" with friendlier helper copy; the new-key placeholder is
generic ("e.g. my website") instead of name-checking a single
tenant. The Workspace ID card was removed entirely, payloads no
longer need a
workspace_idsince each API key implies its own workspace.
Removed
- Shared-secret webhook auth. The legacy
WEBSITE_WEBHOOK_SECRETenv-var path on/api/webhooks/website-leadis gone. Every active integration was rotated onto a per-workspacecpsk_…API key, so the fallback path was carrying audit / revocation cost for no caller. Removed:- The
SecretGeneratorUI component and its card onSettings → Integrations. - The
shared_secretauth branch in the webhook route, thesafeCompareimport, and theauth_modefield on lead activity metadata. - The "Setting up the webhook secret" / "Generate a secret"
sections from
/help/integrations-overview,/help/webhook-zapier, and/help/website-form, plus the matchingWEBSITE_WEBHOOK_SECRETreferences in/docs/webhook. - The
workspace_id_required(400) andwebhook_not_configured(503) response paths, neither is reachable now that auth implies a workspace.
- The
Added
- Invoice MVP. New
/invoicessurface lets a workspace generate a numbered tax invoice (ABN, line items, optional GST) and print it to PDF via the browser's print dialog. Built for the "Javiera does a $30 hair job for Margarita and needs a tax record" scenario but works for any sole-trader flow.Settings → Invoicingstores the invoicing identity once: business name, ABN, address, contact info, GST-registered toggle, BSB / account number, payment terms, next number./invoiceslists every invoice with status (draft / sent / paid)./invoices/newcreates one;?lead_id=prefills from a lead./invoices/[id]renders a print-friendly Tax Invoice with aPrint / Save as PDFbutton that opens the browser print dialog. Action bar hides in print via@media print.- Migration
20260513070000_invoices.sql: newinvoicestable (RLS viaprivate.is_workspace_member) andworkspaces.invoice_settings jsonb. - Zero new dependencies. Print-to-PDF handled entirely by the browser; no server-side PDF library or rendering pipeline.
Security
Closed 9 of 10 Supabase advisor security findings. Two migrations (
20260518000000_advisor_fixes.sql,20260518000100_advisor_function_grants.sql) address the full output ofsupabase db advisors --linked --type security:function_search_path_mutableontouch_updated_at. setsearch_path = ''.public_bucket_allows_listingon theavatarsbucket. dropped the broad SELECT policy onstorage.objects. Direct URL access still works for public buckets via the storage CDN; only the LIST path is closed.anon_security_definer_function_executableandauthenticated_security_definer_function_executableonhandle_new_user,is_workspace_member,rls_auto_enable. revoked EXECUTE frompublicfor the trigger-only functions, and relocatedis_workspace_memberto a newprivateschema that PostgREST does not expose at/rest/v1/rpc/*. RLS policies now callprivate.is_workspace_member(...)and the public-schema copy was dropped.
The one remaining advisor finding (
auth_leaked_password_protection) is a Supabase Dashboard toggle, not a SQL change. Tracked inLAUNCH_CHECKLIST.md§ 4.
Performance
Closed 51 of 60 Supabase advisor performance findings. Same two migrations:
unindexed_foreign_keys(7). added covering indexes onjobs.lead_id,lead_activities.created_by,leads.{assigned_to, created_by, package_id, stage_id},workspaces.owner_id.auth_rls_initplan(8). rewrote 8 policies onprofiles,workspaces,passkey_credentials,user_totpto wrapauth.uid()in(select auth.uid()), turning per-row calls into single InitPlans.multiple_permissive_policies(36). six workspace-scoped tables had overlapping "members read" (FOR SELECT) and "members write" (FOR ALL) policies; SELECT was being checked twice per row. Replaced with a single… members accessFOR ALL policy targetingauthenticatedonly (the old{public}role grant letanonevaluate the policy too, even thoughis_workspace_memberwould never match).
The 16 remaining findings are all
unused_index(INFO), expected because production has zero real traffic yet. The flagged indexes back the dashboard widgets and lead lists; leaving them in. Will revisit after a few weeks of real load.
Security
Email-confirmation gating on writes. Unverified users can still browse the dashboard, but every server action that mutates state now calls a new
requireVerifiedSession()helper that bounces them to/verify-email. Reads stay open. The new page wraps the existing resend / change-email server actions in a full-card layout so the user can fix a typo or trigger a new email without leaving the gate. Onboarding actions deliberately remain on plainrequireSession()so a brand-new user can get through the wizard while their inbox is loading; writes start gating the moment they hit a real dashboard surface. Trade-off documented insrc/lib/auth.ts: ~1% conversion loss vs. real spam-account containment + reliable password-reset.Files updated:
src/lib/auth.tsaddsrequireVerifiedSession().- new
src/app/verify-email/{page,actions-client}.tsx. located at root level (outside(dashboard)so the onboarding gate doesn't bounce a brand-new unverified user into a redirect loop). src/app/(dashboard)/{pipeline,leads/[id],settings/...}/actions.tsswappedrequireSession→requireVerifiedSession(8 files, 32 callsites).src/app/api/leads/import/route.tssame swap.
Fixed
- Production QA pass. 2026-05-09. Walked the live site via
Chrome MCP, caught a handful of real issues:
/clientsempty-state copy was hard-coded to "Mark a lead as won..."; on workspaces that renamed the won-mapped stage (e.g. ours uses "Booked"), the instruction was wrong. Now looks up the workspace's actual won-stage name and uses it. The "won clients" header count uses the same label./calendarwas rendering Lost leads alongside upcoming bookings. The page subhead's colour legend doesn't even list Lost, so showing them was confusing. Filteredstatus !== 'lost'from both the upcoming and past lists.- Em-dash audit across
/docs/webhook(5 instances), the backup-code settings card (2 instances). All replaced with commas or colons per the project's no-em-dash rule. Em dashes in JSX comments are deliberately left alone (AGENTS.md allows them in non-rendered text). - Sample seed data ("Add 5 sample leads") now populates
partner_1_nameandpartner_2_namefrom the display name so the Couple card on the lead-detail page renders with realistic values instead of two empty inputs.
Operational
- Hands-on launch session 2026-05-09. Drove every signup +
config that Compass needs to talk to the world via Chrome MCP
(with explicit user consent for the OAuth + TOS confirmations):
- Brevo account created (org "Compass Studio",
gonzalo@novoa.me). API key generated and stored as
BREVO_API_KEYin Vercel Production.BREVO_FROMset toCompass <noreply@getcompass.studio>. - Four Brevo DNS records added at Namecheap for
getcompass.studio(Brevo verification TXT, DKIM 1+2 CNAME, DMARC TXT). Domain still showing "Not authenticated" because Namecheap's authoritative NS hasn't synced; up to 48h propagation per Namecheap's docs. - Sentry activated on the existing pre-flighted scaffolding.
Org
compass-51p, projectjavascript-nextjs, US data region. All 5 env vars (SENTRY_DSN,NEXT_PUBLIC_SENTRY_DSN,SENTRY_ORG,SENTRY_PROJECT,SENTRY_AUTH_TOKEN) set in Vercel Production. Redeployed so the build picked them up. - UptimeRobot account created via GitHub SSO. Monitor on
https://getcompass.studio/api/auth/meat the default 5-min interval, email alerts to gonzalo@novoa.me. - Supabase Pro-only items (leaked-password protection +
Free-tier usage alerts) documented as blocked-on-upgrade in
LAUNCH_CHECKLIST.md§ 4. www.getcompass.studiodomain identified as belonging to another Vercel account; documented the unblock action inLAUNCH_CHECKLIST.md§ 3.
- Brevo account created (org "Compass Studio",
gonzalo@novoa.me). API key generated and stored as
Added
- /api/sentry-check route for verifying Sentry activation in
one curl. Returns a JSON snapshot of which Sentry env vars
reached the deploy;
?throw=1fires a recognisable test error the Issues page should pick up within 60s. Auth-gated byCRON_SECRETso it can't be tripped accidentally. Delete after Sentry is verified working. it's a one-shot tool, not product surface.
Changed
- Lint sweep. 248 problems → 0. Disabled
react/no-unescaped-entities(220 false positives on JSX apostrophes), added the standardargsIgnorePattern: ^_to@typescript-eslint/no-unused-vars, dropped a few staleeslint-disabledirectives, replaced two<a>tags with<Link>(csv-import.tsx → /leads, global-error.tsx kept as<a>with an explicit suppression because Link doesn't work in a document-replacing error boundary). Reordered helper declarations inpasskeys.tsxandnav-progress.tsxto satisfy React Compiler's "cannot access variable before declared" check. Replaced twowindow.location.href = …assignments withwindow.location.assign(…)to dodge a false positive in React Compiler's immutability rule. The handful of remaining set-state-in-effect cases are one-shot hydrations (theme, consent banner, command palette open) suppressed with inline rationale.
Added
- Sentry pre-flight. Installed
@sentry/nextjsand scaffolded every file needed to ship error monitoring + performance traces + session replay:instrumentation.ts(server + edge),instrumentation-client.ts(browser),sentry.server.config.ts,sentry.edge.config.ts.next.config.tsis wrapped withwithSentryConfig(sourcemap upload, tunnel route at/monitoring, automatic Vercel cron monitors).global-error.tsxforwards exceptions viaSentry.captureException. Proxy and robots.txt allowlist the tunnel route. Privacy posture is mask- by-default:maskAllText+blockAllMediaon session replay,sendDefaultPii: falseon the Node + Edge SDKs. All paths no-op cleanly whenSENTRY_DSNis unset, so this commit is safe to ship before the Sentry account exists. Activation = paste 5 env vars (SENTRY_DSN,NEXT_PUBLIC_SENTRY_DSN,SENTRY_ORG,SENTRY_PROJECT,SENTRY_AUTH_TOKEN); steps inLAUNCH_CHECKLIST.md§ 4.
Changed
- Email provider: Resend → Brevo. Resend's free tier ties
verified domains to a single workspace, and that workspace was
already claimed by the photography domain. Brevo gives 300/day
free with custom-domain support, which is enough headroom for
the welcome / backup-code / share-results flows for the
foreseeable future. Code change is single-file
(
src/lib/email/send.ts), with the Waypoint share-results route refactored to call the shared helper instead of its own Resend fetch. Env vars renamedRESEND_API_KEY→BREVO_API_KEY,RESEND_FROM→BREVO_FROM. Privacy page, help article, README, LAUNCH_CHECKLIST, SMOKE_TEST, and TODO updated. - Marketing pages truly static:
/changelog,/docs/webhook,/help,/help/[slug],/pricing,/privacy,/status,/terms,/tree, and the globalnot-found.tsxnow render as○static (or●SSG) instead ofƒdynamic. The win comes from a new<SiteNavStatic />client component that fetches/api/auth/meon mount instead of reading the Supabase cookie during render. Marketing surfaces are edge-cached HTML, faster on first load, and don't hit the database for guests. Dashboard surfaces still use the original server-component<SiteNav />for instant per-workspace vocabulary. - Tree of Compass status sweep: corrected stale statuses on
/tree. Discount calculator moved from "exploring" to "done" (it shipped a while back). Added shipped-but-missing entries: Calendar, Soft-delete & Trash, Bulk actions, Custom fields under Pipeline; Financial year toggle and Status page under Insights; Account security, Data export & deletion, Dark mode, and Billing (in-progress) under Foundation. Wrong shipped markers erode trust, so the page now matches the codebase. - Lead-detail copy audit: the leads list table headers ("Couple", "Wedding") and the pipeline quick-create placeholders ("Partner 1", "Partner 2", "+ New lead") now route through the workspace terminology layer. Solo-industry workspaces see "Contact / Second contact (optional) / + New enquiry"; planners see "Event"; etc. Also softened the packages placeholder ("e.g. Wedding: Premium" → "e.g. Premium") and the CSV-import summary ("wedding directory" → "industry directory").
Added
- Click event date → jump to calendar (Studio Ninja request,
score 88). The Wedding column on
/leadsis a link to/calendar?focus=YYYY-MM-DD&lead=<id>. The calendar reads the focus param, highlights the matching month tile, and smooth- scrolls it into view via a small client island. - Lost-lead reason (SN score 32). When status moves to
lost, the lead detail surfaces a free-text reason input with a datalist suggester (budget / ghosted / style mismatch / date unavailable / went with another vendor / postponed / cancelled / not the right fit). Saves stamplost_at; reverting the status clears both. Migration:supabase/migrations/20260517000000_lead_lost_reason.sql. - Package column on
/leadslist (SN score 43). Workspace packages join vialead.package_id; shows "(removed)" if the package row was deleted, "–" if no package set. - Day-of-week prefix on every event date (Studio Ninja FB-group
top request, score 214). New shared
formatEventDate()inlib/format.tsrenders "Sat, 15 Nov 2026" (or compact "Sat, 15 Nov" inside narrow surfaces). Routed through pipeline cards, leads list, clients view, dashboard widgets, and lead detail. - Pronouns / gender-inclusive fields on leads (SN score 112).
New
contact_primary_pronounsandcontact_secondary_pronounscolumns. Lead-detail Couple card has datalist-backed inputs (she/her, he/him, they/them, she/they, he/they, any pronouns, ask me. plus free-text). Pronouns surface in the lead header. Webhook normalizer acceptspronouns/partner1pronouns/partner2pronounsaliases. Migration:supabase/migrations/20260515000000_lead_pronouns.sql. - Financial-year toggle on the dashboard (SN score 154).
Workspace setting (Settings → Workspace → Financial year) picks
the start month (Jan / Apr / Jul / Oct), and a Period dropdown
on
/dashboardscopes every metric and widget to that FY (?fy=fy26query string). Also supports "All time". Helper library atsrc/lib/fiscal-year.ts. Migration:supabase/migrations/20260516000000_workspace_fy.sql. - Lead activity timeline grouped by day: Today / Yesterday / weekday / dated, each with a sticky-style header. Time-only on each row; full timestamp shows on hover.
- Custom fields on leads: Settings card on the lead detail page
reads/writes
leads.custom_fieldsjsonb. Add / rename / delete arbitrary string-keyed fields. Edits log a genericfield_updatedactivity entry (without leaking values). - Waypoint → workspace.goals sync: when a signed-in user saves
Waypoint state, the True North numbers (annual take-home, jobs
target, revenue per job, tax bracket) mirror onto
workspaces.goalsso the dashboard + roadmap can read a canonical source. Defensive fallback if the column doesn't exist. - Status page at
/statuswith four client-side probes (web, API+DB, auth, static Waypoint) and a coloured overall badge. Refresh-driven; for proper incident history wire BetterStack. - Discount calculator on the Waypoint result page. Drag the slider; the card answers "to absorb a 15% discount, you'd need 18% more bookings to land the same revenue".
- Mobile pass at ≤480px / ≤380px: tighter SiteNav, smaller link text, full-width settings cards, stacked lead-detail columns, bigger button tap targets.
- A11y: stage-move buttons (
←/Stage name →) now mirror theirtitleintoaria-labelso screen readers get the full intent. - ⌘K / Ctrl-K command palette with fuzzy-matched commands across every dashboard route, settings page, tool, and help surface. Mounted only on signed-in routes. Keyboard nav (↑/↓/↵/Esc).
- Status toasts for one-shot URL flags. The pipeline
?deleted=1, dashboard?seeded=1, billing?status=active|cancelled, and the proxy's?gated=…redirect now surface as toasts and the flag is stripped from the URL so a refresh doesn't re-fire. - Waypoint Download PDF button in the Save & Share modal. Wires
the existing
exportPDF()(jsPDF + html2canvas) to a UI control with a "Building PDF…" pending state. - Defensive lead query:
listLeadsForWorkspaceandlistTrashedLeadsForWorkspacenow catch SQLSTATE 42703 ("undefined_column") and fall back gracefully. a forgotten migration won't take production down again. - Mobile nav polish at ≤480px: tighter spacing, smaller links, hidden help icon (it's reachable from the avatar dropdown and ⌘K).
/changelogpublic page that rendersCHANGELOG.mdstraight from disk. Linked in the SiteFooter and the sitemap./clientsview: filtered slice of leads wherestatus='won', ordered by event date so upcoming work is at the top. Empty state links back to/pipeline.- Bulk actions on
/leads: checkbox-per-row + a top action bar that bulk-moves selected rows to a status or trash. NewbulkLeadOpserver action does the work in one query. /docs/webhookdeveloper-facing reference for the website lead webhook: endpoint, auth, body shape, example curl, error matrix, rate limits.- Sample data seed: dashboard empty state has an "Add 5
sample leads" button that drops realistic data so a brand-new
user can play with the kanban + dashboard tiles. Idempotent. marks rows with
custom_fields.seed_sampleso re-clicks don't pile up. - Lead-detail terminology: partner-1 / partner-2 / ceremony- venue / reception-venue labels now flow through the workspace terminology layer. Solo-industry presets (hair_makeup, other) collapse to "Primary contact / Second contact (optional)" and "Location / Backup location".
- Dark mode: token-only override at
html[data-theme="dark"]with brand-dot kept constant. FOUC-free inlineThemeScriptin the root layout. New Settings → Account → Appearance card with light / system / dark toggle. - Trash auto-cleanup cron:
/api/cron/cleanup-trashhard- deletes leads wheredeleted_at < now() - 30 days. Wired invercel.json; setCRON_SECRETto enable. - Stripe billing scaffolding: workspaces gain
tier,stripe_customer_id,stripe_subscription_id,plan_period_end. New/api/billing/{checkout,portal,webhook}routes use the Stripe SDK. New Settings → Billing card branches onBILLING_LIVE: shows the waitlist while off, the upgrade and manage flows when on. Help article/help/billing-plansexplains the model. LAUNCH_CHECKLIST.mdat the repo root consolidates every user-action step (migrations, env vars, DNS, Stripe setup, monitoring, day-one ops) into one document.- Help article search: client-side filter on
/helpwith a search input that matches title (×3), tags (×2), and blurb (×1). Cmd/Ctrl-K focuses the field. Empty results surface a "tell us what's missing" mailto. - Global toast system:
<ToastProvider>mounted at the root layout,useToast()hook for any client component to push a non-form notice (info/success/error). Auto-dismisses after 6 s, dismissable. Used as the home for ephemeral confirmations that aren't tied to a specific form. - Soft-delete + Trash for leads. Deleting a lead now sets
deleted_atand removes it from the working surfaces (pipeline, leads, calendar, dashboard). Settings → Trash lists deleted leads, with Restore (clearsdeleted_at) and Delete forever (hard remove) actions per row. Migration:supabase/migrations/20260512000000_lead_soft_delete.sql. - Lead-source enum expansion: 12 new values for non-photography
trades (TikTok, Pinterest, LinkedIn, YouTube, Yelp, EasyWeddings,
Thumbtack, Fash, "Cold outreach", "Past client", "Event /
market", "Vendor directory"). Single-source LEAD_SOURCE_LABEL is
now the truth; the import alias router derives its valid list
from it. Migration:
supabase/migrations/20260513000000_lead_source_expand.sql. - Backup recovery code on signup. Every new account gets a
single-use 12-character backup code emailed to them on the spot,
in a branded HTML email with explicit "don't delete this email"
copy. The code can be used at the
/loginsecond-factor step (new "Use a backup code instead" link) to bypass the OTP if the user loses access to their authenticator app or inbox. Codes are scrypt-hashed at rest, single-use (consumed on success), and regeneratable from Settings → Account → Backup code (which re-emails the new plaintext). Migration:supabase/migrations/20260511000000_backup_code.sql. - Per-user sign-in security mode. Settings → Account →
Sign-in security card lets users pick between:
simple: email + password (default).two_factor: email + OTP (TOTP if enrolled, else email-OTP) + password. Stored asprofiles.auth_mode. The/loginflow looks up the mode at the email step and either skips the OTP step entirely (simple) or branches into TOTP/email-OTP (two-factor). Passkeys remain available regardless of mode.
- TOTP (authenticator app) as the OTP source. Settings → Account
has a new "Authenticator app" card with a QR-code enrollment
wizard (Google Authenticator, 1Password, Authy compatible). Once
enrolled, sign-in branches: the OTP step prompts for the
authenticator-app code instead of emailing one. Email-OTP remains
the fallback for users who haven't enrolled. Secret is encrypted
at rest with AES-256-GCM. Migration:
supabase/migrations/20260509000000_user_totp.sql. - Three-step login (email → email-OTP code → password): Replaces the single-form login with an explicit 2FA-style flow. OTP arrives by email via Supabase auth; the verified-email marker is a short-lived signed cookie. SMS swap-in documented in the README. single-line change once a Twilio / Brevo SMS provider is configured in Supabase.
- Passkey scaffolding (off by default):
supabase/migrations/20260508000000_passkeys.sqlmigration for thepasskey_credentialstable with RLS.@simplewebauthn/server+@simplewebauthn/browserdeps./api/passkey/register/{options,verify},/api/passkey/login/{options,verify},/api/passkey/list,/api/passkey/[id](delete).- Settings → Account → Passkeys panel for adding / removing / naming registered credentials.
- "Use a passkey" button on the
/loginemail step. - Flip
PASSKEYS_ENABLED=1after applying the migration to turn the surfaces on.
- Launch-readiness pass:
robots.ts,sitemap.ts,opengraph-image.tsx,icon.tsx,apple-icon.tsx,manifest.tsso the site has a proper crawl map, share card, and PWA install metadata.- Site-wide security headers in
next.config.ts(HSTS, X-Frame-Options, Referrer-Policy, Permissions-Policy, COOP). - Vercel Web Analytics + Speed Insights wired in the root layout.
- Cookie / data-use consent banner with localStorage memory.
/privacyand/termspages with the legal-prose treatment, revalidate-weekly cache.- Shared
<SiteFooter>rendered on every public + signed-in surface (Pipeline, Pricing, Help, Tree, Privacy, Terms, dashboard, etc.). - Dashboard empty state. first-run users see a four-tile welcome
panel instead of a wall of
–placeholders. - Signup now requires a Terms-of-Service / Privacy-Policy
checkbox (both client-side
requiredand server-side guard). /api/account/exportreturns a JSON dump of profile, workspaces, leads, activity, stages, packages, expenses, jobs (GDPR data portability).- Account deletion flow at Settings → Account → Your data: re-auth via password + email confirmation, cascade-deletes everything via the Supabase admin client.
- Pricing CTAs for Captain / Fleet now route to a "Join the
waitlist" mailto until Stripe is wired (
BILLING_LIVEflag inpricing/page.tsx); paid cards show a "Coming soon" badge. - Page titles +
robots: noindexon/login,/signup,/forgot-password,/reset-password.
- Help articles now render as a table-of-contents + collapsed
sections. Each
<h2>becomes a native<details>(closed by default, multiple can be open at once), and the TOC at the top jumps to + opens the matching section on click. Deep links like/help/waypoint-overview#step-3-job-costsauto-open the target. - Loading skeletons for
/pipeline,/leads,/calendarso the layout anchors instantly while Supabase resolves. - Top-edge navigation progress bar that fires the moment any in-app link is clicked, so clicks always feel acknowledged.
- Speculation rules in the dashboard layout so Chrome / Edge prerender the most-likely next route while the user reads the current one.
- View Transitions CSS for a 180ms cross-fade between routes, with the SiteNav logo as a shared element that morphs in place.
- Optimistic UI on pipeline stage-move buttons: the button dims and nudges the moment it's clicked, before Supabase round-trips.
- SiteNav skeleton + Suspense boundary on every marketing page so the page outline streams without waiting on the auth fetch.
Changed
- Marketing pages (
/help,/help/[slug],/tree,/pricing) now declarerevalidate = 3600. The pages remainƒ(dynamic) until the SiteNav cookie read is moved client-side; until then the revalidate just documents intent. - Aggressive
prefetchon the SiteNav primary links + tools dropdown so Safari and Firefox (no Speculation Rules support) still warm the next route on hover/focus. - Tree feature grid is now
next/dynamic-imported so its hydration chunk loads in parallel with the page shell. - Help articles registry:
findArticleis O(1) (Map index) andarticlesByCategoryis memoized at module load. - Pricing feature matrix uses a discriminated union, dropping noisy
pilot/captain/fleet: falsetriplets on every group-row. - Waypoint static HTML: third-party scripts (Sortable, html2canvas,
jsPDF) now
deferso the hero paints before they download. - Reduced-motion: global override pares all animations to 0.01ms, plus the compass-rose spin pauses when the tab is hidden.
- Avatar img in SiteNav has explicit
width/heightto kill CLS on first paint. - Swept em dashes from all user-facing copy (help articles, pricing,
Tree of Compass, aria-labels). Documented the no-em-dashes rule in
AGENTS.mdso future agents pick it up. - Tightened the Waypoint and Roadmap heroes: smaller wordmark (was 64–132px, now 40–64px), smaller compass-rose mark, less padding above and below. Reclaims about 200px of vertical space on first paint.
[0.1.0]. 2026-05-07
The first internal milestone. Compass CRM, Waypoint pricing
calculator, and Roadmap planner all live under
getcompass.studio, with a shared nav, account system, and
help knowledge base.
Added
Domain & deployment
- Connected the custom domain
getcompass.studio(Vercel + Namecheap DNS for the apex andwwwsubdomain). - Permanent (301) redirect from the auto-generated
compass-crm-five.vercel.appto the canonical domain. - Retired the standalone
compass-calculator.netlify.appdeployment; every URL there now 301s togetcompass.studio/waypoint.
Waypoint (pricing calculator)
- Renamed the calculator from "Compass" to "Waypoint" across every user-facing surface (topbar, hero, results page, picker, PDF export, email subjects).
- New optional Step 0. North / Star: yearly, monthly, and weekly
inputs that auto-sync (52 weeks, 12 months). State persists as
state.northStar.yearly. "Skip for now" jumps straight to Step 1. - New comparison block on Step 5 (Your Waypoint): only shown when North Star is filled in. Compares the dream income against the business's required revenue, with three styled states (green "+$X headroom", amber "within 10%", red "−$X short"), each with a tailored note.
- Star-glyph stepper indicator for the optional Step 0 (visually distinct from the numbered main flow).
- Cross-device state sync for signed-in users:
/api/waypoint/state(GET + PUT). Browser hydrates from server on load (debounced 1s PUTs on save). Guest users continue to use localStorage only. - Replaced the React port with the original Netlify static-HTML
calculator served at
/waypoint, restoring the polished animations and single-page UX. The Netlify email function ported to a Next.js Route Handler (/api/waypoint/send-results).
Pipeline & leads
- Universal lead-import normalizer (
src/lib/lead-import.ts): field-alias router accepts any payload shape (name/full_name/firstname+lastname,email/mail,phone/mobile/tel,event_date/wedding_date/shoot_date, etc.). Smart name parser handlesSam Smith,Smith, Sam,Sam & Alex,Sam & Alex Smith,Dr. Sam Smith Jr., single names. Strips honorifics and suffixes. - Coercion helpers:
parseMoney,parseDate(ISO + DMY/MDY heuristic + named months),parseEmail,parsePhone,parseSource. - CSV upload at Settings → Import. Browser-side parser handles RFC-4180 quoting, escaped quotes, CRLF/LF, BOM. Limit 5MB / 5,000 rows. Preview the first five rows before commit. Per-row failure reporting (imported / duplicates / skipped / errors). Dedup by email within the workspace.
/api/leads/importroute handler. same normalizer the webhook uses, plus per-row error attribution.- Empty states on Pipeline, Leads, and Calendar with action CTAs (Import a CSV, Set up a webhook, Connect your website).
Roadmap (/roadmap)
- Public feature roadmap at
/tree("The Tree of Compass") with click-to-detail modals. Five categories, ~30 seed features by status (done / in progress / planned / exploring / pruned).
Public pages & marketing
- Pricing page at
/pricingwith three tiers (Pilot, Captain, Fleet), feature matrix, FAQ. - Help & support knowledge base at
/helpwith category index and per-article pages at/help/[slug]. 18 articles covering: Compass overview, first steps, vocabulary system, pipeline stages, CSV import, webhook + Zapier, Meta Lead Ads, website-form integrations, integrations index, Waypoint overview, Roadmap overview, dashboard customisation, metric definitions, calendar view, change password, verify email, troubleshooting email delivery, sign out. - Per-feature help links from each Settings page that has a matching article (Import, Integrations, Pipeline, Profile, Account, Workspace).
Auth & account
- Sign up signs the user in immediately (no "wait for email" wall).
- Verification banner at the top of every signed-in page: surfaces the email, with inline Resend and "Wrong email?" edit controls.
- Forgot-password / reset-password flow at
/forgot-passwordand/reset-password. "Forgot?" link added next to the password field on/login. Generic "if an account exists" copy to avoid account enumeration. - In-app password change at Settings → Account. Verifies the current password before applying the new one.
- Avatar upload at Settings → Profile (server-side via
/api/profile/avatar, stored in Supabase Storageavatarsbucket, public URL). Cleans out stale uploads on each save.
Site-wide nav
- Unified
<SiteNav />Server Component used on every signed-in surface and the public/help,/tree,/pricingpages. - Compass-rose Tools dropdown (icon-only, Waypoint + Roadmap with blurbs).
- Help (?) icon next to the avatar links to
/help. - Avatar dropdown: hover shows a Google-style identity card (name / email / workspace), click opens a Studio-Ninja-style menu (identity header / workspace / Profile / Workspace settings / Account & password / Help & support / Sign out).
- Tools and Avatar are mutually exclusive. opening one closes the other.
- Static-HTML at
/waypointand/roadmapmirrors the same DOM and behavior in vanilla JS so the nav looks identical there. - Logo links to
/dashboardfor signed-in users.
Schema (additive, non-breaking)
- New
display_name(NOT NULL, backfilled),event_date,event_location, andcustom_fieldsjsonb columns onleads. Webhook + CSV import write all of these alongside the legacy columns.leadDisplayName()helper prefers the new column with a legacy fallback. - Renamed
workspaces.calculator_state→waypoint_stateto match the rebrand. - New Supabase Storage
avatarsbucket (public read, 2MB cap).
Public roadmap signals
/waypoint?gated=<route>shows a "this feature needs an account" banner above the mode selector when a signed-out user is bounced here from a protected CRM route.- Mode selector got a third card ("See pricing" →
/pricing).
Documentation
TODO.mdat the repo root: nine categories of deferred work.SMOKE_TEST.mdat the repo root: ~50-checkpoint runbook to run after every meaningful deploy.
Changed
- Calculator URL moved from
/compassto/waypoint(and/compassreferences purged). - Brand wordmark "Compass." now uses Fraunces serif consistently across login, signup, dashboard nav, Waypoint, and the static-HTML pages.
- Industry-aware terminology: "wedding" → "event", "ceremony venue" → "event location", etc., where appropriate. Photographer remains one of several supported industries (videography, copywriting, graphic design, web design, DJ, hair and makeup, personal training, event planning, other).
- Em dashes scrubbed from all user-facing copy (per copy preference);
retained in code comments and the placeholder
', 'rendered for null numeric values. - Old "Compass" tagline replaced with "Every great journey starts with knowing where you are." across auth pages.
app/(dashboard)/top-nav.tsx→src/components/site-nav.tsx(now shared across the whole product).- Proxy: signed-out users hitting a protected CRM route bounce to
/waypoint?gated=<route>(was/login). API routes now return 401 instead of redirecting. - Lead-source enum tightened to a curated set; future migration will open it to industry-specific values.
Fixed
- Static-HTML Waypoint reveal-observer fallback: page no longer silently renders invisible if the IntersectionObserver fails to fire (a 1.5s setTimeout + visibilitychange listener force-reveal anything still hidden).
- "Change industry" button on Waypoint now works for returning users
whose
state.industrywas already set (the click listener was previously bound only when the picker had been opened at least once). - Mode-row pills on
/waypointand/roadmapno longer overlap the CRM-style top nav (now positioned attop: 58pxinstead oftop: 0). - Layout bug where the body's existing
padding-top: 138px(to clear the floating mode-row pills) pushed the sticky CRM nav below the fold; CRM nav switched toposition: fixed; top: 0to avoid the offset. - Vercel "compass-crm-five" URL no longer serves the same app alongside the canonical domain. permanent redirect installed.
- DNS migration:
getcompass.studiorecords point at Vercel; old Namecheap parking page removed. - Resend SMTP configured on Supabase Auth so signup verification and password-reset emails actually deliver (was previously rate-limited by Supabase's built-in mailer).
Removed
- React port of the Waypoint calculator (
src/app/waypoint/*andsrc/lib/compass/*). replaced by the more polished static Netlify HTML. src/app/(dashboard)/top-nav.tsx. collapsed into the sharedSiteNavcomponent.- "Photography Pricing" eyebrow text where it was misleading outside that industry.
Security
- All inbound webhooks require an
Authorization: Bearer …header matchingWEBSITE_WEBHOOK_SECRET. Endpoint refuses every request without it. - Avatar uploads go through the admin client server-side; no bucket-level RLS dance required, validation happens at the Next.js handler boundary.
- Forgot-password flow returns generic "if an account exists" copy regardless of whether the email is on file (avoids account enumeration).
- Password change requires the current password (verified via re-auth) before applying the new one.