No description
  • TypeScript 84.1%
  • CSS 15.7%
  • HTML 0.1%
  • Dockerfile 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Jason Artemis Winstanley eb2b2121f4 Initial commit of DeployHub
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 20:23:42 +00:00
backend Initial commit of DeployHub 2026-07-28 20:23:42 +00:00
frontend Initial commit of DeployHub 2026-07-28 20:23:42 +00:00
.gitignore Initial commit of DeployHub 2026-07-28 20:23:42 +00:00
compose.yml Initial commit of DeployHub 2026-07-28 20:23:42 +00:00
DESIGN.md Initial commit of DeployHub 2026-07-28 20:23:42 +00:00
README.md Initial commit of DeployHub 2026-07-28 20:23:42 +00:00

Bridge Command Crew Hub

Crew management and sharing platform for naval simulation campaign crews. Members share mission logs and fan art within their crew/campaign — access is controlled entirely by OIDC groups synced on login.


Stack

Layer Technology
Backend Node.js + Express + TypeScript
Frontend React + TypeScript + Vite
Database PostgreSQL 15
File storage MinIO (S3-compatible)
Auth OIDC via openid-client (VoidAuth or any standard provider)
Sessions express-session + connect-pg-simple
Reverse proxy lucaslorentz/caddy-docker-proxy (external, label-based)

Quick start

1. Prerequisites

  • Docker + Docker Compose
  • An existing caddy-docker-proxy container connected to a Docker network named caddy (or change networks.caddy.external: true in docker-compose.yml to match your setup)

2. Configure environment

cp .env.example .env
# Edit .env — see the variable reference below

3. Start everything

docker compose up -d

On first start the backend will:

  1. Wait for PostgreSQL to be healthy
  2. Run all SQL migrations in backend/migrations/ in order
  3. Initialise the OIDC client (discovery against OIDC_ISSUER)
  4. Create the S3 bucket if it doesn't exist

The seed data (two example crews + three campaigns) is applied by 002_seed.sql.


Environment variables

Variable Required Default Description
DATABASE_URL Full PostgreSQL connection string
POSTGRES_DB bridge_crew Database name (used by the postgres container)
POSTGRES_USER bridge DB username
POSTGRES_PASSWORD bridge_secret DB password
OIDC_ISSUER Base URL of your OIDC provider (e.g. https://auth.example.com)
OIDC_CLIENT_ID Client ID registered on the provider
OIDC_CLIENT_SECRET Client secret
OIDC_REDIRECT_URI Full callback URL, e.g. https://hub.example.com/api/auth/callback
SESSION_SECRET Random string ≥ 32 chars (openssl rand -hex 64)
S3_ENDPOINT http://minio:9000 S3/MinIO endpoint
S3_BUCKET bridge-crew-hub Bucket name (auto-created)
S3_ACCESS_KEY minioadmin S3 access key
S3_SECRET_KEY minioadmin123 S3 secret key
CADDY_HOST localhost Hostname Caddy routes for (passed to caddy-docker-proxy labels)
NODE_ENV development development or production

OIDC provider setup (VoidAuth / any provider)

Groups convention

The app derives access entirely from group membership synced at login. No in-app admin UI is needed.

Group name Access granted
crew:red-squadron Member of the Red Squadron crew (all its campaigns)
campaign:operation-trident Member of Operation Trident only
campaign:battle-of-the-reaches Member of Battle of the Reaches only
  • A crew:* group grants access to all campaigns in that crew.
  • A campaign:* group grants access to that campaign only.
  • Groups are read from the groups claim in the OIDC userinfo response.

What to configure on the provider

  1. Create a client with:
    • Redirect URI: https://your.domain.com/api/auth/callback
    • Scopes: openid email profile groups
  2. Create groups following the naming convention above and assign users to them.
  3. Ensure the groups claim is included in the userinfo/ID token response.

Caddy / reverse proxy

This project uses lucaslorentz/caddy-docker-proxy.
The Caddy container is external — connect it to the caddy Docker network, and it will automatically pick up the routing labels on the app and frontend services:

/api/*  →  app:3000       (backend)
/*      →  frontend:5173  (Vite dev server)

For production with Vite's static build, replace the frontend service with a served dist/ directory and update the label accordingly.

To use a different external network name, change networks.caddy.external in docker-compose.yml.


Project layout

.
├── backend/
│   ├── migrations/        # SQL migration files (run in filename order)
│   ├── src/
│   │   ├── config.ts      # Zod-validated env config
│   │   ├── app.ts         # Express app setup
│   │   ├── index.ts       # Entry point (migrations → OIDC init → listen)
│   │   ├── db/            # Pool, migrate, seed, types
│   │   ├── middleware/    # requireAuth, errorHandler
│   │   ├── routes/        # auth, crews, logs, art
│   │   └── services/      # oidc, s3, groups
│   └── Dockerfile
├── frontend/
│   ├── src/
│   │   ├── api/           # Typed API client
│   │   ├── components/    # Navbar, Layout, ArtCard, Lightbox, etc.
│   │   ├── hooks/         # useAuth
│   │   ├── pages/         # One file per route
│   │   └── styles/        # global.css (dark naval theme)
│   └── Dockerfile
├── docker-compose.yml
└── .env.example

Development notes

  • Hot reload — both containers mount the source tree as a volume; the backend uses tsx watch and the frontend uses Vite's HMR.
  • MinIO console — available at http://localhost:9001 (credentials from S3_ACCESS_KEY / S3_SECRET_KEY).
  • Run migrations manually: docker compose exec app npm run migrate
  • Run seed manually: docker compose exec app npm run seed