Field Service Customer Portal
Three customer-facing surfaces — work order status, estimate accept/reject, and service report signature. Token-gated, no customer login required.
Field Service exposes three customer-facing pages under /portal/fsm/.... Each is gated by a share token — a short URL fragment that contains both the entity reference and the access permission. No customer login required; the token IS the credential.
| Surface | URL | Permission | Generated by |
|---|---|---|---|
| Work order view | /portal/fsm/[token] | view | Manually from work-order detail |
| Estimate accept/reject | /portal/fsm/estimate/[token] | view, respond | When you send an estimate (token prefix est_) |
| Service report signature | /portal/fsm/service-report/[token] | view, sign | When the appointment completes (token prefix srp_) |
Treat tokens like passwords. Anyone with the URL can act on the entity. Rotate / revoke tokens when no longer needed; tokens can carry an expires_at for time-bounded access.
Work-order view
The simplest portal — read-only customer view of a single work order.
What the customer sees:
- Work order number + title
- Status badge (with friendly labels)
- Customer-facing description
- Location
- Completion timestamp (when applicable)
How to share: open the work order in /fsm/work-orders/[id], mint a share token, send the URL.
Estimate portal
The customer-facing approval surface for an estimate.
What the customer sees:
- Estimate number + valid-until date
- Notes (the proposal body, your choice of formatting)
- Line items with quantities + prices
- Optional lines clearly marked (optional)
- Subtotal / tax / total
- Accept and Decline buttons (when status is still
draftorsent)
When the customer clicks Accept:
- Estimate status flips to
approved, stampsapproved_at - The portal shows: "Thank you — this estimate is accepted."
- The dispatcher can now convert it to a work order
When the customer clicks Decline:
- Estimate status flips to
rejected, stampsrejected_at - The portal shows: "This estimate has been declined."
Once the estimate is in a terminal state (approved, rejected, expired, converted), the buttons disappear — re-opening the link shows the read-only outcome.
Generating the link: when you click Send to customer on an estimate, mint a token via the v1 API or AI tool (send_estimate + a follow-up token-mint step). Phase 4.8 will add a one-click Send via email that handles token + composed message together.
Service-report signature portal
The customer-facing signature pad — see Service Reports for the lifecycle.
What the customer sees:
- Work performed (the technician's narrative)
- Attached photos / files (list)
- A signature canvas (480×160, scales responsively)
- A typed-name field
- Submit signature button
Signature capture:
- Pointer events (mouse + touch + stylus)
- Path data exported as SVG (compact — capped at 10 KB)
- Server stamps
signed_at+signed_ipfor audit
After submission the canvas is replaced with a green confirmation. The signed PDF is generated in the background and stored in Supabase storage — the customer doesn't see a "Download" link in this version; the dispatcher can pull the PDF from the work-order detail and email it.
Token lifecycle
| Action | Effect |
|---|---|
| Generate | New random token (<prefix>_<40 hex>), permission list, optional expires_at |
| Validate | On every portal page load — checks not revoked + not expired |
| Use | Updates last_accessed_at + increments access_count |
| Revoke | Stamps revoked_at; the URL stops working immediately |
Tokens are workspace-scoped (RLS on the token tables). A token for one workspace can't accidentally point at another workspace's data.
What customers can NOT do via the portal
The portal is intentionally minimal. Customers cannot:
- Edit the work order, estimate, or report contents (only accept/reject/sign)
- See other work orders or estimates beyond the one in their URL
- Upload attachments
- Message the technician through Workestra (use email or your channel of choice)
- Trigger rebookings or new requests (the link is one-shot per entity)
Self-service rebooking + customer-initiated requests are queued for the next release.
Branding (limited today)
The portal pages use Workestra's default styling. Per-workspace branding (logo, colors, custom domain) is queued — today the customer sees neutral white/black portal pages with your workspace name at the top of the service-report PDF.
Related
- Estimates — the dispatcher-side flow
- Service Reports — the dispatcher-side flow
- Work Orders — the parent entity for the read-only view