- Created `project-structure.md` to outline the directory layout, crate dependencies, design principles, module guidelines, and naming conventions for the NxMesh codebase. - Introduced `roadmap.md` detailing the development phases, milestones, tasks, deliverables, and resource requirements for the NxMesh project, spanning from foundational setup to enterprise features.
1108 lines
20 KiB
Markdown
1108 lines
20 KiB
Markdown
# NxMesh API Specification
|
|
|
|
## Overview
|
|
|
|
This document outlines the API structure for NxMesh. The system exposes:
|
|
- **REST API** for external integrations and Web UI
|
|
- **gRPC API** for master-agent communication
|
|
- **WebSocket API** for real-time events
|
|
|
|
---
|
|
|
|
## REST API
|
|
|
|
### Base Information
|
|
|
|
| Property | Value |
|
|
|----------|-------|
|
|
| Base URL | `https://api.nxmesh.io/v1` |
|
|
| Content-Type | `application/json` |
|
|
| Authentication | Bearer Token (JWT) |
|
|
| Rate Limit | 1000 requests/minute |
|
|
|
|
### Authentication
|
|
|
|
#### Login
|
|
```http
|
|
POST /auth/login
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"email": "user@example.com",
|
|
"password": "secure_password"
|
|
}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...",
|
|
"expires_in": 3600,
|
|
"token_type": "Bearer"
|
|
}
|
|
```
|
|
|
|
#### Refresh Token
|
|
```http
|
|
POST /auth/refresh
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4..."
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Organizations
|
|
|
|
#### List Organizations
|
|
```http
|
|
GET /organizations?page=1&per_page=20
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"data": [
|
|
{
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"name": "Acme Corp",
|
|
"slug": "acme-corp",
|
|
"created_at": "2026-01-15T10:30:00Z",
|
|
"updated_at": "2026-01-15T10:30:00Z"
|
|
}
|
|
],
|
|
"meta": {
|
|
"page": 1,
|
|
"per_page": 20,
|
|
"total": 1
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Create Organization
|
|
```http
|
|
POST /organizations
|
|
Authorization: Bearer {token}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"name": "Acme Corp",
|
|
"slug": "acme-corp"
|
|
}
|
|
```
|
|
|
|
#### Get Organization
|
|
```http
|
|
GET /organizations/{organization_id}
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
#### Update Organization
|
|
```http
|
|
PATCH /organizations/{organization_id}
|
|
Authorization: Bearer {token}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"name": "Acme Corporation"
|
|
}
|
|
```
|
|
|
|
#### Delete Organization
|
|
```http
|
|
DELETE /organizations/{organization_id}
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
---
|
|
|
|
### Workspaces
|
|
|
|
#### List Workspaces
|
|
```http
|
|
GET /organizations/{organization_id}/workspaces?page=1&per_page=20
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"data": [
|
|
{
|
|
"id": "660e8400-e29b-41d4-a716-446655440001",
|
|
"organization_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"name": "Production",
|
|
"slug": "production",
|
|
"created_at": "2026-01-15T10:30:00Z"
|
|
}
|
|
],
|
|
"meta": {
|
|
"page": 1,
|
|
"per_page": 20,
|
|
"total": 3
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Create Workspace
|
|
```http
|
|
POST /organizations/{organization_id}/workspaces
|
|
Authorization: Bearer {token}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"name": "Staging",
|
|
"slug": "staging"
|
|
}
|
|
```
|
|
|
|
#### Get Workspace
|
|
```http
|
|
GET /workspaces/{workspace_id}
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
#### Update Workspace
|
|
```http
|
|
PATCH /workspaces/{workspace_id}
|
|
Authorization: Bearer {token}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"name": "Staging Environment"
|
|
}
|
|
```
|
|
|
|
#### Delete Workspace
|
|
```http
|
|
DELETE /workspaces/{workspace_id}
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
---
|
|
|
|
### Agents
|
|
|
|
#### List Agents
|
|
```http
|
|
GET /workspaces/{workspace_id}/agents?page=1&per_page=20&state=online
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
Query Parameters:
|
|
- `state` - Filter by state: `online`, `offline`, `degraded`, `all`
|
|
- `label_selector` - Filter by labels: `env=production,region=us-east`
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"data": [
|
|
{
|
|
"id": "770e8400-e29b-41d4-a716-446655440002",
|
|
"workspace_id": "660e8400-e29b-41d4-a716-446655440001",
|
|
"name": "web-server-01",
|
|
"hostname": "web-01.internal",
|
|
"ip_address": "10.0.1.10",
|
|
"version": "0.1.0",
|
|
"state": "online",
|
|
"deployment_mode": "docker_sidecar",
|
|
"last_seen_at": "2026-03-02T12:00:00Z",
|
|
"capabilities": ["http2", "websocket"],
|
|
"labels": {
|
|
"env": "production",
|
|
"region": "us-east-1"
|
|
},
|
|
"created_at": "2026-02-01T10:00:00Z"
|
|
}
|
|
],
|
|
"meta": {
|
|
"page": 1,
|
|
"per_page": 20,
|
|
"total": 5
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Get Agent
|
|
```http
|
|
GET /agents/{agent_id}
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
Response includes health details:
|
|
```json
|
|
{
|
|
"id": "770e8400-e29b-41d4-a716-446655440002",
|
|
"workspace_id": "660e8400-e29b-41d4-a716-446655440001",
|
|
"name": "web-server-01",
|
|
"hostname": "web-01.internal",
|
|
"ip_address": "10.0.1.10",
|
|
"version": "0.1.0",
|
|
"state": "online",
|
|
"deployment_mode": "docker_sidecar",
|
|
"last_seen_at": "2026-03-02T12:00:00Z",
|
|
"capabilities": ["http2", "websocket"],
|
|
"labels": {
|
|
"env": "production",
|
|
"region": "us-east-1"
|
|
},
|
|
"health": {
|
|
"nginx_status": "running",
|
|
"nginx_uptime_seconds": 86400,
|
|
"active_connections": 42,
|
|
"requests_per_second": 150.5,
|
|
"cpu_percent": 25.0,
|
|
"memory_used_mb": 512,
|
|
"config_version": 42
|
|
},
|
|
"created_at": "2026-02-01T10:00:00Z"
|
|
}
|
|
```
|
|
|
|
#### Create Agent Registration Token
|
|
```http
|
|
POST /workspaces/{workspace_id}/agents/tokens
|
|
Authorization: Bearer {token}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"name": "web-server-02",
|
|
"labels": {
|
|
"env": "production",
|
|
"region": "us-west-1"
|
|
},
|
|
"expires_in_hours": 24
|
|
}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"token": "nxmesh_agent_eyJhZ2VudF9pZCI6ICI3NzBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDMi...",
|
|
"agent_id": "770e8400-e29b-41d4-a716-446655440003",
|
|
"expires_at": "2026-03-03T12:00:00Z"
|
|
}
|
|
```
|
|
|
|
#### Update Agent
|
|
```http
|
|
PATCH /agents/{agent_id}
|
|
Authorization: Bearer {token}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"name": "web-server-01-renamed",
|
|
"labels": {
|
|
"env": "production",
|
|
"region": "us-east-1",
|
|
"tier": "web"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Delete Agent
|
|
```http
|
|
DELETE /agents/{agent_id}
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
#### Reload Agent Nginx
|
|
```http
|
|
POST /agents/{agent_id}/reload
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Nginx reloaded successfully",
|
|
"timestamp": "2026-03-02T12:05:00Z"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Virtual Hosts
|
|
|
|
#### List Virtual Hosts
|
|
```http
|
|
GET /workspaces/{workspace_id}/virtual-hosts?page=1&per_page=20
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"data": [
|
|
{
|
|
"id": "880e8400-e29b-41d4-a716-446655440004",
|
|
"workspace_id": "660e8400-e29b-41d4-a716-446655440001",
|
|
"name": "Main Website",
|
|
"server_name": "example.com www.example.com",
|
|
"listen_port": 443,
|
|
"ssl_enabled": true,
|
|
"ssl_certificate_id": "990e8400-e29b-41d4-a716-446655440005",
|
|
"http2_enabled": true,
|
|
"target_agents": {
|
|
"type": "all"
|
|
},
|
|
"created_at": "2026-02-01T10:00:00Z",
|
|
"updated_at": "2026-02-15T14:30:00Z"
|
|
}
|
|
],
|
|
"meta": {
|
|
"page": 1,
|
|
"per_page": 20,
|
|
"total": 10
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Create Virtual Host
|
|
```http
|
|
POST /workspaces/{workspace_id}/virtual-hosts
|
|
Authorization: Bearer {token}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"name": "API Gateway",
|
|
"server_name": "api.example.com",
|
|
"listen_port": 443,
|
|
"ssl_enabled": true,
|
|
"ssl_certificate_id": "990e8400-e29b-41d4-a716-446655440005",
|
|
"http2_enabled": true,
|
|
"locations": [
|
|
{
|
|
"path": "/api/v1",
|
|
"upstream_id": "aa0e8400-e29b-41d4-a716-446655440006",
|
|
"custom_headers": [
|
|
{
|
|
"name": "X-Forwarded-Proto",
|
|
"value": "$scheme"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"path": "/health",
|
|
"proxy_pass": "http://localhost:8080/health"
|
|
}
|
|
],
|
|
"target_agents": {
|
|
"type": "selector",
|
|
"label_selector": "env=production"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Get Virtual Host
|
|
```http
|
|
GET /virtual-hosts/{virtual_host_id}
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
#### Update Virtual Host
|
|
```http
|
|
PATCH /virtual-hosts/{virtual_host_id}
|
|
Authorization: Bearer {token}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"name": "API Gateway v2",
|
|
"locations": [
|
|
{
|
|
"path": "/api/v2",
|
|
"upstream_id": "aa0e8400-e29b-41d4-a716-446655440007"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
#### Delete Virtual Host
|
|
```http
|
|
DELETE /virtual-hosts/{virtual_host_id}
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
---
|
|
|
|
### Upstreams
|
|
|
|
#### List Upstreams
|
|
```http
|
|
GET /workspaces/{workspace_id}/upstreams?page=1&per_page=20
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"data": [
|
|
{
|
|
"id": "aa0e8400-e29b-41d4-a716-446655440006",
|
|
"workspace_id": "660e8400-e29b-41d4-a716-446655440001",
|
|
"name": "api-backend",
|
|
"algorithm": "round_robin",
|
|
"servers": [
|
|
{
|
|
"address": "10.0.1.20:8080",
|
|
"weight": 1,
|
|
"backup": false,
|
|
"max_fails": 3,
|
|
"fail_timeout": 30
|
|
},
|
|
{
|
|
"address": "10.0.1.21:8080",
|
|
"weight": 1,
|
|
"backup": false,
|
|
"max_fails": 3,
|
|
"fail_timeout": 30
|
|
}
|
|
],
|
|
"health_check": {
|
|
"enabled": true,
|
|
"path": "/health",
|
|
"interval": 10,
|
|
"timeout": 5
|
|
},
|
|
"created_at": "2026-02-01T10:00:00Z",
|
|
"updated_at": "2026-02-15T14:30:00Z"
|
|
}
|
|
],
|
|
"meta": {
|
|
"page": 1,
|
|
"per_page": 20,
|
|
"total": 5
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Create Upstream
|
|
```http
|
|
POST /workspaces/{workspace_id}/upstreams
|
|
Authorization: Bearer {token}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"name": "web-backend",
|
|
"algorithm": "least_connections",
|
|
"servers": [
|
|
{
|
|
"address": "10.0.1.30:8080",
|
|
"weight": 2,
|
|
"backup": false
|
|
},
|
|
{
|
|
"address": "10.0.1.31:8080",
|
|
"weight": 1,
|
|
"backup": false
|
|
},
|
|
{
|
|
"address": "10.0.1.32:8080",
|
|
"weight": 1,
|
|
"backup": true
|
|
}
|
|
],
|
|
"health_check": {
|
|
"enabled": true,
|
|
"path": "/health",
|
|
"interval": 10,
|
|
"timeout": 5
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Get Upstream
|
|
```http
|
|
GET /upstreams/{upstream_id}
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
#### Update Upstream
|
|
```http
|
|
PATCH /upstreams/{upstream_id}
|
|
Authorization: Bearer {token}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"servers": [
|
|
{
|
|
"address": "10.0.1.30:8080",
|
|
"weight": 3,
|
|
"backup": false
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
#### Delete Upstream
|
|
```http
|
|
DELETE /upstreams/{upstream_id}
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
---
|
|
|
|
### Certificates
|
|
|
|
#### List Certificates
|
|
```http
|
|
GET /workspaces/{workspace_id}/certificates?page=1&per_page=20
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"data": [
|
|
{
|
|
"id": "990e8400-e29b-41d4-a716-446655440005",
|
|
"workspace_id": "660e8400-e29b-41d4-a716-446655440001",
|
|
"domain": "example.com",
|
|
"is_wildcard": false,
|
|
"provider": "letsencrypt",
|
|
"status": "active",
|
|
"issued_at": "2026-02-01T10:00:00Z",
|
|
"expires_at": "2026-05-01T10:00:00Z",
|
|
"auto_renew": true,
|
|
"created_at": "2026-02-01T10:00:00Z"
|
|
}
|
|
],
|
|
"meta": {
|
|
"page": 1,
|
|
"per_page": 20,
|
|
"total": 3
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Request Certificate
|
|
```http
|
|
POST /workspaces/{workspace_id}/certificates
|
|
Authorization: Bearer {token}
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"domain": "api.example.com",
|
|
"provider": "letsencrypt",
|
|
"auto_renew": true
|
|
}
|
|
```
|
|
|
|
#### Get Certificate
|
|
```http
|
|
GET /certificates/{certificate_id}
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
#### Delete Certificate
|
|
```http
|
|
DELETE /certificates/{certificate_id}
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
---
|
|
|
|
### Metrics
|
|
|
|
#### Get Workspace Metrics
|
|
```http
|
|
GET /workspaces/{workspace_id}/metrics?from=2026-03-01T00:00:00Z&to=2026-03-02T00:00:00Z
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"requests_total": 1234567,
|
|
"requests_per_second": 150.5,
|
|
"error_rate": 0.001,
|
|
"active_connections": 42,
|
|
"bandwidth": {
|
|
"in_bytes": 1073741824,
|
|
"out_bytes": 5368709120
|
|
},
|
|
"status_codes": {
|
|
"2xx": 1230000,
|
|
"3xx": 4000,
|
|
"4xx": 500,
|
|
"5xx": 67
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Get Agent Metrics
|
|
```http
|
|
GET /agents/{agent_id}/metrics?from=2026-03-01T00:00:00Z&to=2026-03-02T00:00:00Z
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
---
|
|
|
|
### Access Logs
|
|
|
|
#### Query Access Logs
|
|
```http
|
|
GET /workspaces/{workspace_id}/access-logs?from=2026-03-01T00:00:00Z&to=2026-03-02T00:00:00Z&status_code=500&limit=100
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"data": [
|
|
{
|
|
"id": "bb0e8400-e29b-41d4-a716-446655440008",
|
|
"agent_id": "770e8400-e29b-41d4-a716-446655440002",
|
|
"timestamp": "2026-03-02T10:30:00Z",
|
|
"remote_addr": "192.168.1.100",
|
|
"method": "GET",
|
|
"uri": "/api/error",
|
|
"protocol": "HTTP/1.1",
|
|
"host": "api.example.com",
|
|
"status": 500,
|
|
"body_bytes_sent": 123,
|
|
"response_time_ms": 150.5,
|
|
"user_agent": "Mozilla/5.0...",
|
|
"referer": "https://example.com/",
|
|
"request_id": "req-123-456"
|
|
}
|
|
],
|
|
"meta": {
|
|
"total": 67,
|
|
"limit": 100
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Error Responses
|
|
|
|
All errors follow this format:
|
|
|
|
```json
|
|
{
|
|
"error": {
|
|
"code": "VALIDATION_ERROR",
|
|
"message": "Request validation failed",
|
|
"request_id": "req-abc-123",
|
|
"details": [
|
|
{
|
|
"field": "server_name",
|
|
"message": "Invalid domain format",
|
|
"code": "INVALID_FORMAT"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
### Error Codes
|
|
|
|
| Code | HTTP Status | Description |
|
|
|------|-------------|-------------|
|
|
| `UNAUTHORIZED` | 401 | Authentication required or invalid credentials |
|
|
| `FORBIDDEN` | 403 | Insufficient permissions |
|
|
| `NOT_FOUND` | 404 | Resource not found |
|
|
| `VALIDATION_ERROR` | 422 | Request validation failed |
|
|
| `CONFLICT` | 409 | Resource conflict (e.g., duplicate slug) |
|
|
| `RATE_LIMITED` | 429 | Too many requests |
|
|
| `INTERNAL_ERROR` | 500 | Server internal error |
|
|
| `SERVICE_UNAVAILABLE` | 503 | Service temporarily unavailable |
|
|
|
|
---
|
|
|
|
## gRPC API (Master-Agent)
|
|
|
|
### Service Definition
|
|
|
|
```protobuf
|
|
syntax = "proto3";
|
|
package nxmesh.agent.v1;
|
|
|
|
option go_package = "github.com/nxmesh/api/agent/v1";
|
|
|
|
// AgentService defines the bidirectional communication between master and agents
|
|
service AgentService {
|
|
// Stream establishes a persistent connection for real-time communication
|
|
rpc Stream(stream AgentMessage) returns (stream MasterMessage);
|
|
|
|
// ReportHealth sends a health report to the master
|
|
rpc ReportHealth(HealthReport) returns (Ack);
|
|
|
|
// ReportMetrics sends metrics batch to the master
|
|
rpc ReportMetrics(MetricsBatch) returns (Ack);
|
|
}
|
|
|
|
// Messages sent from agent to master
|
|
message AgentMessage {
|
|
string agent_id = 1;
|
|
int64 timestamp = 2;
|
|
oneof payload {
|
|
RegistrationRequest registration = 3;
|
|
HealthReport health = 4;
|
|
ConfigStatus config_status = 5;
|
|
MetricsBatch metrics = 6;
|
|
LogBatch logs = 7;
|
|
Event event = 8;
|
|
}
|
|
}
|
|
|
|
// Messages sent from master to agent
|
|
message MasterMessage {
|
|
int64 timestamp = 1;
|
|
oneof payload {
|
|
RegistrationResponse registration_response = 2;
|
|
ConfigUpdate config_update = 3;
|
|
Command command = 4;
|
|
Ack ack = 5;
|
|
Error error = 6;
|
|
}
|
|
}
|
|
|
|
// Registration
|
|
message RegistrationRequest {
|
|
string token = 1;
|
|
string hostname = 2;
|
|
string ip_address = 3;
|
|
string version = 4;
|
|
repeated string capabilities = 5;
|
|
map<string, string> labels = 6;
|
|
DeploymentMode deployment_mode = 7;
|
|
}
|
|
|
|
message RegistrationResponse {
|
|
string agent_id = 1;
|
|
bool success = 2;
|
|
string error_message = 3;
|
|
int64 heartbeat_interval_seconds = 4;
|
|
}
|
|
|
|
enum DeploymentMode {
|
|
DEPLOYMENT_MODE_UNSPECIFIED = 0;
|
|
DOCKER_SIDECAR = 1;
|
|
KUBERNETES_SIDECAR = 2;
|
|
STANDALONE = 3;
|
|
}
|
|
|
|
// Health Reporting
|
|
message HealthReport {
|
|
NginxStatus nginx = 1;
|
|
SystemMetrics system = 2;
|
|
string config_checksum = 3;
|
|
int64 config_version = 4;
|
|
repeated Alert alerts = 5;
|
|
}
|
|
|
|
message NginxStatus {
|
|
bool is_running = 1;
|
|
uint32 pid = 2;
|
|
uint64 uptime_seconds = 3;
|
|
uint32 active_connections = 4;
|
|
uint64 total_requests = 5;
|
|
float requests_per_second = 6;
|
|
}
|
|
|
|
message SystemMetrics {
|
|
float cpu_percent = 1;
|
|
uint64 memory_used_bytes = 2;
|
|
uint64 memory_total_bytes = 3;
|
|
uint64 disk_used_bytes = 4;
|
|
uint64 disk_total_bytes = 5;
|
|
float load_average_1m = 6;
|
|
}
|
|
|
|
message Alert {
|
|
string id = 1;
|
|
string severity = 2; // info, warning, error, critical
|
|
string message = 3;
|
|
int64 timestamp = 4;
|
|
}
|
|
|
|
// Configuration
|
|
message ConfigUpdate {
|
|
string config_id = 1;
|
|
int64 version = 2;
|
|
repeated VirtualHost virtual_hosts = 3;
|
|
repeated Upstream upstreams = 4;
|
|
map<string, Certificate> certificates = 5;
|
|
GlobalSettings global_settings = 6;
|
|
}
|
|
|
|
message VirtualHost {
|
|
string id = 1;
|
|
string name = 2;
|
|
string server_name = 3;
|
|
uint32 listen_port = 4;
|
|
bool ssl_enabled = 5;
|
|
string ssl_certificate_id = 6;
|
|
bool http2_enabled = 7;
|
|
bool http3_enabled = 8;
|
|
repeated Location locations = 9;
|
|
map<string, string> custom_directives = 10;
|
|
}
|
|
|
|
message Location {
|
|
string path = 1;
|
|
string proxy_pass = 2;
|
|
string upstream_id = 3;
|
|
string root = 4;
|
|
string index = 5;
|
|
repeated Header custom_headers = 6;
|
|
repeated RewriteRule rewrite_rules = 7;
|
|
map<string, string> custom_directives = 8;
|
|
}
|
|
|
|
message Header {
|
|
string name = 1;
|
|
string value = 2;
|
|
bool always = 3;
|
|
}
|
|
|
|
message RewriteRule {
|
|
string pattern = 1;
|
|
string replacement = 2;
|
|
string flag = 3;
|
|
}
|
|
|
|
message Upstream {
|
|
string id = 1;
|
|
string name = 2;
|
|
LoadBalanceAlgorithm algorithm = 3;
|
|
repeated UpstreamServer servers = 4;
|
|
HealthCheckConfig health_check = 5;
|
|
uint32 keepalive_connections = 6;
|
|
}
|
|
|
|
enum LoadBalanceAlgorithm {
|
|
LOAD_BALANCE_ALGORITHM_UNSPECIFIED = 0;
|
|
ROUND_ROBIN = 1;
|
|
LEAST_CONNECTIONS = 2;
|
|
IP_HASH = 3;
|
|
WEIGHTED_ROUND_ROBIN = 4;
|
|
}
|
|
|
|
message UpstreamServer {
|
|
string address = 1;
|
|
uint32 weight = 2;
|
|
bool backup = 3;
|
|
bool down = 4;
|
|
uint32 max_fails = 5;
|
|
uint32 fail_timeout_seconds = 6;
|
|
}
|
|
|
|
message HealthCheckConfig {
|
|
bool enabled = 1;
|
|
string path = 2;
|
|
uint32 interval_seconds = 3;
|
|
uint32 timeout_seconds = 4;
|
|
uint32 healthy_threshold = 5;
|
|
uint32 unhealthy_threshold = 6;
|
|
}
|
|
|
|
message Certificate {
|
|
string id = 1;
|
|
string domain = 2;
|
|
string certificate_pem = 3;
|
|
string private_key_pem = 4;
|
|
int64 expires_at = 5;
|
|
}
|
|
|
|
message GlobalSettings {
|
|
map<string, string> nginx_directives = 1;
|
|
map<string, string> env_vars = 2;
|
|
}
|
|
|
|
message ConfigStatus {
|
|
string config_id = 1;
|
|
int64 version = 2;
|
|
ConfigApplyStatus status = 3;
|
|
string error_message = 4;
|
|
int64 applied_at = 5;
|
|
}
|
|
|
|
enum ConfigApplyStatus {
|
|
CONFIG_APPLY_STATUS_UNSPECIFIED = 0;
|
|
PENDING = 1;
|
|
VALIDATING = 2;
|
|
APPLYING = 3;
|
|
SUCCESS = 4;
|
|
FAILED = 5;
|
|
ROLLED_BACK = 6;
|
|
}
|
|
|
|
// Metrics
|
|
message MetricsBatch {
|
|
int64 timestamp = 1;
|
|
repeated Metric metrics = 2;
|
|
}
|
|
|
|
message Metric {
|
|
string name = 1;
|
|
double value = 2;
|
|
int64 timestamp = 3;
|
|
map<string, string> labels = 4;
|
|
MetricType type = 5;
|
|
}
|
|
|
|
enum MetricType {
|
|
METRIC_TYPE_UNSPECIFIED = 0;
|
|
GAUGE = 1;
|
|
COUNTER = 2;
|
|
HISTOGRAM = 3;
|
|
}
|
|
|
|
// Logs
|
|
message LogBatch {
|
|
repeated LogEntry entries = 1;
|
|
}
|
|
|
|
message LogEntry {
|
|
int64 timestamp = 1;
|
|
string level = 2;
|
|
string message = 3;
|
|
map<string, string> fields = 4;
|
|
}
|
|
|
|
// Commands
|
|
message Command {
|
|
string command_id = 1;
|
|
oneof command {
|
|
ReloadCommand reload = 2;
|
|
RestartCommand restart = 3;
|
|
StopCommand stop = 4;
|
|
GetStatusCommand get_status = 5;
|
|
ValidateConfigCommand validate_config = 6;
|
|
}
|
|
}
|
|
|
|
message ReloadCommand {
|
|
bool graceful = 1;
|
|
}
|
|
|
|
message RestartCommand {
|
|
bool force = 1;
|
|
}
|
|
|
|
message StopCommand {
|
|
bool graceful = 1;
|
|
uint32 timeout_seconds = 2;
|
|
}
|
|
|
|
message GetStatusCommand {}
|
|
|
|
message ValidateConfigCommand {
|
|
string config_content = 1;
|
|
}
|
|
|
|
// Events
|
|
message Event {
|
|
string event_id = 1;
|
|
string event_type = 2;
|
|
int64 timestamp = 3;
|
|
map<string, string> data = 4;
|
|
}
|
|
|
|
// Common messages
|
|
message Ack {
|
|
string message_id = 1;
|
|
bool success = 2;
|
|
string error_message = 3;
|
|
}
|
|
|
|
message Error {
|
|
string code = 1;
|
|
string message = 2;
|
|
map<string, string> details = 3;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## WebSocket API
|
|
|
|
### Connection
|
|
|
|
Connect to WebSocket endpoint with JWT token:
|
|
|
|
```javascript
|
|
const ws = new WebSocket('wss://api.nxmesh.io/v1/events?token={jwt_token}');
|
|
```
|
|
|
|
### Event Types
|
|
|
|
#### Agent Connected
|
|
```json
|
|
{
|
|
"type": "agent.connected",
|
|
"timestamp": "2026-03-02T12:00:00Z",
|
|
"data": {
|
|
"agent_id": "770e8400-e29b-41d4-a716-446655440002",
|
|
"hostname": "web-01.internal",
|
|
"ip_address": "10.0.1.10"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Agent Disconnected
|
|
```json
|
|
{
|
|
"type": "agent.disconnected",
|
|
"timestamp": "2026-03-02T12:05:00Z",
|
|
"data": {
|
|
"agent_id": "770e8400-e29b-41d4-a716-446655440002",
|
|
"reason": "connection_timeout"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Config Applied
|
|
```json
|
|
{
|
|
"type": "config.applied",
|
|
"timestamp": "2026-03-02T12:10:00Z",
|
|
"data": {
|
|
"agent_id": "770e8400-e29b-41d4-a716-446655440002",
|
|
"config_id": "config-123",
|
|
"version": 42,
|
|
"duration_ms": 150,
|
|
"success": true
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Health Alert
|
|
```json
|
|
{
|
|
"type": "health.alert",
|
|
"timestamp": "2026-03-02T12:15:00Z",
|
|
"data": {
|
|
"agent_id": "770e8400-e29b-41d4-a716-446655440002",
|
|
"alert_id": "alert-456",
|
|
"severity": "warning",
|
|
"message": "High CPU usage: 85%",
|
|
"metric": "cpu_percent",
|
|
"value": 85.0
|
|
}
|
|
}
|
|
```
|
|
|
|
### Subscribing to Events
|
|
|
|
Clients can subscribe to specific event types:
|
|
|
|
```json
|
|
{
|
|
"action": "subscribe",
|
|
"events": ["agent.*", "config.*"],
|
|
"filter": {
|
|
"workspace_id": "660e8400-e29b-41d4-a716-446655440001"
|
|
}
|
|
}
|
|
```
|