A lightweight Express service that schedules and sends Firebase Cloud Messaging (FCM) push notifications to wake up registered devices. Device registrations are stored in a local **SQLite** database (not JSON). ## Dev ```bash cp .env.example .env ``` Edit .env — set `FIREBASE_SERVICE_ACCOUNT_JSON`. Here is one way to generate the contents: `cat your-downloaded-key.json | jq -c .` Optionally set `ENDORSER_URL` if you are not using the default production Endorser API (`https://api.endorser.ch`). Optionally set `NOTIFY_DATA_DIR` if you want the SQLite database somewhere other than `./data`. ```bash pnpm install pnpm run dev ``` The server starts on `http://localhost:3003` (or the port in `PORT`). Hot-reloads on file changes. On first use, the service creates `NOTIFY_DATA_DIR` (default `./data`) and the SQLite file `notify.sqlite` with the required schema. ### Authentication `POST /notifications/register` and `POST /notifications/refresh` require a Bearer JWT. After local JWT verification, the service checks the token with Endorser (`GET /api/report/rateLimits` on `ENDORSER_URL`). Registration and refresh continue only if Endorser accepts the JWT. **Local notification test bypass:** send `testMode: true` in the JSON body and omit the `Authorization` header. The request skips JWT and Endorser checks and uses a synthetic local test user, same as before. Set `NODE_ENV=test-local` in `.env` to bypass ethr JWT *expiry* verification during local development (this is separate from the `testMode` bypass above). ## Storage ### Database location | Path | Description | |---|---| | `{NOTIFY_DATA_DIR}/notify.sqlite` | Primary SQLite database (default dir: `./data`) | | `{NOTIFY_DATA_DIR}/notify.sqlite-wal` | WAL journal (present while the process is running) | | `{NOTIFY_DATA_DIR}/notify.sqlite-shm` | Shared-memory file used with WAL mode | `NOTIFY_DATA_DIR` defaults to `./data` (relative to the process working directory). The `data/` directory is gitignored. ### Schema (high level) Table `fcm_registrations` holds one row per registered device: - Identity: `id`, `user_id`, `device_id`, `fcm_token`, `platform` - Flags: `test_mode` - Timestamps: `created_at`, `updated_at`, `last_notified_at` Unique on `(user_id, device_id)`. Indexes also exist on `user_id`, `device_id`, `fcm_token`, and `(user_id, fcm_token)`. The schema is created automatically on startup if the database or tables do not already exist. ### JSON → SQLite There is **no automatic migration** from the old JSON file (`fcm-tokens.json`). That format is no longer used. If you still have a local `fcm-tokens.json` from earlier development, it is ignored; re-register devices or import data manually if you need it. ### Backup Persist or back up the SQLite files under `NOTIFY_DATA_DIR`: 1. Prefer stopping the service, then copy `notify.sqlite` (and any `-wal` / `-shm` sidecars if present). 2. Or, while the service is running, copy **all three** files (`notify.sqlite`, `-wal`, `-shm`) together so the backup stays consistent under WAL mode. 3. For Docker, mount a volume at the data directory (or set `NOTIFY_DATA_DIR` to a mounted path) so registrations survive container recreation. ## Production Runs TypeScript directly via `tsx` (no compile step). ```bash pnpm install --prod pnpm start ``` Ensure `NOTIFY_DATA_DIR` points at a durable location (or accept the default `./data` next to the process cwd). Or with Docker: ```bash docker build --no-cache -t notify-wakeup-api:amd-$NOTIFY_WAKEUP_API_VERSION --platform linux/amd64 . docker run --env-file notify-wakeup-api.env -p 3003:3003 \ -v notify-wakeup-data:/app/data \ notify-wakeup-api ``` Mount a volume over `/app/data` (or whatever path you set with `NOTIFY_DATA_DIR`) so the SQLite database is not lost when the container is replaced. Required environment variables: | Variable | Description | |---|---| | `FIREBASE_SERVICE_ACCOUNT_JSON` | Inline service account JSON (one line). If unset, falls back to Application Default Credentials. | | `PORT` | HTTP port (default: `3003`). | | `ENDORSER_URL` | Endorser API base URL used for auth checks on register/refresh (default: `https://api.endorser.ch`). | | `NOTIFY_DATA_DIR` | Directory for the SQLite database file `notify.sqlite` (default: `./data`). |