{"repo": "axif0/study-plan", "files": {"study-wellbeing-app-PRD.md": {"00b230fd699ed101d40a1da37af26748be9a87ee": {"t": 1785595267.8195398, "n": 45466, "h": "afb069a198735c57", "c": "# Product Requirements Document (PRD)\n## Nigakoi — Personalized Study & Digital Wellbeing App\n\n| Field | Value |\n|---|---|\n| **Version** | 2.4 |\n| **App version** | 0.1.0 (`versionCode` 1) |\n| **Launcher name** | Nigakoi |\n| **Internal / project name** | StudyCoach |\n| **Package** | `com.studycoach.app` |\n| **Platform** | Native Android (Kotlin + Jetpack Compose) |\n| **minSdk / targetSdk / compileSdk** | 26 / 35 / 35 |\n| **Status** | Shipped local v0.1 + engagement (§6.10) + vault habit enrichment (v2.4) — canonical product spec |\n| **Supersedes** | PRD v2.3; PRD v2.2; PRD v2.1; PRD v2.0; PRD v1.2 (Draft) |\n\n> **Implementation note:** Build native Android — Accessibility Service (§6.3) requires it. Use the schema in §8 as the single source of truth (Room DB). Every LLM call re-serializes a trimmed slice of this schema into the prompt; never rely on LLM conversation memory.\n>\n> **v2.4 rule:** Where code and older draft PRD disagree, **code is truth**. Original v1.2 intent that is not shipped lives under §11 Deferred / Future. Status tags: **[Shipped]** | **[Partial]** | **[Deferred]**.\n>\n> **v2.1 delta:** Phrase pools + no-repeat-last-3; light tie shuffle; “why this now” reason lines; pre-session phone hook; CHUNK subject interleave; variable-ratio bonus + weekly streak freeze. All offline / LocalCoach — no new network or permissions.\n>\n> **v2.2 delta:** Pomodoro work/break duration derives from today’s `energy_log` check-in (`LocalCoach.pomodoroDurationsFor`) — low → 15/3, ok/unset → 25/5, high → 30/5. Phone-Down target stays fixed 25 min. No schema migration.\n>\n> **v2.3 delta:** Wire LLM `performanceOneLiner` + `distractionInsight` (once/day → `cached_phrases`, LocalCoach fallback); Pomodoro elapsed work → `StudySession.duration_minutes` on swipe-done; same-day focus momentum badge; hotspot-aware nudge cooldown; derived `WeeklyQuest` on Overall. **No schema migration.**\n>\n> **v2.4 delta:** Vault habit enrichment — `HabitStore.suggestDailyCap` / week trend from last-90 entries; Banglish `LocalCoach.habitMessage` PhrasePick pools (vault-only); optional Banglish LLM upgrade with history payload. `h.json` still isolated from study `trimCtx`. **No Room schema migration.**\n\n---\n\n## 1. Problem Statement\n\nStudents and job-exam candidates get distracted by social media (e.g. Facebook via Chrome) while trying to study. Generic digital-wellbeing reminders are ignored because they are not personalized and do not understand:\n\n- What the user is actually studying\n- Which topics are weak and need repeated revision\n- The user’s own behavior pattern (when / why they get distracted)\n- Curated external content (YouTube channels, websites) they *want* to follow — without falling into the platform’s distraction trap (algorithmic feed, recommended videos)\n\nThe app must feel like a **personal study coach**, not a generic screen-time blocker — and it must **survive LLM API key expiry** without losing what it has learned about the user.\n\n**Cultural layer (shipped):** Bangla–English UX copy, partner/friend coach tones, and a daily completion ritual (“Umma”). Brand name **Nigakoi** on launcher, notifications, setup, and widget.\n\n---\n\n## 2. Goals\n\n| Goal | Success looks like | Status |\n|---|---|---|\n| Reduce distracted scrolling (FB via Chrome / apps) | Contextual nudges at the right moment, in the user’s tone | **[Shipped]** UsageAccess + Accessibility |\n| Build a personalized study plan without heavy effort | Syllabus OCR / paste / manual → structured subjects & topics | **[Shipped]** LLM optional; local parse fallback |\n| Daily work without rigid auto-calendar | Monthly topic pool + derived / manual daily picks | **[Shipped]** Auto calendar **disabled** |\n| No quizzes / tests — zero “teaching” burden | App organizes / schedules only; content stays user-driven | **[Shipped]** |\n| Persistent personalization independent of LLM key | All personal data in app DB; new key = instant continuity | **[Shipped]** Room + EncryptedSharedPreferences for key |\n| Curated, distraction-free external content | Followed sites/channels → update cards only, no open feed | **[Partial]** RSS on open; YouTube needs API key UI |\n| Smart, importance-weighted revision | High-priority / shaky topics recur sooner | **[Shipped]** Explicit intervals §6.5 |\n| Focus tools that reduce phone pull | Phone-down timer, Pomodoro | **[Shipped]** |\n| Offline coach continuity | LocalCoach phrase pools when key missing / call fails | **[Shipped]** |\n| Reduce study-flow boredom | Varied coach copy, tie shuffle, reason lines, bonus flourish, micro-quest, momentum | **[Shipped]** §6.10 |\n| Protect streak fairness | Once-a-week freeze for exactly one miss | **[Shipped]** §6.5 / §6.10 |\n| Right-time distraction nudges | Hotspot-aware cooldown — rarer outside windows, prioritize hour before risk | **[Shipped]** §6.3 |\n\n---\n\n## 3. Non-Goals (explicitly out of scope)\n\n- No quizzes, tests, or grading of any kind\n- No AI “teaching” / explaining concepts inside the app (app organizes / schedules only)\n- No open-ended social feed browsing (YouTube / website feeds are never shown — only followed-item updates)\n- No dependency on the LLM for remembering user history (LLM is stateless; context sent each call)\n- No light theme (always dark)\n- No iOS / web v1 (Accessibility monitoring is Android-specific)\n- No cloud sync in v1 (§11)\n\n---\n\n## 4. Users\n\n**Primary:** Self-learners preparing for a job exam / academic syllabus within a fixed deadline (typically 2–3 months), prone to social-media distraction, who want a personalized, non-clinical study companion that speaks in a Bangla–English mix and optional affectionate / strict friend register.\n\n**Defaults in schema (editable in Settings):** height 177 cm, weight 80 kg — used only for grounded accountability in vault / LLM context, never for body-shaming.\n\n---\n\n## 5. Core Architecture Principle\n\n> **The LLM is a disposable tool. The app’s database is the brain.**\n\n- Behavior, plan, weak topics, preferences, and history live **locally** (Room `nigakoi.db` / profile document). API keys live in **EncryptedSharedPreferences**, never in profile JSON.\n- Every LLM call sends a **trimmed context payload** derived from §8 — not raw distraction event timestamps.\n- If the API key expires and the user adds a new one (possibly a different OpenAI-compatible provider), the new model “knows” the user because context comes from the DB.\n- **Provider-agnostic:** any OpenAI-compatible `/chat/completions` endpoint works via Settings (base URL + model + key).\n- **LocalCoach** supplies Bangla–English phrase **pools** (6–10 variants per trigger × tone) when the key is absent or the call fails; in-memory **no-repeat-last-3** phrase IDs avoid copy fatigue. Cached LLM phrases in `cached_phrases` survive key expiry for display.\n\n```mermaid\nflowchart LR\n subgraph brain [Local brain]\n RoomDB[nigakoi.db profile]\n HabitFile[h.json vault]\n KeyStore[EncryptedSharedPreferences]\n end\n UI[Compose UI]\n LocalCoach[LocalCoach fallback]\n LLM[OpenAI-compatible API]\n Monitors[UsageMonitor / Accessibility]\n UI --> RoomDB\n UI --> HabitFile\n Monitors --> RoomDB\n UI --> LocalCoach\n UI -->|\"trimmed JSON + prompt\"| LLM\n Monitors -->|\"nudge\"| LLM\n KeyStore -->|\"Authorization\"| LLM\n LLM -.->|\"optional upgrade\"| UI\n```\n\n---\n\n## 6. Feature Set\n\n### 6.0 Navigation & shell **[Shipped]**\n\n**Entry:** `MainActivity` → `StudyCoachTheme` → `StudyCoachNav`.\n\n| Condition | Start route |\n|---|---|\n| `!setup_complete` | `setup` |\n| else | `daily` |\n\n**Bottom nav (5 tabs)** — hidden on `setup`, `a11y`, `vault`:\n\n| Route | Label | Icon |\n|---|---|---|\n| `daily` | Daily | Today |\n| `monthly` | Monthly | CalendarMonth |\n| `overall` | Overall | Dashboard |\n| `topics` | Topics | List |\n| `settings` | Settings | Settings |\n\nNav: `popUpTo(startDestination)`, `launchSingleTop`, `saveState` / `restoreState`.\n\n**Stack-only routes:**\n\n| Route | Screen | How reached |\n|---|---|---|\n| `a11y` | Accessibility explainer | Settings → Digital Wellbeing |\n| `vault` | Habit tracker | 5 taps on “Settings” title |\n\nOn setup complete: `UsageMonitor.checkAndNudge` + revision notify if due.\n\n---\n\n### 6.1 Interface A — One-Time Study Plan Builder (Setup) **[Shipped]**\n\n**Trigger:** First launch, or Settings → “Full setup again” (`resetSetup`).\n\n**Branding:** Logo avatar, headline **Nigakoi**, tagline: *OCR / paste / manual topics → local plan. LLM structures syllabus only.*\n\n#### Inputs\n\n| Field | Default / notes |\n|---|---|\n| Your name | `\"\"` |\n| About you | Free text (exam, struggle…) |\n| Best study hours | `\"21:00-24:00\"` |\n| LLM API key | Prefills from `LlmDefaults` when present; stored only in KeyStore on save |\n| Base URL | `https://token-plan-sgp.xiaomimimo.com/v1` |\n| Model | `mimo-v2.5-pro` |\n| Deadline | Today + 3 months (`yyyy-MM-dd`) |\n| Goal | `\"Finish full syllabus before exam\"` |\n| Syllabus text | OCR append and/or paste |\n| Weak topics | Comma-separated → substring match → `priority = high` |\n| YouTube channels | One per line → `followed_content.youtube_channels` |\n| Websites / RSS | One per line → `followed_content.websites` |\n| Use LLM to structure | Switch, default **on** |\n| Manual subject / topic | Appends `# Subject` + topic lines to draft |\n\n**Personal on first save:** tone hardcoded `casual_bangla_english` (full tone picker lives in Settings). \n**Default distraction apps:** `facebook`, `instagram`, `tiktok`, `chrome_facebook`.\n\n#### Syllabus format (local parser)\n\n```\n# Math\nAlgebra\nCalculus\n# Bangla\nGrammar\n```\n\n- Lines starting with `#` = subject headers\n- Other non-empty lines = topics (leading `-` / `*` stripped)\n- Junk filter strips meta / page / chapter noise (`PlanBuilder.isJunkTopicName`)\n- Weak hints: case-insensitive substring → `high` priority\n\n#### OCR **[Shipped]**\n\n- Camera or gallery → ML Kit Latin text recognition (`ImageUtils.uriToOcrText`)\n- Denied camera → toast `\"Camera permission lagbe\"`\n- Scan path sets `source = scanned_syllabus`, `entry_method = ocr_scan` when LLM path applies\n\n#### Processing\n\n1. Local parse: `PlanBuilder.parseSyllabusLocal(syllabus, hints)`\n2. If LLM on + key + syllabus: **stream** `streamSyllabusToJson` → live “LLM thinking…” panel (reasoning chunks, display capped ~800 chars); fallback non-stream `parseSyllabusToJson`\n3. Apply: `PlanBuilder.applyLlmSyllabusJson` (falls back to local parse on bad JSON)\n4. **`daily_plan` cleared** — no LLM calendar generation in product flow\n5. High-priority topics without `next_revision_due` get `PerformanceEngine.nextRevisionDue`\n6. `setup_complete = true`; monthly log: `\"Plan built (N topics)\"` (+ `\" via LLM\"` when used)\n\n#### Validation\n\n- **Review & save** enabled when `(syllabus.isNotBlank() || draftPreview.isNotEmpty()) && deadline.isNotBlank()`\n- Confirm dialog: parsed subjects / topics (preview capped ~12 topics per subject)\n- **Test LLM:** ping → success banner with model reply\n\n#### Offline path\n\nLLM toggle off → local parse only; status `\"Plan ready (offline).\"`\n\n#### Deferred from v1.2 (setup)\n\n- Editable drag-drop draft calendar UI\n- YouTube playlist suggestions at setup\n- PDF / notes resource uploads as first-class setup inputs\n- Nested subtopic tree UI (schema field exists; UI treats flat topics)\n\n---\n\n### 6.2 Interface B — Daily Dashboard **[Shipped]**\n\n**Screen:** `DailyScreen`. Title **\"Aaj\"** for today, **\"Daily\"** for past days.\n\n#### Header chrome\n\n| Element | Behavior |\n|---|---|\n| Streak flame | `🔥 {current_streak_days}` — infinite pulse (§6.9) |\n| FocusStreakCard | Phone-down completion history summary |\n| Phone-Down CTA | `\"📵 Start 25min Phone-Down Focus\"` → `PhoneDownDialog` |\n\n#### Date navigation\n\n- **WeekStrip:** Sunday-start week; green = studied, amber = planned; today amber border\n- Prev / next day; **future days disabled**\n- Past days: **PastDayRecord** read-only (no swipe / mark-done)\n\n#### Today-only blocks\n\n| Block | Behavior |\n|---|---|\n| Exam countdown | Days to `goal.deadline`; color <10 red, <30 amber, else green; alpha pulse if <10 |\n| All-done badge | `\"Aaj sব shesh!\"` + reopen Umma |\n| Distraction banner | If Usage Access + data: total min + worst app; red bg if total > 30 min |\n| Energy check-in | Chips `low` / `ok` / `high` → `energy_log` (also drives Pomodoro durations — §6.6) |\n| Coach phrase | `LocalCoach.dailyOpenMessage` (pooled variants); 👍/👎 → `nudge_feedback` (last 50) |\n| Distraction insight card | When `distraction_hotspots.size ≥ 3`: LLM `distractionInsight` or `LocalCoach.distractionInsight`; dismissible for today via `cached_phrases[\"distraction_insight_dismissed\"]` |\n| Focus picker | 1 topic if energy=low else 2; sort: due → high → shaky |\n| Revision due | Up to 8 topics |\n| Followed updates | `ContentTracker.fetchUpdates` on open |\n| Daily mode banner | Reflects `DailyMode` for the day |\n| Focus-choice UI | Mon/Thu: `\"Ajke kon ta?\"` — 2 ranked options → `pickTodayFocus` |\n| Today’s list | `SwipeTopicRow` with **why-this-now** secondary line; CHUNK labels `\"Bite i/n\"` |\n| Empty CTA | If monthly pool empty → instructions; else build pick from pool |\n| Pomodoro FAB | On focused / first topic when viewing today |\n\n#### Overlays (order)\n\n1. `DifficultyDialog` after mark-done (before Umma)\n2. `PomodoroDialog` / `PhoneDownDialog` on demand\n3. `UmmaDialog` when all today topics done (once per date)\n4. Variable-ratio **bonus** toast (occasional, on topic complete — §6.10) may accompany session-complete flash\n\n#### Today queue derivation (`TodayQueue`) **[Shipped]**\n\n> **`today_queue` is not stored.** Derived at read time.\n\n**Priority:** `daily_selected[date]` → ranked from `monthly_topics` → empty (CTA).\n\n| Constant | Value |\n|---|---|\n| `WEEKDAY_COUNT` | 2 |\n| `WEEKEND_COUNT` | 1 |\n\n| `DailyMode` | Days | Behavior |\n|---|---|---|\n| `FOCUS_CHOICE` | Mon, Thu | Wait for user pick; UI shows top 2 choices; queue empty until pick |\n| `CHUNK` | Tue, Fri | Small-bite framing; ≥2 slots; **cross-subject interleave** among equal-rank frontier (§6.10) |\n| `LIGHT` | Wed, Sat | Filter due / shaky / high; 1 slot |\n| `CATCH_UP` | Sun | If `pace_status == behind`: overdue+high; else soft light (1 slot) |\n\n**Ranking sort (desc):** due → high priority → shaky → weightage → status rank. \n**Tie-break:** date + `user_id` seeded shuffle **within fully tied groups only** (not global random). Stable for same day+user.\n\n**Why-this-now:** `TodayQueue.whyThisNow(topic)` — local string from `confidence` / `priority` / `weightage` / `next_revision_due` / `last_touched` / `status`. Shown under topic name on Daily (`SwipeTopicRow`) and Monthly pool. No LLM.\n\n---\n\n### 6.2b Monthly View **[Shipped]**\n\n**Screen:** `MonthlyScreen`.\n\n- Month navigation (current + past; future limited)\n- **MonthCalendarGrid:** heat by session count (0 / 1–2 / 3+); planned days amber; selected / today borders\n- **SelectedDayPanel:** planned topics + study sessions for tapped day\n- Past months: topics touched + activity / monthly log\n- Current month: per-subject progress cards (`LinearProgressIndicator`; thresholds 70% / 40% color)\n- **Monthly pool list:** tap toggles Today; long-press menu; overdue badge; **why-this-now** secondary line under topic name\n- Button: **Build today’s pick from pool**\n- Today’s manual selections summary (`AnimatedVisibility` when non-empty)\n\n---\n\n### 6.2c Topics View **[Shipped]**\n\n**Screen:** `TopicsScreen`.\n\n- Overall coverage banner (animated %)\n- Mini stats: Got it / Need review / Due / Subjects\n- Search + filters: `all`, `due`, `high`, `shaky`, `done`\n- Expandable **SubjectCard** per subject (chevron rotation + `animateContentSize`)\n- `SwipeTopicRow` + delete / monthly / daily context menu\n- **FAB:** Add Subject (name, OCR camera/gallery, topics text, weak topics) → `addSubjectFromText` (LLM if key present)\n\n**UI labels (storage keys unchanged):**\n\n| Storage | Label |\n|---|---|\n| `solid` | Got it |\n| `shaky` | Need review |\n| `unrated` | Not rated |\n| `high` priority | Important |\n\n---\n\n### 6.2d Overall Dashboard **[Shipped]**\n\n**Screen:** `OverallScreen`.\n\n- Animated coverage ring (1000 ms)\n- Streak flame pulse\n- Chips: Pace, Revise %, Got it, Need review\n- **Weekly micro-quest** (`WeeklyQuest.forWeek` — derived, not stored): title + progress bar\n- 4-week distraction sparkline (`weekly_distraction_trend`)\n- Digital Wellbeing Today: per-app minutes + Usage Access CTA\n- Hotspots (top 3 by `frequency_score`)\n- Topic avoidance (top 3)\n- Performance one-liner: LLM `performanceOneLiner` once/day → `cached_phrases[\"performance_oneliner\"]` (+ `_date`); fallback `LocalCoach.performanceSummary`\n- Profile card (name, about, hours, goal, deadline)\n- FocusStreakCard\n- Study History: last 14 days expandable; insight if `phone_minutes_before > 30`\n\n---\n\n### 6.3 Distraction Monitoring & Nudging **[Shipped]**\n\n#### UsageMonitor\n\nWatched packages mapped to labels: Facebook, Instagram, TikTok, Chrome, Twitter, Reddit, WhatsApp.\n\n| Rule | Value |\n|---|---|\n| Window | 20 minutes |\n| Min foreground time to nudge | ≥ 3 minutes |\n| Match | Label must match `personal.distraction_apps` (substring) |\n| Event retention | Last 200 `distraction_events` |\n| Hotspot bump | `frequency_score += 0.1` (cap 1.0); new hotspot starts 0.3 |\n| Avoidance bump | +0.1 on planned topic |\n| **Hotspot-aware cooldown** | After trigger rules pass: `UsageMonitor.nudgeCooldownMs` — **approaching** (hour before hotspot start) **3 min**; **in window** **5 min**; **outside** **20 min**; empty hotspots → **5 min** default. In-memory `lastNudgeAt` — no schema |\n\nMessage: LLM `nudge()` if key else `LocalCoach.distractionWarning` (pooled). \nNotification title: **Nigakoi**.\n\n#### DistractionAccessibilityService\n\n- Watches Chrome / Chrome beta/dev / Firefox / Facebook app\n- Triggers: `facebook_app`, `chrome_facebook`, `chrome_instagram`, `chrome_tiktok` (URL text scan depth ≤ 8)\n- **Debounce:** same hotspot-aware `nudgeCooldownMs` as UsageMonitor (was fixed 5 min)\n- Same profile updates as UsageMonitor\n- Fallback copy pattern: `\"{name}, {plannedName} waiting. Facebook pore — ek minute study e fire asho.\"`\n\n#### Privacy explainer **[Shipped]**\n\n`AccessibilityExplainerScreen` → system Accessibility settings. Manifest description states data stays on device.\n\n#### NudgeNotifier channels\n\n| Channel ID | Name | Importance | Notification ID |\n|---|---|---|---|\n| `nudges` | Study nudges | DEFAULT | 42 |\n| `revisions` | Revision reminders | DEFAULT | 43 |\n| `daily_target` | Daily target | HIGH | 44 |\n| `milestones` | Milestones | HIGH | 50 + pct |\n| `weekly_report` | Weekly report | DEFAULT | 60 |\n\n---\n\n### 6.4 Curated External Content Tracker **[Partial]**\n\n| Source | Behavior | Status |\n|---|---|---|\n| Websites | On-app-open RSS fetch; regex `