# Weekly Reflection Improvement Plan

**Date:** 2026-06-16  
**Feature:** Weekly Reflection (Metacognition / Structured Weekly Review)  
**Status:** Analysis complete; improvement plan defined  
**Scope:** Backend (Laravel/PHP), Frontend (Next.js/TypeScript/React), Data model, UX flows, Integrations, Habit formation  
**Related files (key):**  
- `backend/app/Http/Controllers/WeeklyReflectionController.php`  
- `backend/app/Models/WeeklyReflection.php`  
- `backend/database/migrations/2026_04_26_000001_create_weekly_reflections_table.php`  
- `backend/routes/v1/practice.php`  
- `frontend/components/weekly-reflection-modal.tsx`  
- `frontend/components/review/review-provider.tsx` (trigger, state, `checkWeeklyReflection`)  
- `frontend/components/review/review-modals.tsx` (mount point)  
- `frontend/app/review/page.tsx` (wiring)  
- `frontend/app/layout.tsx` + `frontend/data/landing-i18n.ts` (marketing claims)  
- `backend/app/Http/Controllers/ProfileController.php` (deletion)  
- `frontend/types/domain/dashboard.ts` + mappers (no current integration)  
- Existing notes in `backend/optimize-plan.md` (lazy modals, shared Modal primitive)

---

## Executive Summary

The Weekly Reflection feature was designed to deliver timely, data-grounded metacognitive support: after meaningful review work, surface this-week stats, prompt structured reflection (hardest topic, helpful strategy, next-week focus), and persist history for a "profile journal."

**Current reality:** The prompt reaches some active users (review-queue completers with ≥10 reviews) and collects data, but the feature is severely under-delivering on its intended purpose and marketing positioning ("builds self-awareness... key to becoming a self-directed learner").

**Root problems:** History is write-only (no UI consumes `GET /api/v1/reflections`), triggers are narrow and unreliable, stats are shallow/misleading, reflection is shallow and non-habit-forming, and there are zero feedback loops or integrations with dashboard/review/daily plans.

**Goal of this plan:** Transform Weekly Reflection from an occasional low-engagement modal nag into a visible, valuable learning journal and habit that reinforces the app's science-based identity, increases retention of insights, and measurably supports user self-regulation.

**Expected outcomes (post-implementation):**
- Users can view, revisit, and act on past reflections (journal).
- Reflection surfaces across the product (dashboard reminders, review context, daily plans).
- Higher completion rates via better triggers, "remind later" options, and immediate value.
- More accurate week-scoped insights + personalization.
- Alignment between marketing claims and actual product experience.
- Test coverage + alignment with existing optimization efforts (shared modal, lazy loading).

---

## Identified Issues

### 1. History Exists in Backend but Is Completely Invisible to Users
- `GET /api/v1/reflections` (WeeklyReflectionController::index) returns all past entries ordered by `week_start` desc.
- Controller comment explicitly says "for profile journal."
- **Frontend consumption: zero.** No profile page, no `/stats/journal`, no dashboard widget, no list, no search.
- `stats_snapshot` is stored but never shown historically.
- Consequence: Users derive no cumulative value; reflections feel like a dead-end chore. Metacognition does not compound.

### 2. Trigger Mechanism Is Narrow, Brittle, and Low-Visibility
- Fires only in `review-provider.tsx:1860` inside `handleSubmitAnswer` when the review queue empties.
- Ignores: Daily Mix, sentence/particle/kanji reviews, partial sessions, pure dashboard or practice activity.
- `reflectionChecked` + `setReflectionChecked(true)` is a one-shot in-memory guard per provider mount. Refresh or navigation can suppress it.
- "Remind me later" (modal line 164) simply calls `onClose` with no reschedule, no toast, no future prompt, no push notification.
- Threshold is hardcoded (≥10 reviews this week) + requires being online at the exact moment of finishing a full queue.
- No server-side "pending reflection" indicator, badge, or proactive prompt.

### 3. Stats Snapshot Is Weak, Inaccurate, and Provides Little Insight
- Only three fields: `reviews_this_week`, `accuracy`, `most_forgotten`.
- `most_forgotten` query (controller:56-60) selects global highest `lapse > 0` for the user (via `user_cards` + `cards.kanji`). It is **not** scoped to reviews or lapses that occurred this week. (Prior git history shows this was already a source of bugs.)
- No week-over-week comparison, no new cards studied, no practice volume/time, no streak, no topic or deck breakdown.
- `stats_snapshot` is saved but never used for trends or comparison in the UI.

### 4. Reflection Experience Is Shallow and Does Not Build Habits
- Questions are static/generic with no examples or scaffolding.
- No pre-fill from prior week's focus ("Last week you set X — how did it go?").
- Strategy is limited to 6 preset chips (no "other" free-text, no multi-select).
- Post-save step (step 3) is purely celebratory/generic ("またね！ ... keep up the great work"). No summary of what the user wrote, no immediate action (e.g., "Turn this focus into a daily plan item"), no value reinforcement.
- No visible habit signals: reflection streak, "X weeks reflected", badges, progress toward consistency.
- Save swallows errors and still advances to step 3 (lines 48-49).
- Modal is fully custom (no focus trap, inconsistent with other modals). Per `optimize-plan.md`, it should be refactored to use a shared `ui/modal.tsx` primitive + lazy-loaded.

### 5. Missing Integration and Feedback Loops
- No linkage to dashboard, daily plans, stats pages, or the review experience itself.
- Past focuses are never surfaced ("You wanted to work on te-form...").
- No server-side insights/aggregates (common hard topics across users, accuracy trend for reflected weeks, strategy effectiveness signals).
- No connection between reflections and other metacognitive features (e.g., elaborative interrogation).
- Marketing (landing-i18n.ts, layout keywords) heavily promotes the feature; product delivery does not match.

### 6. Other Technical / Quality Gaps
- Zero dedicated tests (controller logic for `pending`, uniqueness, most-forgotten query, store validation).
- Potential N+1 / perf: full-week `Review` scan + unindexed lapse query on every review completion for eligible users.
- No pagination or export on `index`; no edit of past entries.
- Bilingual surface is minimal (only modal header); questions and placeholders are English-only.
- Deletion path is covered (ProfileController), but no soft-delete or archive option.
- Modal not yet lazy-loaded (called out in optimize-plan).

---

## Proposed Solutions

### A. Make History Visible and Valuable (Core Unlock)
- Consume `GET /api/v1/reflections` in a new or extended frontend surface (Journal tab/section on profile or dedicated `/stats/reflections` or integrated into existing stats).
- Display chronological list + per-week stat cards (replay the snapshot + answers).
- Add simple trends (e.g., accuracy over reflected weeks) and quick actions (e.g., "Re-focus on this" → daily plan or review filter).
- Surface past focuses proactively in dashboard/review.

### B. Broaden, Stabilize, and Humanize the Trigger
- Move check to additional entry points (dashboard mount, after any graded activity, initial app load with debounce).
- Persist check state (localStorage `lastReflectionCheck` + week) or add a lightweight server flag.
- Improve "Remind me later" with choices (tomorrow / in 2 days / next session) + client-side reschedule or queued notification.
- Lower or make configurable the activity threshold; consider "any review activity + no reflection this week."
- Add a non-intrusive "Weekly Reflection pending" indicator/badge that users can click.

### C. Improve Stats Accuracy and Richness
- Scope `most_forgotten` to cards reviewed/lapsed this week (join recent `Review` rows or filter by `reviewed_at` / `updated_at` in the week).
- Add 1-2 more snapshot fields server-side (new cards, practice minutes if available) and compute deltas vs prior week.
- Return prior-week reflection data alongside current stats so the modal can pre-fill "Last focus was...".

### D. Deepen the Reflection Experience + Add Immediate Value
- Add pre-fill + continuity: load last week's `focus_next_week` and `hardest_topic` as context.
- Enhance strategy input (allow custom "Other", perhaps multi-select or rating).
- Post-save: show a concise recap of what they wrote + prominent CTA ("Add focus to Daily Plan", "Review hard items now", "Pin for this week").
- Add lightweight habit mechanics: compute reflection streak (consecutive weeks with entries), show in modal + profile; award simple badges or progress.

### E. Integrate Across the Product (Feedback Loops)
- Dashboard: "This week's focus (from your reflection)" card or reminder; link to journal.
- Review start: optional banner or tooltip referencing current focus.
- Daily Plan creation: suggest turning recent `focus_next_week` text into plan items.
- Optional: lightweight server aggregates or per-user insights (e.g., "Topics you marked hard improved X%").

### F. Technical Polish, Tests, and Alignment with Existing Plans
- Refactor modal to use shared `ui/modal.tsx` (a11y, focus trap, escape, scroll lock) and lazy-load via `next/dynamic` (per optimize-plan.md).
- Add controller + feature tests for pending conditions, most-forgotten scoping, store, uniqueness.
- Add DB index for the lapse/reviews-this-week queries if missing.
- Expand bilingual strings; consider i18n keys for questions.
- Align with optimize-plan modal extraction work to avoid duplication of effort.

---

## Prioritized Action Items

### P0 — High-Impact (Foundation + Immediate User Value)
1. Implement frontend Journal/Reflections list view consuming `GET /api/v1/reflections` (chronological + embedded stats + answers).
2. Fix and scope `most_forgotten` query + enrich stats snapshot (add at least one delta field).
3. Broaden trigger + persist check state; improve "Remind me later" with reschedule options.
4. Add pre-fill of prior week's focus into current modal + post-save recap + "Add to Daily Plan" action.
5. Migrate WeeklyReflectionModal to shared Modal primitive + make it lazy-loaded.

### P1 — Medium (Habit Formation + Integration)
6. Add reflection streak counter (backend derivation or simple count of consecutive `week_start` entries) and surface in modal + profile/dashboard.
7. Surface past/current focus in dashboard and review flows.
8. Enhance strategy input (custom "Other" + optional rating).
9. Add basic trends/insights in the journal view (accuracy over time for reflected weeks).
10. Client-side reminder toasts + optional server notification hook for pending reflections.

### P2 — Deeper / Long-term (Differentiation + Scale)
11. AI-personalized reflection spark question (feed recent hard cards + prior focus into cheap prompt via existing AiGenerativeService patterns).
12. Server-side aggregates/insights (common hard topics, strategy correlation with accuracy).
13. Edit past reflections (PUT endpoint + UI).
14. Export (text/PDF/markdown) and search/filter in journal.
15. Full i18n of modal content + reflection journal.
16. A/B test question variants or trigger timing; instrument conversion metrics.
17. Performance: index queries, extract stats computation to a service, add caching for pending check.

---

## Implementation Steps

### Phase 0 — Alignment & Scaffolding (1-2 days)
- Review and align with `backend/optimize-plan.md` Phase 4 modal extraction work. Decide ownership of shared Modal + lazy wrapper for `weekly-reflection-modal`.
- Add a lightweight ADR or note in `backend/docs` if needed (this plan serves that role).
- Set up tracking: decide on events to log (pending shown, saved, dismissed, "remind later" choice, journal opened, focus used in plan/review). (Can be lightweight internal logging or existing analytics.)
- Create a small todo list or GitHub project board for the P0 items.

### Phase 1 — Data Accuracy + Backend Foundations (2-3 days)
1. **Controller & query improvements** (`WeeklyReflectionController.php`):
   - Refactor `most_forgotten` to be week-scoped: join or subquery recent `Review` rows for the user this week, then find highest-lapse `UserCard` among those cards (or use review-side lapse snapshots if available). Add comment explaining the scope.
   - Optionally expand the stats payload: include `new_cards_this_week` (count of `user_cards` created in the window), `practice_minutes` if trackable, or leave extensible via `stats_snapshot`.
   - In `pending`, when `should_show`, also fetch the user's most recent prior reflection (previous week or last entry) and return a `prior_focus` / `prior_hardest` field for pre-fill.
   - Add or verify DB index on `reviews.user_id + created_at` and on `user_cards.user_id + lapse` (or the join path). Use `EXPLAIN` or Telescope.
2. **Store/index robustness**:
   - Ensure `index` supports optional `?limit` + `?before` for future pagination (even if frontend starts simple).
   - Add validation/normalization for `helpful_strategy` (whitelist or allow free "other:..." values).
3. **Tests**:
   - Feature test for `pending`: no prior reflection + ≥10 reviews → should_show true + correct stats; already reflected → false; <10 reviews → false.
   - Test for most-forgotten scoping (seed reviews + lapses inside/outside week).
   - Test store idempotency on same [user, week_start].
   - Test prior-week context is returned when present.
4. **Profile deletion** — already covered; add a quick regression test if desired.

### Phase 2 — Trigger Reliability + UX Polish (Frontend + Modal) (3-4 days)
1. **Trigger expansion** (`review-provider.tsx` + other entry points):
   - Extract `checkWeeklyReflection` (or a `useWeeklyReflectionPrompt` hook) so it can be called from dashboard, after Daily Mix submit, etc.
   - Add localStorage guard: `lastReflectionCheckWeek` + `lastReflectionCheckTs`. Only re-check if week changed or after a cooldown.
   - On app/dashboard load (with network), call the check (debounced, non-blocking).
2. **"Remind me later" improvements** (modal + provider):
   - Replace single "Remind me later" with a small menu or secondary buttons: "Remind tomorrow", "Remind in 2 days", "Next session".
   - Store choice in localStorage (e.g., `{week: '...', remindAfter: '2026-...'}`) and re-evaluate on relevant mounts.
   - On chosen remind date, surface a non-modal toast/banner ("Time for your weekly reflection?") with direct "Open" action.
3. **Modal refactor + lazy load**:
   - Per optimize-plan: wrap with `next/dynamic` (lazy-modals or dedicated).
   - Refactor `weekly-reflection-modal.tsx` to compose the canonical `ui/modal.tsx` (overlay, backdrop, escape, focus trap, scroll lock). Remove duplicate backdrop/animation logic.
   - Preserve current step animation and visual style.
   - Add proper error toast on save failure instead of silently advancing.
4. **Pre-fill + post-save value** (modal):
   - Accept optional `priorFocus` / `priorHardest` props (from the enriched pending response).
   - In step 2, show a small "Last week you focused on: ..." callout above the focus textarea.
   - After successful save (step 3), show a recap card:
     - Hardest: ...
     - Strategy: ...
     - Focus: ...
   - Add primary CTA buttons under recap: "Add focus to Daily Plan", "Review hard items", "View journal". Wire "Add to Daily Plan" to navigate or open plan composer with pre-filled text.
5. **Bilingual & accessibility quick wins**:
   - Extract question labels/placeholders to i18n (or at minimum add Japanese variants).
   - Ensure strategy chips and inputs are keyboard accessible and have proper labels.

### Phase 3 — Journal / History Surface (Frontend) (3-5 days)
1. **New or extended view**:
   - Options (choose one primary):
     - Dedicated route `/stats/reflections` or tab in existing stats.
     - Or "Journal" section on profile (if profile page exists or is planned).
   - Use TanStack Query (align with optimize-plan Phase 2 direction) for `useQuery(['reflections'])`.
2. **UI components** (new files under `frontend/components/reflection/` or `sections/`):
   - `ReflectionList.tsx`: virtualized or paginated list of weeks.
   - `ReflectionCard.tsx`: shows week date, embedded stats grid (replay snapshot), answers, "Revisit focus" action.
   - Simple line chart (or list of deltas) for accuracy trend across reflected weeks (reuse existing charting if present or lightweight SVG).
3. **Actions from journal**:
   - "Focus on this again" → create daily plan item or filter review queue / challenge mode.
   - "View related reviews" (if data available) or link to hard cards from that week's snapshot.
4. **Empty / first-time state**:
   - Friendly copy explaining the purpose + encouragement to complete the next reflection.
5. **Integration points**:
   - Dashboard: add a small "Recent Reflection" or "Current Focus" card that links to journal or opens the latest entry.
   - Review page: optional subtle banner or tooltip when a current-week focus exists.

### Phase 4 — Habit Signals + Cross-Feature Integration (2-3 days)
1. **Streak & progress**:
   - Backend helper (or simple client computation from the list): count consecutive ISO weeks with a reflection entry.
   - Surface streak in the modal header (step 1/2), post-save, and in the journal header.
   - Optional: simple badge or progress ring ("4-week reflection streak").
2. **Feedback loops**:
   - When starting a review or daily mix, if there is a current-week focus, show a tiny "Your focus this week: ..." line (collapsible).
   - On daily plan creation, offer to pull text from latest `focus_next_week`.
3. **Optional notification hook**:
   - If push notifications are already implemented (`usePushNotifications`), add a "weekly reflection reminder" type that the server can schedule (or client can request on "remind later").

### Phase 5 — Polish, Tests, Performance, Documentation (2-3 days)
1. **Tests (frontend)**:
   - Playwright or component tests for the modal flow (stats → questions → save → recap + CTA).
   - Test "remind later" choices and localStorage reschedule logic.
   - Test journal list loads and renders past entries.
2. **Performance**:
   - Verify `pending` endpoint cost after query changes (aim for indexed lookups).
   - If `pending` is called frequently, consider a lightweight server-side "has_pending_reflection" flag on user or a materialized weekly summary row (future).
3. **i18n & copy**:
   - Full Japanese translation of modal questions, journal UI, and any new dashboard strings.
4. **Documentation**:
   - Update controller PHPDoc if signatures changed.
   - Add a short "How Weekly Reflection works" note in `backend/docs` or developer README.
   - Update landing copy only after delivery to keep claims accurate (or mark as "coming soon" until shipped).
5. **Observability**:
   - Confirm existing error logging covers reflection save failures.
   - Add simple internal metrics if the app has them (impression → save rate, dismiss reasons).

### Phase 6 — Rollout & Iteration
- Soft rollout: enable for a cohort or behind a simple feature flag if available.
- Monitor: save rate, journal visits, "add to plan" clicks, streak distribution.
- Iterate on P1/P2 items based on real usage (e.g., which questions users actually answer, value of streak).
- Consider A/B on trigger timing or post-save CTAs.

---

## Success Metrics (Suggested)

- Reflection save rate (shown → saved) ≥ 60% (baseline TBD from logs).
- Journal page visits per active user per month (target >0.5).
- % of reflections that have a non-empty `focus_next_week` (quality proxy).
- Qualitative: user comments or support tickets mentioning "weekly reflection" or "journal" shift from confusion to appreciation.
- Alignment check: marketing pages accurately describe delivered behavior.

---

## Risks & Mitigations

- **Scope creep on journal UI**: Start minimal (list + cards + basic trend). Defer charts/export to P1/P2.
- **Query performance on most_forgotten**: Prototype the scoped query early; add index; fall back to simpler "most recent hard card this week" if needed.
- **Modal refactor conflict with optimize-plan**: Coordinate with whoever owns the shared Modal extraction; treat the reflection modal as one of the first consumers.
- **Trigger over-notification**: Use localStorage cooldowns and respect "remind later" choices strictly.
- **Bilingual debt**: Prioritize Japanese for questions/placeholders; English can lag if resources are limited.

---

## Open Questions / Decisions Needed

- Preferred primary location for the journal (standalone route vs. profile tab vs. stats section)?
- Do we want server-scheduled push reminders for "remind later," or keep purely client-side for v1?
- Threshold change: keep 10, lower to 5, or make "any activity this week with no reflection"?
- Should `helpful_strategy` become a free-text + optional enum, or keep the chip model + "other"?

---

## References

- Prior detailed analysis (this document's predecessor): full evaluation of design, utility, UX, strengths/weaknesses.
- `backend/optimize-plan.md` (modal extraction, lazy loading, review page split).
- Existing feature marketing in `frontend/data/landing-i18n.ts` and `app/layout.tsx`.
- Current implementation: WeeklyReflectionController, model, migration, modal, review-provider trigger logic.

---

**End of plan.** Next step: pick up Phase 0 alignment, then execute Phase 1 backend accuracy work. All changes should be incremental, testable, and aligned with the broader optimization and science-positioning goals of the product.
