Hardened the app and overhauled journaling UX

by Deariary Official

Production hardening

  • Security and reliability sweep: root 404, PWA manifest, route loading skeletons, runtime env validation, staging Basic Auth warning, and security headers (CSP/HSTS/XFO). Shipped as a bundle in PR #303.
  • Added error boundaries (global-error.tsx and route-level error.tsx) so runtime crashes have recovery paths.
  • Tightened API resilience: wrap fetch in safeFetch (network/timeout), guard JSON parse, parse RFC 7807 Problem Details, and swapped silent catches for visible toast errors. Also fixed rollback for failed optimistic notification updates and added fallbacks in useMarkdown.
  • Graceful timeouts: if journal regeneration polling hits the max attempts, show a clear toast and stop pretending it’s still working.
  • Cleanup and compliance: removed stale TODOs and dead code, and wired up real account deletion. PR #304.
  • Volume: 78 commits, 15 PRs across frontend and brand — big hardening push.

"9 of 13 'unimplemented backend' TODOs were already implemented."

Journals UX and navigation

  • Replaced “On This Day” with the Time Jump system, then refined it: stepped intervals (1mo/3mo/6mo/1y/… up to 5y), dynamic empty-state copy, and moved it to the daily detail page backed by a /time-jump API.
  • Added prev/next day nav and auto-polling when landing directly on pending/generating journals for a smoother wait state. Shipped in PR #268.
  • Failure UX: surfaced failed entries (no more invisible gaps), then simplified to a display-only error with auto-retry messaging and removed inline regenerate buttons to avoid quota traps.
  • Visual polish: ink dividers between cards, fade-in-on-scroll animations, body text clamped to 3 lines in lists, timezone fix for date math, and the age-based overgrowth flora on detail/share pages.
  • Sharing: branded not-found for expired/invalid share links.

Billing, subscriptions, and data export

  • Subscription flows got a full pass: inline confirm panels for upgrade/period switch/resume/cancel-downgrade; unified pending-downgrade/canceling UI; disabled plan changes during pending states; clearer pricing and “Valid until”; hid canceled cards and “Manage billing” on Free; and added short-term polling to sync post-webhook state.
  • Adapted to backend’s downgrade semantics (no immediate charge, resume/cancel-downgrade supported).
  • Data export landed in settings, then ungated to meet GDPR portability (available to all users, no plan wall).

Analytics overhaul

  • Introduced an in-app analytics SDK with auto pageviews and custom events, working for both anonymous and authenticated users (provider moved to root).
  • Instrumented key transactions across auth, onboarding, journals, subscriptions, integrations, and settings.
  • Delivery path iterated quickly: from “await before nav” → queue with timed/threshold flush + keepalive and visibility/pagehide flushing → per-event fallback to match endpoint → bulk POST to the new /analytics/events/bulk. Added tests for flush listeners and queue behavior.

Brand polish

  • Synced design tokens/components with the app: switched JP serif to Klee One, added multilingual CJK support, adjusted journal body size, and removed next/font CSS vars for static use.
  • Expanded the overgrowth system to 6 stages (fresh → ancient) with updated inline SVGs.
  • Tracked in the brand repo via PR #1.

Share

Check out my diary entry on deariary #deariary #diary

Your life, automatically written.

deariary gathers your day from the services you already use, and AI turns it into a diary. No writing required — just a daily record you can look back on.

Turn your passing days into your own diary.

Try it free