Extend authenticated debug endpoints for local iOS notification testing:
add nextEligibleAt (23h prod / 10m test) to device lookup, return success
and failureReason from send-wakeup with masked tokens only, reuse
resolveOwnedDevice for ownership checks, and standardize [DebugEndpoint] logs.
Restore /health to { ok: true }. Scope refresh to owned devices via
deviceId/fcmToken, improve register upsert logging, skip legacy rows in
the scheduler with per-token dedupe, and prefer non-legacy rows for push.
Add GET /debug/device/:token and POST /debug/send-wakeup behind requireAuth,
scope lookups to the authenticated user (404 otherwise), and mask FCM tokens
in logs via maskToken. Mark routes for further restriction before production.
Scope register and refresh to verified JWT identity (req.did). Persist
devices under userId::deviceId, reject client-supplied userId, and dedupe
FCM tokens per user.
Mirror image-api’s DID JWT verification (src/vc + requireAuth) so
/notifications/* require a valid Authorization header while /health
stays public. Attach req.did, req.jwt, and req.auth for downstream use.
Require deviceId on POST /notifications/register, upsert by deviceId
while preserving lastNotifiedAt and internal id, prune duplicate token
rows, migrate legacy fcmToken-keyed JSON, and add register logs.
Extend StoredRow and Device with deviceId; resolve pushes by scanning
fcmToken.
Log scheduler ticks, refresh requests, dedupe skips by device id,
push attempt/success with token hints, and push failures without
extra sensitive fields.
Assign stable ids to stored tokens, migrate legacy ISO lastNotifiedAt
to epoch ms, replace setLastNotifiedAt with db.update, and persist
lastNotifiedAt only after a successful FCM send. Extend Device with
optional lastNotifiedAt (ms).