Files
famapp/docs/decisions/0005-journal-research.md
T

6.3 KiB
Raw Blame History

0005 — Journal / mood tracking

Date: 2026-07-03 Status: accepted (2026-07-04)

Context

Journal module (task 86) needs per-user entries, mood multi-select, charts over time, insights, and /api/v1/journal endpoints. ADR research included Giftyaning/Mood-Tracker (Gitea #20, epic #19).

Build-vs-adopt: Mood-Tracker

Decision: do not adopt the repo.

Factor Mood-Tracker famapp need
License None Must have clear reuse rights
Stack Vite SPA, JS, localStorage Next.js 15, TypeScript, Postgres, Authentik
Mood model Single-select, 5 presets Multi-select fixed catalog
Fields Title + plain text Optional title + TipTap HTML, stress, pills
API / auth None /api/v1/ + session + bearer token
Code shape One 672-line App.jsx src/modules/journal/ manifest pattern

Borrow (reimplement in TypeScript): mood→numeric scoring, day streak, week-over-week trend, insight card layout. Not copied source.

What we decided (2026-07-04)

# Topic Choice
1 Charts Build natively + Recharts for mood/stress trends and correlation views
2 Moods Fixed catalog (~812 presets with emoji + color); multi-select
3 Entries Multiple per day allowed
4 Stress Optional 110 slider
5 Insights v1 Core + correlations — streak, top mood, avg stress; stress↔mood and pills↔avg-mood simple stats
6 Index calendar Month grid with dots on days that have entries; tap day → filtered list
7 Entry shape Optional title + rich-text body (shared RichTextEditor)
8 Chart points All entries as individual points; x-axis uses datetime (not date-only rollup)

Decision

Module: src/modules/journal/

Standard module layout: schema.ts, manifest.tsx, server/, components/, app routes under /journal.

Data model

Table journal_entries:

  • household_id — household scope for DB consistency
  • user_idper-user privacy; all reads/writes filter user_id = current user
  • recorded_at timestamptz — required date+time (defaults to now on create)
  • title text nullable — optional
  • body text — HTML from shared rich-text editor (ADR 0004)
  • moods jsonb — array of catalog mood ids (multi-select)
  • stress smallint nullable — 110
  • pills_taken boolean nullable

No household-shared journal in v1. Wife cannot see Matt's entries and vice versa.

Mood catalog

Fixed in code (src/modules/journal/mood-catalog.ts): ids, label, emoji, color, numeric score for analytics. Users pick from catalog only (no custom tags in v1).

UI surfaces

Route Purpose
/journal Recent 510 entries, browse all link, month calendar, links to mood tracker + insights
/journal/new, /journal/[id] Create/edit entry (date/time required; rest optional)
/journal/mood Recharts mood/stress over time (all entry points)
/journal/insights Streak, top mood, correlations

Rich text: RichTextEditor / RichTextContent from src/components/rich-text/. No share viewer in v1.

Insights v1

  • Entry streak (consecutive days with ≥1 entry)
  • Most common mood (selected period)
  • Average stress (7d / 30d)
  • Week-over-week mood trend (score-based)
  • Correlations: simple aggregates — avg mood score on days pills taken vs not; stress vs mood score scatter or grouped averages

No ML / sentiment analysis in v1.

API

Additive on ADR 0006 foundation:

  • GET/POST /api/v1/journal/entries
  • GET/PATCH/DELETE /api/v1/journal/entries/:id

Bearer token and session auth. Responses scoped to token owner's user id for journal (household token acts as owner user for API mutations per existing pattern, but journal entries are always stored with the authenticated user's id).

Document in docs/api/openapi.yaml.

Testing

  • Playwright: tests/e2e/journal.spec.ts — create minimal entry → list → detail → mood tracker loads
  • Unit tests for mood scoring / streak helpers where non-trivial

Consequences

Positive

  • Recharts gives proper time-series without maintaining custom chart code for long trends.
  • Fixed mood catalog keeps insights comparable across entries.
  • Per-user privacy matches personal journal expectations.
  • Reuses rich-text stack from task 85.

Trade-offs

  • All-entry chart points mean busy days show multiple dots; datetime x-axis required.
  • Fixed catalog may miss nuance — body text carries freeform detail.
  • Correlation stats are descriptive only (no causation); keep copy honest in UI.
  • Recharts adds bundle weight on /journal/mood and /journal/insights only (route-level code split).

Out of scope (ADR)

  • Household-shared journals
  • LLM agent tools for journal (task 88)
  • Custom user-defined mood tags
  • Share links for journal entries

References