2026-03-15 17:15:46 +00:00

gerbeur

A small invite-only social platform for sharing links and files. Users can post URLs and media (YouTube, SoundCloud, Bandcamp, images, …), vote, comment, follow each other, and build playlists. A real-time WebSocket layer handles live presence, vote counts, and notifications.

Stack

Layer Technology
Runtime Deno 2.x
API Oak (HTTP + WebSocket)
Database SQLite via node:sqlite
Frontend React 19 + Vite 8

Development

Prerequisites

  • Deno 2.x

Setup

cp .env.example .env
# Edit .env: set GERBEUR_JWT_SECRET to the output of: openssl rand -hex 32

Run

deno task dev

This starts both the API server (port 8000, with file watching) and the Vite dev server (port 3000) concurrently.

Open http://localhost:3000. On first run a default admin / admin account is created — change the password immediately.

Environment variables

See .env.example for the full list with descriptions. Key variables:

Variable Description Default
GERBEUR_JWT_SECRET JWT signing secret — required, generate with openssl rand -hex 32
GERBEUR_SMTPS_URL SMTPS connection URL used by the email service (smtps://user:pass@host:465) unset
GERBEUR_SITE_NAME Site name used in OG meta tags gerbeur
GERBEUR_PORT API server port 8000
GERBEUR_ALLOWED_ORIGINS Comma-separated list of extra allowed frontend origins; the server's own BASE_URL is always allowed http://localhost:3000
VITE_API_HOSTNAME Override API hostname in the frontend bundle (see Production) unset

Production

The standard deployment runs API and frontend in a single container. The API server (Oak) serves the compiled frontend as static files, so both share the same origin — no VITE_API_* build args needed. The server's own BASE_URL is always allowed for HTTP/WebSocket requests automatically.

docker build -t gerbeur .

docker run -d \
  -p 8000:8000 \
  -v gerbeur-db:/app/api/sql \
  -v gerbeur-uploads:/app/api/uploads \
  -e GERBEUR_JWT_SECRET=$(openssl rand -hex 32) \
  -e GERBEUR_PROTOCOL=https \
  -e GERBEUR_HOSTNAME=example.com \
  -e GERBEUR_PORT=8000 \
  --name gerbeur \
  gerbeur

The two volumes are required for persistence:

  • gerbeur-db — SQLite database (api/sql/gerbeur.db), initialized automatically on first run
  • gerbeur-uploads — user-uploaded files (api/uploads/)

Separate API and frontend (optional)

If you need to run the API on a different host than the frontend, pass the API location as build args so it gets baked into the frontend bundle. In that setup, add the frontend origin to GERBEUR_ALLOWED_ORIGINS so cross-origin HTTP/WebSocket requests are accepted:

docker build \
  --build-arg VITE_API_PROTOCOL=https \
  --build-arg VITE_API_HOSTNAME=api.example.com \
  --build-arg VITE_API_PORT=443 \
  -t gerbeur .

Reverse proxy

Put a reverse proxy (nginx, Caddy, …) in front of the container to handle TLS. Forward everything to port 8000. Example Caddyfile:

example.com {
    reverse_proxy localhost:8000
}

Project structure

api/
  main.ts          # Entry point — Oak application, middleware, routes
  config.ts        # Environment variables
  middleware/      # errorMiddleware, authMiddleware
  routes/          # HTTP routes + WebSocket
  services/        # Business logic
  model/           # Database schema, row types, type guards
  lib/             # JWT, pagination, upload helpers, …
  sql/
    schema.sql     # Database schema
    init.ts        # First-run database initialisation
    gerbeur.db     # SQLite database (not committed)
  uploads/         # User-uploaded files (not committed)
src/               # React frontend (Vite)
  config/api.ts    # API base URL, validation constants
  pages/           # Route-level components
  components/      # Shared UI components
  contexts/        # Auth, WebSocket, player, follows
  hooks/           # Data fetching and UI hooks
public/            # Static assets (favicon, icon sprite)
Description
🚚 à dégager
Readme MIT 2.4 MiB
Languages
TypeScript 84.1%
CSS 15.5%
Dockerfile 0.2%
HTML 0.2%