uv sync resolves ALL extras including hanzo (which depends on
hanzo-kms, not published to PyPI) even with --no-extra flag.
Switch to uv pip install -e ".[dev]" which only resolves the
specified extras.
CI was failing because `uv sync` installs all extras including hanzo-kms
which isn't on PyPI. Switch to `uv sync --extra dev` for test jobs.
Add bootnode API deployment manifest for the hanzo namespace (separate
from the bootnode namespace deployment).
- Remove hardcoded Secret from bootnode-deployment.yaml (conflicted with ExternalSecret)
- Fix Postgres/Redis pods to read passwords from KMS-managed bootnode-secrets
- Expand ExternalSecret from 7 to 30 secrets with UPPERCASE_UNDERSCORE keys matching Pydantic
- Enable hanzo-kms SDK as optional dependency for direct KMS access outside K8s
- Improve inject_secrets() startup logging to indicate active secrets path
- Rewrite secrets.yaml as documentation-only with flow diagram and setup guide
- Fix compose.yml Bitcoin healthcheck to use env vars instead of hardcoded password
- Create /dashboard/organization/billing page with plan comparison
- Wire up disabled "Manage Subscription" button to new billing page
- Fix analytics nav billing link to point to organization/billing
- Shows current plan, usage stats, and upgrade via Commerce checkout
- All 4 tiers displayed: Free, PAYG, Growth, Enterprise
All dashboard pages now use NEXT_PUBLIC_API_URL with localhost fallback
for local dev. Fixes tokens, volumes, storage, clusters, monitoring,
infrastructure, and usage pages for production deployment.
- Replace eval() with json.loads() in usage tracker (security fix)
- Webhook verification fails-closed in production when secret missing
- Add Commerce env vars to K8s deployment (URL, API key, webhook secret)
- Expose ZAP port 9999 in Dockerfile and K8s service
- Replace Stripe env vars with Square in compose.yml
- Update privacy/terms pages: Stripe→Square via Hanzo Commerce
- Add full billing API client module to web/lib/api.ts (17 endpoints)
- Fix hardcoded localhost URLs in dashboard/analytics/organization pages
- Add production webhook rejection test (57 tests passing)
P0: config.py defined hanzo_commerce_* but billing code accessed
settings.commerce_* — causes AttributeError at runtime. Renamed fields
with AliasChoices for backward compat with HANZO_COMMERCE_* env vars.
P1: deps.py silently swallowed JWT errors (bare pass) — now logs them.
Virtual API key used fake UUID for missing projects — now raises 404.
Updated secrets.yaml to replace stale Stripe references with Commerce.
- Fix Lux brand IAM URL: lux.id → iam.lux.network (matches actual deployment)
- Use getBrand().iam.url for IAM URL in HanzoLoginButton (brand-aware auth)
- Fix missing newline at EOF in unified-navigation.tsx
- Update LLM.md with Commerce billing and IAM documentation
Update K8s manifests (Ingress hosts, CRD API groups, CORS origins),
ZAP schemas, pyproject.toml URLs, SDK docs import paths, e2e test
emails, and K8s annotations to use the canonical bootno.de domain.
- OAuth callback accepts redirect_uri from frontend to derive correct
IAM client_id per network (all use lux-web3 shared app)
- Token verification accepts tokens from any known IAM app audience
- Frontend sends redirect_uri in callback POST body
- Login page uses proper /login/oauth/authorize URL with client_id
- Brand configs unified to use lux-web3 IAM app for all networks
- Removed dead code (duplicate get_current_user, unreachable methods)
- IAM init data updated with cloud redirect URIs for pars/zoo/hanzo
The networks module imported get_current_user from bootnode.api.deps
where it doesn't exist — it's in bootnode.core.iam. This broke the
entire API startup (uvicorn can't import bootnode.main:app).
New /v1/networks endpoint orchestrates deploying a complete
white-label blockchain cloud portal:
- K8s deployment + service for bootnode-web with brand env vars
- Ingress with TLS + CORS for cloud.{domain} and api.cloud.{domain}
- IAM integration for SSO
- Scale and teardown endpoints
CI deploy step now restarts all cloud-web deployments (lux, pars,
zoo, hanzo) when new images are pushed.
The CORSMiddleware was initialized with only bootnode.dev origin.
Added all cloud.*.network domains and ALLOWED_ORIGINS env var
for extending origins without code changes.
- Add pars brand config to brand.ts (persian blue + gold, cloud.pars.network)
- Add pars domain detection in getBrandKey()
- Add pars to server-side brand map in layout.tsx
- Replace lux-icon.svg wordmark with upside-down triangle (from @luxfi/logo)
- Add pars logo assets (8-pointed star icon, logo, white variant)
- Dashboard and navigation use dark-mode-aware CSS vars (bg-background,
bg-sidebar, border-border) instead of hardcoded bg-gray-50/bg-white
- isProductionMode() now recognizes 127.0.0.1 and private IPs as local
so login no longer redirects to lux.id on localhost
- Add /dashboard/infrastructure/monitoring page with node health
summary cards, CPU/memory/disk usage bars, 15s auto-refresh
- Quick login button uses [email protected] / admin credentials
- Add apiUrl/wsUrl to brand config for runtime resolution
- Auth and OAuth callback now use brand's apiUrl instead of baked env var
- Pin node:22-alpine to specific digest for supply chain security
Updated all container image references across compose, K8s manifests,
cloud deploy scripts, and tests to use the ghcr.io/hanzoai/bootnode
registry format.
The layout.tsx was missing bootnode case in brand switch,
causing it to fall through to Hanzo. Added bootnode and
changed default from Hanzo to Bootnode.
Build distinct images with NEXT_PUBLIC_BRAND baked in at build time:
- web-latest (bootnode brand for bootno.de)
- web-hanzo-latest (hanzo brand for web3.hanzo.ai)
Next.js NEXT_PUBLIC_* vars are embedded at build, not runtime.
- Split web deployment into hanzo-web3 and bootnode-web
- hanzo-web3: web3.hanzo.ai, auth via hanzo.id
- bootnode-web: bootno.de, auth via iam.bootno.de
- Updated CI to deploy both frontends
- Changed image registry to ghcr.io/bootnode/bootnode
- Updated ingress for both domains with separate TLS certs
CI pushes to ghcr.io/hanzoai/bootnode, but manifests were
referencing hanzoai/bootnode which defaults to docker.io.
This caused deployments to use stale images from docker.io.
- Add CDN-Cache-Control header (60s) for HTML pages
- Keep long cache (1 year) for immutable static assets
- Prevents Cloudflare from serving stale branded content
The hanzo-kms and hanzo-iam packages are not published to PyPI,
causing uv lock to fail. In production K8s, secrets are injected
as env vars directly by the KMS operator.
- Link Hanzo IAM users to Commerce customers via hanzo_id
- Auto-create Commerce customer on first billing access
- New unified billing endpoints:
- GET /billing/account - unified user with IAM + Commerce data
- GET /billing/account/subscriptions - all subscriptions
- GET /billing/account/invoices - all invoices
- GET /billing/account/payment-methods - payment methods
- POST /billing/account/sync - sync IAM to Commerce
- POST /billing/account/subscribe - create subscription
- Support for hanzo.id, zoo.id, lux.id, pars.id orgs
- Update layout.tsx with brand-aware metadata (title, OG, icons)
- Change default brand from bootnode to hanzo in brand.ts
- Update homepage, product pages with brand-aware text
- Replace api.bootnode.dev URLs with api.hanzo.ai
- Update llms.txt route to use brand system
- Update security, privacy pages with Hanzo branding
- Update code-demo, unified-navigation with brand logos
- Update footer status link to status.hanzo.ai