--- title: 'Unified Tasks View — cross-format aggregation study' type: 'feature' created: '2026-05-24' status: 'done' # cancelled — product decision option A (2026-05-24): removed aggregated Tasks view; use Structured Kanban instead context: - '{project-root}/AGENTS.md' - '{project-root}/memento-note/components/notes-list-views.tsx' - '{project-root}/memento-note/lib/types.ts' --- ## Intent **Problem:** The home **Notes / Tasks** toggle only aggregates Markdown `- [ ]` / `- [x]` lines from `Note.content`. Rich-text TipTap task lists (HTML in `content`) and legacy `checklist` notes (`checkItems` JSON) are invisible in Tasks view, stats column, and sort-by-tasks — causing empty or misleading UX when users create to-dos via the editor or legacy data. **Approach:** Introduce a single extraction layer (`lib/tasks/`) that normalizes tasks from all three sources into a stable `UnifiedTask` model with source-specific stable IDs; update toggle/save paths to write back to the correct storage; refresh i18n to explain supported formats without Markdown-only wording. ## Boundaries & Constraints **Always:** No DB schema migration in v1 unless human approves; reuse existing `content` / `checkItems` fields; toggle must use optimistic `updateNote` + `onNotePatch`; all user-facing strings via i18n (EN+FR minimum); no new tests unless explicitly requested; do not conflate Structured Views `checkbox` properties with inline note tasks. **Ask First:** Deprecate vs revive `type: checklist` (dedicated note type); one-way migration of legacy `checkItems` → Markdown or TipTap; nested TipTap task support in aggregated view; scope of 15-locale fill vs EN/FR keys only. **Never:** Treat Structured View kanban/status as Tasks view; store a parallel tasks table; rewrite entire editor serialization to JSON; run destructive DB commands; claim done without manual verification on markdown + richtext + checklist sample notes. ## I/O & Edge-Case Matrix | Scenario | Input / State | Expected Output / Behavior | Error Handling | |----------|--------------|---------------------------|----------------| | Markdown tasks | `type: markdown`, content with `- [ ]` lines | Tasks listed; toggle flips `[ ]`↔`[x]` in content | Skip malformed lines | | TipTap tasks | `type: richtext`, HTML with `ul[data-type="taskList"]` | Tasks listed with text from `

` inside `li`; toggle updates `data-checked` + checkbox | Skip items without parseable text | | Checklist note | `type: checklist`, `checkItems: [{id,text,checked}]` | All items listed; toggle updates matching item by `id` | Normalize legacy `done` → `checked` on read | | Mixed note | Markdown lines + TipTap HTML in same richtext note | Both sources extracted (dedupe by normalized text optional v2) | No double-toggle same semantic item in v1 if ambiguous | | Empty scope | Notebook with no extractable tasks | Empty state with format-agnostic hint | No errors | | Toggle race | User toggles in Tasks while note open in editor | Last write wins or editor refresh via `emitNoteChange` | Log + refetch on mismatch | | API update | `PUT /api/notes` with `checkItems` | Same JSON.stringify behavior as server actions | Align API with actions in same PR | ## Code Map - `memento-note/components/notes-list-views.tsx` — current `extractTasksFromNotes`, `getNoteTasksStats`, `handleToggleTask`, Tasks UI - `memento-note/components/home-client.tsx` — Notes/Tasks toggle, passes notes into list views - `memento-note/lib/types.ts` — `CheckItem`, `NoteType` - `memento-note/lib/utils.ts` — `parseNote`, `checkItems` deserialization - `memento-note/components/rich-text-editor.tsx` — TipTap TaskList/TaskItem extensions - `memento-note/components/note-editor/note-editor-context.tsx` — save forces `checkItems: null`; dormant checklist handlers - `memento-note/components/note-checklist.tsx` — checklist UI (legacy card path) - `memento-note/components/note-card.tsx` — checklist toggle via `updateNote({ checkItems })` - `memento-note/app/actions/notes.ts` — canonical server update, JSON.stringify checkItems - `memento-note/app/api/notes/[id]/route.ts` — API checkItems inconsistency - `memento-note/locales/en.json`, `fr.json` — `notes.viewTasks`, `tasksEmptyHint`, etc. - `memento-note/lib/note-preview.ts` — excerpt may leak `[ ]` syntax ## Tasks & Acceptance **Execution (proposed — after study approval):** - [ ] `memento-note/lib/tasks/types.ts` — define `UnifiedTask`, `TaskSource`, stable `taskKey` — single contract for UI - [ ] `memento-note/lib/tasks/extract-tasks.ts` — extract from markdown lines, TipTap HTML (DOMParser or regex+guard), checkItems — replaces inline regex in list views - [ ] `memento-note/lib/tasks/toggle-task.ts` — source-aware write-back to content or checkItems — replaces fragile lineIndex-only toggle - [ ] `memento-note/components/notes-list-views.tsx` — wire extract/toggle helpers; show source badge optional — keep UI, fix data layer - [ ] `memento-note/locales/en.json`, `fr.json` — tasksEmptyHint, tasksHeader, optional `tasksSourceMarkdown` / `tasksSourceRichText` / `tasksSourceChecklist` — honest UX - [ ] `memento-note/app/api/notes/[id]/route.ts` — stringify checkItems like server actions — fix API drift **Acceptance Criteria:** - Given a markdown note with `- [ ] Buy milk`, when user opens Tasks view for that notebook, then the task appears and toggling persists after reload. - Given a richtext note with TipTap task list in saved HTML, when user opens Tasks view, then tasks appear with correct checked state. - Given a checklist note with `checkItems`, when user opens Tasks view, then items appear and toggle updates `checkItems` not content. - Given empty notebook, when user opens Tasks view, then empty state text does not mention Markdown-only format. - Given user toggles task in aggregated view, when note is reopened, then editor reflects the same checked state. ## Design Notes **Recommended architecture:** pure functions in `lib/tasks/` — no new DB columns. `UnifiedTask` fields: `taskKey`, `noteId`, `noteTitle`, `text`, `completed`, `source: 'markdown'|'tiptap'|'checklist'`, `locator` (lineIndex | domPath | checkItemId). **TipTap HTML (observed):** `ul[data-type="taskList"] > li[data-type="taskItem"][data-checked="true|false"]` with label+checkbox and content in nested `div > p`. Toggle: flip `data-checked`, sync `input:checked`, preserve HTML structure. **Checklist type decision:** AGENTS.md documents type as legacy/semi-dead. v1 should **read** existing `checkItems` in Tasks view; reviving full checklist editor is a separate story. **i18n:** Replace Markdown-only hint with product copy: tasks are collected from checkboxes in notes (lists in rich text, markdown, or checklist notes). Optional short “How it works” link/tooltip. **Out of scope v1:** Structured Views checkbox properties; cross-note deduplication; migrating all checklist notes to richtext; nested task hierarchy display. ## Verification **Commands:** - `cd memento-note && npm run lint` — expected: no new errors in touched files **Manual checks:** - Create 3 notes in one notebook: markdown with `- [ ]`, richtext with TipTap todo block, import/mock checklist with checkItems — all visible in Tasks view, each toggle survives refresh.