Private
Public Access
1
0
Files
MineSeeker/README.md

5.5 KiB

MineSeeker

A real-time 1v1 multiplayer minesweeper game played in the browser. Two players race on the same hidden minefield — uncover safe cells to score points, but hit a mine and you hand the advantage to your opponent. Games are live and synchronised instantly via a Mercure hub; no page reloads, no polling.

Created by SplendidBear.


Features

  • Real-time 1v1 gameplay — moves broadcast instantly over Mercure (server-sent events)
  • Guest & registered play — jump in anonymously or create an account for stats and history
  • Full authentication stack — email/password, passkeys (WebAuthn), TOTP 2FA with backup codes
  • Player profiles — win/loss/draw stats, per-month charts, recent battle history with shareable replay links
  • Profile pictures — uploaded to MinIO object storage, thumbnails generated on-the-fly by LiipImagine
  • Battle replay sharing — share a direct link to any finished game
  • Docker-ready — single make start-build brings up the full production-like stack

Tech stack

Layer Technology
Backend PHP 8.5, Symfony 7.4, Doctrine ORM
Frontend React 19, Vite, MUI, SCSS
Database PostgreSQL 18
Real-time Mercure (built into FrankenPHP / Caddy)
File storage MinIO (S3-compatible)
Image processing LiipImagine + Flysystem
Server FrankenPHP (Caddy + PHP in one binary)
Auth Symfony Security, Scheb 2FA, web-auth/webauthn-framework

Requirements

Bare-metal development

  • PHP >= 8.5 with extensions: pdo_pgsql, gd, intl, zip, sodium
  • Composer 2
  • Node.js 22 + Bun
  • PostgreSQL 18
  • Caddy with FrankenPHP and the Mercure module
  • MailHog (or any SMTP server on port 1025)
  • MinIO (listening on port 9000)

Docker

  • Docker Engine 24+
  • Docker Compose v2
  • Bun (for building frontend assets before make start-build)
  • Composer (for make start-build)

Installation

1. Clone the repository

git clone https://github.com/splendidbear/mineseeker.git
cd mineseeker

2. Configure environment

cp .env.dist .env

Edit .env and fill in every value. Key ones:

Variable What to set
APP_SECRET Random 32-byte hex: openssl rand -hex 32
POSTGRES_USER/PASSWORD/DB Your PostgreSQL credentials
MINIO_ROOT_USER/PASSWORD MinIO admin credentials
MINIO_ENDPOINT http://localhost:9000 (bare-metal)
MINIO_PUBLIC_URL Public URL browsers use to reach MinIO
RECAPTCHA_SITE_KEY/SECRET_KEY Google reCAPTCHA v3 keys for your domain
MERCURE_JWT_SECRET Random secret (generated in step 3)
MERCURE_JWT_TOKEN Signed publisher JWT (generated in step 3)
MERCURE_SUBSCRIBER_JWT Signed subscriber JWT (generated in step 3)
MAILER_DSN smtp://localhost:1025 for MailHog in dev

3. Generate Mercure JWT tokens

composer install
make mercure-jwt

Copy the printed values into .env and into the publisher_jwt / subscriber_jwt lines of your Caddy Mercure block, then reload Caddy:

sudo systemctl reload caddy

4a. Run with Docker

make start-build

This installs PHP dependencies, builds the frontend assets with Bun, builds the Docker image, and starts all services (app, db, mail, minio, minio_init).

The app is available at http://localhost:10080 (or the domain set in APP_PUBLIC_HOSTNAME).

To apply any code changes later, run the same command again.

4b. Run bare-metal (development)

composer install
bun install
bun run dev            # Vite dev server with hot-reload
php bin/console doctrine:migrations:migrate --no-interaction

Start MinIO and MailHog, then open the URL configured in your Caddy vhost.

5. MinIO bucket setup

Docker — handled automatically on first start by the minio_init service. No action needed.

Bare-metal — run once after MinIO is up:

mc alias set local http://localhost:9000 $MINIO_ROOT_USER $MINIO_ROOT_PASSWORD
mc mb local/mineseeker
echo '' | mc pipe local/mineseeker/media/.keep
echo '' | mc pipe local/mineseeker/cache/.keep
# Apply public-read policy for media/ and cache/ — see docker/minio-init.sh for the JSON

Development environment

When running the Docker stack locally you typically want to catch outgoing emails instead of relaying them through a real SMTP server. The production compose.yaml uses Postfix for actual mail delivery and must not be edited for local overrides. Use a compose.override.yaml file instead — Docker Compose merges it automatically on top of the base file whenever both are present.

Email: replace Postfix with MailHog

Create compose.override.yaml in the project root (it is git-ignored and never reaches production):

services:
  app:
    environment:
      MAILER_DSN: smtp://mail:1025?verify_peer=0
  mail:
    image: mailhog/mailhog:latest
    ports:
      - "8025:8025"

This replaces the mail service image with MailHog and points the application's mailer at its SMTP port (1025). No other files need to change.

After adding the file, restart the stack:

make start-build

All emails sent by the application are now captured by MailHog. Open the web UI at http://localhost:8025 to inspect them.

Production notecompose.override.yaml is listed in .gitignore. Never commit it; the production server must only see compose.yaml with Postfix.


License

LGPL-3.0 — see LICENSE for details.

© 2026 SplendidBear