Continues the incremental server TS migration (after utils/*.mts and
paymentValidation.cts): converts 10 services to .cts (CommonJS TypeScript,
run natively via Node type-stripping — no build step), type-checked by
tsconfig.server.json.
Migrated: totpService, amountSuggestionService, encryptionService,
paymentAccountingService, statusService, aprService, driftService,
analyticsService, spendingService, billMerchantRuleService.
- types/db.d.ts: shared minimal better-sqlite3 Db/Statement types (the lib
ships none), reused across the migrated modules.
- Every require of a migrated service updated to the explicit .cts extension
(extensionless require does not resolve .cts) across routes / services /
db migrations / server.js / workers / tests — require-only changes.
- package.json: check:server find pattern now includes *.cts (it silently
skipped .cts before, so paymentValidation.cts had no node --check gate).
Behavior-preserving (types only). Verified: typecheck:server 0,
check:server 0, full server suite 226/226, real boot → /api/health 200.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
- Wire four push channels into runNotifications() with urgency mapping
- push_url and push_token encrypted at rest via AES-256-GCM
- Profile page Push card with master toggle, channel picker, test button
- Calendar CashFlowCard with period/month projections and negative alert
- Tracker card shows projected amount when cashflow data available
Detects when a bill's recent payments have diverged from its configured
expected amount for 2+ consecutive months and surfaces it in a new
collapsible amber panel on the Tracker page.
- Migration v0.71: adds `drift_snoozed_until` to bills and
`notify_amount_change` to users
- New `driftService.getDriftReport()`: computes per-bill payment median
over last 3 months, flags drift above a user-configurable threshold
(default 5%, minimum $1 delta)
- New `GET /api/bills/drift-report` and `POST /api/bills/:id/snooze-drift`
routes (registered before `/:id` to avoid routing conflict)
- `runDriftNotifications()` added to daily worker — sends amber digest
email per user listing all changed bills with old → new amounts
- `notify_amount_change` wired through profile and notifications routes
- `DriftInsightPanel`: collapsible amber panel with per-bill
strikethrough old → new amount, ±% badge, TrendingUp/TrendingDown
icons, "Update to $X.XX" (with undo toast) and "Dismiss" (30 days)
actions; teal palette for price decreases
- `drift_threshold_pct` setting added to SettingsPage Billing Behavior
- "Notify on price changes" toggle added to ProfilePage notifications
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
- invalidateOtherSessions() in authService.js: deletes all sessions except current
- Password change (auth.js + profile.js) now invalidates all other sessions
- Password change rotates current session ID (sets new cookie)
- New POST /api/auth/logout-all endpoint (deletes all sessions + clears cookie)
- Audit logging for logout.all and password.change
- Added last_password_change_at to auth.js change-password for consistency
- Hudson security audit: 6/6 PASS