Documentation
IntroductionArchitectureMonorepo & ToolingRunning Locally
Screen Flow MapUser JourneysPersonas & RolesWeb ScreensClient Portal
Convex OverviewData ModelFunctions ReferenceAuth & SessionsRoles & PermissionsJobs & Providers
Web Design SystemAdmin Console DesignPatterns & Conventions
Web AppiOS AppMarketing Website
Testing & HarnessCI Pipeline

User Journeys

User Journeys

The core paths through the product, end to end. Each journey below is traceable on the Screen Flow Map — select a screen there to see its inbound and outbound connections.

Booking a visit (staff)

planned
due_in
in_house
completed
overdue
cancelled
no_show
cron: early check-in window
checkIn — agreement gate
checkIn (walk-in / early)
checkOut
cron: past checkout grace
checkOut
cancel
cancel
markNoShow
Check-in blocks on unsigned required agreements unless a manager overrides (visits.checkin_override). The cron uses each org's configurable early/late windows.
Visit lifecycle — every transition funnels through one transition() helper; dashed edges are the 15-minute cron sweep
  1. Sign in → /login → /accounts → choose org → /o/{slug}/dashboard.
  2. Find the pet — three ways: Clients list → client detail → pet row; Pets list → pet detail; or global search (⌘K) from anywhere.
  3. Book — "Book visit" on the client or pet page opens /visits/new prefilled with ?client= / ?pet=. Picking a boarding/service product applies its default room and schedule style.
  4. Save — creates the visit as planned (server-enforced state machine) and redirects to the visit detail.
  5. Deposit — the visit links to its order; the deposit can be collected there (deposit_due → deposit_met).
  6. Arrival — the 15-minute cron flips planned → due_in inside the org's early-check-in window. Check-in happens on the Facility Board or the visit detail; it is gated on unsigned required agreements (desk e-sign, or a manager override with visits.checkin_override) and surfaces the deposit state.
  7. The stay — one-tap care logging on the board: feeding, medication doses (paired to standing medication needs), potty, play, walks, photos. Issues can be opened (normal or serious).
  8. Departure — check-out transitions in_house → completed and decrements the live in-house count. Overdue stays get flagged automatically past the late-checkout grace period.
Booking a visit — service selection applies the default room and schedule style; client and pet arrive prefilled
Booking a visit — service selection applies the default room and schedule style; client and pet arrive prefilled

Checkout / point of sale

Order
subtotal + per-location tax (bps) · deposit · paidCents
take payment
Provider branch
paymentMethod.provider / org.paymentProvider
dev
instant simulated settle (local demo)
manual
cash / desk — orders.recordPayment
stripe
SetupIntent vault → off-session PaymentIntent · idempotent per order+paid
payments — append-only ledger
charge / refund rows · status · idempotencyKey · never updated
Refund caps
>30-day-old payment needs orders.refund_override (owner); caps at remaining refundable
Money flow — integer cents end to end, append-only ledger, provider selected per org
  1. /orders → New order — the POS builder: line items by product (grouped service / product / boarding), optional pet, quantity; live subtotal, per-location tax (basis points, default 9.25%), total.
  2. Create → redirects to the order detail.
  3. Take payment — record cash/card/bank/wallet manually, or charge a saved card (dev vault locally; Stripe off-session PaymentIntents in production). Payments cap at the balance.
  4. Refunds — manager-level by default; refunds cap against each payment's remaining refundable balance, and refunding a payment older than 30 days requires the owner-level orders.refund_override grant.
  5. Receipt — printable at /orders/{id}/receipt (print-to-PDF).
  6. Retail products decrement inventoryCount on sale.

Client self-service (portal)

The flagship zero-staff-touch journey, verified end-to-end in the Playwright harness:

  1. Pet parent signs in at the same /login door → lands in /o/{slug}/portal (no staff shell).
  2. Saves a card to their wallet (Stripe Elements in production, dev vault locally).
  3. Books a stay — picks a bookable product, pet, dates; this creates the visit and its order with the deposit.
  4. Pays the deposit with the saved card.
  5. Along the way they can sign agreements, upload vet records to their pets, and message the front desk (two-way threads; staff reply by email/SMS/in-app channel).

Staff can see exactly what a client sees: View portal as client on the client detail starts an audit-logged impersonation (?as={clientId}) with a banner and an exit link back to the client.

The customer portal — pets, upcoming stays, balance, wallet, agreements, and messaging in one self-service surface
The customer portal — pets, upcoming stays, balance, wallet, agreements, and messaging in one self-service surface

Onboarding a new tenant

  1. Prospect lands on /apply (linked from the marketing site and /our-customers) and completes the 3-step wizard: business → contact & scale → review.
  2. The application lands in /platform (platform owners only).
  3. Review → Approve provisions a new inactive org (slug {slug}-new, America/Chicago, manual payment provider) ready for configuration.
  4. Org setup happens in Settings: locations & rooms, role policies, agreements (versioned, require-for-booking), catalog, food brands, reminders, branding.

Staff operations day-to-day

  • Clock in/out from the header clock widget on any org page; the pill shows elapsed time while on the clock.
  • Schedules — managers build the weekly shift grid; staff see "My hours" (/staff/me/hours) from the user menu.
  • Approvals — managers approve time entries; the dashboard HR row surfaces pending approvals, missed punches (open entries >16h), and overtime watch (over / approaching 40h).
  • Notes — managers post to the internal board; urgent notes require acknowledgment with an x/y read-receipt counter.

Automated journeys (no user)

  • Visit status sweep (every 15 min): planned → due_in inside the early window; in_house → overdue past the late grace.
  • Reminder dispatch (every 30 min): active reminder configs (upcoming_visit, vaccine_expiry) fill their template, dedupe against the reminder log, drop an in-app message on the client's thread, and send email via Resend when configured.