Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Dashboard

Primary control plane for managing your agent infrastructure. Built with Svelte frontend and Rust backend.

Overview

The Dashboard provides a web-based interface for deploying, monitoring, and managing agents. It’s the main entry point for most users.

Features

  • Agent CRUD operations
  • Real-time metrics visualization
  • Configuration management
  • Log streaming
  • User management
  • Billing overview

Architecture

┌─────────────────────────────────────────┐
│      Svelte Frontend (Port 3000)        │
│   SvelteKit • TypeScript • Tailwind     │
└─────────────────────────────────────────┘
                  ↓ REST API
┌─────────────────────────────────────────┐
│       Rust Backend (Port 8000)          │
│   Axum • Tokio • SQLx • Serde           │
└─────────────────────────────────────────┘
                  ↓
┌─────────────────────────────────────────┐
│          PostgreSQL Database            │
└─────────────────────────────────────────┘

Running

Development

cd neuais.com/hub.neuais.com/dashboard.neuais.com

# Start backend
cd backend
cargo run

# Start frontend (new terminal)
cd frontend
npm run dev

Access at: http://localhost:3000

Production

# Build backend
cd backend
cargo build --release

# Build frontend
cd frontend
npm run build

# Run
./backend/target/release/dashboard-backend &
cd frontend && npm run preview

API Endpoints

Authentication

POST   /api/auth/login
POST   /api/auth/logout
GET    /api/auth/me

Agents

GET    /api/agents
POST   /api/agents
GET    /api/agents/{id}
PUT    /api/agents/{id}
DELETE /api/agents/{id}
POST   /api/agents/{id}/start
POST   /api/agents/{id}/stop
POST   /api/agents/{id}/restart
GET    /api/agents/{id}/logs
GET    /api/agents/{id}/metrics

Users

GET    /api/users
POST   /api/users
GET    /api/users/{id}
PUT    /api/users/{id}
DELETE /api/users/{id}

Billing

GET    /api/billing/usage
GET    /api/billing/invoices
GET    /api/billing/payment-methods

Frontend Structure

frontend/
├── src/
│   ├── routes/
│   │   ├── +page.svelte          # Home
│   │   ├── agents/
│   │   │   ├── +page.svelte      # Agent list
│   │   │   └── [id]/
│   │   │       └── +page.svelte  # Agent details
│   │   ├── users/
│   │   └── billing/
│   ├── lib/
│   │   ├── components/
│   │   │   ├── AgentCard.svelte
│   │   │   ├── MetricsChart.svelte
│   │   │   └── LogViewer.svelte
│   │   ├── stores/
│   │   └── api/
│   └── app.html
├── static/
└── package.json

Backend Structure

backend/
├── src/
│   ├── main.rs              # Entry point
│   ├── routes/
│   │   ├── agents.rs
│   │   ├── auth.rs
│   │   ├── users.rs
│   │   └── billing.rs
│   ├── models/
│   │   ├── agent.rs
│   │   ├── user.rs
│   │   └── billing.rs
│   ├── db/
│   │   ├── mod.rs
│   │   └── migrations/
│   └── middleware/
│       ├── auth.rs
│       └── cors.rs
└── Cargo.toml

Configuration

backend/config.toml:

[server]
host = "0.0.0.0"
port = 8000

[database]
url = "postgresql://user:pass@localhost/neuais"
max_connections = 10

[auth]
jwt_secret = "your-secret-key"
token_expiry = "24h"

[cors]
allowed_origins = ["http://localhost:3000"]

Database Schema

CREATE TABLE agents (
    id UUID PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    status VARCHAR(50) NOT NULL,
    created_at TIMESTAMP NOT NULL,
    updated_at TIMESTAMP NOT NULL
);

CREATE TABLE users (
    id UUID PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    role VARCHAR(50) NOT NULL,
    created_at TIMESTAMP NOT NULL
);

CREATE TABLE agent_metrics (
    id SERIAL PRIMARY KEY,
    agent_id UUID REFERENCES agents(id),
    cpu_usage FLOAT,
    memory_usage BIGINT,
    timestamp TIMESTAMP NOT NULL
);

Components

AgentCard

<script lang="ts">
  export let agent: Agent;
</script>

<div class="card">
  <h3>{agent.name}</h3>
  <p>Status: {agent.status}</p>
  <p>CPU: {agent.metrics.cpu}%</p>
  <p>Memory: {agent.metrics.memory}MB</p>
</div>

MetricsChart

<script lang="ts">
  import { onMount } from 'svelte';
  export let agentId: string;
  
  let metrics = [];
  
  onMount(async () => {
    const res = await fetch(`/api/agents/${agentId}/metrics`);
    metrics = await res.json();
  });
</script>

<canvas bind:this={canvas}></canvas>

Authentication

Login Flow

  1. User submits credentials
  2. Backend validates against database
  3. Backend generates JWT token
  4. Frontend stores token in localStorage
  5. Frontend includes token in all API requests

Example

// Login
const response = await fetch('/api/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email, password })
});

const { token } = await response.json();
localStorage.setItem('token', token);

// Authenticated request
fetch('/api/agents', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

Real-Time Updates

WebSocket Connection

const ws = new WebSocket('ws://localhost:8000/ws');

ws.onmessage = (event) => {
  const update = JSON.parse(event.data);
  
  if (update.type === 'agent_status') {
    updateAgentStatus(update.agent_id, update.status);
  }
};

Deployment

Docker

# Backend
FROM rust:1.75 as builder
WORKDIR /app
COPY backend/ .
RUN cargo build --release

FROM debian:bookworm-slim
COPY --from=builder /app/target/release/dashboard-backend /usr/local/bin/
CMD ["dashboard-backend"]
# Frontend
FROM node:20 as builder
WORKDIR /app
COPY frontend/ .
RUN npm install && npm run build

FROM node:20-slim
COPY --from=builder /app/build /app
CMD ["node", "/app"]

Fly.io

fly.toml:

app = "neuais-dashboard"

[build]
  dockerfile = "Dockerfile"

[[services]]
  internal_port = 8000
  protocol = "tcp"

  [[services.ports]]
    port = 80
    handlers = ["http"]

  [[services.ports]]
    port = 443
    handlers = ["tls", "http"]

Deploy:

fly deploy

Troubleshooting

Backend won’t start

Check database connection:

psql postgresql://user:pass@localhost/neuais

Frontend build fails

Clear node_modules:

rm -rf node_modules package-lock.json
npm install

CORS errors

Update allowed_origins in config.toml

WebSocket disconnects

Check firewall rules and load balancer settings

Next Steps