Skip to main content
All updates
Bug fixInvoicesPoint of SaleMembersAI Assistant·2026.09.15·

Invoice permissions are enforced everywhere, and Undo recovers instead of sticking

A staff role allowed to create invoices but not to manage them can no longer cancel, delete, credit or mark an invoice paid. Undo no longer gets stuck saying a change is already being undone, and when it cannot tell whether a change was reversed it says so instead of repeating it. Nothing else changes on your screens.

# Invoice permissions are enforced everywhere, and Undo recovers instead of sticking

This is the first of two security releases. It changes what the **database**
accepts; it does not change any screen.

## Invoice permissions

Your permission settings separate two things:

- **Create and edit client invoices** — writing a draft and editing it.
- **Cancel, credit, and record manual payments** — the money decisions.

Until now that separation only held inside the screens. A custom staff role with
only the first permission could still cancel, void, delete, credit or mark an
invoice paid by going around them. It now cannot: those operations, and any edit
of an invoice that has already left draft, require the management permission
wherever the request comes from.

Nothing changes for owners, managers or anyone who holds the management
permission, and nothing changes for the venue's automatic invoicing — checkout,
the overdue run, recurring invoices, course instalments and corporate billing all
keep working exactly as before. If a custom role at your venue was relying on the
gap, give it **Cancel, credit, and record manual payments** as well.

## Undo

Undo now recovers from interruptions. If a reversal is cut short — a dropped
connection, a crash, a failed write afterwards — the change no longer stays
permanently "already being undone". Within the undo window you can simply click
Undo again.

When the system genuinely cannot tell whether a reversal went through, it says so
and asks you to check the record rather than quietly repeating it, because
repeating an unknown reversal is how a record gets damaged twice. Those cases
raise one entry in your Command Center inbox per affected change per day, and
write an audit entry. They send no email, SMS or push.

Undo tickets themselves are now issued and settled only by the server.

## What is still coming

The second security release closes the rest: a signed-in client will no longer be
able to change venue records directly, or look up other clients' invoices,
receipts, message history, tags, scores or health records. It ships separately,
after this release is live, so that no staff screen is broken in between.

## Compatibility

| Combination | Result |
|---|---|
| The release serving production today + this release's database change | Safe. This release creates, drops and alters no access policy and revokes no privilege; a PostgreSQL 16 rehearsal proves the policy catalog is byte-identical, 936 read probes are unchanged and no table privilege moves. Every invoice and undo writer in the product already goes through the server path the guards exempt. |
| This release's code + the database as it is today (before the change) | Undo's revert claim would be rejected by the old status rule, so apply the database change first — the normal order. Everything else in this release works on either schema. |
| This release's code + this release's database change | The intended state. |
| This release + security release B's database change | Safe, and rehearsed: release B's own PostgreSQL 16 run applies production's policy catalog, then this release, then B, and the guards and B's policies agree. |
| The release serving production today + security release B's database change | **Not safe, and not the plan.** Staff screens that read member tags, invoices, POS records and analytics events through the signed-in session would go empty, instructor acknowledgements and the member video counter would fail, and support impersonation would lose those screens entirely. Release B is applied only after this release's code is what both production hosts serve. |
Next update

Pass settings are staff-only, and gift and extension settings save as shown

Only staff who can manage passes can change pass types, and only staff who can manage products can change shop products. The pass editor now explains when a pass cannot be gifted, “0 = unlimited” extensions save correctly, and a client’s offer limit carries over when a flash sale is replaced.