Skip to documentation
OrbitMeshDocs
Browse documentation
Docs/Engineering Specs

ENGINEERING SPECS

Development Framework Specification

This document defines the implementation framework and engineering conventions for OrbitMesh.
View source

1. Goal

This document defines the implementation framework and engineering conventions for OrbitMesh.

Selected stack:

Control Plane: Go + Kratos
Install Service: Cloudflare Workers
Console: Next.js static export on Cloudflare Pages
Edge Runtime: Go standalone binary
Database: PostgreSQL default, MySQL supported
Cache: Redis
Data Plane Runtime: sing-box

2. Architecture Boundary

OrbitMesh is implemented as a cloud-native control-plane system.

The boundary is:

  • Control Plane owns product state, APIs, reconciliation, compilation, policy, health, billing, and audit.
  • Install Service owns the public install.orbitmesh.dev entrypoint and serves installer scripts.
  • Console owns presentation, login pages, forms, charts, and user workflows.
  • Edge Runtime owns node-side identity, sync loops, runtime application, rollback, probes, and local supervision.
  • Data Plane Runtime owns packet forwarding and protocol-specific behavior.

Do not move Control Plane responsibilities into Next.js route handlers.

Do not make the Install Service a Control Plane API. It is a thin Cloudflare Workers edge entrypoint for install scripts.

3. Control Plane Framework

Use Go + Kratos for the Control Plane.

Required conventions:

  • API definitions are protobuf-first.
  • HTTP APIs are exposed through Kratos HTTP transport.
  • gRPC APIs can be enabled for internal or future streaming use cases.
  • Business logic lives in internal/biz.
  • Transport handlers live in internal/service.
  • Database and Redis implementations live in internal/data.
  • HTTP/gRPC bootstrap lives in internal/server.
  • Runtime-specific compilation lives in internal/compiler.
  • Middleware is registered in Kratos server setup, not inside business use cases.

The MVP is a modular monolith. Do not split into microservices before the core lifecycle is stable.

4. Kratos Project Layout

services/control-plane/
  api/
    orbitmesh/
      v1/
        auth.proto
        tenant.proto
        node.proto
        capability.proto
        runtime.proto
        endpoint.proto
        deployment.proto
        desired_state.proto
        traffic_policy.proto
        subscription.proto
        health.proto
        edge_runtime.proto
  cmd/
    orbitmesh-api/
      main.go
  internal/
    service/
    biz/
      auth/
      tenant/
      node/
      capability/
      runtime/
      endpoint/
      deployment/
      desiredstate/
      trafficpolicy/
      subscription/
      health/
      billing/
    data/
      postgres/
      redis/
    server/
      http.go
      grpc.go
    conf/
    middleware/
    compiler/
    event/
  ent/
    schema/
  configs/
  Dockerfile

Layer rules:

  • service converts transport DTOs to use-case inputs and maps errors.
  • biz owns resource lifecycle, validation, state transitions, and authorization decisions.
  • data owns SQL, Redis, transactions, and repository implementations.
  • compiler maps DesiredState to RuntimeConfiguration; it must not call HTTP handlers.
  • event records domain events and can later back async workers.

5. API Design

API groups:

  • AuthService
  • TenantService
  • NodeService
  • CapabilityService
  • RuntimeService
  • EndpointService
  • DeploymentService
  • DesiredStateService
  • TrafficPolicyService
  • SubscriptionService
  • HealthService
  • EdgeRuntimeService

HTTP prefix:

/api/v1

JSON conventions:

  • Use snake_case field names to match protobuf source names and existing API examples.
  • Use UTC RFC3339 timestamps.
  • Use string IDs with resource prefixes only when the generator or model layer supports them consistently.
  • Use request_id in every error response.
  • Use Idempotency-Key for mutating Tenant Console API requests.

Kratos HTTP handlers should use protobuf annotations for routing and generate OpenAPI from the same contract where possible.

Detailed API and backend behavior contracts:

  • specs/engineering-scaffold.md: repository bootstrap, tools, Make targets, Ent schema, and generated code rules.
  • specs/proto-contracts.md: protobuf services, messages, errors, and compatibility rules.
  • specs/state-machines.md: resource states and legal transitions.
  • specs/use-case-transactions.md: transactional behavior for core use cases.

6. Error Model

Use Kratos errors with stable business reasons.

Error response shape:

{
  "request_id": "req_xxx",
  "error": {
    "code": "DEPLOYMENT_TOKEN_EXPIRED",
    "message": "deployment token expired"
  }
}

Rules:

  • code is stable and uppercase.
  • message is safe to show to users.
  • Internal errors are logged with request_id and returned as INTERNAL.
  • Edge Runtime authentication failures return 401.
  • Tenant authorization failures return 403.
  • Missing resources return 404.
  • Invalid resource state returns 409.
  • Validation failures return 400.

7. Persistence

Use an Ent-managed SQL database as source of truth. PostgreSQL with pgx is the default. MySQL 8 is supported through ORBITMESH_DATABASE_DRIVER=mysql.

Recommended implementation:

  • database/sql with pgx or mysql driver mapping.
  • MySQL DSNs include parseTime=true, charset=utf8mb4, and UTC time handling.
  • Ent schema in services/control-plane/ent/schema.
  • Ent schema creation during Control Plane startup through Schema.Create.
  • Repository interfaces defined in internal/biz.
  • Repository implementations in internal/data.
  • Redis for nonce, rate limit, short-lived cache, and distributed locks.

Rules:

  • Database writes that change Node registration must run in a single transaction.
  • Deployment token plaintext is returned once and only token_hash is stored.
  • Console must not connect directly to the Control Plane database.
  • Prisma is not used as the source of truth for OrbitMesh backend domain logic.

8. Control Plane Middleware

Required middleware:

  • request ID.
  • structured logging.
  • panic recovery.
  • authentication.
  • tenant context.
  • permission check.
  • rate limit.
  • idempotency.
  • Edge Runtime request signing verification.
  • unified error mapping.

Headers:

X-Request-Id
X-OrbitMesh-Tenant
Idempotency-Key
X-OrbitMesh-Node-Id
X-OrbitMesh-Timestamp
X-OrbitMesh-Nonce
X-OrbitMesh-Signature

9. Console Framework

Use Next.js App Router with static export and deploy to Cloudflare Pages.

Recommended stack:

Next.js App Router
TypeScript
lucide-react
Cloudflare Pages

The Tenant Console should follow this deployment shape:

  • apps/console owns tenant-console workflows.
  • apps/platform owns platform-operator workflows.
  • apps/web is reserved for the marketing website.
  • component-driven UI.
  • Cloudflare Pages deployment.
  • typed environment variables.
  • reusable API client layer.

OrbitMesh must differ from that reference in one important way:

  • Core backend APIs stay in Go Kratos.
  • Next.js route handlers are allowed only for frontend-owned utilities such as auth callbacks or image/OG generation.
  • Next.js route handlers must not implement Node lifecycle, DesiredState, Edge Runtime sync, billing entitlement, or health aggregation.
  • Platform operator workflows such as plan catalog management, tenant plan assignment, managed resource pools, global runtime catalog administration, and system certificate/DNS operations must be implemented in apps/platform, not apps/console.

Suggested layout:

apps/console/
  app/
    (console)/
      nodes/
      nodes/enroll/
      traffic/subscriptions/
      traffic/policies/
      traffic/usage/
      network/endpoints/
      network/domains/
      runtime-catalog/
      settings/
    login/
  components/
    console/
    ui/
  lib/
    api-client.ts
    auth.ts
    env.ts
  hooks/
  public/

Platform Console layout:

apps/platform/
  app/
    plans/
    tenants/
    managed-nodes/
    runtime-catalog/
    subscription-targets/
    domains/
    certificates/
    audit/
  components/
  lib/
  hooks/
  public/

10. Tenant Console API Client

The Tenant Console must call the Go Control Plane API.

Rules:

  • API calls go through apps/console/app/lib/api-client.ts.
  • Do not scatter raw fetch calls across pages.
  • Server components may fetch read-only data.
  • Client components may call mutation helpers for user actions.
  • Auth/session state is mapped to Control Plane credentials or session tokens.
  • Tenant context is sent explicitly through X-OrbitMesh-Tenant.
  • API errors are displayed from the stable error code and user-safe message.
  • Mutation feedback must use semantic presentation consistently: success is green, validation/API errors are red, warnings are amber, and informational notices use the neutral brand tone.
  • Success and error messages must not share a generic error-styled notice component.
  • Console API requests must use the typed OpenAPI client from apps/console/app/lib/api-client.ts.
  • New Console API response and request types should come from the generated OpenAPI types instead of hand-written local interfaces.
  • Hand-written Console types are allowed only for view models, component state, and derived UI data that do not directly mirror API payloads.

10.1 Tenant Console OpenAPI Client Generation

The Tenant Console uses a generated TypeScript SDK from the Control Plane OpenAPI document. Application code calls generated SDK functions and uses apps/console/app/lib/api-client.ts only for runtime client configuration and error normalization.

Source contract:

services/control-plane/api/orbitmesh/v1/*.proto

Generated Control Plane artifacts:

services/control-plane/api/openapi.yaml
services/control-plane/api/orbitmesh/v1/*.pb.go
services/control-plane/api/orbitmesh/v1/*_grpc.pb.go
services/control-plane/api/orbitmesh/v1/*_http.pb.go

Generated Console artifact:

apps/console/app/generated/client/

Generated Platform Console artifact:

apps/platform/app/generated/client/

Generation flow:

make proto
make api-client

The app-specific generation commands are:

pnpm --filter @orbitmesh/console generate:openapi
pnpm --filter @orbitmesh/platform generate:openapi

Field naming rules:

  • OpenAPI generation must use naming=proto.
  • OpenAPI generation must use enum_type=string so proto enum fields are exposed as string enum values in TypeScript SDK types.
  • API schema fields, query parameters, and path parameters are snake_case.
  • Console code must treat generated OpenAPI types as snake_case.
  • Do not introduce camelCase aliases in generated client types.
  • If a component needs camelCase for local derived state, map it explicitly at the feature boundary.

Typed API usage:

import { subscriptionServiceRotateSubscription } from "./generated/client";
import { apiClient, apiData } from "./lib/api-client";

const client = apiClient({ apiURL, token, tenantId });
const response = await apiData(
  subscriptionServiceRotateSubscription({
    client,
    path: { id },
    body: { id },
  }),
  { operation: "SubscriptionService_RotateSubscription", token },
);

Client rules:

  • Use generated SDK functions from apps/console/app/generated/client for endpoints present in OpenAPI.
  • Do not call OpenAPI paths directly from feature code.
  • Put path and query parameters under path and query.
  • Put request payloads under body; non-trivial payloads should use generated request types from apps/console/app/generated/client/types.gen.ts.
  • Console-facing Control Plane APIs must be present in OpenAPI. /healthz and /readyz remain probe-only endpoints and must not be called from Console feature code.
  • Do not add new hand-written API mirror types.
  • API-backed console domain types should be derived with NormalizedOpenAPI<...> in apps/console/app/types/console.ts; keep form state, row models, and view models as local UI types.

Regeneration is required when proto contracts change. A generated artifact change is expected for:

  • services/control-plane/api/openapi.yaml
  • docs/api/openapi.yaml
  • apps/console/app/generated/client/

CI should fail if OpenAPI or Console generated types are stale after proto changes.

Environment variables:

NEXT_PUBLIC_ORBITMESH_API_URL
NEXTAUTH_URL
NEXTAUTH_SECRET

11. Domain Plan

OrbitMesh uses orbitmesh.dev as the only public domain family for this project during MVP and early production.

Reserved domain boundaries:

orbitmesh.cloud  reserved for the separate virtual network SaaS product
orbitmesh.host   reserved for the separate virtual network SaaS product
orbitmesh.cc     reserved for the separate virtual network SaaS product or defensive redirect
orbitmesh.app    reserved for applications built with OrbitMesh, not this platform surface

Required orbitmesh.dev allocation:

orbitmesh.dev              marketing site and product entry
docs.orbitmesh.dev         documentation
console.orbitmesh.dev      Tenant Console
platform.orbitmesh.dev     Platform Console
api.orbitmesh.dev          Control Plane API
auth.orbitmesh.dev         authentication callbacks and identity surface
install.orbitmesh.dev      public installer entrypoint
downloads.orbitmesh.dev    Edge Runtime artifact CDN prefix
status.orbitmesh.dev       public status page

Network-facing names should stay under delegated edge.orbitmesh.dev subzones and must be modeled by resource instance. A tenant can own multiple Traffic Entry endpoints, Gateway endpoints, and Tunnel endpoints.

<node-id>.node.edge.orbitmesh.dev

<endpoint-id>.traffic.edge.orbitmesh.dev
<tenant-slug>--<endpoint-slug>.traffic.edge.orbitmesh.dev

<endpoint-id>.gateway.edge.orbitmesh.dev
<endpoint-id>.tunnel.edge.orbitmesh.dev

Traffic Entry names are externally reachable client access endpoints. User-owned domains should CNAME to the system endpoint name.

TLS certificate ownership is split into two scopes:

system certificate   platform-managed certificate for system endpoint names
tenant certificate   tenant-managed or tenant-requested certificate for custom domains

System-level ACME automation owns default endpoint names and renews certificates without tenant action.

Tenant-level ACME automation validates custom domain ownership before issuance. Tenant custom domains should CNAME to the system endpoint name. DNS-01 may be added later for wildcard or provider-integrated issuance.

Control Plane stores certificate metadata, status, expiration, issuer, DNS names, and secret references. It must not store private keys as plaintext database fields.

Implementation boundaries:

  • Domain allocation, ownership validation, Certificate metadata, ACME order state, and Endpoint readiness live in Control Plane.
  • DNS changes must go through a provider abstraction. The first production provider is Cloudflare for delegated edge.orbitmesh.dev zones.
  • Certificate private keys must live behind secret_ref, local Node materialization, Kubernetes Secret, or an external secret manager. Do not add plaintext key columns.
  • Runtime adapters consume domain, certificate_ref, and resolved local certificate paths. They must not implement their own tenant certificate lifecycle.
  • Subscription distribution reads ready Endpoint records only. It must not create ACME orders or publish DNS records.

Rules:

  • Do not use orbitmesh.cloud, orbitmesh.host, orbitmesh.cc, or orbitmesh.app for this project's control plane, tenant console, platform console, installer, or data plane.
  • Keep one canonical SEO and product entry domain: orbitmesh.dev.
  • All public endpoints must use HTTPS.
  • ORBITMESH_PUBLIC_URL should use https://api.orbitmesh.dev in production.
  • NEXT_PUBLIC_ORBITMESH_API_URL should use https://api.orbitmesh.dev in production.
  • ORBITMESH_INSTALL_ENDPOINT_URL should use https://install.orbitmesh.dev in production.
  • ORBITMESH_EDGE_RUNTIME_DOWNLOAD_PREFIX should use https://downloads.orbitmesh.dev/edge-runtime/latest in production.
  • Endpoint DNS names must not be allocated only by tenant. They must include endpoint or node identity.
  • Local development may continue to use localhost, 127.0.0.1, and Control Plane /downloads fallback paths.

12. Edge Runtime Framework

Edge Runtime is a Go standalone program.

Repository package path:

edge-runtime/

Command names:

orbitmesh
orbitmeshd

It owns:

  • registration.
  • heartbeat.
  • desired state sync.
  • runtime config apply.
  • sing-box adapter.
  • health probe.
  • rollback.
  • local state persistence.

It may use generated API client code. It must not import Kratos server framework.

13. Edge Runtime Local Conventions

Local paths:

/usr/local/bin/orbitmesh
/usr/local/bin/orbitmeshd
/etc/orbitmesh/edge-runtime.yaml
/etc/orbitmesh/node.json
/etc/orbitmesh/secrets.json
/var/lib/orbitmesh/edge-runtime/desired-state.json
/var/lib/orbitmesh/edge-runtime/runtime-configuration.json
/var/lib/orbitmesh/edge-runtime/runtime-configuration.last-good.json
/var/log/orbitmesh/edge-runtime.log
/etc/systemd/system/orbitmeshd.service

Runtime rules:

  • Control Plane is pulled, not pushed over SSH.
  • Last known good config is retained locally.
  • Runtime config writes are atomic.
  • runtime adapters run their configured validation command before reload.
  • orbitmeshd installs runtime dependencies from Control Plane runtime install profiles after pulling desired state; the public installer only installs OrbitMesh binaries and starts the daemon.
  • failed apply results are reported with a safe error.
  • logs must redact deployment tokens, device private keys, and runtime passwords.

14. Development Commands

Recommended local flow:

docker compose up -d postgres redis
go run ./services/control-plane/cmd/orbitmesh-api
go run ./edge-runtime/cmd/orbitmesh --help
cd apps/console && pnpm run dev

CI gates:

go test ./...
go vet ./...
openapi validation
Ent schema generation check
cd apps/console && pnpm run lint
cd apps/console && pnpm run type-check

Recommended top-level Make targets:

make proto
make openapi
make api-client
make migrate
make test
make dev-control-plane
make dev-edge-runtime
make dev-console
make docker-up
make docker-down

Target ownership:

  • make proto: generate Kratos HTTP/gRPC code from proto files.
  • make openapi: generate or validate OpenAPI from proto contracts.
  • make api-client: generate Tenant Console OpenAPI TypeScript types and Edge Runtime clients.
  • make migrate: apply Ent schema migration to the configured local SQL database.
  • make test: run Control Plane and Edge Runtime tests.
  • make dev-control-plane: run local Kratos API.
  • make dev-edge-runtime: run local Edge Runtime with fake adapter or --help.
  • make dev-console: run apps/console locally.
  • make docker-up: start PostgreSQL, Redis, and optional Control Plane.
  • make docker-down: stop local dependencies.

15. Testing Rules

Control Plane tests must cover:

  • DeploymentToken one-time use.
  • Node registration transaction.
  • Edge Runtime request signing and replay nonce.
  • DesiredState versioning.
  • TrafficPolicy matching.
  • tenant isolation.
  • Subscription token revoke.

Edge Runtime tests must cover:

  • request signing client.
  • local identity loading.
  • desired state version comparison.
  • runtime config validate/apply.
  • rollback.
  • redaction.

Tenant Console tests must cover:

  • API client error mapping.
  • tenant context propagation.
  • form validation for deployment token creation.
  • node list/status rendering.

16. Deployment Model

MVP deployment:

Cloudflare Pages
  apps/console

VPS or container host
  services/control-plane
  PostgreSQL
  Redis

Customer or managed node host
  orbitmesh
  orbitmeshd
  sing-box

Later:

  • Kubernetes deployment for Control Plane.
  • managed node pools.
  • private enterprise deployment.

17. Non-Goals

Do not implement these in MVP:

  • microservice split.
  • Control Plane APIs in Next.js route handlers.
  • direct database access from Tenant Console.
  • RuntimeConfiguration as product source of truth.
  • Kubernetes CRD implementation.
  • multi-runtime abstraction beyond the sing-box adapter interface.
OrbitMesh DocumentationContent follows the repository's main branch.