345 lines
15 KiB
Markdown
345 lines
15 KiB
Markdown
<!-- 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.
|