Fork of https://github.com/MSHack2026-BlinkenLights/web for local deployment.
  • TypeScript 85.7%
  • JavaScript 9.4%
  • PLpgSQL 2.1%
  • CSS 1%
  • PowerShell 0.8%
  • Other 1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-29 11:28:41 +02:00
docs Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
prisma Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
public Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
src Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
tests Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
docker-compose.yml Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
Dockerfile Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
eslint.config.js Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
next.config.js Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
package-lock.json Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
package.json Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
postcss.config.js Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
prettier.config.js Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
README.md Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
seed-database.ps1 Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
seed-database.sh Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
server.js Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
start-database.ps1 Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
start-database.sh Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00
tsconfig.json Fork of https://github.com/MSHack2026-BlinkenLights/web 2026-09-29 11:28:41 +02:00

web-blinkin-lights

Next.js app (T3 Stack) with tRPC, Prisma (PostgreSQL), Better Auth and Tailwind CSS.

Prerequisites

  • Node.js (LTS recommended) and npm
  • Docker or Podman for the local PostgreSQL database
  • On Windows: use start-database.ps1 (native PowerShell) or run start-database.sh inside WSL

Setup

1. Install dependencies

npm install

This also runs prisma generate automatically (postinstall), which creates the Prisma client in generated/prisma.

2. Configure environment variables

Copy the example file and fill in the values:

cp .env.example .env
Variable Description
DATABASE_URL PostgreSQL connection string, e.g. postgresql://postgres:password@localhost:5432/web-blinkin-lights
BETTER_AUTH_SECRET Secret for Better Auth (optional in development, required in production). Generate one with openssl rand -base64 32

If you add new variables, also update the schema in src/env.js and keep .env.example in sync.

3. Start the database

macOS / Linux (or WSL):

./start-database.sh

Windows (PowerShell, no WSL required):

powershell -ExecutionPolicy Bypass -File .\start-database.ps1

The script reads DATABASE_URL from .env and starts a PostgreSQL container named <db-name>-postgres on the configured port.

  • If the password in DATABASE_URL is still password, the script offers to generate a random one and writes it into .env.
  • If the container already exists, it is simply restarted.
  • The script aborts if Docker/Podman is not running or the port is already in use.

If the script is not executable, run chmod +x start-database.sh first. On Windows, -ExecutionPolicy Bypass allows the unsigned script to run without changing your system policy.

4. Push the schema to the database

npm run db:push

This syncs prisma/schema.prisma to the database (creates/updates tables) and regenerates the Prisma client.

Rerun this command whenever you change prisma/schema.prisma.

5. Seed dummy data (optional)

Fills every table in prisma/schema.prisma with dummy data from prisma/seed.sql (controllers around Münster, game types, games with pixels, users with nicknames of different lengths).

macOS / Linux (or WSL):

./seed-database.sh

Windows (PowerShell):

powershell -ExecutionPolicy Bypass -File .\seed-database.ps1
  • Never runs automatically: not part of npm install, db:push, db:migrate or Docker. Run it by hand, only against a development database.
  • Rerunning is safe: rows use fixed ids and existing ones are skipped.
  • All seeded users log in with the password password123, e.g. jo@example.com.

6. Start the development server

npm run dev

The app is available at http://localhost:3000.

Rhythm-game prototype

Open http://localhost:3000/rhythm-lab for a browser-only LED rhythm game with generated audio. Click Demo starten, listen to the count-in, then use the arrow keys or simulated panels to step on the white cues.

See the rhythm lab guide for timing, calibration, architecture, and test commands. Hardware and streaming-service integration are intentionally not included yet.

Production build

npm run build
npm run start

Or build and start in one step with npm run preview. Make sure BETTER_AUTH_SECRET is set, since it is required in production.

Docker deployment

Runs the app (distroless Node image), a one-shot migration job (prisma/migrate-deploy.sh, runs prisma migrate deploy) and PostgreSQL:

cp .env.example .env   # set BETTER_AUTH_SECRET, POSTGRES_PASSWORD, APP_PORT
docker compose up -d --build

The app is available at http://localhost:$APP_PORT. If port 3000 is taken on the host, change APP_PORT. All Docker variables are listed in .env.example.

WebSocket

server.js is a custom Next.js server (used by dev, start and Docker) that serves a WebSocket at /ws. Controllers connect there and send JSON messages; handlers live in src/server/ws/. The server pings every 30 s (a text ping is also answered with pong).

msgType Fields Effect
hello id (hardware ID), x, y (grid size) Binds the connection to the controller, creating it if unknown, and stores the grid size. Means the controller restarted, so a running game is marked as aborted. Send first.
reconnect id (hardware ID) Binds the connection to a known controller after a reconnect (e.g. server restart) with its stored grid size. The running game continues.
gameStart game (game type key) Starts a game of that type; a game still running is marked as aborted first.
gameEnd – Ends the running game as finished normally (not aborted). gameEnds is accepted too.
change x, y (1-based), color (rgb(r, g, b)) Updates the live view; while a game runs, stores the color as that cell of the game.

The server sends change (same fields) to a controller to set a panel's color, e.g. for the claim pattern after a game (see setColor in src/server/bridge/interface.ts).

It also sends buttonPress with x, y (1-based) to simulate someone stepping on a panel, e.g. from the admin page /admin/controller/<id>/steuern. The controller runs the game logic and answers with change messages as usual (see pressButton in src/server/bridge/interface.ts).

The hardware counts panels from 1, the server from 0: incoming x/y are decremented on receipt and outgoing ones incremented before sending, so everything past src/server/ws/controller.js and setColor is 0-based.

Messages of a connection are handled in the order they arrive. Anything sent before hello or reconnect (e.g. the current state as change messages after a reconnect) is held back and handled right after it; without one within 10 s, the held messages are dropped with an error.

Numbers may be sent as strings. Valid messages get no answer; anything invalid (bad JSON, unknown msgType, missing hello, out-of-grid panel, …) is answered with {"msgType":"error","error":"..."}.

Connect with the page's protocol so it works both with and without SSL:

const ws = new WebSocket(
  `${location.protocol === "https:" ? "wss" : "ws"}://${location.host}/ws`,
);

For wss://, terminate TLS at a reverse proxy and forward the upgrade headers, e.g. nginx:

location /ws {
    proxy_pass http://localhost:3000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
}

Caddy and Traefik forward WebSockets automatically.

Useful scripts

Command Description
npm run dev Start the dev server (Turbopack, with /ws)
npm run build Create a production build
npm run start Start the production server (after build)
npm run db:push Sync the Prisma schema to the database
npm run db:generate Create and apply a new migration (prisma migrate dev)
npm run db:migrate Apply existing migrations (prisma migrate deploy)
npm run db:studio Open Prisma Studio to browse the database
npm run check Lint and type-check
npm run format:write Format code with Prettier

Stopping the database

docker stop web-blinkin-lights-postgres

(Use podman instead of docker if applicable. The container name is <db-name>-postgres, based on DATABASE_URL.)