v0.5.0 (2026-09-05)
Theme: Email channel completion + object storage + observability
v0.5.0 clears the entire v0.4.0 email design debt, promotes object storage from ADR to production code, and adds observability for the cron worker. The security domain completes login rate-limit consolidation, session device management, and a Passkey pilot.
Email Channel
- Digest folding: a user's notifications merge into one email; same-type groups of ≥3 fold into a single "N × type" line, details capped at 5 with an overflow count.
- Retry & dead-letter: a single user's send failure no longer aborts the whole run; retry counters accumulate per notification and after 3 attempts the notification is dead-lettered (excluded from the queue) for manual inspection.
- Real-time delivery: security alerts, team invites, role changes, and successful payments send immediately at event time (preference-gated, with sent receipts); the cron digest acts as the retry fallback.
- Timezone staggering: the digest only sends to users whose local time is 08:00 (hourly external cron recommended); missing/invalid timezones fall back to Asia/Shanghai.
- Marketing channel: double opt-in (toggle → confirmation email → click to confirm), public confirm/unsubscribe routes with tokens, and a mandatory unsubscribe footer on every marketing email.
Object Storage
StorageDriverabstraction with two drivers: Supabase Storage by default (zero config), Aliyun OSS when all fourOSS_*variables are present (SDK loaded dynamically, not bundled by default).- Server-relayed uploads: images up to 2MB, content-type whitelist, extensions derived from the whitelist to prevent path traversal.
- Avatar upload (profile edit) and project cover (project settings) are wired.
Observability
- Appark APM: lightweight first-party wrapper (no vendor SDK), off by default; enabled when both env vars are present. Checkout and cron runs are instrumented.
- Worker run records: every digest run persists pulled/sent/failed/duration.
- Backlog alert: Sentry report when pending notifications exceed 500.
Auth Security
- Rate-limit consolidation: email dimension (5 failures / 15 min) plus a new IP dimension (20 / 15 min), unified in the rate-limit keyed sliding window.
- Session devices: device list (UA/IP/last active) + per-device revocation; sessions register automatically via the auth callback and a dashboard heartbeat.
- Passkey pilot: registration/verification loop behind the
NEXT_PUBLIC_FEATURE_PASSKEYflag (default off); session issuance awaits native Supabase support.
Performance & Quality
- Tailwind v4 native theme:
@configbridge andtailwind.config.tsremoved in favor of@theme inline/@custom-variant/@utility(ADR-013). - TanStack Query cache consolidation: single-source query keys + three cache presets across 8 call sites.
- Coverage gates: branches 78% → 85% (measured 85.7%); unit tests 556 → 668.
Upgrade Notes
- Run migrations 016–019 (marketing subscriptions / worker runs / session devices / passkey credentials).
- Change the external digest cron to hourly (for timezone staggering).
- Optional enablements:
OSS_*(storage switch),NEXT_PUBLIC_APPARK_*(APM),NEXT_PUBLIC_FEATURE_PASSKEY=true(passkeys).
See CHANGELOG.md in the repo root for the complete list.