Remaining features
CI / ci (push) Canceled after 0s

Built
No-show flag and block:
Two new numbers under Booking Rules (blank means off).
A symbol appears on the clients list, client page, calendar entries and appointment pages.
Online booking is refused at the block number, and customers are told at the details step.
Staff can still book a blocked customer in, and an owner can reset someone with a two-tap button.
The count resets when they attend, and matches the same email or phone, so a guest can’t dodge it with a new profile.
Email rules: staff and owners get email only for customer cancellations, schedule changes and invitations. Routine events (new booking, reschedule) are push-only. Nobody is told about their own action. A barber reassignment sends one customer email instead of two. Reward expiry sends one warning.
Email redesign: your brand colour, a details card, Add to calendar and View on map links, a preferences link, hidden preview text, and dark mode. Replies now go to the business’s own email.
WhatsApp “due now” queue: a list in time order with a highlighted next one, an owner setting for how many hours ahead (12–72), and a once-a-day push telling each barber how many reminders are waiting.
Monitoring: /api/health now reports whether notifications are actually going out. The worker resets stuck deliveries and alerts the owner on the first setup failure (such as a bad SMTP login). The app emails your operator address about server errors, and the manager pushes that address to each business.
Google scope: now only calendar.app.created. Events go to a calendar the app creates in the staff member’s Google account, called “<Business> bookings”.
This commit is contained in:
Stefan Lazic committed 2026-10-17 23:10:18 +01:00
1 parent 17eee5b932
commit 68a62e02a4
116 files changed
+3089 -766

No files matched your search

+8 -7
View File
@@ -63,16 +63,17 @@ service. State lives next to `global-settings.json`, under
over; on boot, jobs left "running" are marked failed and their locks
released.
- **Backups** (`src/lib/backup*.ts`, `restore.ts`; UI at a business's
*Backups* page and the global *Restore* page): an encrypted `.7z`
(`7zz`, AES-256, encrypted headers) of the database dump, media and
*Backups* page and the global *Restore* page): a plain `.7z`
(`7zz`, **not password-protected**) of the database dump, media and
config, in `STACKS_DIR/backups/<slug>/`. Written as `.partial`, verified
with `7zz t`, then renamed; the newest N (default 2, per business) are
kept. Safety backups (before an update or a replacing restore) and final
backups (before a delete) are kept separately and never evict them. One
passphrase protects everything: generated at the first enable / first
*Back up now*, stored encrypted (`MANAGER_SETTINGS_ENCRYPTION_KEY`),
**shown once** — save it, a fresh server needs it to restore. Restore
works onto an existing business (after a safety backup) or a server that
backups (before a delete) are kept separately and never evict them.
Because there is no password, an archive holds the business's secrets in
the clear (its `.env`: database password, auth secret, SMTP password,
VAPID private key) — files are written owner-only (0600) and the
download route is behind the Manager login; keep any downloaded copy as
private as the server itself. Restore works onto an existing business (after a safety backup) or a server that
never had it; see `RESTORE_STEPS` in `src/lib/restore.ts`. A backup
whose last migration is newer than the app image's is refused.
- **Alerts** (`src/lib/health-watcher.ts`): per-business ok / degraded /