Vite + React 19 + @hanzo/gui + @hanzo/iam (PKCE) + @hanzo/base. Three views — ticket queue, ticket detail + replies, new ticket — over two org-scoped Base collections (tickets, replies). Split list/detail with severity + status badges and one-tap triage. Forked from hanzo-apps/hanzo-starter; provider stack, vite.config, auth flow, and deploy contract identical.
3.7 KiB
deskline — agent notes
A support ticket queue built on the canonical Hanzo app stack: Vite + React 19 +
@hanzo/gui (UI) + @hanzo/iam (auth) + @hanzo/base (data). Forked from
hanzo-apps/hanzo-starter; the provider stack, vite.config.ts, auth flow, and
deploy contract are identical to it. Keep it minimal and REAL — every surface
must build and run, no fabricated UI.
What it is
Three views over two org-scoped Base collections (tickets, replies):
- Ticket queue (
views/queue.tsx) — status filter chips + a list ordered live-first (open/pending) then by severity then newest. Selecting a row opens it in the detail pane. - Ticket detail + replies (
views/detail.tsx) — the request, segmented triage ofstatusandpriority(tickets.update), the reply thread, and a composer (replies.create). First reply on an Open ticket → Pending. - New ticket (
views/compose.tsx) — subject/body/severity/requester →tickets.create(statusopen), then the shell selects the new row.
views/home.tsx is the signed-in shell: it owns the two useQuerys and the
split queue/detail layout; lib/tickets.ts holds the types + status/severity
metadata + ordering/relative-time helpers; views/badges.tsx is the one
badge/avatar shape every surface reuses.
One way, decomplected
- Providers (
src/providers.tsx) mountGuiProvider→IamProvider→BaseProvider, with the BaseClient carrying the IAM access token (rebuilt when the token changes,src/lib/base.ts). That seam makes everyuseQuery/useMutationorg-scoped to the signed-in user. - Env is one place (
src/env.ts), read fromimport.meta.env.VITE_*. - UI is one system —
@hanzo/guiprimitives only (no second kit, no Tailwind). Status/severity render through onePill.
Gotchas (do not regress)
@hanzo/guiunder Vite needs three things invite.config.ts(it is the Tamagui line): (1) aliasreact-native→react-native-web, (2)defineprocess.env.TAMAGUI_TARGET/NODE_ENV/__DEV__, (3)dedupereact/react-dom/react-native-web. No Tamagui compiler, noone, no Expo.@hanzo/guiprops are Tamagui LONGHAND:alignItems/justifyContent/backgroundColor/padding/paddingHorizontal/borderRadius/textAlign/alignSelf— NOT theitems/justify/bg/p/rounded/text/selfshorthands. Shorthands pass at runtime but FAILtsc.ButtonusesonPressand accepts rich children +hoverStyle/pressStyle;Input/TextAreausevalue/onChangeText.- PKCE storage is
localStorageso the verifier/state survive the round-trip to hanzo.id. schema.sqlis the data contract — thedatabaseSchemaDDL the deploy translates into Base collections (provisionBaseFromDDL, rule@request.auth.org_id = org). Keep it in lockstep withlib/tickets.tsand the views.
Deploy contract (Hanzo Cloud)
- Static SPA:
npm run build→dist/, served at<slug>.hanzo.app. No server. - On publish,
schema.sql→provisionBaseFromDDLcreates the collections (org-scoped, IAM-native). Runtime read/write is browser →VITE_HANZO_BASE_URLwith the IAM token. - IAM redirect registration is the one external requirement: the IAM client
(
VITE_HANZO_CLIENT_ID, defaulthanzo-app) must allow this origin's/auth/callback(https://*.hanzo.app/auth/callbackwildcard, or a per-apphanzo-<app>client).
Proven
tsc --noEmit clean · vite build → dist/ · renders under Vite with zero
console errors. CI (.github/workflows/ci.yml) runs npm ci && npm run typecheck && npm run build — build-verification only, NEVER a container image
(Hanzo Cloud owns deploys; do not build images locally).