10 Commits
Author SHA1 Message Date
zeekayandHanzo Dev c1996cacc8 api: read Hanzo KV from KV_URL; a KV outage no longer fails requests
Hanzo CI/CD / cicd (push) Successful in 8m30s
CI/CD / cicd (push) Successful in 8m30s
The cache client is now the KV client (core/cache/kv.py, kv_client),
configured by KV_URL. rate_limit_check allows the request and logs when KV
is unreachable, and the RPC cache treats an outage as a miss. cloud_billing
reads KV directly instead of a missing usage_tracker.redis attribute; the
NFT refresh enqueues through an arq pool.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-23 00:29:49 -07:00
zeekayandHanzo Dev 1f30a4c21c fix(lux): the fleet is observed through lux-k8s, on /v1
luxd serves /v1 only — server/http/server.go pins baseURL="/v1" — so every
/ext call in this repo was a silent no-op. The fleet collector's _rpc()
returns None on non-200, so the lux.cloud dashboard rendered nodes_rpc_ok:0,
version:null and every node rpc_reachable:false while the fleet was in fact
running luxd/1.36.2 (mainnet), 1.36.24 (testnet), 1.36.25 (devnet).

Fixing the path alone would not have helped: the collector addressed each
validator by a hardcoded public LoadBalancer IP, and there are now zero
LoadBalancer Services in lux-mainnet/testnet/devnet. Those IPs time out. So
node addressing is no longer configured — it is derived from the cluster on
every collection, and the one way to reach a validator is the lux-k8s API
server's pod proxy, since luxd RPC is cluster-internal.

That collapses the old MODE A / MODE B split into a single path: read the CR
for the declared shape, the pods for phase/readiness/IP, then each pod's
JSON-RPC through the proxy. One credential authenticates both. Deleting the
endpoint ConfigMap and its 15 baked-in IPs removes the failure mode where
infrastructure moves and a dashboard quietly reports zeros.

Probes move to /v1/health/liveness, not /v1/health: a degraded-but-running
validator answers /v1/health with 503, so probing it would restart nodes that
are merely behind. Any fleet from charts/lux could never have gone Ready.

LuxNode.external_ip becomes .ip — with no public per-pod endpoint, the honest
value is the pod IP.

Avalanche endpoints keep /ext; that is their API, not ours.

Measured, with controls: pod-proxy POST /v1/info -> 200 on all 15 pods;
/ext/health -> 404; /zzz/health -> 404; nonexistent pod -> 404. A test asserts
every probe path is under /v1 and fails if /ext returns.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-27 19:18:04 -07:00
zeekayandHanzo Dev 7d293212cb refactor: web/ is now console/ — bootnode/bootnode is the backend, bootnode/console the frontend
Names the two halves for what they are. The repo already holds both (12407e9 merged
bootnode/bootnode into this history); this makes the frontend directory say so, so the layout
reads the way the owner describes the system: backend and frontend separate, one repo.

git mv throughout — 187 renames, history preserved. Every path reference follows: hanzo.yml
build context and dockerfile, compose.yml, compose.prod.yml, start.sh, LLM.md,
infra/k8s/web-deployments.yaml, infra/cloud/deploy.sh, and the Dockerfile's own COPY paths.
Image and container names (bootnode-web, the -web tag suffix) are deliberately NOT renamed here:
those are a deploy contract the App CR and ingress bind to on port 3001, and breaking them is a
separate, staged change.

Console builds green after the move; the Go tree builds.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-26 17:47:51 -07:00
zeekay 8f353bf348 one console shell, one image, brand from the Host header
The shell and design system half of the console merge. lux.cloud's look and
feel comes across as tokens and shell geometry, so all 67 existing routes
inherit it without one page being edited, and the per-deployment brand is
replaced by a hostname resolve.

DESIGN SYSTEM — lux.cloud's palette becomes the token layer
  app/globals.css now states lux.cloud's scheme in the variables Tailwind
  already reads: #000 ground, #f5f5f5 ink, 55% muted, 8% hairline / 18% strong
  border, #1a1a1a active fill, its status greens/ambers/reds, 10px/16px radii,
  clamp() display type, -0.01em tracking. Light is a faithful inversion, kept
  because the app ships a theme toggle. Because these are the same variables
  `bg-background` / `border-border` / `text-muted-foreground` always resolved
  to, every page changed appearance without changing.

  The shared primitives then say it in their own geometry: Card is lux's
  `.panel` (16px, hairline, no shadow — a shadow is invisible on black and
  grime on white), Table is `.vtable` (12px uppercase heads, border on the TOP
  of each row so the header needs no rule and the table ends flush), Badge is
  `.pill` with the status dot, Button and Input are `.btn` and `.stake-input`.

SHELL
  One header for marketing and console, as on lux.cloud — 57px, blurred, one
  hairline, brand lockup with the retracting wordmark, actions hard right,
  collapsing behind a single hamburger below `lg` into an OPAQUE sheet (a
  nested backdrop-filter re-roots the backdrop, the bug lux.cloud documents).
  ConsoleLayout adds the one thing the console needs: a 236px sticky rail that
  becomes a horizontally-scrolling strip on a phone — 7% of a 390x844 screen
  measured, against the 27% a wrapped grid of pills costs.

  Deleted: unified-navigation.tsx, a second console-only top bar with its own
  logo, an org switcher whose options changed nothing, and a bell wired to no
  notification source. The hard-coded `pl-64 pt-16` offsets are now the
  --header-h / --sidebar-w tokens, so the header and rail cannot disagree.

  Loading, empty and error are three components in one file instead of nine
  hand-rolled spinners at four sizes, and the callback page's `bg-green-100` /
  `text-red-600` — the only two colours in the app that ignored the tokens and
  so stayed light-mode on a black page — are gone.

WHITE-LABEL BY HOSTNAME — one image, five hosts
  lib/brand.ts resolves brand, theme, API origin, IAM issuer and OIDC client
  from window.location.hostname. Every triple was verified against the live
  /v1/iam/oauth/authorize (302 = registered, 400 = not):

    id.bootno.de  bootnode-platform  bootno.de/auth/callback           302
    hanzo.id      hanzo-web3         web3.hanzo.ai/auth/callback       302
    lux.id        lux-cloud          lux.cloud/auth/callback           302
    zoolabs.id    zoo-cloud          zoo.cloud/auth/callback           302
    zoolabs.id    zoo-cloud          cloud.zoo.network/auth/callback   302
    zoolabs.id    zoo-web3           cloud.zoo.network/auth/callback   400  ← was shipping

  Deleted, because all three were the same defect — a value picked at deploy
  time while ONE deployment serves five hosts:
    • public/config.json + config.example.json (the shipped catalog had the
      400 client above, and named apiUrls whose hosts do not resolve)
    • the Dockerfile's NEXT_PUBLIC_BRAND / _API_URL / _WS_URL, which were also
      inert — the runtime is the Go static binary, which never reads env
    • four near-identical Deployments differing only in those variables, now
      one, with the nine ingress rules pointing at the single service
    • NEXT_PUBLIC_AUTH_MODE and four NEXT_PUBLIC_* docs URLs

  Matching is exact-or-dot-suffix, never substring: `includes("lux.cloud")`
  hands lux.cloud's OIDC client to lux.cloud.attacker.example.

  Each brand also gets its own mark. public/logo/{brand}-icon.svg existed for
  all five and nothing used them — every brand pointed at one shared
  /logo.svg. bootnode's is fill="currentColor" and lux's is fill="white",
  which as an <img> (an isolated document) render invisible on black and on
  white respectively, so those two are painted in the current text colour via
  a CSS mask — which is what lux.cloud does with its own pyramid.

FIXED ALONG THE WAY
  • AuthProvider's local getApiUrl() shadowed the import at the top of the
    file and its last line called itself — infinite recursion on localhost,
    127.0.0.1, 192.168.* and 10.*. Every checkAuth/login/register in local
    development overflowed the stack. Deleted; lib/api's resolver is the one.
  • The console nav could not reach eight of its own pages —
    /dashboard/settings, assets/{tokens,nfts}, infrastructure/{lux,services,
    observability}, /chains, /agents rendered and were linked from nowhere.
  • No row was ever marked current: the image serves clean URLs as directory
    indexes, so the pathname is `/dashboard/` and an equality test never
    matched. Nested routes also lit two rows at once. Both are one selection
    rule now — longest matching href wins.
  • Two dead links in the chrome: /products (a directory of pages with no
    index — the static server answers it with the home page) and
    /docs/tutorials (a plain 404).

TESTS — 26, node:test with native TS stripping, no new dependency
  The five-host contract including the substring-matching attack; the nav
  reaching every built route; the trailing-slash and most-specific-row rules;
  and a whole-source dead-link check that derives routes by walking app/ so it
  cannot go stale. That check holds the shell at ZERO dead links and ratchets
  the 36 that predate this work in the docs and product pages — a test that
  fails on the day it is written gets deleted, one that stops the bleeding
  gets kept.

VERIFIED
  pnpm build exit 0, 77/77 pages, route set byte-identical to the baseline
  taken before any change. In a real browser against the built static export:
  body #000 / #f5f5f5, --border rgba(255,255,255,.08), header 57px sticky
  blur(24px), sidebar 236px sticky at top:57px, exactly one active row with
  #1a1a1a fill and aria-current, the phone strip 7% of the viewport scrolling
  inside itself with the body never scrolling sideways, the sheet opaque with
  no nested backdrop-filter, and the favicon, mark and "Sign in with Bootnode
  ID" all coming from the resolved brand.

Not deployed. No page bodies touched.
2026-07-26 15:32:42 -07:00
zeekayandHanzo Dev 4f0c68df12 fix: get the API booting (stale refactor imports + qdrant healthcheck)
The api crashed on import after a half-finished model refactor, and the qdrant
healthcheck used a binary not in the image.

- compose.yml: qdrant ships no wget/curl, so its healthcheck always failed and
  blocked the api (depends_on service_healthy). Dropped the broken healthcheck and
  gate the api on qdrant service_started (qdrant itself serves fine on :6333).
- db/__init__.py: reconcile to the real models — drop removed Node + Cluster
  (now CRDs) and MPCWalletModel; export the actual set (User, OrgCluster,
  SmartWallet, Subscription, TeamMember, etc.).
- api/mpc + api/keys: MPCWalletModel -> SmartWallet (the renamed model).

API now boots healthy: GET /health 200 {"status":"healthy","version":"2.0.0"},
/docs serving, 42 node/chain/fleet endpoints live (fleets deploy/scale, presets,
pod health/logs). Full local stack up: postgres, redis, clickhouse, qdrant,
meilisearch, api.

Note (follow-up, not blocking boot): api/nodes/db_nodes.py + db/seed_nodes.py
still import removed Node/Cluster models — dead code to remove or port to the
fleet/CRD path; the web frontend build fails on a stale pnpm lockfile.

Co-authored-by: Hanzo Dev <[email protected]>
2026-06-18 22:33:54 +00:00
zeekay 0aa9c4e346 feat: add Explorer + MPC product pages, fleet management, operator, Helm charts, and CI/CD
- Add Explorer product page with branded block explorer deployment, contract
  verification, Etherscan-compatible API, and multi-chain support
- Add MPC product page with deep Lux MPC integration: CGGMP21 (ECDSA),
  FROST (EdDSA), LSS resharing, 15+ chain support, threshold signing API
- Update landing page with 6-product grid (Node, Data, Wallets, Explorer,
  MPC, Rollups) and 8 API cards including Explorer API and MPC Signing
- Update navbar and command menu with Explorer and MPC products
- Add Lux fleet management dashboard, observability, and services pages
- Add AI chat component and unified navigation with org switcher
- Add Kubernetes operator (Rust) for multi-chain node lifecycle management
- Add Lux Helm charts with genesis configs for devnet/testnet/mainnet
- Add docker-release.yml CI/CD pipeline for automated DOKS deployment
- Add monitoring, network policies, web deployments, and ingress updates
- Refactor API: fleet management, billing tracker, observability endpoints
- Update brand config, API client, and infrastructure manifests
2026-03-12 14:48:40 -07:00
zeekay 97c8a5842d feat: add Graph Node + IPFS + subgraph infrastructure
- Add graph-node, graph-ipfs, graph-postgres to compose.yml (subgraph profile)
- Add k8s manifests for Graph Node stack (lux/graph-node.yaml)
- Add deploy-subgraph.sh for AMM V3/V2 subgraph deployment
- Update deploy.sh with 'graph' target for Graph Node infrastructure
- Matches existing lux-k8s lux-explorer namespace setup
2026-03-07 00:03:44 -08:00
zeekay 385ff6f460 feat: add planet-scale caching and omnichain query layer
Cloudflare Edge Caching (near-$0 costs for free tier):
- Multi-tier cache: L0 (in-memory) + L1 (Redis) + L2 (Cloudflare edge)
- Cache shared across ALL accounts (blockchain data is public)
- Aggressive TTLs: immutable data (1yr), finalized blocks (1hr)
- Cloudflare Worker script for edge caching
- Cache bypass only for state-dependent calls (eth_call, eth_getBalance)

Omnichain Query Layer (100+ chains):
- Unified query client for blocks, transactions, addresses, tokens
- PostgreSQL for metadata, ClickHouse for analytics
- Qdrant vector search for semantic queries (similar contracts)
- Meilisearch full-text search (addresses, tokens, contracts)
- GraphQL API with Strawberry (subscriptions for real-time)
- Cross-chain queries (address across all chains)

Infrastructure Updates:
- Added Qdrant and Meilisearch to compose.yml
- ClickHouse schema for omnichain analytics (blocks, txs, DeFi, NFTs)
- Materialized views for hourly/daily aggregates

Integrates with lux/indexer for 100+ chain data.
2026-02-04 11:00:57 -08:00
zeekay d55d0b03cb feat: comprehensive bootnode platform updates
- Add brand assets and logos
- Add KMS integration for secure key management
- Add infrastructure configs (cloud providers, monitoring)
- Add indexer service with documentation
- Update K8s deployments and ingress
- Enhance dashboard pages (analytics, assets, infrastructure)
- Update auth and API components
- Add .gitignore for embedded repos
2026-02-03 12:48:01 -08:00
zeekay 73a3d23053 feat: production deployment with shared Hanzo infrastructure
- Add k8s configs for production deployment
- Use shared postgres/datastore in hanzo namespace
- Fix image registry to ghcr.io/hanzoai/bootnode
- Add deploy script with shared infra support
- Simplify compose.yml for local development
2026-02-02 16:39:52 -08:00