Map of the server/ directory and its contents.
Project Roadmap & Tree
The server/ directory contains the Go backend and embedded LiveKit media server. The apps/ directory contains the client applications.
bedrud/
├── apps/ # Client Applications
│ ├── web/ # React Frontend (TanStack Start)
│ ├── android/ # Native Android Application
│ └── ios/ # Native iOS Application
├── server/ # Go Backend (The "Appliance")
│ ├── cmd/ # CLI Entry points (run, install)
│ ├── internal/ # Private application code
│ │ ├── auth/ # JWT, Passkeys, OAuth logic
│ │ ├── handlers/ # HTTP Controllers
│ │ ├── models/ # Database Schemas
│ │ ├── repository/ # GORM Data Access Layer
│ │ └── livekit/ # Media Server Management
│ ├── frontend/ # (Generated) Compiled web assets
│ ├── config.yaml # Configuration template
│ └── Makefile # Build & Deploy automation
└── docs/ # System Documentation (MkDocs)Directory Map
/cmd/bedrud
main.go: The entry point of the application. It handles CLI commands likerun,install, andlivekit.
/config
config.go: Defines theConfigstruct and loads settings fromconfig.yamlor Environment Variables.livekit.yaml: Default configuration for the embedded LiveKit server.
/internal
/auth: contains logic for JWT generation, OAuth providers, and Passkey (WebAuthn) registration/login./database: manages the connection to SQLite or PostgreSQL and runs migrations./handlers: Fiber HTTP handlers. This is where you find the logic for each API endpoint (e.g.,auth_handler.go,room_handler.go)./models: GORM database models. These files define the tables in your database./repository: The “Data Access Layer”. Handlers call repositories instead of writing DB queries directly, keeping handler logic clean./livekit: Integration with the LiveKit Go SDK. Manages room creation and generates “Join Tokens” for participants./middleware: Custom Fiber middleware for authentication checks, logging, and CORS./server: The glue code that brings everything together. It initializes the database, repositories, and starts the Fiber server./install: Logic for thebedrud installcommand which automates systemd and TLS setup on Linux./scheduler: Background tasks (if any)./utils: Small helper functions (e.g., password hashing, random strings).
/migrations
- contains SQL or Go files for database schema updates.
/docs (within server)
- contains Swagger/OpenAPI documentation files (generated by
swag).
Technical Deep Dive
1. Binary Embedding (The “Trick”)
Bedrud uses the //go:embed directive to bundle files into the compiled binary.
- Frontend: The React
dist/client/folder (plus a pre-renderedindex.html) is embedded inserver/ui.go. Static files are served directly from memory using Fiber’sfilesystemmiddleware. - LiveKit Server: The pre-compiled
livekit-serverexecutable is embedded ininternal/livekit/bin/. At runtime, Bedrud extracts it to/tmp/bedrud-livekit-serverand launches it as a background process (internal/livekit/server.go).
2. LiveKit Reverse Proxy
To avoid opening multiple ports (signaling, API, etc.), Bedrud routes all LiveKit signaling traffic through its main HTTP(S) port.
- Any request starting with
/livekitis intercepted ininternal/server/server.go. - A Reverse Proxy (using
httputil.NewSingleHostReverseProxy) forwards these requests to the internal LiveKit instance (usually running on127.0.0.1:7880). - The proxy strips the
/livekitprefix before forwarding, allowing LiveKit to function as if it were the root application.
3. Middleware Context & Locals
The backend uses Fiber’s .Locals to pass data between middleware and handlers.
- Auth Middleware (
internal/middleware/auth.go): Validates the JWT and stores theClaimsobject inc.Locals("user"). - Handlers: Can access the current user’s ID and permissions using:
claims := c.Locals("user").(*auth.Claims) userID := claims.UserID
4. Configuration Overrides
While Bedrud uses a config.yaml file, almost every setting can be overridden using Environment Variables. This is essential for Docker and CI/CD environments.
| Variable | Description |
|---|---|
SERVER_PORT | The port the backend listens on (default: 8090). |
SERVER_ENABLE_TLS | Boolean (true/false) to enable HTTPS. |
SERVER_DOMAIN | Your production domain (used for ACME and Passkey RP ID). |
DB_TYPE | sqlite or postgres. |
DB_PATH | Path to the .db file (if using SQLite). |
LIVEKIT_HOST | The public URL for LiveKit (e.g., https://meet.example.com/livekit). |
LIVEKIT_API_KEY | Key for LiveKit authentication. |
JWT_SECRET | Secret key used to sign Access Tokens. |
Coding Standards and Patterns
The backend follows these patterns:
1. Repository Pattern
Handlers should not talk to the database directly. Use a Repository. This makes the code easier to test and allows database logic changes without touching the API handlers.
2. Standardized Error Handling
API handlers should return clear error messages.
- Use
c.Status(fiber.StatusBadRequest).JSON(...)for validation errors. - Use
c.Status(fiber.StatusUnauthorized).JSON(...)for auth errors. - Use
c.Status(fiber.StatusInternalServerError).JSON(...)for database or server errors.
3. Structured Logging
The backend uses Zerolog for logging.
log.Info(): For important events (e.g., server started).log.Error(): For failures.log.Debug(): For detailed development information.
Avoid using fmt.Println for logging in core logic.
4. Naming Conventions
- Files: snake_case (e.g.,
user_handler.go). - Structs/Functions: PascalCase (e.g.,
GetUserByEmail). - Variables: camelCase (e.g.,
hashedPassword).