Vinyl-centric smart link page: a big cover with a stack of streaming buttons, plus an artist admin to edit the release + links and see per-link click counts. @hanzo/gui UI, PKCE auth via @hanzo/iam against hanzo.id, org-scoped release/links collections via @hanzo/base. tsc + vite build green; public landing verified rendering headless.
4.3 KiB
release-smartlink (Dropmark) — agent notes
Dropmark is a single-release smart link: one page with a big cover and a button
to every streaming service, and an artist admin to edit the release + links and
see click counts. A real Hanzo app forked from hanzo-starter —
Vite + React 19 + @hanzo/gui (UI) + @hanzo/iam (auth) + @hanzo/base (data).
Keep it REAL — every surface builds and runs, no fabricated UI or metrics.
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 artist. - Env is one place (
src/env.ts), read fromimport.meta.env.VITE_*. The IAM client id isimport.meta.env.VITE_IAM_CLIENT_ID(fallbackhanzo-app). - UI is one system —
@hanzo/guiprimitives only (no second kit, no Tailwind).src/lib/catalog.tsis the pure domain (row shapes + streaming brand chips + cover palettes);src/views/holds the surfaces.
Views
views/smartlink.tsx— the fan-facing page (presentational): color-bled backdrop, centered square cover (realcover_urlor a generated vinyl), and a stack of streaming buttons. Shared by the public landing and the live preview.views/signed-out.tsx— public landing: the smart link for a demo release (honest showcase) + an "Artist sign in" PKCE affordance.views/home.tsx— signed-in shell: live preview beside the editor.views/admin.tsx— the editor: edit therelease, add/edit/deletelinks, see per-link click counts.views/chip.tsx— the brand mark shared by buttons and the editor.
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/borderRadius/textAlign/alignSelf— NOT theitems/justify/bg/p/rounded/text/selfshorthands. Shorthands pass at runtime but FAILtsc.ButtonusesonPress;Inputusesvalue/onChangeText.- Absolute fills need a positioned parent. A
fullscreen/absoluteLinearGradientor ring only fills its box if that box isposition="relative"(seeCoverand the SmartLink root) — otherwise it escapes to the viewport. LinearGradientimports from@hanzo/gui/linear-gradient(subpath), not the package root.- 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 withviews/admin.tsx+views/smartlink.tsx(release,links).
Deploy contract (Hanzo Cloud)
- Static SPA:
npm run build→dist/, served at<slug>.hanzo.appfrom object storage (the*.hanzo.apppublished-sites edge). No server process. - On publish,
schema.sql→provisionBaseFromDDLcreates the collections (org-scoped, IAM-native: rule@request.auth.org_id = org). 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 provisions a per-apprelease-smartlinkclient (or ahttps://*.hanzo.app/auth/callbackwildcard on the shared client).
Proven
tsc --noEmit clean · vite build → dist/ · the public landing renders under
headless Chromium with zero console errors and no horizontal overflow (cover +
title + streaming buttons), and login() starts 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; do not build images locally).