mirror of
https://github.com/hanzo-apps/changelog-ship.git
synced 2026-10-30 19:24:26 +00:00
Forked from hanzo-starter (provider stack, vite.config, PKCE auth, deploy contract unchanged). Three views in @hanzo/gui with a monospace terminal aesthetic: changelog feed (reverse-chron timeline, type/tag filter, lime newest-release highlight), post detail (full body + related), and a signed-in compose editor. Auth is @hanzo/iam PKCE against hanzo.id (client id from VITE_IAM_CLIENT_ID). Data is entries/tags/entry_tags on @hanzo/base, org-scoped, provisioned from schema.sql.
3.8 KiB
3.8 KiB
Shipwright (changelog-ship) — agent notes
A real Hanzo app forked from hanzo-starter: a public product changelog
paired with a longer-form blog. Vite + React 19 + @hanzo/gui (UI) +
@hanzo/iam (auth) + @hanzo/base (data). Keep it minimal and REAL — every
surface builds and runs, no fabricated UI.
What it is
- Three views: the changelog feed (reverse-chron timeline, type/tag
filter), the post detail (full body + related), and compose (signed-in
editor). The signed-out landing is a public changelog page with a preview
timeline. Router-less:
src/views/home.tsxholds aNavstate machine. - Design: a monospace-accented terminal aesthetic — a connector line down
the left gutter (
TimelineRow), JetBrains-style version chips, muted graphite with a single lime highlight reserved for the newest release. All visual constants live insrc/theme.ts; shared gui compositions insrc/ui.tsx.
One way, decomplected (unchanged from the starter)
- Providers (
src/providers.tsx) mountGuiProvider→IamProvider→BaseProvider.BaseProvidergets aBaseClientcarrying the IAM access token; it is rebuilt when the token changes (src/lib/base.tsbaseAs). That seam makes everyuseQuery/useMutation/useBaseorg-scoped to the user. - 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): (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/borderRadius/textAlign— NOT theitems/justify/bg/p/rounded/textshorthands. Shorthands pass at runtime but FAILtsc.- Mono without a
$monotoken: the v5 config registers onlybody/heading.fontFamilyaccepts a raw string, sotheme.tssetsMONOto a literal monospace stack — a non-$value renders verbatim. Do NOT writefontFamily="$mono"(typechecks but has no token → wrong render). Buttoncarries nofontFamily(it is a Stack, not a text node). Wrap the label in<Mono>— seePrimaryButton/GhostButtoninui.tsx.ButtonusesonPress;Input/TextAreausevalue/onChangeText(and rejectlineHeight/placeholderTextColoras raw values — style withcolor).- PKCE storage is
localStorageso verifier/state survive the hanzo.id round-trip. schema.sqlis the data contract. It is thedatabaseSchemaDDL the deploy translates into Base collections. Three collections —entries/tags/entry_tags— kept in lockstep withfeed.tsx/detail.tsx/compose.tsx.
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 via@request.auth.org_id = org, IAM-native). - IAM redirect registration is the one external requirement: the IAM client
(
VITE_IAM_CLIENT_ID) must allow this origin's/auth/callback.
Proven
tsc --noEmit clean · vite build → dist/ · the landing renders under Vite
with the terminal aesthetic and zero console errors · login() performs a real
PKCE S256 redirect to hanzo.id.
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).