Dedicated nginx server block on :8543 (not proxied under the dashboard's 80/443) because the dashboard sets Permissions-Policy: geolocation=() server-wide, which would silently break Regress's core claim/link mechanic. Also documents a found-but-not-fixed gap: the dashboard's app iframe has no allow="geolocation", so the in-dashboard launch path won't get location access either until that shared component is patched.
4.7 KiB
Regress
A location-based capture game in the spirit of Ingress, built as a nostr-native web app. Real Bitcoin-accepting businesses from BTC Map stand in for Ingress's portals — players physically visit them to claim them for their team (orange or green), then link claimed places into triangular control fields. First scope: Madeira, Portugal.
See DESIGN.md for the full research/design writeup.
Stack
server/— Fastify + better-sqlite3 + nostr-tools (TypeScript), same pattern as podsteadr.frontend/— Vue 3 + Vite + Pinia + Tailwind + Leaflet.- Auth is NIP-98 (signed-event login → session cookie), same as podsteadr.
frontend/public/nostr-provider.jsis vendored so the app can also be launched identity-aware from inside an Archipelago dashboard, the same way as podsteadr — see that repo's README for how the registration side works.
Running locally
# server
cd server
npm install
npm run dev # http://localhost:8096
# frontend (separate terminal)
cd frontend
npm install
npm run dev # http://localhost:5173, proxies /api to :8096
On first run, the places table is empty — call POST /api/sync (or click
"Sync from BTC Map" in the UI) to pull the current Madeira dataset from BTC
Map's public API.
Game rules (v0)
- Claiming or linking from a place requires being within
CLAIM_RADIUS_METERS(default 40m) of it, via browser geolocation — no claiming from the couch. - Claiming an enemy-held place captures it for your team and tears down any links running through it.
- A link can be created between any two places your team currently holds, as long as you're standing at the origin place — no maximum link distance.
- A new link can't cross any existing link (either team) — same as Ingress.
Links sharing an endpoint don't count as crossing. See
services/geo.ts#segmentsIntersectandroutes/links.ts. - Three mutually-linked, same-team places form a field (computed live, not
stored) — see
server/src/services/fields.ts. - Team choice is one-way once made.
Tests
cd server
npm test
Deployment
Live at https://archy-x250-dev3.tail08d8f2.ts.net:8543 (Tailscale-only —
this node has no public IP, so it isn't reachable from the open internet like
podsteadr is; anyone playing needs to be on the same tailnet).
-
Single container (
Dockerfile, server + built frontend in one image),podman run --restart unless-stopped, data on a bind-mounted volume at/var/lib/archipelago/regress-dataon the node. -
Fronted by a dedicated nginx server block,
deploy/nginx-archy-node.conf, on its own port (8543) rather than being proxied under the node's main dashboard (80/443).Why a dedicated port, not
/app/regress/like other installed apps: archipelago's own nginx config setsPermissions-Policy: geolocation=()server-wide on its 80/443 blocks — inherited by everylocationunder them that doesn't set its ownadd_headers. Regress's entire claim/link mechanic depends onnavigator.geolocation, so being proxied under those blocks would silently break the core game with no clear error. A separate server block sidesteps this entirely and setsPermissions-Policy: geolocation=(self)explicitly.Also found, not yet fixed: the Archipelago dashboard's own app-iframe element (
neode-ui/src/views/appSession/AppSessionFrame.vue) has noallow="geolocation"attribute, so even a geolocation-permitting app would have geolocation blocked by the browser's default iframe permission delegation if launched inside the dashboard iframe. This isn't Regress-specific — it'd affect any app needing geolocation. Until that's patched (a shared-component change, out of scope for this deploy), players should open Regress directly (the URL above, or "open in new tab" from the dashboard) rather than through the in-dashboard iframe. -
Non-standard port gotcha: nginx's
$hostvariable strips the port before forwarding, which breaks NIP-98 login (utag URL won't match). Useproxy_set_header Host $http_host;(preserves the original port) — already set correctly indeploy/nginx-archy-node.conf. -
PUBLIC_URLpassed to the container must include the:8543for the same reason.
To redeploy after a code change: git pull in
/var/lib/archipelago/regress-src on the node, podman build -t localhost/regress:latest ., then podman run -d --name regress-app --replace --restart unless-stopped -p 127.0.0.1:8199:8199 -v /var/lib/archipelago/regress-data:/data -e PUBLIC_URL=https://archy-x250-dev3.tail08d8f2.ts.net:8543 localhost/regress:latest.