mirror of
https://github.com/hanzoai/id.git
synced 2026-11-03 00:42:22 +00:00
Replaces the Cloudflare Worker (hanzo.id-worker) and the Next.js portal
with a pnpm monorepo following the a-monorepo/id pattern.
Layout:
apps/web/ Vite + React 19 SPA, embeds @hanzo/gui shell
k8s/ Deployment(2) + Service + Ingress (4 hosts, 4 TLS)
pkgs/shared/ @hanzo/id-shared — TenantConfig, resolveTenant,
loadBrand (browser + node)
pkgs/auth/ @hanzo/id-auth — AuthClient (wraps @hanzo/iam REST)
+ LoginForm/SignupForm/ForgotForm/OTPForm
pkgs/idv/ @hanzo/id-idv — pluggable IDV (stub, persona,
onfido, veriff) behind one
IDVProvider interface
legacy-nextjs/ Frozen — Next.js predecessor. Delete after v0.1.0 ships.
Dockerfile Two-stage: pnpm build → hanzoai/static:0.4.1 serves /spa
README.md
LLM.md Architecture, dev, deploy, cutover plan
Tenant resolution: hostname → TenantConfig (orgId, iamUrl, clientId,
appName, publicOrigin, brandPackage). Built-in defaults for
hanzo.id/lux.id/zoo.id/pars.id; runtime override via
IAM_TENANT_CONFIG_JSON env (served as /config.json at pod startup).
Brand resolution: each per-org brand pkg (@hanzo/brand, @luxfi/brand,
@zooai/brand, @parsdao/brand) ships brand.json. The Vite plugin
brandJsonPlugin emits /brand/<pkg>/brand.json verbatim; the browser
fetches the right one based on the resolved tenant. No bundle bloat.
IDV: stub (default for dev), persona, onfido, veriff. Each adapter
implements `IDVProvider` from pkgs/idv/src/provider.ts. Swap providers
with one registration call at boot — portal code unchanged.
Cutover (separate ops PR — not in this commit):
1. Tag + push image ghcr.io/hanzoai/id:0.1.0
2. Apply k8s manifests, cert-manager issues TLS
3. Remove CF Worker routes for hanzo.id/lux.id/zoo.id/pars.id
4. CF A records → 129.212.164.5 (hanzo ingress LB)
5. Archive hanzo.id-worker repo
69 lines
1.4 KiB
CSS
69 lines
1.4 KiB
CSS
@tailwind base;
|
|
@tailwind components;
|
|
@tailwind utilities;
|
|
|
|
:root {
|
|
/* Default Hanzo colors - overridden by branding config */
|
|
--color-primary: #e4e4e7;
|
|
--color-primary-text: #09090b;
|
|
--color-background: #000000;
|
|
--color-surface: #0a0a0a;
|
|
--color-text: #ffffff;
|
|
--color-text-muted: #a1a1aa;
|
|
--color-border: #27272a;
|
|
--color-error: #dc2626;
|
|
}
|
|
|
|
body {
|
|
background-color: var(--color-background);
|
|
color: var(--color-text);
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
}
|
|
|
|
/* Login card styling */
|
|
.login-card {
|
|
background-color: var(--color-surface);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: 12px;
|
|
}
|
|
|
|
/* Button styling */
|
|
.btn-primary {
|
|
background-color: var(--color-primary);
|
|
color: var(--color-primary-text);
|
|
transition: opacity 0.2s;
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
opacity: 0.9;
|
|
}
|
|
|
|
/* Input styling */
|
|
.input {
|
|
background-color: var(--color-background);
|
|
border: 1px solid var(--color-border);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
.input:focus {
|
|
border-color: var(--color-primary);
|
|
outline: none;
|
|
box-shadow: 0 0 0 2px rgba(228, 228, 231, 0.2);
|
|
}
|
|
|
|
/* Link styling */
|
|
.link {
|
|
color: var(--color-primary);
|
|
}
|
|
|
|
.link:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
/* Quote card styling */
|
|
.quote-card {
|
|
background: linear-gradient(135deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%);
|
|
border-radius: 12px;
|
|
padding: 24px;
|
|
}
|