mirror of
https://github.com/hanzo-apps/product-trailmap.git
synced 2026-10-30 19:07:34 +00:00
4.3 KiB
4.3 KiB
product-trailmap — agent notes
Trailmap — a public product roadmap (Now / Next / Later) built on the canonical
Hanzo stack. Forked from hanzo-apps/hanzo-starter; the provider stack,
vite.config.ts, auth, and deploy contract are unchanged from the starter — only
the app (its three views + schema.sql) is Trailmap-specific.
Vite + React 19 + @hanzo/gui (UI) + @hanzo/iam (auth) + @hanzo/base (data).
Keep it minimal and REAL — every surface must build and run, no fabricated UI.
The app
- Model is one place (
src/lib/model.ts): the horizon lanes (now/next/later), the status ladder (planned/building/shipped), and the theme palette +themeColor(). The board, detail, and editor all import it. - Three views (
src/views/):roadmap.tsxis the signed-in shell + the Now/Next/Later board;initiative.tsxis the detail;editor.tsxcreates and moves initiatives.card.tsxis the one initiative card, shared by the board and the landing preview.signed-out.tsxis the public landing. - One write path. Every mutation goes through the editor's
initiativescreate/update/delete. The board and detail are read + navigation only. - Two collections (
schema.sql):initiatives(title, summary, horizon, status, theme) andthemes(name, color).DEFAULT_THEMESkeeps the board legible before any theme row is saved.
One way, decomplected
- Providers (
src/providers.tsx) mount in the canonical order every Hanzo surface ships:GuiProvider→IamProvider→BaseProvider.BaseProvidergets aBaseClientcarrying the IAM access token; it is rebuilt when the token changes (src/lib/base.tsbaseAs). That single seam is what makes everyuseQuery/useMutationorg-scoped to the signed-in user. Trailmap fixes the light theme for its pastel look. - Env is one place (
src/env.ts), read fromimport.meta.env.VITE_*. The IAM client id isVITE_IAM_CLIENT_ID(fallbackhanzo-app). - UI is one system —
@hanzo/guiprimitives only (no second kit, no Tailwind).
Gotchas (do not regress)
@hanzo/guiunder Vite needs three things invite.config.ts(it is the Tamagui line; the in-browser builder runtime can't do this, which is the whole reason this ships as a real repo): (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 with this v5 config:alignItems/justifyContent/backgroundColor/padding/paddingHorizontal/alignSelf/borderRadius/textAlign— NOT theitems/justify/bg/p/self/rounded/textshorthands. Shorthands pass at runtime but FAILtsc.Buttonis a Stack, not Text. It does NOT accept text-style props (color/fontWeight/letterSpacing/fontSize). Put the label in a<Text>child and style that; keep only frame props (backgroundColor/borderRadius/size/chromeless/hoverStyle/onPress) on theButton.ButtonusesonPress;Input/TextAreausevalue/onChangeText.- PKCE storage is
localStorage(not sessionStorage) so the verifier/state survive the round-trip to hanzo.id. schema.sqlis the data contract. It is thedatabaseSchemaDDL the deploy translates into Base collections (provisionBaseFromDDL). Keep it in lockstep withsrc/lib/model.ts.
Deploy contract (Hanzo Cloud)
- Static SPA:
npm run build→dist/, served at<slug>.hanzo.appfrom object storage. No server process. - 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_IAM_CLIENT_ID, defaulthanzo-app) must allow this origin's/auth/callback. Production needs ahttps://*.hanzo.app/auth/callbackwildcard on the shared client (or a per-apphanzo-trailmapclient).
Build
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).