- Asset Manager: search/filter/sort, list+grid views, rename, move between R2 folders, tag chips, bulk actions, used-in counts; fix R2 delete lookup
- Inbox: readable wrapped rows with subject/preview, real read state, type filters, bulk actions, mojibake repair
- Broadcast: pick a Resend template to fill subject and body
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Adds forgot/reset password, signup email verification, sign-out-of-all-devices,
note-usage and certificate display in account settings, and password-changed
security emails. Fixes study sessions being lost on server restart by
persisting them to disk, and fixes sanitizeStudyUsers silently dropping the
new pending-token fields on load. Also surfaces the lesson discussion board
in the main site nav, trims the sign-in page for returning users, and renames
colossiansStudy.tsx/colossiansStudyData.ts to studyPages.tsx/legacyColossiansData.ts
now that the study system covers more than Colossians.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Upload dropdown lets you choose R2 folder (uploads/images/guides/finished)
or local server disk. Asset table shows location column for each file.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New uploads route to R2 with folder selection (uploads/images/guides/finished).
Existing local files continue to be served via express.static for backward compat.
Adds R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET,
R2_PUBLIC_URL env vars. listUploadedAssets merges R2 objects + local files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Admin can set birthday (month/day) per student in Study Users panel
- Summer birthdays (Jun–Aug) prompt admin to set an alternate school-year date
- 🎂 badge on student card header during birthday week
- Dismissible happy birthday banner shown to student on their study hub
- Admin receives email notification on the celebration day, once per year
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Critical fixes:
- sanitizeLoadedHitStats/VisitorStats: restore full state shape so a
snapshot restore no longer crashes hit-counting middleware (missing
byPathReal, byPathBot, byDayReal, byDayBot, botReasons, ipHashIndex)
- /questions/share/🆔 read state.questions only, not draft questions
- inbound-email: validate date with Number.isFinite before toISOString
- study-reminders: wrap each send in try/catch so one failure doesn't
block remaining users; persist sent-markers after each success
Security:
- getClientIp: use req.ip (trust-proxy-resolved) instead of raw
x-forwarded-for header to prevent IP spoofing
- env-snapshot.env: delete immediately after backup tar stream ends
so secrets don't linger on disk between exports
Correctness / UX:
- contact form: email failures no longer 500 the user after the
submission is already saved; log and fall through instead
- study-account profile: cap data URI avatar at 6 MB
- admin enrollment PATCH: validate slug against study catalog
- signup: return 503 at MAX_STUDY_USERS instead of silently dropping
oldest accounts
Memory leaks:
- contactHits, downloadHits Maps: prune stale entries at 5000 entries
- resendEmailSubmissionIndex: trim to 2000 entries (oldest first)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>