zooqueenandHanzo Dev 8d32227a03 0.2.19 — the device page names the right client, and the checkbox ships
0.2.18 was cut, built and published BEFORE the two fixes it is named after
landed. The build workflow refuses to rebuild an existing version — correctly,
since re-pushing a tag yields two digests for one name — so f03c778 (drop the
confirmation checkbox) and everything after it never produced an image. The tag
in universe stayed 0.2.18 and the cluster kept serving the bytes it already had,
which is why the platform owner has asked four times for a checkbox that has
been gone from source the whole time.

A version is the only thing that publishes. Patch-bump, never a re-push.

Ships: the self-attestation checkbox removal (f03c778), and the approval page
naming the client that actually minted the code (5c6bf45).

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-01 20:43:40 -07:00
2026-02-14 05:26:48 -08:00
2026-06-28 20:06:13 -07:00

id

@hanzo/id

White-label login + identity verification portal. One Vite SPA, four hosts (hanzo.id, lux.id, zoo.id, pars.id), per-tenant brand resolved from the request hostname at runtime.

Layout

apps/
  web/                Vite + React 19 + @hanzo/gui — the actual SPA
    k8s/              Deployment + Service + Ingress (4 hosts, 4 TLS secrets)
pkgs/
  shared/             @hanzo/id-shared  — TenantConfig + brand resolver
  auth/               @hanzo/id-auth    — composable login/signup/OTP flows
                                          on top of @hanzo/iam SDK
  idv/                @hanzo/id-idv     — pluggable identity verification
                                          (Persona, Onfido, Veriff, stub)
legacy-nextjs/        Frozen — predecessor Next.js implementation. Kept
                     for reference until v0.1.0 ships to production.

Local dev

pnpm install
pnpm dev                 # http://localhost:5173 (defaults to hanzo brand)

To preview a different brand locally, edit /etc/hosts:

127.0.0.1  lux.id zoo.id pars.id

then visit http://lux.id:5173.

Build

pnpm build               # builds apps/web -> dist/
docker build -t ghcr.io/hanzoai/id:0.1.0 .

Adding a brand

  1. Publish or workspace-link the new per-org brand pkg (must ship brand.json at the package root and match the BrandContract shape in pkgs/shared/src/types.ts).
  2. Add a DEFAULT_TENANTS entry in pkgs/shared/src/tenant.ts OR put the override in the runtime catalog (IAM_TENANT_CONFIG_JSON env) so no rebuild is needed.
  3. Add the hostname to apps/web/vite.config.ts::BRAND_PACKAGES (lets dev + build serve /brand/<pkg>/brand.json).
  4. Add the hostname + TLS secret to apps/web/k8s/ingress.yaml.
  5. DNS: CNAME or A record → cluster ingress IP.

That's it — no per-brand Worker, no per-brand image, no per-brand deployment. One binary, four brands.

Plugging an IDV provider

import { registerProvider, createPersonaProvider } from '@hanzo/id-idv'
registerProvider(createPersonaProvider({
  templateId: import.meta.env.VITE_PERSONA_TEMPLATE_ID,
  apiKey: import.meta.env.VITE_PERSONA_API_KEY,
  environment: 'production',
}))

The portal stays unchanged — switching providers is a single registration call at boot.

S
Description
No description provided
Readme MIT
3.7 MiB
Languages
TypeScript 92.1%
CSS 4.5%
JavaScript 2.6%
Dockerfile 0.6%
HTML 0.2%