Appearance
vela-dashboard
Merchant-facing application surface. Both a product surface and a backend boundary that sits between merchants and the protocol.
Purpose and Role
Since v1.9, the dashboard is also the canonical Commerce OS data plane. It owns Payment Intents, standalone invoices, strict Solana transfer verification, receipts and credit notes, Refund Intents, Customer Vault, unified payments, exports, merchant verification, commerce authentication/scopes, audit records, and the transactional event outbox.
- Merchant wallet auth and email-primary session handling (Better Auth).
- Plan creation, subscription-facing business views, and subscriber management.
- Helius-powered event indexing and webhook delivery.
- Merchant-facing visibility into protocol state (mandates, pulls, streams).
- Billing analytics and revenue dashboards.
- Service binding target for
vela-adminbackend access. - Webhook endpoint management (CRUD, secret rotation, delivery retry).
Tech Stack
| Technology | Version | Purpose |
|---|---|---|
| Vite | 7.x | Build tool (Vite SSR + SPA hybrid; produces both client bundle and Bun server bundle) |
| React | 19.x | UI library |
| TanStack Router | 1.166.x | File-based, type-safe client routing (paired with router-generator and router-plugin) |
| TanStack Query | ~5.95.x | Server-state caching |
| Hono | 4.12.x | API layer — runs on the Cloudflare Worker (worker/) and on the Bun-on-Railway server (src/server/) |
| Better Auth | ^1.6.9 | Authentication (email-primary, Google SSO, SIWS wallet linking, MFA) |
| Drizzle ORM | ^0.45.x | Database ORM (D1) |
| drizzle-kit | ^0.31.x | Migration tooling — generates SQL from schema.ts |
| Cloudflare D1 | GA | SQLite database (merchant data, sessions, analytics) |
| Cloudflare KV | — | Session storage, caching |
| Cloudflare Queues | — | Async webhook fan-out (vela-webhook-events-dev, vela-webhook-dispatch-dev) |
| Cloudflare R2 | — | File storage (vela-invoices-dev bucket — exports, receipts) |
| Tailwind CSS | 4.2.x | Styling (CSS-first config; design tokens come from @vela/brand) |
@vela/sdk | file:../vela-sdk | Protocol interactions, instruction builders, PDAFactory |
@vela/brand | file:../vela-brand | Design tokens, font stack, UI primitives |
@vela/mail | file:../vela-mail | Transactional email dispatch wrapper |
@arcium-hq/client | ^0.9.3 | Arcium client — encrypts mandate inputs and decrypts billing event payloads |
| helius-sdk | 2.2.x | RPC, webhooks, DAS |
| wrangler | 4.78.x | Cloudflare CLI |
| Playwright | 1.59.x | E2E test runner (multiple playwright.phaseNN.config.ts per feature area) |
Directory Structure
vela-dashboard/
├── src/
│ ├── app/ # React SPA
│ │ ├── components/ # UI components
│ │ │ ├── plans/ # Plan creation and management
│ │ │ ├── subscribers/ # Subscriber views
│ │ │ ├── analytics/ # Billing analytics
│ │ │ ├── webhooks/ # Webhook endpoint management
│ │ │ └── settings/ # Org settings, wallet linking, 2FA
│ │ ├── hooks/ # React hooks for data fetching
│ │ └── pages/ # Route pages
│ ├── worker/ # Hono Worker (backend API)
│ │ ├── index.ts # Worker entry, Hono app
│ │ ├── auth.ts # Better Auth configuration
│ │ ├── session.ts # Session management
│ │ ├── routes/ # API route handlers
│ │ │ ├── plans.ts
│ │ │ ├── subscribers.ts
│ │ │ ├── webhooks.ts
│ │ │ ├── admin.ts # Admin service binding endpoints
│ │ │ └── checkout.ts # Checkout session management
│ │ └── middleware/ # Auth, rate limiting, CORS
│ ├── db/ # Drizzle schema and migrations
│ │ ├── schema.ts # Drizzle schema definition
│ │ └── migrations/ # SQL migration files
│ └── lib/ # Shared utilities
├── drizzle.config.ts # Drizzle Kit configuration
├── wrangler.toml # Cloudflare Worker config (D1, KV, R2 bindings)
├── vite.config.ts # Vite build config
└── package.jsonDeployment Target
The dashboard is dual-runtime — a Bun-on-Railway tier handles SSR / heavy backend work, and a Cloudflare Worker handles edge-bound traffic and binds the data plane.
- Railway (Bun runtime): Runs
src/server/serve.ts. Built via the repoDockerfile(oven/bun:1-alpine, two-stage build that bringsvela-sdkandvela-mailworkspace dependencies into the image). Serves the Vite-built dashboard SSR shell + the heavier API surface (Hono app atsrc/server/app.ts). - Cloudflare Workers:
worker/is a separate Hono Worker (entryworker/src/index.ts, deploys viaworker/wrangler.toml). Owns D1, KV, R2, and Queues bindings — the canonical data plane. Service-binding target forvela-admin. - Cloudflare D1 (
vela-dashboard-devdatabase, bindingDB): merchant data, sessions, analytics, billing events, invoices. - Cloudflare KV (binding
KV): session storage and caching. - Cloudflare R2 (
vela-invoices-devbucket, bindingINVOICE_BUCKET): invoice PDFs and exports. - Cloudflare Queues (
vela-webhook-events-devproducer + consumer,vela-webhook-dispatch-devproducer): async ingest from Helius and async fan-out to merchant endpoints. - Stream keeper: separate Worker (
worker/wrangler.stream-keeper.toml) that runs the streaming-mandate settlement loop on its own cadence.
Dependencies
What It Depends On
| Dependency | Type | Purpose |
|---|---|---|
@vela/sdk | local alias to sibling SDK | Protocol interactions, instruction builders, PDAFactory |
| Cloudflare D1 | Infrastructure | Database |
| Helius | Infrastructure | RPC, webhooks, DAS API |
| Better Auth | Library | Authentication |
What Depends on It
| Consumer | How | What They Use |
|---|---|---|
vela-admin | Service binding | Backend API access, D1 operations |
vela-checkout | API proxy | Checkout session creation |
vela-portal | API proxy | Checkout session for plan switching |
Current Status
- v1.8 complete: Multi-token support, plan upgrades, webhook management.
- v1.9 accepted on devnet: Commerce APIs and UI, canonical D1 migration, RPC-backed payment/refund verification, reconciliation, documents, scoped API keys, and auditor access.
- Auth: Email-primary (Better Auth) with Google SSO and SIWS wallet linking.
- Webhooks: Full endpoint management with HMAC-SHA256 delivery and retry.
Notable Design Decisions
Email-Primary Auth (v1.3)
Pivoted from wallet-first to email-primary auth in v1.3. Merchants need traditional login, team access, and session persistence. Wallets are treasury tools, not identity providers.
Service Binding Target
The dashboard Worker exposes internal API routes that vela-admin accesses via Cloudflare service binding. Admin never directly accesses D1 — all database operations go through the dashboard.
Dual Runtime (Railway + Cloudflare)
The React SPA runs on Railway for SSR while the API runs on Cloudflare Workers. This split allows the frontend to use Node.js features while the backend leverages Cloudflare's edge network and D1 integration.
D1 Batch API (No Interactive Transactions)
D1 doesn't support interactive transactions. Better Auth and Drizzle use D1's batch() API for atomicity. This is a known limitation accepted during development with a migration path to Postgres at PMF.
Commerce transitions batch all related business records and the outbox event. Constraints, partial unique indexes, and refund reservation triggers enforce invariants that request-level validation alone cannot protect under concurrency.
Helius Webhook Integration
Real-time on-chain event indexing via Helius Enhanced webhooks. Mandate creation, pull execution, cancellation, stream events, and upgrade events all trigger dashboard updates.