Bedrud Documentation

The Bedrud server is a Go application that provides the REST API, serves the embedded web frontend, and manages the LiveKit media server.

Technology Stack

TechnologyPurpose
Go 1.24Core language
Fiber v2Web framework (Express-like)
GORMORM for SQLite and PostgreSQL
LiveKit Protocol SDKWebRTC room and token management
ZerologStructured JSON logging
GothMulti-provider OAuth2
go-passkeysFIDO2/WebAuthn support
golang-jwtJWT token creation and validation
gocronBackground job scheduling
Swagger (swaggo)API documentation generation

Directory Structure

server/
├── cmd/
│   ├── server/main.go        # Development entry point
│   └── bedrud/main.go        # Production entry point (with install/livekit flags)
├── internal/
│   ├── auth/                  # Authentication services
│   │   ├── auth.go            # Core auth service (register, login, OAuth)
│   │   ├── jwt.go             # JWT token creation and validation
│   │   └── session_store.go   # Gorilla session store for OAuth state
│   ├── database/              # Database initialization and migrations
│   ├── handlers/              # HTTP request handlers (controller layer)
│   │   ├── auth_handler.go    # Auth endpoints
│   │   ├── recording_handler.go # Recording start/stop/list/get
│   │   ├── room.go            # Room endpoints
│   │   └── users.go           # User management endpoints
│   ├── middleware/             # Fiber middleware
│   │   ├── auth.go            # JWT validation, permission checks
│   │   └── recordings_enabled.go # Recordings sys-setting gate
│   ├── models/                # GORM models (database schemas)
│   │   ├── user.go            # User model
│   │   ├── webhook.go         # Webhook model
│   │   ├── recording.go       # Recording model
│   │   ├── room.go            # Room model
│   │   └── passkey.go         # Passkey model
│   ├── repository/            # Data access layer (SQL via GORM)
│   │   ├── user_repository.go
│   │   ├── webhook_repository.go
│   │   ├── recording_repository.go
│   │   ├── room_repository.go
│   │   └── passkey_repository.go
│   ├── services/               # Business logic layer
│   │   ├── recording_service.go # Recording gate chain + LK egress
│   │   └── room_cleanup.go     # Room deletion/suspend cascade
│   ├── livekit/               # Embedded LiveKit server management
│   ├── scheduler/             # Background job scheduling
│   └── utils/                 # TLS and other utilities
├── frontend/                  # Embedded web frontend (populated at build time)
├── config.yaml                # Development configuration
├── livekit.yaml               # Development LiveKit configuration
├── go.mod
└── go.sum

Layered Architecture

The server follows a layered architecture:

flowchart TB
    HTTP[HTTP Request] */} Middleware
    Middleware["Middleware<br/>JWT validation, CORS, logging"] */} Handlers
    Handlers["Handlers<br/>Parse requests, call services, format responses"] */} Services
    Services["Services<br/>Business logic (auth, room management)"] */} Repository
    Repository["Repository<br/>Database queries via GORM"] */} Database
    Database["Database<br/>SQLite (dev) or PostgreSQL (production)"]

Key Patterns

Embedded Frontend

The web frontend is compiled to static files and embedded into the Go binary using //go:embed:

//go:embed frontend/*
var frontendFS embed.FS

At build time, bun run build:embed SSR pre-renders the React app and copies dist/client/ into server/frontend/. The Go compiler then bundles it into the binary. The Fiber server serves these files for any non-API route.

Authentification JWT

Le middleware extrait le JWT de l’en-tête Authorization: Bearer <token> (repli cookie en lecture), le valide et attache le contexte utilisateur à la requête. Les routes protégées utilisent RequireAccess pour les rôles.

  • Les jetons à usage (email_verify, password_reset) partagent la clé de signature mais ne peuvent pas servir de jeton d’accès sur les routes Protected.
  • Les mutations (POST/PUT/PATCH/DELETE authentifiées) exigent un en-tête Bearer via RequireBearerForMutations — les POST cookie seuls cross-site sont rejetés (défense CSRF).
  • La révocation des jetons d’accès (déconnexion / changement de mot de passe) est persistée en base et survit aux redémarrages et déploiements multi-instances.
  • Les listes d’identités de présence de salle exigent une authentification ; les salles publiques peuvent exposer ?countOnly=1 (compte seul, sans identités).

LiveKit Token Generation

When a user joins a room, the server:

  1. Validates room permissions
  2. Creates a LiveKit access token signed with the API secret
  3. Returns the token to the client
  4. The client connects directly to LiveKit using the token

Enregistrements et LiveKit Egress

Les handlers de file process_recording et recording_delete sont enregistrés sur le worker. Les webhooks LiveKit egress_ended enfilent process_recording (téléchargement → stockage → marquer terminé → webhook optionnel recording.completed).

🚧 Les routes HTTP d’enregistrement (start/stop/list via l’API) restent // TODO oncoming feature sur la table de routes de production — ne vous fiez pas aux endpoints REST d’enregistrement publics tant qu’ils ne sont pas livrés. Les clés YAML sous recording: configurent le stockage du pipeline.

Webhooks

Webhook system allows superadmins to register HTTP callbacks for real-time events. Active events: room.created, room.ended, participant.joined, and ping (test). recording.completed is reserved for a planned feature. Delivery headers: X-Bedrud-Signature, X-Bedrud-Event, X-Bedrud-Timestamp.

  • Storage: Webhook model in database, CRUD via WebhookRepository
  • Dispatch: Background job (dispatch_webhook) sends HMAC-SHA256 signed POST requests with 10s timeout
  • Secrets: Per-webhook HMAC secret, rotatable via admin panel
  • See the Webhooks API for endpoint details.

Swagger Documentation

API documentation is auto-generated from code annotations using swaggo. In development, it’s available at /api/swagger/.

Database

SQLite (Default)

For development and small deployments, Bedrud uses SQLite. The database file is stored at the configured database.path (default: data.db).

PostgreSQL

For production with higher concurrency requirements, configure a PostgreSQL connection string. GORM handles both dialects transparently.

Migrations

GORM auto-migrates the schema on startup based on the model structs. The models are defined in internal/models/.

Background Jobs

The gocron scheduler runs periodic tasks such as:

  • Cleaning up expired refresh tokens
  • Removing stale room participants

See also