<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->

# UI Plan 2 — Backlog Board Tab Implementation

**Status:** Proposed plan.  
**Primary target:** Implement the finalized Backlog tab shown in the two supplied mockups.  
**Default mockup:** `mockups/backlog_board_default.png`.  
**Drawer mockup:** `mockups/backlog_task_drawer.png`.  
**Execution mode:** Feed this folder to Codex and execute block files in numeric order. Use `xhigh` reasoning for all chunks unless Ashley explicitly says otherwise.  
**Implementation branch suggestion:** `block-ui-backlog-board` or the repo’s closest existing branch convention.

---

## 1. Purpose

Build the desktop-first Backlog tab for FocusFlow as a real Flutter screen, not a throwaway static mockup. The final state should provide:

1. Sidebar navigation with `Backlog` active.
2. Backlog title, task count, search, filters, sort, group, board/compact toggle, settings button, and `New Task` primary action.
3. Four-column backlog board:
   - `Do Next`
   - `Need Time Block`
   - `Break Up First`
   - `Not Now`
4. Backlog task cards with project, priority, duration, difficulty bars, reward icons, child-task previews, and selection styling.
5. Right-side Backlog summary panel in the default state.
6. Right-anchored task detail drawer when a backlog card is selected.
7. Suggested slots and task actions in the drawer.
8. New task / add task entry points wired to backlog-safe capture.
9. Tests and validation that preserve the existing backend-source-of-truth rule.

This plan intentionally treats the mockups as finalized visual direction and uses the current repo architecture as implementation truth.

---

## 2. Source truth and constraints

Use sources in this order:

1. Repo files, especially `AGENTS.md`, package boundaries, existing app structure, and tests.
2. This plan folder.
3. The two mockups in `mockups/`.
4. Existing completed UI Plan 1 files.
5. Human documentation and UX flow documents already in the repo.

Hard constraints:

- V1 is SQLite-first. Do not add MongoDB runtime work.
- `scheduler_core` remains pure Dart and is the scheduling/application source of truth.
- Flutter must not import scheduler `src/`, Drift/SQLite adapters, notification platform packages, backup/export internals, or OS APIs directly.
- UI may own local visual selection state, menu open/closed state, scroll position, text controller state, and drawer open/closed state.
- UI must not own canonical scheduling rules, placement rules, task lifecycle rules, or persistence mutations.
- Any scheduling/task mutation must go through public scheduler application commands/controllers.
- New Dart files require file-level Dartdoc library docs plus Dartdoc for every public/private class, enum, enum value, constructor, method, field, and top-level declaration, following `AGENTS.md`.
- New project files require SPDX metadata.

---

## 3. Confirmed repo observations from this planning pass

The supplied repo already contains:

- Flutter app target: `apps/focus_flow_flutter/`.
- Current provisional/Plan 1 Today UI with sidebar, app shell, theme tokens, top bar, timeline cards, difficulty bars, reward icons, and selected-task modal pieces.
- Current simple `BacklogPane` and `BacklogRow` that are not visually aligned with the finalized board mockup.
- Existing public scheduler application/query concepts:
  - `V1ApplicationManagementUseCases.getBacklog`.
  - `BacklogQueryResult`.
  - `BacklogItemReadModel`.
  - `GetBacklogRequest`.
  - `BacklogView`, `BacklogFilter`, and `BacklogSortKey`.
  - `V1ApplicationCommandUseCases.quickCaptureToBacklog`.
  - `V1ApplicationCommandUseCases.scheduleBacklogItemToNextAvailableSlot`.
  - `V1ApplicationCommandUseCases.breakUpTask`.
- Existing domain `Task` supports core scheduling fields, project id, duration, priority, reward, difficulty, backlog tags, parent task id, stats, timestamps, scheduled/actual/completed intervals, status, and type.
- Current domain `Task` does **not** appear to include freeform notes or general tags, which the drawer mockup shows.
- Current application commands do **not** appear to include a general update/edit-backlog-task command, push-to-someday command, or remove/archive backlog command.

Plan implication: this is a UI implementation plus a small application/domain read-model expansion, not only a widget rewrite.

---

## 4. Product assumptions to implement unless Ashley changes them

These assumptions unblock Codex without inventing broad product scope:

1. **Backlog columns are a V1 read-model policy.** The Flutter board consumes a `BacklogBoardReadModel`; it does not independently decide canonical task grouping.
2. **Column assignment is deterministic and explainable.** Each item exposes `bucket`, `bucketReason`, and optional `reasonMetadata` so the UI can show why it is in that column.
3. **General tags and notes are V1 task metadata.** Add minimal domain/persistence/application support needed for the drawer and create/edit flows.
4. **Remove means archive from active backlog, not physical delete.** Use an application-level remove/archive transition that hides the task from backlog. Prefer `TaskStatus.noLongerRelevant` unless a repo-local convention already says otherwise.
5. **Push to Someday means mark the task as a someday/wishlist backlog item.** Use existing `BacklogTag.wishlist` where possible. This should move or keep the task in `Not Now`.
6. **Suggested slots are non-mutating previews.** They must be generated by application/core read logic or by calling scheduler logic against cloned/current state. They must not save anything until the user presses `Schedule`.
7. **Schedule button chooses a suggested slot only through backend intent.** If the current command only supports “next available slot,” wire the primary button to that command and label suggested rows as preview-only until a slot-specific command exists.
8. **Compact mode can remain a non-primary visual affordance.** Board mode is the acceptance target because only Board has a finalized mockup. If a low-risk compact list already exists, it may be reused behind the toggle, but do not invent a second finalized design.
9. **Settings remains visible and inert for this plan** unless a settings surface already exists.
10. **Project dropdown and tag controls in the drawer should support inline edits only after the relevant update command exists.** If the command is not completed in the same block, render them as disabled/read-only with active visual styling deferred only at the final polish pass.

Non-blocking clarification items for Ashley after plan review:

- Exact board bucket policy thresholds for `Do Next`, `Need Time Block`, `Break Up First`, and `Not Now`.
- Whether `Remove` should be reversible archive, cancellation, no-longer-relevant, or hard delete.
- Whether slot rows should support picking a specific slot in V1 or only preview the result of next-available scheduling.
- Whether freeform tags should be global reusable tags or simple task-local strings in V1.

Do not stop implementation on those questions unless Ashley explicitly requests a policy change before coding.

---

## 5. Visual target summary

### App shell and sidebar

- Keep the dark rounded app frame and left sidebar style from UI Plan 1.
- Sidebar width remains approximately 250 px.
- `Backlog` nav item is active with magenta-tinted fill and outline.
- `Today`, `Projects`, `Reports`, and `Settings` remain visible.
- Bottom-left status card shows:
  - green check icon,
  - `Schedule up to date`,
  - `All changes are saved.`

### Backlog default state

At desktop width around 1672×941:

- Main content has a left board region and a right summary panel.
- Header row:
  - `Backlog` title,
  - `24 tasks` count pill,
  - subtitle: `Choose work that fits your current energy.`
  - right controls: `Compact`, `Board` active, `Settings`.
- Control row:
  - search field with placeholder `Search backlog...`,
  - `Filters` button,
  - `Sort: Custom` dropdown,
  - `Group: None` dropdown,
  - magenta `+ New Task` button with trailing chevron.
- Board columns:
  - each column has an icon, title, count pill, subtitle, add icon, card stack, and `+ Add task` footer.
- Summary panel:
  - `Backlog summary` header with sparkle icon and collapse chevron,
  - total tasks and total estimated time,
  - priority counts,
  - project counts,
  - duration distribution donut/list,
  - planning tip card.

### Selected-card drawer state

- Selecting/clicking a backlog card opens a right-side drawer.
- Drawer is anchored to the right edge of the app content/window.
- Drawer overlays existing content and does **not** shift columns, header controls, or summary panel.
- No heavy scrim; underlying board remains visible.
- Selected card remains highlighted with magenta outline behind the drawer.
- Drawer width should be approximately 460–470 px at mockup width, clamped for smaller desktop windows.
- Drawer sections:
  - header with bucket/status icon, title, sparkle icon, close icon,
  - subtitle and age/created metadata,
  - notes panel,
  - project selector and tag chips,
  - duration/reward/difficulty metric tiles,
  - suggested slots list,
  - action buttons: `Schedule`, `Break Up`, `Push to Someday`, `Remove`.

---

## 6. Feature scope

### In scope

- Backlog route/tab under current Flutter app.
- Sidebar nav state and Backlog active rendering.
- Backlog-specific controllers/read state.
- Backlog board read models in public scheduler/application API.
- Demo seed data sufficient to render the exact mockup composition.
- Four board columns with counts and card ordering.
- Default summary panel.
- Drawer open/close/select-another behavior.
- Search/filter/sort/group controls with at least deterministic basic behavior.
- New Task and Add Task entry points with backlog-safe capture.
- Schedule action for a selected backlog item.
- Break Up action path if the existing `breakUpTask` command can be surfaced safely; otherwise the drawer button may open a non-persisting placeholder form until Block 8 completes the command wiring.
- Push to Someday command using `BacklogTag.wishlist` or equivalent.
- Remove/archive command using the chosen non-destructive lifecycle transition.
- Notes and tags support needed for drawer/create/edit read and persistence.
- Responsive handling for desktop width reductions.
- Widget tests and core/application tests.

### Out of scope

- Week/month views.
- Drag-and-drop card movement.
- Reports implementation.
- Shield/Recovery flows.
- Calendar sync.
- OS notifications.
- Backup/restore UI.
- Export/import UI.
- Full settings implementation.
- Perfect pixel golden tests.
- Mobile-first layout.

---

## 7. Target data/read-model shape

Codex may adjust exact names to match repo conventions, but preserve the information architecture.

```dart
enum BacklogBoardBucket {
  doNext,
  needTimeBlock,
  breakUpFirst,
  notNow,
}

class BacklogBoardQueryResult {
  final String ownerId;
  final CivilDate localDate;
  final BacklogBoardSummaryReadModel summary;
  final List<BacklogBoardColumnReadModel> columns;
  final List<ProjectOptionReadModel> projectOptions;
}

class BacklogBoardColumnReadModel {
  final BacklogBoardBucket bucket;
  final String title;
  final String subtitle;
  final String accentToken;
  final int count;
  final List<BacklogBoardItemReadModel> items;
}

class BacklogBoardItemReadModel {
  final String taskId;
  final String title;
  final String? subtitle;
  final String projectId;
  final String projectName;
  final String projectColorToken;
  final int? durationMinutes;
  final PriorityLevel? priority;
  final RewardLevel reward;
  final DifficultyLevel difficulty;
  final BacklogBoardBucket bucket;
  final String bucketReason;
  final DateTime createdAt;
  final DateTime updatedAt;
  final bool hasChildren;
  final List<BacklogChildPreviewReadModel> childPreview;
  final List<String> tags;
}

class BacklogTaskDetailReadModel {
  final BacklogBoardItemReadModel item;
  final String? notes;
  final String addedLabel;
  final List<String> tags;
  final List<ProjectOptionReadModel> projectOptions;
  final List<SuggestedSlotReadModel> suggestedSlots;
}
```

Summary should include:

- total tasks,
- total estimated minutes,
- priority distribution,
- project distribution,
- duration distribution buckets: `0–30`, `30–60`, `60–120`, `120+`,
- planning tip string.

Suggested slots should include:

- stable id,
- local date label,
- start/end display text,
- duration minutes,
- fit label (`Great Fit`, `Okay`, no-fit/conflict if relevant),
- fit severity token,
- whether it is the primary/default scheduling target.

---

## 8. Block list

Execute these files in order:

1. `UI_PLAN_2_BLOCK_01_REPO_SCOPE_AND_ASSETS.md`
2. `UI_PLAN_2_BLOCK_02_BACKLOG_READ_MODELS_AND_METADATA.md`
3. `UI_PLAN_2_BLOCK_03_NAVIGATION_AND_SCREEN_SHELL.md`
4. `UI_PLAN_2_BLOCK_04_BOARD_COLUMNS_AND_CARDS.md`
5. `UI_PLAN_2_BLOCK_05_SEARCH_FILTER_SORT_GROUP.md`
6. `UI_PLAN_2_BLOCK_06_SUMMARY_PANEL.md`
7. `UI_PLAN_2_BLOCK_07_TASK_DETAIL_DRAWER.md`
8. `UI_PLAN_2_BLOCK_08_COMMANDS_CREATE_AND_ACTIONS.md`
9. `UI_PLAN_2_BLOCK_09_TESTING_VALIDATION_HANDOFF.md`

---

## 9. Expected final changed areas

Likely changed or added areas:

```text
packages/scheduler_core/lib/src/domain/models/entities/task.dart
packages/scheduler_core/lib/src/application/application_management/**
packages/scheduler_core/lib/src/application/application_commands/**
packages/scheduler_core/lib/src/persistence/document_mapping/tasks/**
packages/scheduler_core/lib/src/persistence/persistence_contract/fields/tasks/**
packages/scheduler_persistence/lib/persistence/repositories/task_repository.dart
packages/scheduler_persistence_memory/**
packages/scheduler_persistence_sqlite/lib/src/scheduler_db/tables/tasks/tasks.dart
packages/scheduler_persistence_sqlite/lib/src/scheduler_db/daos/task_dao.dart
packages/scheduler_persistence_sqlite/lib/src/sqlite_repositories/sqlite_task_repository.dart
apps/focus_flow_flutter/lib/app/**
apps/focus_flow_flutter/lib/controllers/**
apps/focus_flow_flutter/lib/models/backlog/**
apps/focus_flow_flutter/lib/widgets/backlog/**
apps/focus_flow_flutter/lib/widgets/sidebar.dart
apps/focus_flow_flutter/lib/theme/**
apps/focus_flow_flutter/test/**
```

Do not modify unrelated packages unless tests prove a required boundary update.

---

## 10. Final acceptance criteria

The plan is complete when:

- Backlog sidebar item opens/renders the Backlog tab and is visually active.
- Default Backlog board state closely matches `backlog_board_default.png`.
- Selecting `Review Q3 budget` or any task card opens a right-side drawer matching `backlog_task_drawer.png`.
- Drawer overlays content without moving columns or summary.
- Search/filter/sort/group controls are visible and do not break board state.
- Board columns, cards, summary, and drawer are all driven by scheduler/application read models or controller-level display models derived from those read models.
- Schedule action uses scheduler application command(s); UI does not compute canonical placement.
- New task capture creates backlog tasks through scheduler application command(s).
- Push to Someday and Remove are non-destructive domain/application commands, not Flutter-only state deletion.
- Tests cover default render, navigation, controls, card selection, drawer close, summary data, and command callbacks.
- `flutter analyze` and `flutter test` pass under `apps/focus_flow_flutter`.
- Root/package tests touched by domain/persistence changes pass or are explicitly reported if environment prevents full validation.
