Files
RelayOps/docs/api.md
2026-06-07 02:32:28 +03:00

13 KiB

API

Purpose

This document defines the MVP REST API for the server panel backend.

Conventions

  • Base path: /api/v1
  • Authentication: Bearer token
  • Response format: JSON
  • Time format: ISO 8601 UTC
  • Errors should return a stable code and human-readable message
  • Error responses also include request_id for log correlation

Authentication

POST /auth/login

Authenticate a user and return access and refresh tokens.

Request:

{
  "username": "admin",
  "password": "strong-password"
}

Response:

{
  "access_token": "jwt-access-token",
  "refresh_token": "jwt-refresh-token",
  "token_type": "bearer",
  "user": {
    "id": 1,
    "username": "admin",
    "role": "admin"
  }
}

POST /auth/refresh

Refresh the access token.

Request:

{
  "refresh_token": "jwt-refresh-token"
}

Response:

{
  "access_token": "new-access-token",
  "token_type": "bearer"
}

POST /auth/logout

Invalidate the current session by bumping the user's token version.

Response:

{
  "success": true
}

Notes:

  • invalidates both the current access token and refresh token family for the user;
  • password or role changes also invalidate older tokens.

GET /auth/me

Return the current authenticated user.

Response:

{
  "id": 1,
  "username": "admin",
  "role": "admin",
  "is_active": true
}

Users

GET /users

Return user list. Admin only.

Response:

[
  {
    "id": 1,
    "username": "admin",
    "role": "admin",
    "is_active": true
  }
]

POST /users

Create a user. Admin only.

Request:

{
  "username": "operator1",
  "password": "strong-password",
  "role": "operator"
}

PATCH /users/{user_id}

Update a user role or active flag. Admin only.

Request:

{
  "role": "viewer",
  "is_active": true
}

Servers

GET /servers

Return all configured servers visible to the current user.

Response:

[
  {
    "id": 1,
    "name": "prod-app-1",
    "host": "10.0.0.10",
    "port": 22,
    "ssh_username": "deploy",
    "environment": "production",
    "is_active": true
  }
]

POST /servers

Create a server definition. Admin only.

Request:

{
  "name": "prod-app-1",
  "host": "10.0.0.10",
  "port": 22,
  "ssh_username": "deploy",
  "connection_type": "ssh",
  "environment": "production",
  "is_active": true
}

GET /servers/{server_id}

Return server details.

Response:

{
  "id": 1,
  "name": "prod-app-1",
  "host": "10.0.0.10",
  "port": 22,
  "ssh_username": "deploy",
  "connection_type": "ssh",
  "environment": "production",
  "is_active": true
}

PATCH /servers/{server_id}

Update server metadata. Admin only.

Request:

{
  "name": "prod-app-main",
  "host": "10.0.0.11",
  "port": 2222,
  "ssh_username": "ops",
  "environment": "staging",
  "is_active": true
}

DELETE /servers/{server_id}

Soft-delete or deactivate a server. Admin only.

Response:

{
  "success": true
}

GET /servers/{server_id}/health

Return basic reachability and health information.

Response:

{
  "server_id": 1,
  "reachable": true,
  "status": "ok",
  "checked_at": "2026-06-07T00:00:00Z"
}

GET /servers/{server_id}/metrics

Return current server metrics.

Notes:

  • currently implemented for ssh servers only;
  • requires ssh_username to be configured on the server record.

Response:

{
  "server_id": 1,
  "cpu_percent": 32.5,
  "memory_percent": 61.2,
  "disk_percent": 48.9,
  "uptime_seconds": 345600,
  "load_average": [0.55, 0.72, 0.80],
  "collected_at": "2026-06-07T00:00:00Z"
}

Managed Services

POST /servers/{server_id}/services

Create a managed service definition for a server. Admin only.

Request:

{
  "name": "nginx",
  "service_type": "systemd",
  "control_enabled": true,
  "log_source": "file:/var/log/nginx/error.log"
}

GET /servers/{server_id}/services

Return all managed services for a server.

Notes:

  • status is resolved at request time;
  • if the remote check fails, status may be unknown with a detail message.

Response:

[
  {
    "id": 1,
    "server_id": 1,
    "name": "nginx",
    "service_type": "systemd",
    "status": "running",
    "control_enabled": true,
    "log_source": null,
    "created_at": "2026-06-07T00:00:00Z",
    "last_checked_at": "2026-06-07T00:00:00Z"
  },
  {
    "id": 2,
    "server_id": 1,
    "name": "app",
    "service_type": "docker",
    "status": "running",
    "control_enabled": true,
    "log_source": null,
    "created_at": "2026-06-07T00:00:00Z",
    "last_checked_at": "2026-06-07T00:00:00Z"
  }
]

GET /servers/{server_id}/services/{service_name}

Return details for a managed service.

Response:

{
  "id": 1,
  "server_id": 1,
  "name": "nginx",
  "service_type": "systemd",
  "status": "running",
  "control_enabled": true,
  "log_source": null,
  "created_at": "2026-06-07T00:00:00Z",
  "last_checked_at": "2026-06-07T00:00:00Z"
}

PATCH /servers/{server_id}/services/{service_name}

Update a managed service definition. Admin only.

Request:

{
  "name": "nginx-edge",
  "service_type": "docker",
  "control_enabled": false,
  "log_source": "file:/var/log/nginx/error.log"
}

POST /servers/{server_id}/services/{service_name}/start

Queue a service start action.

Current implementation note:

  • the system already creates action and audit records;
  • execution is queued and completed by the worker process.

Response:

{
  "id": 101,
  "server_id": 1,
  "service_id": 1,
  "target_type": "service",
  "target_name": "nginx",
  "action": "start",
  "status": "pending",
  "source": "web",
  "requested_by": 1,
  "result_message": null,
  "requested_at": "2026-06-07T00:00:00Z",
  "completed_at": null
}

POST /servers/{server_id}/services/{service_name}/stop

Queue a service stop action.

Response:

{
  "id": 102,
  "status": "pending"
}

POST /servers/{server_id}/services/{service_name}/restart

Queue a service restart action.

Response:

{
  "id": 103,
  "status": "pending"
}

Logs

GET /servers/{server_id}/logs

Return available log sources for the server.

Response:

{
  "server_id": 1,
  "sources": [
    "nginx",
    "app"
  ]
}

GET /servers/{server_id}/logs/{service_name}

Return recent log lines.

Query params:

  • lines: integer, optional, default 100, max 500

Notes:

  • currently implemented for ssh servers only;
  • if log_source is set, it must use the format file:/absolute/path;
  • otherwise logs come from journalctl for systemd services or docker logs for Docker services.

Response:

{
  "server_id": 1,
  "service_name": "nginx",
  "source_type": "file",
  "lines": [
    "2026-06-07T00:00:01Z info service started",
    "2026-06-07T00:00:03Z info ready"
  ],
  "retrieved_at": "2026-06-07T00:00:10Z"
}

Actions

POST /actions

Generic action endpoint if the frontend later uses a unified action form.

Request:

{
  "server_id": 1,
  "target_type": "service",
  "target_name": "nginx",
  "action": "restart"
}

Response:

{
  "action_id": 104,
  "status": "pending"
}

GET /actions

Return recent actions with optional filters.

Suggested query params:

  • server_id
  • status
  • requested_by
  • limit

Response:

[
  {
    "id": 104,
    "server_id": 1,
    "service_id": 1,
    "target_type": "service",
    "target_name": "nginx",
    "action": "restart",
    "status": "success",
    "requested_by": 1,
    "source": "web",
    "requested_at": "2026-06-07T00:00:00Z",
    "completed_at": "2026-06-07T00:00:04Z"
  }
]

GET /actions/{action_id}

Return details for a single action.

Response:

{
  "id": 104,
  "server_id": 1,
  "target_type": "service",
  "target_name": "nginx",
  "action": "restart",
  "status": "success",
  "source": "web",
  "requested_by": 1,
  "result_message": "service restarted successfully",
  "requested_at": "2026-06-07T00:00:00Z",
  "completed_at": "2026-06-07T00:00:04Z"
}

Audit

GET /audit

Return audit records. Admin only by default.

Suggested query params:

  • actor_id
  • target_type
  • action
  • limit

Response:

[
  {
    "id": 1001,
    "actor_id": 1,
    "actor_source": "web",
    "target_type": "service",
    "target_id": "nginx",
    "action": "restart",
    "result": "success",
    "details": {
      "server_id": 1,
      "action_id": 104,
      "message": "service restarted successfully"
    },
    "created_at": "2026-06-07T00:00:04Z"
  }
]

GET /audit/{audit_id}

Return one audit record.

Response:

{
  "id": 1001,
  "actor_id": 1,
  "actor_source": "telegram",
  "target_type": "service",
  "target_id": "nginx",
  "action": "restart",
  "result": "success",
  "details": {
    "server_id": 1
  },
  "created_at": "2026-06-07T00:00:04Z"
}

Telegram

GET /telegram/status

Return backend Telegram integration status. Admin only.

Response:

{
  "enabled": true,
  "mode": "polling",
  "linked_users_count": 2
}

POST /telegram/link

Issue a one-time Telegram link code for the authenticated user.

Response:

{
  "link_code": "ABC123DEF456",
  "expires_at": "2026-06-07T00:10:00Z"
}

GET /telegram/link/me

Return the current user's Telegram link if one exists.

Response:

{
  "id": 1,
  "user_id": 1,
  "telegram_user_id": "123456789",
  "chat_id": "123456789",
  "linked_at": "2026-06-07T00:05:00Z",
  "created_at": "2026-06-07T00:00:00Z"
}

If no link exists yet, the endpoint returns null.

Remove a Telegram link.

Response:

{
  "success": true
}

POST /telegram/test-message

Send a test notification to the current user's linked Telegram chat.

Response:

{
  "success": true
}

Internal Telegram Bot Endpoints

These endpoints are intended for the bot process and require X-Telegram-Bot-Secret.

POST /telegram/bot/link/complete

Complete Telegram linking by consuming a previously issued link code.

Request:

{
  "link_code": "ABC123DEF456",
  "telegram_user_id": "123456789",
  "chat_id": "123456789"
}

Response:

{
  "id": 1,
  "user_id": 1,
  "telegram_user_id": "123456789",
  "chat_id": "123456789",
  "linked_at": "2026-06-07T00:05:00Z",
  "created_at": "2026-06-07T00:00:00Z"
}

POST /telegram/bot/status

Return server health data for the linked Telegram user.

Request:

{
  "telegram_user_id": "123456789"
}

Response:

{
  "username": "admin",
  "role": "admin",
  "servers": [
    {
      "name": "prod-app-1",
      "environment": "production",
      "host": "10.0.0.10",
      "status": "ok",
      "reachable": true,
      "checked_at": "2026-06-07T00:00:00Z",
      "detail": null
    }
  ]
}

POST /telegram/bot/services

Return managed services visible to the linked Telegram user.

Request:

{
  "telegram_user_id": "123456789",
  "server_name": "prod-app-1"
}

Response:

{
  "username": "admin",
  "role": "admin",
  "services": [
    {
      "server_name": "prod-app-1",
      "service_name": "nginx",
      "service_type": "systemd",
      "status": "running",
      "detail": null
    }
  ]
}

POST /telegram/bot/restart

Queue a restart action for a linked Telegram user with sufficient permissions.

Request:

{
  "telegram_user_id": "123456789",
  "server_name": "prod-app-1",
  "service_name": "nginx"
}

Response:

{
  "id": 103,
  "status": "pending"
}

POST /telegram/webhook

Webhook endpoint if webhook mode is used.

Response:

{
  "success": true
}

Common Error Examples

401 Unauthorized

{
  "code": "unauthorized",
  "message": "Authentication required",
  "request_id": "5b2d4a5d3b8745028b89f927c3ef98f8"
}

403 Forbidden

{
  "code": "forbidden",
  "message": "Insufficient permissions",
  "request_id": "5b2d4a5d3b8745028b89f927c3ef98f8"
}

404 Not Found

{
  "code": "not_found",
  "message": "Requested resource was not found",
  "request_id": "5b2d4a5d3b8745028b89f927c3ef98f8"
}

409 Conflict

{
  "code": "action_in_progress",
  "message": "A similar action is already running",
  "request_id": "5b2d4a5d3b8745028b89f927c3ef98f8"
}

422 Validation Error

{
  "code": "validation_error",
  "message": "Invalid request payload",
  "request_id": "5b2d4a5d3b8745028b89f927c3ef98f8"
}

Minimal MVP Endpoint Set

If you want to keep the first implementation extremely small, the minimum useful set is:

  • POST /auth/login
  • GET /auth/me
  • GET /servers
  • POST /servers
  • GET /servers/{server_id}/health
  • GET /servers/{server_id}/metrics
  • GET /servers/{server_id}/services
  • POST /servers/{server_id}/services/{service_name}/restart
  • GET /servers/{server_id}/logs/{service_name}
  • GET /actions/{action_id}
  • GET /audit
  • POST /telegram/test-message