|
Some checks failed
build-apk / build (push) Failing after 1h56m52s
Anonymous Mode — "Park without signing in" on the login screen (with a popup of what works vs needs a login). Anonymous users browse parking areas from our mirror, see labels, and start free check-in timers; paying, sessions, and account screens prompt to sign in. AuthContext gains an 'anonymous' status + enterAnonymous/requireLogin. Zone mirror — server gains a `zones` table + public GET /api/zones and admin POST /api/zones/sync. Signed-in admins push the zones they pull (authed) from ParkSmarter after each map search, so anonymous users can read areas without a ParkSmarter login. Map/Scan read the mirror when anonymous. Also: the free "Check in" button is now always available with a 2h/3h/4h picker (no longer gated on a prior label) — fixes "couldn't start a timer on a free zone". CORS probe confirmed ParkSmarter allows any origin but only Content-Type, so a future PWA can't auth to it — the mirror is what makes anonymous browsing (and a PWA) possible. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| deploy | ||
| src | ||
| test | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
BigBrainParking zone-labels API
A tiny service that classifies parking zones so the app knows whether a space is
free for a limit (free_2h / free_3h / free_4h) or a pay-immediately
lot (pay_immediate). Public reads; writes require the admin password.
Lives in the monorepo but is not an npm workspace (keeps its native
better-sqlite3 dep out of the app/CI install). Deploy it independently.
API
| Method | Path | Auth | Notes |
|---|---|---|---|
| GET | /healthz |
– | liveness |
| GET | /api/labels |
– | all labels { labels: [...] } (app bulk-caches) |
| GET | /api/labels/:zoneId |
– | one label, 404 if none |
| PUT | /api/labels/:zoneId |
admin | upsert { kind, zoneName?, customerId?, note? } |
| DELETE | /api/labels/:zoneId |
admin | remove |
| GET | /api/whoami |
admin | { admin: true } — used by the app's "test password" |
Auth: Authorization: Bearer <BBP_ADMIN_TOKEN> (timing-safe compare). Reads are
public but rate-limited (~120/min/IP; writes ~20/min). Repeated bad tokens from an
IP auto-block it for a cooldown; blocked_ips (DB) + BBP_BLOCKED_IPS (env) are a
manual denylist. zoneId is the ParkSmarter ZoneId (e.g. 113165).
Develop
cd server
npm install
npm test # node --test via tsx
BBP_ADMIN_TOKEN=dev-secret-please-change npm run dev
Deploy (Docker + nginx on the host the CNAME points to)
cd server
cp .env.example .env
sed -i "s#change-me-to-a-long-random-secret#$(openssl rand -base64 32)#" .env # set the admin secret
docker compose up -d --build
# nginx + TLS (first time)
sudo cp deploy/bigbrainparking.mowden.top.conf /etc/nginx/sites-available/bigbrainparking.mowden.top
sudo ln -s ../sites-available/bigbrainparking.mowden.top /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d bigbrainparking.mowden.top
curl https://bigbrainparking.mowden.top/healthz # {"ok":true}
The admin secret (from .env) is what you paste into the app under
Settings → Admin. Rotate by editing .env and docker compose up -d.
Update
git pull && docker compose up -d --build