129 lines
6.3 KiB
Markdown
129 lines
6.3 KiB
Markdown
# 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** (~8–12 presets with emoji + color); **multi-select** |
|
||
| 3 | Entries | **Multiple per day** allowed |
|
||
| 4 | Stress | Optional **1–10** 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 — 1–10
|
||
- `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 5–10 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
|