008887ab60df8348fb0ac8a49c06d4bb16e69027
Public:
- /escape-rooms: Leaflet + OpenStreetMap map with marker clustering and a
searchable list, both built from a cached slim JSON feed
- /escape-rooms/{id}-{slug}: room detail with a mini-map and user reviews
(rating + title + body, login required)
- /escape-rooms/suggest: visitor submission form with click-to-drop-pin map
and reCAPTCHA v3; new rooms land as pending
Data:
- EscapeRoom / EscapeRoomReview entities (soft-delete), migration
- app:escaperooms:import-osm console command pulls leisure=escape_game from
the Overpass API, upserts by (osmType, osmId), skips locked rows;
--tiled / --area / --bbox options
Admin (new "Website Admin" area, separate from Game Admin):
- src/Website/Controller/AdminEscapeRoomController.php at /admin/escape-rooms:
status-filtered list, new/edit, publish/hide/reject, delete, review removal
- game admin sidebar extracted into a block and cross-linked
Assets: leaflet + leaflet.markercluster; escaperoom-map and escaperoom-detail
Encore entries.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
EscapePage — Online Escape Room
This repository contains a Symfony 7.3 (PHP >= 8.5.1) application for a collaborative online escape room experience.
- Start here: doc/FILES.md — quick file index.
- Development standards and workflows: doc/CONTRIBUTING.md
- All documentation is located under the doc/ directory.
Getting Started (brief)
-
Local machine (no Docker):
- Copy
.envto.env.localand set database andAPP_SECRET. - Install PHP deps:
composer install - Create database and run migrations (when present):
php bin/console doctrine:database:create --if-not-exists && php bin/console doctrine:migrations:migrate -n - Install/import JS deps:
php bin/console importmap:install - Run the server:
symfony server:start -d(or your preferred web server) - Run tests:
vendor/bin/phpunit
- Copy
-
With Docker:
cd docker && docker compose up -d- Install vendors inside the PHP container:
docker compose exec php bashcomposer install
- Initialize DB:
php bin/console doctrine:database:create --if-not-existsphp bin/console doctrine:migrations:migrate -n
- App is at http://localhost:8080
Email (Mailpit in dev, Mailgun for prod)
- Dev: a
mailerservice (Mailpit) runs in Docker.- SMTP DSN in
.env:MAILER_DSN=smtp://mailer:1025 - Mailpit UI: http://localhost:8025 (or mapped port 8025)
- Send a test mail:
php bin/console app:mail:test you@example.com
- SMTP DSN in
- Staging/Prod: use Mailgun.
- Require package (already in composer):
symfony/mailgun-mailer. - Set environment variables (do NOT commit secrets):
MAILER_DSN=mailgun+api://${MAILGUN_API_KEY}:${MAILGUN_DOMAIN}@default?region=euMAILGUN_API_KEY=YOUR_REAL_KEYMAILGUN_DOMAIN=YOUR_SENDING_DOMAIN(e.g.mg.escapepage.nl)- Optional:
MAILER_FROM=no-reply@your-domain.tld
- Drop
region=eu(or useregion=us) depending on which region your Mailgun domain was created in. - Alternatively via SMTP (no extra package):
MAILER_DSN="mailgun+smtp://USERNAME:PASSWORD@default?region=eu"
- Require package (already in composer):
Troubleshooting:
- If emails don’t appear in dev, open Mailpit at http://localhost:8025 and verify messages.
- In prod, check logs for HTTP 2xx responses from Mailgun and verify sender domain is verified (SPF/DKIM) in Mailgun.
Frontend assets with Webpack Encore
We use Webpack Encore to build and minify JS/CSS from the assets/ directory into public/build/.
Install Node dependencies (on your host machine):
npm install
Common commands:
# One-time dev build
npm run dev
# Watch & rebuild on changes
npm run watch
# Production build (minified, versioned filenames)
npm run build
How it’s wired:
- Entry file:
assets/app.js(importsassets/styles/app.css). - Webpack config:
webpack.config.jsoutputs topublic/build/. - Twig template includes built assets via Encore:
- In
templates/base.html.twig:{{ encore_entry_link_tags('app') }}(CSS){{ encore_entry_script_tags('app') }}(JS)
- In
Notes:
- The PHP Docker image does not include Node. Run the build commands on your host, or ask to add a Node build container if you prefer fully containerized builds.
- Built files are ignored by git except for
public/build/.gitignoreto keep the directory.
See doc/CONTRIBUTING.md for code style and more details.
Real‑time updates with Mercure
We use a Mercure hub (Docker service) to push server updates to browsers via Server‑Sent Events (SSE).
Quick start (dev):
- Start Docker stack:
This starts
cd docker && docker compose up -dmercureat http://localhost:8090 and the app at http://localhost:8080. - Install PHP deps inside the PHP container if you haven't yet:
You should see a console log like
docker compose exec php bash composer install[Mercure] Update received: { ... }on the Game Hub page.
Configuration:
- Env vars (defined in
.env, override in.env.localas needed):MERCURE_URL=http://mercure/.well-known/mercure(internal URL from PHP to the hub)MERCURE_PUBLIC_URL=http://localhost:8090/.well-known/mercure(browser URL)MERCURE_JWT_SECRET=!ChangeThisMercureJWT!(dev secret; do not use in prod)MERCURE_TOPIC_BASE=https://escapepage.dev(base topic URL)
- Docker service
mercureis based ondunglas/mercureand allows anonymous subscribers in dev.
Topics:
- Topics must be URLs. We use
MERCURE_TOPIC_BASEto control the domain per environment.- Dev:
.envsetshttps://escapepage.dev - Prod: set
MERCURE_TOPIC_BASE=https://escapepage.com
- Dev:
- The Game Hub demo topic is
${MERCURE_TOPIC_BASE}/game/hub.
Production notes:
- Disable anonymous subscribers and require JWTs for subscriptions (configure the Mercure container accordingly).
- Use a strong, rotated
MERCURE_JWT_SECRETand keep it out of VCS (use real env/secrets). - Serve Mercure over HTTPS and set proper CORS/allowed origins for your production domain(s).
Languages
PHP
59.1%
Twig
28.5%
JavaScript
8.5%
Shell
2.7%
CSS
0.7%
Other
0.5%