Admin guide (back office)
The back office lives at /app in the application. Everything in this guide is Dutch in the UI; the
Dutch labels are quoted so you can find them. For how the engine behaves underneath, see
02-concepts.md.
Contents
- Roles and what each one sees
- First-time setup
- Daily work: the calendar
- Appointments
- Services
- Staff
- Customers
- Packages
- Events
- Payments
- Coupons
- Notifications
- Settings
- Public pages your customers see
- Known limitations
Roles and what each one sees
Four roles exist: owner, admin, front_desk, staff. The nav shows only what the role may use;
everything else redirects to the role's home (the dashboard, or the calendar for roles without one).
| Menu item (Dutch) | Route | owner | admin | front_desk | staff |
|---|---|---|---|---|---|
| Overzicht | /app |
✓ | ✓ | – | – |
| Agenda | /app/calendar |
✓ | ✓ | ✓ | ✓ (own agenda) |
| Afspraken | /app/appointments |
✓ | ✓ | ✓ | ✓ (own agenda) |
| Klanten | /app/customers |
✓ | ✓ | ✓ | – |
| Pakketten | /app/packages |
✓ | ✓ | ✓ | – |
| Evenementen | /app/events |
✓ | ✓ | view only | – |
| Diensten | /app/services |
✓ | ✓ | – | – |
| Medewerkers | /app/staff |
✓ | ✓ | – | – |
| Betalingen | /app/payments |
✓ | ✓ | ✓ | – |
| Kortingscodes | /app/coupons |
✓ | ✓ | – | – |
| Meldingen | /app/notifications |
✓ | ✓ | – | – |
| Instellingen | /app/settings |
✓ | ✓ | – | – |
Two extra gates:
- Payment settings and the Mollie key can only be changed by owner/admin. Everyone else sees the payments tab disabled with "Alleen een eigenaar of beheerder kan dit wijzigen."
- A staff login is linked to one or more
staffrecords (staff.user_id); they only see and change appointments of those staff members, and cannot move an appointment to another staff member. Unlinked they see "Je account is nog niet aan een medewerker gekoppeld."
There is no user-management screen yet: you cannot invite colleagues or change roles in the UI. Contact nisebookings to add a colleague (with one of the four roles) or to change a role.
First-time setup
After signing up (/signup) you land on /onboarding ("Je bedrijf"): fill in Bedrijfsnaam,
Webadres (slug: lowercase letters, digits, hyphens) and Tijdzone, then "Verder". This creates
your account, makes you owner, and installs the default Dutch e-mail templates. You start with no
services or staff.
Recommended order:
- Instellingen → Algemeen — company name, time zone, time step, how far ahead customers may book.
- Instellingen → Openingstijden — the weekly template that new staff inherit.
- Instellingen → Vrije dagen — company-wide closing days.
- Medewerkers — add the people/resources. Each new staff member gets the opening hours as their weekly schedule.
- Diensten — add what can be booked, and tick which staff perform it (Medewerkers → Diensten).
- Instellingen → Bedrijf en e-mail — sender name, reply-to, phone/address/website (used in mails).
- Instellingen → Boekingsformulier — cart, chain, recurrence, occupancy display, waiting list.
- Instellingen → Betalingen — VAT inclusive/exclusive, deposit mode, local/Mollie, Mollie API key.
- Instellingen → Insluiten — copy the embed snippet to your website, restrict allowed websites.
- Test: book something yourself through the widget, then watch Meldingen → Verzendlog.
Daily work: the calendar
/app/calendar — the default landing page for front desk and staff.
- Views: Dag / Week / Maand (week by default). Vorige / Vandaag / Volgende, a date field, and selects for Medewerker and Dienst. Keyboard: ← / → / T (today).
- Click an empty grid cell → Afspraak maken prefilled with staff, date and time (snapped to the time step).
- Colours follow the booking status; cancelled/rejected appointments are muted and struck through. Mixed-status appointments are labelled "Gemengd"; an appointment without customers shows "Geen klant"; a recurring appointment carries a "reeks" marker; groups show "N pers."
- Events of staff linked to them appear as blocks ("Evenement").
- A rental (Verhuur ≥ 1 day) fills the whole day on every covered day and is labelled "N dagen" instead of a clock time.
- Grey areas are times outside the staff's schedule, breaks, and holidays.
- Week view hides non-business days when Alleen werkdagen tonen is on; day view hides staff without appointments when Medewerkers zonder afspraken verbergen is on; visible hours follow opening hours when Alleen de uren binnen de openingstijden tonen is on (all in Instellingen → Agenda).
Appointments
List — /app/appointments
Tabs Komend / Voorbij, status tabs (Alle statussen, In afwachting, Bevestigd, Geannuleerd, Afgewezen, Afgerond, Wachtlijst). Each row shows date/time, service, staff and note, then per customer: name, "N personen", a payment badge (Betaald / Aanbetaling / Open), an inline status select, the Klant mailen checkbox (on by default) and Opslaan. The appointment itself can be deleted ("Deze afspraak en de boekingen erin verwijderen?"). 50 rows per page.
Create — /app/appointments/new
Needs at least one simple service and one staff member. Fields: Dienst, Medewerker, Datum, Begintijd, Personen, Status (default = Instellingen → Afspraken), a customer block ("Bestaande klant" from the first 200 matches, or "Nieuwe klant" with Naam/E-mailadres/Telefoon — an existing e-mail address is matched and reused), Interne notitie, and two checkboxes: Toch inplannen bij een waarschuwing and Klant mailen.
With ?package=<id> (from a package page) the service, customer and persons are fixed to the package.
Edit — /app/appointments/[id]
- Details: staff, service, date, start and end time (end follows start + service duration until you change it), internal note. A rental shows only the date — it always starts at 00:00 and runs the service's number of days.
- Live warnings after you change something: overlap with another appointment, duration differing from the service, outside the schedule/breaks, or a holiday. These are non-blocking: the button becomes Toch opslaan. Blocking errors are capacity ("Dat past niet: deze medewerker heeft bij deze dienst plek voor maximaal N personen, dit worden er M."), end before start, or a staff member that does not offer the service.
- Klanten: shows "X van maximaal Y plaatsen bezet" (only In afwachting and Bevestigd count) and the waiting-list count. Per customer: persons, status, Klant mailen, Opslaan, and Verwijderen (no mail is sent). Under the customer you also see the answers to the service's Velden ("Vraag: antwoord", per-person answers joined per person; a deleted question shows its raw id). A file answer is a link to the upload, opening in a new tab; the link is short-lived, and once the file is deleted the stored name is shown without one. Waitlisted customers get Plaats geven (refused when the slot is full: "Er is geen plek: N van M plaatsen zijn bezet."). Adding a customer uses the same existing/new block. Empty state: "Nog geen klanten. De tijd blijft wel bezet." — an appointment without bookings still blocks its time.
- Recurring: when the booking belongs to a series, a scope select appears — Alleen deze / Deze en volgende / Hele reeks. Other occurrences shift by the same number of days and adopt the new start time, keeping their own duration, staff and service. Partial results are reported ("N van M andere afspraken in de reeks gewijzigd; de rest mocht je niet wijzigen of bestond niet meer.").
- Compound/collaborative: "Onderdeel van {service} — N delen. Een statuswijziging geldt voor alle delen."
- Delete: checkbox Klanten informeren (on): approved bookings are cancelled, pending ones rejected, each mailed; other statuses get no mail. For series/appointments you choose the scope, and a booking that was moved out of the series is kept.
Services
/app/services — grouped by category ("Zonder categorie" for uncategorised). Badges: Samengesteld,
Samenwerkend, Pakket, "Verborgen", "tot N personen". Dienst toevoegen starts with a type, which
cannot be changed later:
| Type (UI) | What it is | Needs |
|---|---|---|
| Gewone dienst | one appointment with one staff member, optional extras | duration, price, capacity |
| Samengesteld | parts one after another (wash → cut → dry), with spare-time rows | ordered parts |
| Samenwerkend | parts at the same time by different staff (skipper + boat) | ordered parts, one per staff |
| Pakket | prepaid bundle of N appointments of one simple service | base service, size, validity |
Common fields: Naam, Categorie, Omschrijving, Zichtbaarheid (Zichtbaar voor klanten / Verborgen, alleen intern te boeken), Aanbetaling ("100%", "30%" or a fixed amount per person), Btw-tarief (21 / 9 / 0 / Ander tarief).
Simple services add: Duur (minuten), Verhuur (dagen) (0 = an ordinary appointment with times; 1 or more = whole-day rentals — see below), Tijdstap (minuten) ("Leeg = standaard (N min)"), Prijs (EUR), Minimaal/Maximaal aantal personen, Tijd vooraf and Tijd achteraf (preparation/cleanup; blocks the calendar but is invisible to customers), Eén boeking per tijdslot, Herhalen (Dagelijks / Wekelijks / Om de week / Maandelijks; none ticked = no repeats), Wachtlijst (maximaal aantal personen) (empty = unlimited, 0 = off), and Als de klant geen medewerker kiest (Goedkoopste / Duurste / Volgorde van de medewerkerslijst).
Verhuur (dagen) ≥ 1 turns the service into a rental: the customer picks a start date, the appointment covers that whole day plus the following days, and the price is the daily price times the number of days. Business hours and the weekly schedule never apply to a rental — days off and existing appointments do. An appointment you make yourself for a rental always starts at 00:00 on the chosen date; extra's, chains and the waiting list do not apply, and the calendar shows the span as "N dagen" on every covered day.
Sections below the form:
- Onderdelen (compound/collaborative): ordered rows of service or Vrije tijd (minuten), plus the flags Alle onderdelen bij dezelfde medewerker / Alle onderdelen even lang bezet.
- Extra's (simple services): Naam, Prijs, Extra minuten, Min., Max., Volgorde. Minimaal 1 makes it mandatory. Existing bookings keep the extras they were booked with.
- Velden (every service): the intake questions the customer answers in the booking form. Per row:
Vraag (the label), Soort (Tekst / Tekstvak / Keuzelijst / Aanvinkvakje / Getal / Datum /
Bestand), Keuzes (one per line, only for a Keuzelijst: 1–20 choices of 1–100 characters),
Volgorde, Verplicht (the customer cannot book without an answer) and Per persoon (one
answer per person), plus Toon alleen als + Antwoord: pick an earlier question and the answer
that should reveal this one (e.g. "Kleur = rood", a checkbox with "aangevinkt" =
true, a number as3). A question whose condition does not hold is not shown, not required and not stored; the controlling question must be earlier in the list, unconditional and not per-person or a file. Answers show on the appointment and can be mailed with{fields}. A Bestand question takes one file of at most 5 MB (JPG, PNG, WebP or PDF). The file is stored with the booking and opens from the appointment page through a short-lived link; in a mail{fields}shows the file name only. Deleting a question keeps the answers on existing bookings; without a label such an answer shows its raw id. - Categorieën (on the list page): rename, delete (services survive), add.
Prices are per staff member (Medewerkers → Diensten); the service price is the fallback.
Staff
Staff is a generic "bookable resource": a person, a room, a boat, a device. /app/staff has Actief
and Gearchiveerd tabs, with Verborgen for private staff.
On a staff page:
- Gegevens: naam, e-mail, telefoon, omschrijving, zichtbaarheid.
- Diensten: which services this staff member performs, with per-staff Prijs, Min./Max. personen and Aanbetaling (empty = follow the service).
- Rooster: fixed weekly hours (Open / Van / Tot / Pauzes per weekday). Breaks are written as
12:00-12:30, several separated by commas. A day with Open off is a day off. New staff start with the company opening hours — later changes to opening hours do not touch existing staff. - Vrije dagen: per-date rows, "Eenmalig" / "Elk jaar" / "Toch open (uitzondering op een jaarlijkse vrije dag)". These come on top of the company holidays. Deleting an archived staff member is not possible; archiving keeps history.
Customers
/app/customers — search on name, e-mail or phone. Detail page shows and edits Naam, E-mailadres,
Telefoon, Notities, plus the appointment history and Klant verwijderen
("Deze klant en al zijn boekingen verwijderen? Dit kun je niet ongedaan maken.").
Customers are created automatically on booking (matched on e-mail within your account).
Packages
/app/packages lists bought packages: customer, package, staff, scheduled visits, validity
("Vanaf de eerste afspraak" until the first visit is planned).
- Pakket aanmaken: package service, optional staff ("Nog niet kiezen"), customer, Betaling
("Ter plaatse betalen (open betaling)" or "Geen betaling" — an open payment is completed later at
Betalingen), note, Klant mailen (sends the
package_newmail with the personal link). - Package detail: Afspraak inplannen (only while visits remain and it has not expired) opens
/app/appointments/new?package=<id>; Persoonlijke link with a copy button; the visit list. - Validity starts at the first planned visit: that date + the package's life days. Persons are fixed to 1 and only the package's own service can be planned. Errors: "Alle N afspraken van dit pakket zijn al ingepland.", "Dit pakket was geldig tot en met {datum}. Kies een eerdere datum."
Events
/app/events — Komend / Voorbij. An event has Titel, Status (Gepubliceerd, te koop /
Verborgen), Omschrijving, Afbeelding (webadres), start/end, Verkoop stopt op (empty = until
the start), a Ticketcode mask (each * becomes a random character, at least 4), and
Medewerkers (Niet betrokken / Organisator / Ondersteuning (agenda geblokkeerd)) — organisers simply
show in the calendar; only Ondersteuning has their time blocked for bookings while the event runs.
Tickettypes: Naam, Prijs, Btw %, Aantal, Gereserveerd ("Gereserveerde tickets worden niet online verkocht"), Volgorde. Deleting an event is refused once tickets are sold — hide it instead.
Deelnemers (/app/events/[id]/attendees): Code, Klant, Ticket, Status (Wacht op betaling /
Geldig / Geannuleerd), Betaling. Annuleren frees the ticket for resale and sends no mail.
Payments
/app/payments — newest first, filter by status (Open / Voltooid / Mislukt / Terugbetaald) and type
(Ter plaatse / Online (Mollie) / Gratis). Footer totals use the whole filtered set, not just the page.
Payment detail:
- Betaling voltooien — local, open payments: marks it fully paid.
- Terugbetalen — completed Mollie payments with a reference: refunds through Mollie. Appointments are not cancelled automatically.
- Te laat betaald: the payment arrived after the booking was rejected and the slot is gone. The alert says "Te laat betaald: de tijd was al vergeven. Betaal het bedrag terug." — refund it.
- Bedragen repeats the stored breakdown (subtotal, discount, gateway surcharge, total, VAT, deposit/later te betalen, paid); Boekingen links the appointments.
Coupons
/app/coupons — code (case-insensitive), Korting (%) and Aftrek (EUR) (both zero is rejected),
Aantal keer te gebruiken (account-wide), Eén keer per klant, validity dates (the booking date
counts, not the appointment date), min/max appointments per order, and restrictions to services
and/or staff (none ticked = all). Genereer code expands a mask like WELKOM-****.
Notifications
/app/notifications groups templates by type (Nieuwe afspraak, Statuswijziging, Herinnering,
Wachtlijst, Plek vrij (wachtlijst), Nieuw pakket, Tickets), with an Aan/Uit toggle. The editor covers
recipients (Klant / Medewerker / Beheerders / Andere adressen), status filter, service filter,
reminder timing, subject, body with {codes} and {#if …} blocks, an optional .ics attachment, a
Test versturen button (to your own address) and the code reference. /app/notifications/log is the
send log with statuses Verstuurd / In wachtrij / Bezig / Mislukt and retry count.
Full detail: 06-notifications.md.
Settings
/app/settings/<tab>:
| Tab | What you set |
|---|---|
| Algemeen | Bedrijfsnaam, Tijdzone, Tijdstap (minutes between start times), Minimaal vooraf (minutes), Maximaal vooruit (days), Taal van het boekingsformulier (Nederlands / Engels — the language customers see in the widgets; an individual embed can override it with data-lang). |
| Bedrijf en e-mail | Naam afzender (empty = company name), Antwoordadres, Telefoonnummer, Website, Adres, Verzendmarge herinneringen (uur), Annuleren tot (minutes before the appointment; 0 = until the start). |
| Afspraken | Status van nieuwe boekingen (Direct bevestigd / Eerst door jou goedkeuren) and the automatic status change (Van → Naar, after the appointment has passed). |
| Agenda | Alleen werkdagen tonen, Alleen de uren binnen de openingstijden tonen, Medewerkers zonder afspraken verbergen. |
| Boekingsformulier | Cart, chain ("direct na elkaar boeken"), extras × persons, Herhalende afspraken + Betalen bij een reeks (Hele reeks / Alleen de eerste afspraak), Bezetting tonen (Niet tonen / Bezette plaatsen 3/8 / Vrije plaatsen "nog 5"), Wachtlijst + "Wachtlijst telt mee als bezet", Prijs van samengestelde/samenwerkende diensten (Eigen prijs / Optelsom van de onderdelen) and "Klanten kiezen geen medewerker bij samenwerkende diensten". |
| Betalingen | Prijzen inclusief btw, Aanbetaling (alleen aanbetaling / klant kiest, aanbetaling voor / klant kiest, volledig voor), Ter plaatse betalen, Online betalen via Mollie + API-sleutel (write-only, shows a hint afterwards), Toeslag Mollie (%) en vast bedrag, Betaaltermijn (minuten), Status na betaling. Owner/admin only. |
| Openingstijden | Weekly template for new staff schedules. |
| Vrije dagen | Company-wide closing days. |
| Insluiten | Publieke sleutel, HTML snippet (on WordPress, paste it into a Custom HTML block; the shortcode shown there is not needed), and Toegestane websites (one origin per line; empty = every site may embed). |
| Webhooks | Owner/admin. Add an endpoint (URL + the events to send; the signing secret is shown once), Test versturen, Uitzetten / Aanzetten, Verwijderen, and the last 20 deliveries per endpoint with status, attempts and error. Rotating the secret and resending a delivery go through the API — see Webhooks. |
| API | Create and revoke API keys for the management API: name, scopes (catalogue/settings), shown once, plus the most recent writes per key. Server-side use only — the key is not for browsers. |
Public pages your customers see
No login, noindex, styled minimally in the same design language:
/b/<booking token>— Je afspraak: service, date/time, staff, persons, and "Afspraak annuleren" while the cancellation window (Instellingen → Bedrijf en e-mail) is open. "Afspraak verzetten" offers the next free times of the same service and staff (14 days, max 40 options); moving an appointment with several bookings moves them all. Friendly states for already cancelled, too late, already started, rejected and done./p/<package token>— Je pakket: remaining visits, validity, planned visits, and the booking widget in package mode to plan the next one./w/<waitlist token>— Plek vrijgekomen: "Plek innemen", first come first served; states for taken ("Helaas, iemand anders was je net voor.") and gone./o/<order token>— Je afspraken: all appointments of one order with their statuses and one button ("Alle afspraken annuleren") that cancels everything still inside the cancellation window; appointments that are too late stay and are explained instead.
Known limitations
- No user/role management UI, no invitations, no account switcher (the first membership wins).
- No CSV import/export, no print views, no activity log, no remembered filters.
- Customer pickers search as you type (20 matches at a time); type more to narrow down, or pick "Nieuwe klant" and enter the e-mail — an existing address is matched and reused.
- Warnings (overlap, schedule, holiday, duration) never block saving — "Toch opslaan" is always possible.
- Language of the admin UI is Dutch only.