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

129 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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](https://github.com/Giftyaning/Mood-Tracker) (Gitea [#20](https://gitea.ginnoir.com/ginnoir/famapp/issues/20), epic [#19](https://gitea.ginnoir.com/ginnoir/famapp/issues/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_id`**per-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
- Task brief: `docs/tasks/86-journal-module.md`
- Rich text: `docs/decisions/0004-rich-text-editor.md`
- API: `docs/decisions/0006-api-llm-agent.md`
- Mood-Tracker research: https://github.com/Giftyaning/Mood-Tracker