BigBrainParking/server/README.md
Erik c14081d85f server: zone-labels API (Fastify + SQLite) — Phase A
New server/ service classifying zones as free_2h/3h/4h street vs pay_immediate
lots. Public reads; writes require the admin bearer token (timing-safe compare).
@fastify/rate-limit (120/min global, 20/min writes), manual IP denylist +
auto-block on repeated auth failures. SQLite via better-sqlite3. Dockerfile +
compose (loopback-only, mem/cpu capped) + nginx block + README. 9 tests pass.

Deployed live at https://bigbrainparking.mowden.top (behind nginx + certbot).
Not an npm workspace — kept out of the app/CI install to avoid the native dep.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 18:09:03 +00:00

59 lines
2.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
```bash
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)
```bash
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
```bash
git pull && docker compose up -d --build
```