Service-desk ticketing (with public portal / feedback-style categories),
salon-style appointments + stylists, and how they connect — including the
real code path where booking can create a billable ticket.
Public portal can be enabled per tenantAppointments → ticket link exists in codeNot movie admission seating tickets
Two related products (not one blob)
Tickets (service desk)
Appointments (booking)
Job
Track work items: support, repair, feedback, orders-as-tickets, etc.
Your instinct was right
Appointments can create/link a ticket for billing/tracking.
Public ticket portal + categories (including “Compliment”) is how feedback-style intake works —
not a separate “feedback app,” but the same ticket system with portal + categories enabled.
Optional bill / POS invoice hooks on tickets (maybeCreatePosInvoiceForTicket)
Public portal & feedback-style use
flowchart LR
SET[Ticket settings publicPortalEnabled]
CAT[Categories Inquiry · Issue · Compliment …]
FORM[Portal form designer]
PUB[Public URLs]
TK[(tickets table)]
STAFF[Staff service desk]
SET --> PUB
FORM --> PUB
CAT --> PUB
PUB -->|submit| TK --> STAFF
Enablement (per tenant)
Setting
Meaning
publicPortalEnabled
Turn public intake on/off
allowGuestTickets
Guests without login can submit
requireLogin
Opposite policy — force account
Portal URL
Backend-generated: /{tenantSlug}/public/ticket
Theme / language / timezone
Portal presentation
Public endpoints (public.tickets.routes.js)
Path
Purpose
GET /api/public/portal-form/:tenantSlug
Form config for designer-driven portal
GET /api/public/categories/:tenantSlug
Categories for the form
POST /api/public/tickets/:tenantSlug
Submit a ticket
POST …/track
Track existing ticket
Comments endpoints
Public follow-up on a ticket number
Knowledge base route
KB surface for tenant
Feedback without a separate product
Default category seeds include things like General Inquiry and
Compliment (“Share positive feedback”). Businesses enable the public portal
and use categories (or custom categories) for feedback, complaints, warranty, etc.
Same ticket pipeline → same workflows/SLA/staff desk.
API: /api/appointments (+ staff sub-routes) with feature gate appointments
Public: /api/public/appointments/:tenantSlug — available slots, staff, create booking
Stylists managed via /api/appointments/staff — “active stylists appear in public portal”
Do appointments use the ticketing system?
Yes — partly, by design in code
When an appointment is created, the appointments route can
INSERT a row into tickets (billable ticket), then set
appointments.ticketId / ticketNumber.
If ticket create fails, the appointment still succeeds (logged, non-fatal).
flowchart TD
BOOK[Public / staff book appointment]
AP[(appointments)]
TK[(tickets)]
BILL[Optional ticket bill / POS invoice hooks]
BOOK --> AP
AP -->|on create: try create ticket| TK
AP -->|store ticketId ticketNumber| AP
TK --> BILL
So stylists/booking is not implemented as “just tickets,” but it
can hang a ticket off the appointment for tracking/billing.
Day-to-day stylist UI is appointments + staff APIs, not the full service-desk screens.
Billable tickets → Core Invoicing
Tickets carry a bill (line items, amount, status). Checkout creates a
service invoice via Core Invoicing; crypto invoice and mark-paid paths also exist.
Full owner-facing money + audit story:
27 · Auditability & invoicing.
What this is not
Concept
Reality in GPE today
Movie admission / seat inventory tickets
Different product idea — floor seat IDs + invoicing; not this service-desk ticket engine
Kitchen tickets
kitchen_tickets / KDS — separate table and flow (see DocHub 15)
Standalone “Feedback app”
Portal + categories + tickets, not a separate app package