# PRD: FocusOne — ADHD Next-Task Assistant

> **Version:** 2.0 (Rewrite)
> **Date:** 2026-04-26
> **Status:** BUILD
> **Stack:** Next.js 14 · TypeScript · Tailwind · Supabase (Postgres) · Stripe · Todoist REST API · OpenAI API

---

## 1. Problem & User

**Target User:** Adults with ADHD doing self-managed knowledge work. They already use Todoist or Notion to capture tasks but freeze when it's time to start — they open their task list, see 30–100 items, and can't choose. This is called "task paralysis" or "activation energy barrier."

**Core Pain:** The problem isn't task management — it's task *activation*. Existing tools are excellent at storing and organizing work, but terrible at answering "what should I actually do right now, given my energy and available time?" ADHD users specifically need external scaffolding to bridge the gap from "I should work" to "I'm working on X."

**Evidence:** Reddit, X, and HN data (Apr 2026) show this as the single highest-emotion complaint in ADHD productivity communities. Multiple indie developers are building similar tools from scratch because nothing in the market solves it well.

---

## 2. Target Outcome & KPIs

| KPI | Target at 90 Days |
|-----|-------------------|
| Activated users (completed first check-in → got task recommendation) | 70% of signups |
| D7 retention | ≥ 40% |
| Paid conversion (free trial → paid) | ≥ 15% |
| MRR | $800 (100 paid users × $8) |
| "Task actually started" self-report (in-app survey) | ≥ 65% of recommendations |

---

## 3. MVP Scope (In)

1. **Todoist integration** — connect via personal API token; import active tasks + project names
2. **Daily check-in** — 3-question form: energy level (low/medium/high), available time (15/30/60/90 min), context (work/personal/side project)
3. **AI-powered single task recommendation** — show exactly ONE task with one-sentence rationale
4. **One-click micro-step breakdown** — "Break it down" button generates 3–5 concrete sub-steps via OpenAI
5. **Done / Skip** — mark task complete (sync back to Todoist) or skip to next recommendation
6. **Auth + billing** — email/password login via Supabase Auth, Stripe for $8/month subscription
7. **14-day free trial** — no credit card required at signup

---

## 4. Out of Scope

- Mobile native apps (iOS/Android)
- Notion integration (post-MVP)
- Google Calendar / time-blocking
- Team / shared workspaces
- Custom AI model fine-tuning
- Recurring task creation
- Browser extension
- Offline support

---

## 5. User Flow (Happy Path)

1. User signs up → connects Todoist API token → tasks imported in background
2. User arrives at `/today` → sees check-in prompt: "How's your energy? How much time do you have?"
3. User fills in check-in (3 clicks) → AI selects one task and shows it full-screen with rationale
4. User optionally clicks "Break it down" → sees 3 micro-steps in a modal
5. User works on task → clicks "Done" → task marked complete in Todoist, streak updated
6. Repeat or end session

---

## 6. Functional Requirements (P0 Only)

| ID | Requirement |
|----|-------------|
| FR-01 | User can connect Todoist by entering personal API token; app fetches and stores active tasks |
| FR-02 | Daily check-in stores energy (low/medium/high), time_available (15/30/60/90), context (work/personal/side) |
| FR-03 | Recommendation engine selects one task: priority = overdue → due_today → high_priority → lowest_effort → lowest_friction; filtered by time_available and context |
| FR-04 | OpenAI call generates 3–5 micro-steps from task title + project context; response cached per task_id |
| FR-05 | "Done" marks task complete via Todoist REST API PATCH; "Skip" deprioritizes task for current session only |
| FR-06 | Stripe Checkout creates subscription; webhook updates `users.subscription_status` |
| FR-07 | After trial expires, `/today` page shows paywall; all other routes redirect to `/billing` |
| FR-08 | User can manually add tasks (title + estimated minutes) without Todoist |

---

## 7. Minimal Data Model

```sql
-- Supabase tables

users
  id uuid PK
  email text UNIQUE
  todoist_token text  -- encrypted at rest
  subscription_status text  -- 'trial' | 'active' | 'expired'
  trial_ends_at timestamptz
  streak_count int DEFAULT 0
  created_at timestamptz

tasks
  id uuid PK
  user_id uuid FK → users.id
  todoist_task_id text  -- null if manually added
  title text
  project_name text
  due_date date
  priority int  -- 1-4 (Todoist scale)
  estimated_minutes int
  friction_score int DEFAULT 3  -- 1-5, user-adjustable
  context text  -- 'work' | 'personal' | 'side'
  is_completed bool DEFAULT false
  skipped_at timestamptz
  synced_at timestamptz

checkins
  id uuid PK
  user_id uuid FK → users.id
  energy text  -- 'low' | 'medium' | 'high'
  time_available int  -- minutes
  context text
  recommended_task_id uuid FK → tasks.id
  task_started bool  -- optional self-report
  created_at timestamptz

micro_steps
  id uuid PK
  task_id uuid FK → tasks.id
  steps jsonb  -- array of step strings
  created_at timestamptz
```

---

## 8. API / Integration Notes

**Todoist REST API v2**
- `GET https://api.todoist.com/rest/v2/tasks` — fetch active tasks
- `POST https://api.todoist.com/rest/v2/tasks/{id}/close` — mark complete
- Auth: `Authorization: Bearer {personal_token}` header
- Rate limit: 450 req/15min — safe for MVP sync-on-login

**OpenAI API**
- Model: `gpt-4o-mini` (cheap, fast, good enough)
- Prompt: `"Break this task into 3-5 tiny, concrete, immediately actionable steps. Task: {title}. Project: {project}. Return JSON array of strings."`
- Cache response in `micro_steps` table to avoid re-calling per task

**Stripe**
- Product: `FocusOne Pro` — $8/month recurring
- Use Stripe Checkout hosted page (no custom payment UI)
- Webhook events: `checkout.session.completed`, `customer.subscription.deleted`
- Endpoint: `POST /api/webhooks/stripe`

---

## 9. Acceptance Criteria

| ID | Criterion |
|----|-----------|
| AC-01 | Connecting a valid Todoist token imports ≥1 task within 5 seconds, shows success toast |
| AC-02 | Submitting check-in redirects to `/today/recommendation` with exactly one task card visible |
| AC-03 | "Break it down" modal shows 3–5 micro-steps within 3 seconds; error state if OpenAI fails |
| AC-04 | Clicking "Done" calls Todoist close endpoint; task disappears from queue; streak increments |
| AC-05 | Clicking "Skip" hides current task and shows next recommendation without page reload |
| AC-06 | Expired trial user hitting `/today` sees paywall with "Upgrade for $8/month" CTA |
| AC-07 | Stripe Checkout completes → `subscription_status` updates to `active` within 10 seconds (via webhook) |
| AC-08 | Manual task (no Todoist) appears in recommendation pool and can be marked Done |

---

## 10. Delivery Plan

### Milestone 1 — Core Data + Todoist Sync (Hours 1–7)

**Goal:** Users can log in, connect Todoist, and see their imported tasks.

Files to create/modify:
- `prisma/schema.prisma` → define `User`, `Task`, `Checkin`, `MicroStep` models (replace placeholder schema)
- `app/api/integrations/todoist/route.ts` → `POST` to save token, trigger sync; `DELETE` to disconnect
- `lib/todoist.ts` → `fetchTasks(token)` wrapper for Todoist REST v2
- `app/api/tasks/sync/route.ts` → upsert tasks from Todoist into DB
- `app/settings/page.tsx` → Todoist token input form + sync status
- `app/api/auth/[...nextauth]/route.ts` → configure Supabase Auth provider

Exit criteria:
- `POST /api/integrations/todoist` with valid token returns 200 and persists token
- `GET /api/tasks` returns imported task list (≥1 item) for authenticated user
- Unauthenticated request to any `/api/*` returns 401

---

### Milestone 2 — Check-in + Recommendation Engine (Hours 8–14)

**Goal:** Users complete daily check-in and receive one AI-selected task recommendation.

Files to create/modify:
- `app/today/page.tsx` → check-in form (energy / time / context) with 3-step UI
- `app/api/checkins/route.ts` → `POST` saves check-in, calls recommendation logic, returns `task_id`
- `lib/recommend.ts` → pure function: takes `tasks[]` + `checkin` → returns single best `Task`; priority order: overdue → due_today → high_priority → min(estimated_minutes) within time_available
- `app/today/recommendation/page.tsx` → full-screen task card with Done / Skip / Break it down
- `app/api/tasks/[id]/done/route.ts` → mark done in DB + call Todoist close endpoint
- `app/api/tasks/[id]/skip/route.ts` → set `skipped_at`, return next recommendation
- `app/api/tasks/[id]/breakdown/route.ts` → call OpenAI, cache in `micro_steps`, return steps

Exit criteria:
- `POST /api/checkins` with valid body returns `{ task_id, task_title, rationale }`
- `POST /api/tasks/{id}/done` returns 200 and task is closed in Todoist (verify via Todoist API)
- `POST /api/tasks/{id}/breakdown` returns JSON array of 3–5 strings; second call uses cache (no OpenAI hit)
- Recommendation page renders on mobile viewport (375px) without horizontal scroll

---

### Milestone 3 — Billing + Trial Gate + Polish (Hours 15–20)

**Goal:** Stripe subscription works end-to-end; expired trial users see paywall.

Files to create/modify:
- `app/billing/page.tsx` → upgrade CTA, current plan status, manage subscription link
- `app/api/billing/checkout/route.ts` → create Stripe Checkout session, return URL
- `app/api/webhooks/stripe/route.ts` → handle `checkout.session.completed` and `customer.subscription.deleted`; update `users.subscription_status`
- `middleware.ts` → check `subscription_status`; redirect expired users from `/today` to `/billing`
- `app/onboarding/page.tsx` → 3-step onboarding: account → connect Todoist → first check-in
- `components/StreakBadge.tsx` → show current streak on recommendation page

Exit criteria:
- End-to-end Stripe test: checkout with card `4242 4242 4242 4242` → webhook fires → DB updates to `active`
- Expired trial user (`trial_ends_at` < now, `subscription_status = 'trial'`) hitting `/today` redirects to `/billing`
- Active subscriber completes full happy-path flow: check-in → recommendation → done → streak increments
- Lighthouse performance score ≥ 85 on `/today` route

---

## 11. Risks & Mitigations

| Risk | Likelihood | Mitigation |
|------|-----------|------------|
| Todoist token auth deprecation | Low | Design `integrations` table to support OAuth swap without schema change |
| OpenAI latency >3s on breakdown | Medium | Show spinner with ADHD-friendly copy ("Thinking of tiny steps..."); cache aggressively |
| Low D7 retention (ADHD users abandon new tools) | High | Implement streak + gentle email nudge at Day 3 and Day 7 of inactivity |
| Recommendation feels wrong → user distrust | Medium | Show 1-line rationale ("Chosen because: overdue + 15 min task"); allow "Not today" to teach preferences |
| Stripe webhook delivery failure | Low | Idempotency key on webhook handler; Stripe auto-retries for 3 days |

---

## 12. Chargeability Rationale

FocusOne solves a well-documented, emotionally urgent problem (ADHD task paralysis) that existing $8–$34/month tools fail to address directly; users already spend on task managers and will pay for a low-friction activation layer that demonstrably helps them start working.

