All Decisions

ADR-0014: DailyReflection Data Model — Structured Answers + Optional Notes

DateFebruary 8, 2026
CategoryData Architecture
Tags
data-modelreflection

Context

  • Phase 3 introduces a Daily Reflection feature with prompts and a DailyReflection entity.
  • Roadmap open question: Structured vs free-text reflection data.
  • Phase 4/5 (Weekly Synthesis / Morning Briefing) will later package reflection history into an LLM context window to generate weekly guidance and advice.
  • We need a data shape that is:
    • Easy to render in UI (prompt → answer)
    • Aggregatable (week-level rollups, trends)
    • Stable for long-term exports and LLM packaging
    • Flexible enough for users to write freely on low-energy days

Constraints:

  • Local-first, offline-only (no server-side schema evolution helpers).
  • Room-backed persistence; migrations must be manageable.

Decision

We will store Daily Reflections as answers to a living set of questions, plus an optional free-form notes field.

  • Each reflection consists of:
    • A DailyReflection record representing the day/session.
    • A list of DailyReflectionAnswer rows: one per question.
    • Optional notes for unstructured, user-written text not tied to a specific question.

We will treat the reflection as ultimately renderable into free text for weekly overview/LLM packaging. The question/answer structure exists to support a consistent UI and gentle guidance during daily entry.

Scope boundaries:

  • This ADR defines the logical data model and invariants.
  • Exact Room entity names/column types are deferred to the schema migration ADRs.

Suggested Persistence Shape (logical)

daily_reflections

  • id
  • day_key (see ADR-0017)
  • status (DRAFT | SUBMITTED)
  • notes (nullable)
  • created_at, updated_at

reflection_questions (see ADR-0015)

  • id
  • question_text (unique)
  • is_default
  • is_active
  • created_at, updated_at

daily_reflection_answers

  • id
  • daily_reflection_id (FK)
  • question_id (FK → reflection_questions)
  • position (int, stable ordering within the active question list)
  • question_text_snapshot (TEXT; optional but recommended)
  • answer_text (nullable/empty allowed)
  • created_at, updated_at

Invariants:

  • A reflection may have zero answers while in DRAFT.
  • On SUBMITTED, answers are expected to exist for each active question at the time the reflection is created, but may be empty (skipping is allowed).
  • question_text_snapshot (if stored) is written at answer creation time to preserve readability even if the question later changes.

Rationale

  • LLM packaging friendliness: question-answer pairs can be rendered deterministically into a free-text block (question text + answer + ordering), while still allowing weekly overview to treat the result as plain text.
  • Aggregation and analytics (future): structured answers enable simple counts and heuristics (e.g., common “learned” themes) without NLP.
  • User expressiveness: notes provides a “just write” escape hatch without turning the whole model into unstructured blobs.
  • Question evolution without heavy machinery: questions can be edited/curated over time; storing question_text_snapshot preserves historical readability without needing versioning.
  • Room pragmatism: a parent row + child rows maps naturally to Room relations; avoids complex JSON migrations while still being flexible.

Consequences

Positive effects:

  • Clean UI mapping: render prompts in order and bind answers directly.
  • Weekly synthesis can operate on a stable data contract: ordered list of (prompt, answer) plus optional notes.
  • Export/backup can serialize reflections consistently and reproducibly.

Known downsides:

  • More tables and joins than a single free-text column.
  • If questions are edited in-place and question_text_snapshot is not stored, historical answers may become harder to interpret.

Follow-up work:

  • Define the schema migration(s) for these entities.
  • Define a canonical “LLM packet” rendering format, e.g.:
    • Day header (local date + zone)
    • Bulleted questions + answers
    • Notes section

Alternatives Considered

  • Free-text only (single TEXT column) — rejected: hard to aggregate, weaker for deterministic LLM packaging, and prompt semantics are lost.
  • Structured only (no notes) — rejected: reduces expressiveness and increases friction on low-energy days.
  • Single JSON column for answers — deferred: simpler schema, but migrations and partial updates become harder; can be revisited if relational overhead becomes painful.

Notes

  • Skipping is explicitly allowed to preserve the principle “Reflection is lightweight and repeatable”.
  • “Structured” here means “question-indexed”, not rigid validation.