Files
galaxy-game/backend/docs/examples.md
T
2026-05-06 10:14:55 +03:00

3.5 KiB

Configuration and Contract Examples

Example values that complement ../README.md §4 and the OpenAPI contract.

Local .env

# HTTP and gRPC listeners
BACKEND_HTTP_LISTEN_ADDR=:8080
BACKEND_GRPC_PUSH_LISTEN_ADDR=:8081

# Postgres
BACKEND_POSTGRES_DSN=postgres://galaxy:galaxy@localhost:5432/galaxy_backend?sslmode=disable&search_path=backend

# SMTP relay (mailpit by default for dev)
BACKEND_SMTP_HOST=localhost
BACKEND_SMTP_PORT=1025
BACKEND_SMTP_FROM=galaxy-backend@galaxy.test
BACKEND_SMTP_TLS_MODE=none

# Docker
BACKEND_DOCKER_HOST=unix:///var/run/docker.sock
BACKEND_DOCKER_NETWORK=galaxy-dev

# Game engine
BACKEND_GAME_STATE_ROOT=/var/lib/galaxy-game

# Admin bootstrap
BACKEND_ADMIN_BOOTSTRAP_USER=bootstrap
BACKEND_ADMIN_BOOTSTRAP_PASSWORD=change-me-immediately

# GeoLite2
BACKEND_GEOIP_DB_PATH=/var/lib/galaxy/geoip.mmdb

# Telemetry (stdout for dev)
BACKEND_OTEL_TRACES_EXPORTER=stdout
BACKEND_OTEL_METRICS_EXPORTER=stdout

The above is enough for go run ./backend/cmd/backend to boot locally. Required-but-empty admin variables can be set to bootstrap and any non-empty password; rotate immediately after first sign-in.

Public REST examples

POST /api/v1/public/auth/send-email-code

POST /api/v1/public/auth/send-email-code HTTP/1.1
Host: backend.internal
Content-Type: application/json
Accept-Language: en-US

{"email": "pilot@example.com"}
HTTP/1.1 200 OK
Content-Type: application/json

{"challenge_id": "9c8c47f0-3a9a-4f1d-8b7d-2bfca6c6a431"}

The Accept-Language header is captured as preferred_language for the new account; the body schema rejects unknown fields, so locale must travel through the header.

POST /api/v1/public/auth/confirm-email-code

POST /api/v1/public/auth/confirm-email-code HTTP/1.1
Host: backend.internal
Content-Type: application/json

{
  "challenge_id": "9c8c47f0-3a9a-4f1d-8b7d-2bfca6c6a431",
  "code": "123456",
  "client_public_key": "<base64 raw 32-byte Ed25519>",
  "time_zone": "Europe/Berlin"
}
HTTP/1.1 200 OK
Content-Type: application/json

{"device_session_id": "5e7ae3e6-3f4f-4d59-9b9b-2f2c3d2e0a91"}

Internal REST examples (gateway-only)

GET /api/v1/internal/sessions/5e7ae3e6-3f4f-4d59-9b9b-2f2c3d2e0a91 HTTP/1.1
Host: backend.internal
HTTP/1.1 200 OK
Content-Type: application/json

{
  "device_session_id": "5e7ae3e6-...",
  "user_id": "f3a17a32-...",
  "client_public_key": "<base64>",
  "status": "active"
}
POST /api/v1/internal/sessions/5e7ae3e6-.../revoke HTTP/1.1
Host: backend.internal

Admin REST examples

GET /api/v1/admin/mail/deliveries?page=1&page_size=10 HTTP/1.1
Host: backend.internal
Authorization: Basic <base64 of bootstrap:secret>
HTTP/1.1 200 OK
Content-Type: application/json

{
  "items": [
    {
      "delivery_id": "...",
      "template_id": "auth.login_code",
      "status": "sent",
      "attempts": 1,
      "next_attempt_at": null,
      "created_at": "2026-05-05T06:34:46Z"
    }
  ],
  "total": 1
}

Resend on a sent row returns 409 Conflict:

POST /api/v1/admin/mail/deliveries/{id}/resend HTTP/1.1
Authorization: Basic ...
HTTP/1.1 409 Conflict
Content-Type: application/json

{"error": {"code": "conflict", "message": "delivery already sent"}}

Standard error envelope

Every error response across the four route groups uses:

{"error": {"code": "<machine_readable>", "message": "<human_readable>"}}

The closed set of code values lives in components/schemas/ErrorBody of ../openapi.yaml.