Next.js Dashboard & OpenNext Isolate

Comprehensive engineering specification for the Next.js 16 Hoox Dashboard, covering Turbopack builds, OpenNext adapters, and Cloudflare® Workers hosting.

This page

The Hoox Dashboard is the web-based command center of the trading platform. Rather than running on a traditional server, the dashboard is a Next.js 16 application compiled using the OpenNext adapter and hosted natively on Cloudflare® Workers. This edge-first layout allows for real-time portfolio monitoring, dynamic form-based settings editing, and interactive kill-switch controls at microsecond speeds.

Dashboard setup wizard welcome and infrastructure
Setup wizard with Cloudflare® infrastructure map
GIF of dashboard sidebar navigation
Navigating primary dashboard pages

Page-by-page stills: Interface gallery.

Positions & test trading

The Positions table integrates with exchange testnet fills produced when webhooks carry "test": true:

UI featureBehavior
Mode filterLive only (default) · Testnet · Live + Test
TEST badgeShown next to the exchange for rows whose id contains -testnet-
Close actionSends test: true on the trade-worker webhook when closing a testnet position
Headline statsD1 dashboard stats exclude TEST_EXECUTED trades and *-testnet-* positions

See Test Trading.

Agent Reasoning & Usage pages

These dashboard pages call dashboard /api/agent/* routes, not agent-worker:

PageRouteBehavior
ReasoningPOST /api/agent/reasoningWorkers AI when the model id includes deepseek; otherwise a mock reasoning/answer plus a note to configure keys
UsageGET /api/agent/usageReads CONFIG_KV agent:usage; empty object when unset
Chat streamingPOST /api/agent/chatSSE from the dashboard AI binding when stream is true

agent-worker itself has chat, vision, embedding, risk-override, status, config, models, health, and housekeeping — and does not implement /agent/reasoning or /agent/usage. See agent-worker.


🏗️ Next.js to Cloudflare® Edge Architecture

When deploying the dashboard, the monorepo uses @opennextjs/cloudflare to convert standard Node.js server-side features into Edge-compliant JavaScript:

Diagram

Rendering…

  • Server Isolate (.open-next/worker.js): Handles Server-Side Rendering (SSR), React Server Components (RSC) hydration, API routes, and cookies encryption.
  • Static Assets (.open-next/assets/): Houses all static assets, which are bound to the worker via ASSETS bindings to serve static pages at sub-millisecond CDN latency.

⚡ 1. Declared Wrangler Configurations & Bindings

The dashboard's wrangler.jsonc maps out its internal service links to extract D1 databases metrics and agent status updates:

jsonc
{
  "name": "dashboard",
  "main": ".open-next/worker.js",
  "compatibility_date": "2026-06-08",
  "compatibility_flags": ["nodejs_compat"],
  "account_id": "<CLOUDFLARE_ACCOUNT_ID>",
  "assets": {
    "directory": ".open-next/assets",
    "binding": "ASSETS",
  },
  "kv_namespaces": [
    {
      "binding": "CONFIG_KV",
      "id": "<KV_NAMESPACE_ID>",
    },
    {
      "binding": "NEXT_INC_CACHE_KV",
      "id": "<KV_NAMESPACE_ID>",
    },
  ],
  "services": [
    { "binding": "D1_SERVICE", "service": "d1-worker" },
    { "binding": "AGENT_SERVICE", "service": "agent-worker" },
    { "binding": "WEB3_WALLET_SERVICE", "service": "web3-wallet-worker" },
    { "binding": "PYNE_SERVICE", "service": "pyne-worker" },
  ],
  "ai": {
    "binding": "AI",
  },
}

Worker name is dashboard. Smart Placement is off so the UI stays close to operators. Secrets (DASHBOARD_USER, DASHBOARD_PASS, SESSION_SECRET, INTERNAL_KEY_BINDING, optional PYNE_API_KEY) are set with wrangler secret put. Do not put live *.workers.dev URLs in committed wrangler.


🔑 2. Environmental Variables & Encrypted Secrets

  • DASHBOARD_USER & DASHBOARD_PASS: Administrative credentials required to access the visual panel.
  • SESSION_SECRET: A secure 32-character encryption key used to cryptographically sign session cookies at the edge.
  • INTERNAL_KEY_BINDING: Shared key used to validate calls to d1-worker, agent-worker, and web3-wallet-worker.
  • PYNE_API_KEY: Optional; match pyne-worker API_KEY when the dashboard calls PYNE_SERVICE.

Local Development Mocking (.env.local)

Create a gitignored .env.local file inside workers/dashboard/ for local Next.js runs:

bash
DASHBOARD_USER=admin
DASHBOARD_PASS=admin_dev_passkey_183
SESSION_SECRET=abandon_abandon_abandon_abandon_32

🎛️ 3. Schema-Driven Settings System

To allow operators to extend the platform's settings without touching React code, the dashboard implements a schema-driven configuration manager parsed dynamically from config.schema.json:

json
{
  "sections": [
    {
      "id": "risk",
      "title": "Risk Management",
      "fields": [
        {
          "key": "trade:max_daily_drawdown_percent",
          "label": "Max Daily Drawdown (%)",
          "type": "number",
          "default": 5,
          "category": "risk"
        }
      ]
    }
  ]
}

Form Submission Flow

  1. When you save the settings form, the Next.js server actions intercept the payload.

  2. The server action iterates over the JSON schema keys and writes the values directly to the bound CONFIG_KV namespace.

  3. The changes propagate globally to your edge executors in under 10 seconds.


🚢 4. Production Build & Rollout Runbook

To compile and deploy the Next.js dashboard to Cloudflare®:

bash
# 1. Navigate to the dashboard directory
cd workers/dashboard

# 2. Build the application using OpenNext
bun run opennext:build

# 3. Deploy the compiled bundles to Cloudflare® Workers
bun run opennext:deploy

Warning

Framer Motion components and interactive visual elements used in Next.js pages must declare the 'use client' directive at the top of the file. Under OpenNext, client-side pages cannot export metadata directly—move metadata definitions to separate metadata.ts files!

🛡️ Security Headers

The dashboard applies 7 security headers on every response via the shared @hoox-sh/hoox-shared/middleware secureHeaders() factory:

HeaderValue
X-Content-Type-Optionsnosniff
X-Frame-OptionsDENY
X-XSS-Protection1; mode=block
Referrer-Policystrict-origin-when-cross-origin
Permissions-PolicyAll features disabled
Strict-Transport-Securitymax-age=31536000; includeSubDomains
Content-Security-Policydefault-src 'self'

Headers are applied via the withSecurityHeaders() wrapper in src/middleware.ts, covering all return paths including static files, login pages, CSRF errors, and auth failures.

🔗 Next Steps