xx
66
docs/plans/2026-01-21-bugfinder-design.md
Normal file
@@ -0,0 +1,66 @@
|
||||
<section name="problem">
|
||||
Review Bugfinder feedback in docs/sprints/phase-ongoing/Bugfinder/rpt1-8 to identify root causes across
|
||||
Analytics, Home, Meetings, People, Post Meeting, and Tasks pages, then outline ideal fixes that restore
|
||||
data visibility, interaction, and persistence.
|
||||
</section>
|
||||
|
||||
<section name="findings">
|
||||
- analytics_reports (branch finding: treat rpt1-rpt3 as equally urgent)
|
||||
- rpt1 Analytics - Meetings: totals and charts depend on meeting.segments; ListMeetings returns
|
||||
include_segments=false and no summary, so word counts and speaker stats remain zero. Root cause in
|
||||
src/noteflow/grpc/mixins/meeting/meeting_mixin.py#L197 and client/src/pages/Analytics.tsx#L75.
|
||||
- rpt2 Analytics - Performance: metrics come only from server psutil snapshots and heuristic latency
|
||||
(src/noteflow/infrastructure/metrics/collector.py, client/src/components/features/analytics/performance-tab.tsx).
|
||||
No client/server toggle exists, and high resource usage likely reflects ongoing post-processing or
|
||||
other server workloads rather than a UI issue.
|
||||
- rpt3 Analytics - Speech: entity map and speech patterns rely on meeting.segments/words in
|
||||
client/src/components/features/analytics/speech-analysis-tab.tsx. With empty segments, entities are
|
||||
blank and speech metrics show zeros; heuristics are placeholders rather than NER output.
|
||||
- home_meetings (branch finding: missing data wiring and core interactions)
|
||||
- rpt4 Home Page: MeetingCard renders meeting.segments[0]?.text so all cards show "No transcript
|
||||
available" when ListMeetings omits segments (client/src/components/features/meetings/meeting-card.tsx).
|
||||
Tasks come from meeting.summary.action_items, but ListMeetings omits summary, so tasks disappear on
|
||||
reload (client/src/pages/Home.tsx, client/src/pages/Tasks.tsx). The Ask AI button has no handler
|
||||
(client/src/components/layout/app-sidebar.tsx). Home uses HOME_RECENT_MEETINGS_LIMIT=5 and slices to 6,
|
||||
conflicting with the requested "last 3" (client/src/lib/constants/timing.ts, client/src/pages/Home.tsx).
|
||||
Summary generation does not update meeting titles, and there is no calendar-link signal in meeting
|
||||
payloads to gate that behavior.
|
||||
- rpt5 Meetings: UI calls listMeetings(limit=MEETINGS_PAGE_LIMIT) once with no offset or pagination UI,
|
||||
even though the API returns total_count (client/src/pages/Meetings.tsx).
|
||||
- people_post_meeting (branch finding: People list never populating due to data layer)
|
||||
- rpt6 People: aggregateSpeakers uses meeting.segments and preferences-only speaker names
|
||||
(client/src/lib/audio/speaker.ts, client/src/pages/People.tsx). With listMeetings returning empty
|
||||
segments, speaker metrics are all zero. Speaker renames are local only; the renameSpeaker API exists
|
||||
but is not used.
|
||||
- rpt7 Post Meeting: transcript row clicks only trigger playback in Tauri; in web they only toggle
|
||||
selection (client/src/pages/meeting-detail/use-playback.ts). Speaker renaming is hidden behind
|
||||
double-click on SpeakerBadge and is local-only (client/src/components/common/badges/speaker-badge.tsx).
|
||||
Summary tab is concise and relegated to the right panel; no dedicated view for call metrics or
|
||||
background process status. Action items and entities are read-only.
|
||||
- tasks_page (branch finding: task list empty)
|
||||
- rpt8 Tasks: tasks are derived from meeting.summary.action_items, but summaries are not included in
|
||||
ListMeetings, so lists are empty after refresh. Completion is stored in preferences only, and the
|
||||
UI supports list view only (client/src/pages/Tasks.tsx). Backend already has TaskModel but no gRPC
|
||||
endpoints, so edits/ownership/kanban are not supported.
|
||||
</section>
|
||||
|
||||
<section name="recommendation">
|
||||
- Selected strategy: build dedicated aggregate endpoints for analytics, speaker stats, and tasks.
|
||||
- Add gRPC endpoints (e.g., GetAnalyticsOverview, ListSpeakerStats, ListTasks) with pagination and
|
||||
time-series responses to replace client-side aggregation of segments/summary fields.
|
||||
- Client Analytics, People, Home, and Tasks pages should consume these aggregates instead of listMeetings.
|
||||
- Selected strategy: TaskModel CRUD as source of truth for action items.
|
||||
- On summary persistence, create/update TaskModel rows linked to action_items for provenance.
|
||||
- Add task CRUD endpoints (list/update/status/delete) to support owner, priority, due date, and kanban.
|
||||
- Remove preferences-only completion state; sync status updates through the API.
|
||||
- Selected strategy: move the LLM summary into the transcript panel and repurpose the right panel.
|
||||
- Transcript pane shows verbose summary as the primary view; summary generation should target higher
|
||||
verbosity templates by default.
|
||||
- Right panel becomes call metrics (model/tokens/latency) plus processing status (summary/entities/
|
||||
diarization, background jobs) and editing surfaces for tasks/entities.
|
||||
- Supporting fixes: wire Ask AI to a route or modal, add Meetings pagination using total_count, expose
|
||||
renameSpeaker in the UI for persistent names, add Analytics client/server toggle for performance metrics,
|
||||
and add calendar-link indicators so summary title updates only apply to non-calendar meetings.
|
||||
- Transcript interaction: in web mode, highlight transcript rows on click and surface a desktop-playback
|
||||
message until web playback is implemented.
|
||||
</section>
|
||||
@@ -0,0 +1,9 @@
|
||||

|
||||
|
||||
Issues
|
||||
|
||||
1. The header cards for Total Words and Unique Speakers has always been 0 and never changed
|
||||
|
||||
2. The graphs for Speaker Particiaption and Word Count Trends has never visualized any data
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 172 KiB |
@@ -0,0 +1,10 @@
|
||||

|
||||
|
||||
Issues
|
||||
|
||||
1. The UI here is actually fine, however this is about 30 mins after my last recording and resources are still nearly fully allocated still - I suspect something to be hanging
|
||||
|
||||
|
||||
Changes
|
||||
|
||||
1. If the server and client are on differing IP addresses or devices, then there should be a switch or a toggle to view the Server or Client performance.
|
||||
|
After Width: | Height: | Size: 193 KiB |
@@ -0,0 +1,7 @@
|
||||

|
||||
|
||||
Issues
|
||||
|
||||
1. Entity Word Map has always been blank
|
||||
|
||||
2. Speech patters are either mocked data or incomplete
|
||||
BIN
docs/sprints/phase-ongoing/Bugfinder/rpt3/Analytics - Speech.png
Normal file
|
After Width: | Height: | Size: 135 KiB |
16
docs/sprints/phase-ongoing/Bugfinder/rpt4/Home Page.md
Normal file
@@ -0,0 +1,16 @@
|
||||

|
||||
|
||||
Issues
|
||||
|
||||
1. Every meeting says “No Transcript Available” no matter how long ago it finished processing
|
||||
|
||||
2. Tasks and action items dont seem to be persisted
|
||||
|
||||
3. Ask AI button does not seem to be working
|
||||
|
||||
|
||||
Change requests
|
||||
|
||||
1. Home screen should only show the last 3 recorded meetings, it currenly shows 5.
|
||||
|
||||
2. Summarization task should also update the meeting title ONLY if the meeting isn’t connected to a calendar appointments
|
||||
BIN
docs/sprints/phase-ongoing/Bugfinder/rpt4/Home Page.png
Normal file
|
After Width: | Height: | Size: 169 KiB |
5
docs/sprints/phase-ongoing/Bugfinder/rpt5/Meetings.md
Normal file
@@ -0,0 +1,5 @@
|
||||

|
||||
|
||||
Issues
|
||||
|
||||
1. The past recordings displayed does not seem to be paginated and risks excessive resource consumption
|
||||
BIN
docs/sprints/phase-ongoing/Bugfinder/rpt5/Meetings.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
7
docs/sprints/phase-ongoing/Bugfinder/rpt6/People.md
Normal file
@@ -0,0 +1,7 @@
|
||||

|
||||
|
||||
Issues
|
||||
|
||||
1. None of the diararized speakers identified in any of the meetings have ended up here.
|
||||
|
||||
2. Metrics dont seem to be gathered or stored
|
||||
BIN
docs/sprints/phase-ongoing/Bugfinder/rpt6/People.png
Normal file
|
After Width: | Height: | Size: 98 KiB |
18
docs/sprints/phase-ongoing/Bugfinder/rpt7/Post Meeting.md
Normal file
@@ -0,0 +1,18 @@
|
||||

|
||||
|
||||
Issues
|
||||
|
||||
1. Clicking on a transcript line doesn’t seem to do anything
|
||||
|
||||
2. No way to update speaker names
|
||||
|
||||
|
||||
Changes
|
||||
|
||||
1. The LLM Generated Summary should be significantly more verbose and be what’s displayed as a primary tab in the current transcript component.
|
||||
|
||||
2. If the summary is moving to the transcript component, then executive summary should be replaced with call metrics, model/token usage, and any additional processes still running in the background.
|
||||
|
||||
3. Should be able to edit or delete the tasks and action items, identify owners, criticality, and deadline.
|
||||
|
||||
1. similar capabilities should be extended to extracted entities
|
||||
BIN
docs/sprints/phase-ongoing/Bugfinder/rpt7/Post Meeting.png
Normal file
|
After Width: | Height: | Size: 220 KiB |
12
docs/sprints/phase-ongoing/Bugfinder/rpt8/Tasks.md
Normal file
@@ -0,0 +1,12 @@
|
||||

|
||||
|
||||
Issues
|
||||
|
||||
1. Tasks only show up when they are first extracted from a recording but never persisted past restarts.
|
||||
|
||||
|
||||
Changes
|
||||
|
||||
1. Should be able to display in List, Card, and Kanban views
|
||||
|
||||
2. Tasks should display what meeting they came from and link to that post meeting summary
|
||||
BIN
docs/sprints/phase-ongoing/Bugfinder/rpt8/Tasks.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
@@ -0,0 +1,399 @@
|
||||
# Sprint Bugfinder Strategy B: Aggregates + Tasks + Summary Layout
|
||||
|
||||
> **Size**: XL | **Owner**: TBD | **Prerequisites**: `docs/plans/2026-01-21-bugfinder-design.md`
|
||||
> **Phase**: Ongoing - Bugfinder follow-ups
|
||||
|
||||
---
|
||||
|
||||
## Open Issues & Prerequisites
|
||||
|
||||
> ✅ **Review Date**: 2026-01-21 — Strategy B selected for aggregates, TaskModel CRUD, and summary layout.
|
||||
|
||||
### Blocking Issues
|
||||
|
||||
| ID | Issue | Status | Resolution |
|
||||
|----|-------|--------|------------|
|
||||
| **B1** | None | ✅ | N/A |
|
||||
|
||||
### Design Gaps to Address
|
||||
|
||||
| ID | Gap | Resolution |
|
||||
|----|-----|------------|
|
||||
| G1 | Cache TTL and invalidation rules for analytics aggregates | Default to 60s TTL; invalidate on summary/segment writes if hook available |
|
||||
| G2 | Task de-duplication key definition | Use meeting_id + normalized text; ignore case/punctuation |
|
||||
| G3 | Summary verbosity default after layout move | Use existing template defaults, add client toggle in follow-up |
|
||||
|
||||
### Prerequisite Verification
|
||||
|
||||
| Prerequisite | Status | Notes |
|
||||
|--------------|--------|-------|
|
||||
| TaskModel exists in DB | ✅ | `src/noteflow/infrastructure/persistence/models/organization/task.py` |
|
||||
| Action items persisted in summaries | ✅ | `src/noteflow/infrastructure/persistence/models/core/summary.py` |
|
||||
| Meeting list supports project filters | ✅ | `src/noteflow/grpc/mixins/meeting/meeting_mixin.py` |
|
||||
|
||||
---
|
||||
|
||||
## Validation Status (2026-01-22)
|
||||
|
||||
### IMPLEMENTED
|
||||
|
||||
| Component | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| Analytics aggregate endpoints | ✅ Implemented | `GetAnalyticsOverview`, `ListSpeakerStats` gRPC methods + repositories |
|
||||
| Task CRUD API | ✅ Implemented | Domain entity, service, repository, and gRPC endpoints (`ListTasks`, `UpdateTask`) |
|
||||
| Analytics UI | ✅ Implemented | `Analytics.tsx` uses `getAnalyticsOverview` and `listSpeakerStats` |
|
||||
| People page | ✅ Implemented | `People.tsx` uses server-backed `listSpeakerStats` endpoint |
|
||||
| Tasks page | ✅ Implemented | `Tasks.tsx` uses server-backed `listTasks` and `updateTask` |
|
||||
|
||||
### IMPLEMENTED (All Components Complete)
|
||||
|
||||
**Summary layout in transcript panel** has been implemented:
|
||||
- Summary now appears in a collapsible section above the transcript
|
||||
- Right panel tabs reduced to Entities and Notes only
|
||||
- Summary supports compact horizontal grid layout
|
||||
|
||||
### PARTIALLY IMPLEMENTED
|
||||
|
||||
| Component | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| Task storage | ✅ Complete | TaskModel in DB, API implemented, task ingestion from summary action items via `_ingest_tasks_from_summary` in `_generation_mixin.py` |
|
||||
|
||||
**Downstream impact**: Meeting Detail page (summary layout move).
|
||||
|
||||
---
|
||||
|
||||
## Objective
|
||||
|
||||
Provide server-backed analytics aggregates and task persistence so Analytics, People, and Tasks pages no
|
||||
longer depend on loading meeting segments. Move the LLM summary into the transcript panel and repurpose
|
||||
the right panel for metrics/status to align with Bugfinder feedback.
|
||||
|
||||
---
|
||||
|
||||
## Key Decisions
|
||||
|
||||
| Decision | Choice | Rationale |
|
||||
|----------|--------|-----------|
|
||||
| **Analytics data source** | Dedicated aggregate endpoints with in-memory caching | Scales better than listMeetings; avoids heavy payloads |
|
||||
| **Task persistence** | TaskModel CRUD as source of truth | Enables edits, ownership, kanban, and sync across devices |
|
||||
| **Summary layout** | Summary becomes primary content inside transcript panel | Matches requested UX priority and keeps metrics in sidebar |
|
||||
| **Task dedupe** | Only new, deduped tasks on summary regen | Honors user directive; preserves user-edited tasks |
|
||||
|
||||
---
|
||||
|
||||
## What Already Exists
|
||||
|
||||
| Asset | Location | Implication |
|
||||
|-------|----------|-------------|
|
||||
| TaskModel schema + relationships | `src/noteflow/infrastructure/persistence/models/organization/task.py` | Reuse existing DB table and FK links |
|
||||
| Action items in summaries | `src/noteflow/infrastructure/persistence/models/core/summary.py` | Seed tasks from action items |
|
||||
| Summary save flow | `src/noteflow/grpc/mixins/summarization/_generation_mixin.py` | Hook task ingestion after summary persistence |
|
||||
| Segment + word timing models | `src/noteflow/infrastructure/persistence/models/core/meeting.py` | Aggregate words/speakers for analytics |
|
||||
| Usage aggregate query pattern | `src/noteflow/infrastructure/persistence/repositories/usage_event/_aggregations.py` | Reuse structure for analytics queries |
|
||||
| Observability metrics endpoint | `src/noteflow/grpc/mixins/observability.py` | Co-locate performance data in analytics UI |
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
| Task | Effort | Notes |
|
||||
|------|--------|-------|
|
||||
| **Domain Layer** | | |
|
||||
| Add Task entity + TaskStatus enum | M | Align with DB statuses: open/done/dismissed |
|
||||
| Add analytics DTOs (overview, speaker stats, speech metrics) | M | Plain dataclasses for service outputs |
|
||||
| **Infrastructure Layer** | | |
|
||||
| Build SqlAlchemyTaskRepository | L | CRUD, list filters (status, project_id(s), meeting_id) |
|
||||
| Add analytics aggregation queries | L | Meeting trends, word counts, speaker stats, entity frequencies |
|
||||
| Add index migration (tasks.status, tasks.meeting_id, segments.speaker_id) | M | Improve query performance |
|
||||
| **Application Layer** | | |
|
||||
| TaskService (CRUD + summary ingestion) | L | Create tasks from action items (dedupe) |
|
||||
| AnalyticsService with TTL cache | L | Query aggregates, cache by workspace/project/date range |
|
||||
| **API Layer** | | |
|
||||
| Extend proto with analytics + task messages | L | New gRPC methods and enums |
|
||||
| Add AnalyticsMixin + TaskMixin | L | Wire into `NoteFlowServicer` and stubs |
|
||||
| Update Rust + TS generated clients | L | Regenerate stubs and adapters |
|
||||
| **Client Layer** | | |
|
||||
| Analytics page uses aggregate endpoints | M | Replace computeAnalytics with API data |
|
||||
| People page uses speaker stats endpoint | M | Remove listMeetings dependency |
|
||||
| Tasks page uses TaskModel data | L | Persist completion/status, keep project filters |
|
||||
| Meeting detail layout: summary in transcript panel | L | Refactor transcript panel to include summary section |
|
||||
|
||||
**Total Effort**: XL (1-2 days)
|
||||
|
||||
---
|
||||
|
||||
## Domain Model
|
||||
|
||||
### Task Entity
|
||||
|
||||
```python
|
||||
# src/noteflow/domain/entities/task.py
|
||||
|
||||
class TaskStatus(Enum):
|
||||
"""Task lifecycle status."""
|
||||
|
||||
OPEN = "open"
|
||||
DONE = "done"
|
||||
DISMISSED = "dismissed"
|
||||
|
||||
|
||||
@dataclass
|
||||
class Task:
|
||||
"""User-managed task derived from an action item."""
|
||||
|
||||
id: UUID
|
||||
workspace_id: UUID
|
||||
meeting_id: UUID | None
|
||||
action_item_id: int | None
|
||||
text: str
|
||||
status: TaskStatus = TaskStatus.OPEN
|
||||
assignee_person_id: UUID | None = None
|
||||
due_date: datetime | None = None
|
||||
priority: int = 0
|
||||
completed_at: datetime | None = None
|
||||
created_at: datetime = field(default_factory=utc_now)
|
||||
updated_at: datetime = field(default_factory=utc_now)
|
||||
```
|
||||
|
||||
**Constraints**:
|
||||
- TaskStatus limited to open/done/dismissed (match DB constraint).
|
||||
- Task dedupe key = meeting_id + normalized text (lowercase, trim, strip punctuation).
|
||||
|
||||
---
|
||||
|
||||
## API Schema
|
||||
|
||||
### Proto Additions (gRPC)
|
||||
|
||||
```protobuf
|
||||
enum TaskStatus {
|
||||
TASK_STATUS_UNSPECIFIED = 0;
|
||||
TASK_STATUS_OPEN = 1;
|
||||
TASK_STATUS_DONE = 2;
|
||||
TASK_STATUS_DISMISSED = 3;
|
||||
}
|
||||
|
||||
message Task {
|
||||
string id = 1;
|
||||
string meeting_id = 2;
|
||||
int32 action_item_id = 3;
|
||||
string text = 4;
|
||||
TaskStatus status = 5;
|
||||
string assignee_person_id = 6;
|
||||
double due_date = 7;
|
||||
int32 priority = 8;
|
||||
double completed_at = 9;
|
||||
}
|
||||
|
||||
message TaskWithMeeting {
|
||||
Task task = 1;
|
||||
string meeting_title = 2;
|
||||
double meeting_created_at = 3;
|
||||
string project_id = 4;
|
||||
}
|
||||
|
||||
message ListTasksRequest {
|
||||
repeated TaskStatus statuses = 1;
|
||||
int32 limit = 2;
|
||||
int32 offset = 3;
|
||||
optional string project_id = 4;
|
||||
repeated string project_ids = 5;
|
||||
optional string meeting_id = 6;
|
||||
}
|
||||
|
||||
message ListTasksResponse {
|
||||
repeated TaskWithMeeting tasks = 1;
|
||||
int32 total_count = 2;
|
||||
}
|
||||
|
||||
message UpdateTaskRequest {
|
||||
string task_id = 1;
|
||||
string text = 2;
|
||||
TaskStatus status = 3;
|
||||
string assignee_person_id = 4;
|
||||
double due_date = 5;
|
||||
int32 priority = 6;
|
||||
}
|
||||
|
||||
message UpdateTaskResponse {
|
||||
Task task = 1;
|
||||
}
|
||||
|
||||
message AnalyticsOverviewRequest {
|
||||
double start_time = 1;
|
||||
double end_time = 2;
|
||||
optional string project_id = 3;
|
||||
repeated string project_ids = 4;
|
||||
}
|
||||
|
||||
message DailyMeetingStats {
|
||||
string date = 1;
|
||||
int32 meetings = 2;
|
||||
double total_duration = 3;
|
||||
int32 word_count = 4;
|
||||
}
|
||||
|
||||
message AnalyticsOverviewResponse {
|
||||
repeated DailyMeetingStats daily = 1;
|
||||
int32 total_meetings = 2;
|
||||
double total_duration = 3;
|
||||
int32 total_words = 4;
|
||||
int32 total_segments = 5;
|
||||
int32 speaker_count = 6;
|
||||
}
|
||||
|
||||
message SpeakerStat {
|
||||
string speaker_id = 1;
|
||||
string display_name = 2;
|
||||
double total_time = 3;
|
||||
int32 segment_count = 4;
|
||||
int32 meeting_count = 5;
|
||||
double avg_confidence = 6;
|
||||
}
|
||||
|
||||
message ListSpeakerStatsRequest {
|
||||
double start_time = 1;
|
||||
double end_time = 2;
|
||||
optional string project_id = 3;
|
||||
repeated string project_ids = 4;
|
||||
}
|
||||
|
||||
message ListSpeakerStatsResponse {
|
||||
repeated SpeakerStat speakers = 1;
|
||||
}
|
||||
|
||||
service NoteFlowService {
|
||||
rpc ListTasks(ListTasksRequest) returns (ListTasksResponse);
|
||||
rpc UpdateTask(UpdateTaskRequest) returns (UpdateTaskResponse);
|
||||
rpc GetAnalyticsOverview(AnalyticsOverviewRequest) returns (AnalyticsOverviewResponse);
|
||||
rpc ListSpeakerStats(ListSpeakerStatsRequest) returns (ListSpeakerStatsResponse);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
### Phase 1: Schema
|
||||
1. Add index on `noteflow.tasks.status` and `noteflow.tasks.meeting_id` for list filters.
|
||||
2. Add index on `noteflow.segments.speaker_id` for speaker aggregates.
|
||||
|
||||
### Phase 2: Backfill
|
||||
1. Optional: backfill tasks from existing summaries by replaying summary action items per meeting.
|
||||
|
||||
### Migration Risks
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| Large segment tables slow aggregate queries | Use TTL cache + add indexes; consider materialized view later |
|
||||
| Task dedupe false positives | Normalize text conservatively; log collisions |
|
||||
|
||||
---
|
||||
|
||||
## Shared Types & Reuse Notes
|
||||
|
||||
- **Aggregation pattern**: reuse SQL aggregation style from `src/noteflow/infrastructure/persistence/repositories/usage_event/_aggregations.py`.
|
||||
- **Processing status UI**: reuse `ProcessingStatus` component in meeting detail sidebar.
|
||||
- **Task priority badges**: reuse `client/src/components/common/PriorityBadge` and `client/src/types/task.ts`.
|
||||
|
||||
---
|
||||
|
||||
## UI Components (if applicable)
|
||||
|
||||
### Meeting Summary Section
|
||||
|
||||
```tsx
|
||||
// client/src/pages/meeting-detail/summary-panel.tsx
|
||||
|
||||
export function SummaryPanel({ summary, summaryMeta, onGenerateSummary }: SummaryPanelProps) {
|
||||
// Render executive summary, key points, and action items inside transcript panel
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deliverables
|
||||
|
||||
### Backend
|
||||
|
||||
**Domain Layer**:
|
||||
- [x] `src/noteflow/domain/entities/task.py` — Task entity + TaskStatus enum
|
||||
|
||||
**Infrastructure Layer**:
|
||||
- [x] `src/noteflow/infrastructure/persistence/repositories/task_repo.py` — Task CRUD + list filters
|
||||
- [x] `src/noteflow/infrastructure/persistence/repositories/analytics_repo.py` — aggregate queries
|
||||
- [x] `src/noteflow/infrastructure/persistence/repositories/__init__.py` — export repositories
|
||||
|
||||
**Application Layer**:
|
||||
- [x] `src/noteflow/application/services/tasks/service.py` — CRUD + summary ingestion
|
||||
- [x] `src/noteflow/application/services/analytics/service.py` — cached aggregates
|
||||
|
||||
**API Layer**:
|
||||
- [x] `src/noteflow/grpc/proto/noteflow.proto` — new messages + RPCs (TaskStatusProto, TaskProto, DailyMeetingStatsProto, SpeakerStatProto, etc.)
|
||||
- [x] `src/noteflow/grpc/proto/noteflow_pb2.pyi` — Python type stubs for new proto types
|
||||
- [x] `src/noteflow/grpc/mixins/analytics_mixin.py` — GetAnalyticsOverview + ListSpeakerStats
|
||||
- [x] `src/noteflow/grpc/mixins/tasks.py` — ListTasks + UpdateTask
|
||||
- [x] `src/noteflow/grpc/mixins/converters/_domain.py` — Task/Analytics proto converters
|
||||
- [x] `src/noteflow/grpc/service.py` — register mixins (AnalyticsMixin, TasksMixin)
|
||||
|
||||
**Migrations**:
|
||||
- [x] `src/noteflow/infrastructure/persistence/migrations/versions/v6w7x8y9z0a1_add_task_analytics_indexes.py` — indexes for tasks.status, tasks.meeting_id, segments.speaker_id
|
||||
|
||||
### Client
|
||||
|
||||
- [x] `client/src/api/types/features/analytics.ts` — analytics request/response types
|
||||
- [x] `client/src/api/types/features/tasks.ts` — task request/response types
|
||||
- [x] `client/src/api/interface.ts` — new API methods
|
||||
- [x] `client/src/api/adapters/tauri/sections/analytics.ts` — analytics endpoint bridge
|
||||
- [x] `client/src/api/adapters/tauri/sections/tasks.ts` — task CRUD bridge
|
||||
- [x] `client/src-tauri/src/commands/analytics.rs` — Rust Tauri commands
|
||||
- [x] `client/src-tauri/src/commands/tasks.rs` — Rust Tauri commands
|
||||
- [x] `client/src-tauri/src/grpc/client/analytics.rs` — Rust gRPC client methods
|
||||
- [x] `client/src-tauri/src/grpc/client/tasks.rs` — Rust gRPC client methods
|
||||
- [x] `client/src-tauri/src/grpc/types/analytics.rs` — Rust type definitions
|
||||
- [x] `client/src-tauri/src/grpc/types/tasks.rs` — Rust type definitions
|
||||
- [x] `client/src/pages/Analytics.tsx` — use aggregates (uses getAnalyticsOverview, listSpeakerStats)
|
||||
- [x] `client/src/pages/People.tsx` — use speaker stats (uses listSpeakerStats endpoint)
|
||||
- [x] `client/src/pages/Tasks.tsx` — use TaskModel data (uses listTasks, updateTask)
|
||||
- [x] `client/src/pages/meeting-detail/index.tsx` — summary in collapsible section above transcript
|
||||
- [x] `client/src/pages/meeting-detail/summary-panel.tsx` — added compact mode with horizontal grid layout
|
||||
|
||||
---
|
||||
|
||||
## Test Strategy
|
||||
|
||||
### Fixtures to extend or create
|
||||
|
||||
- `tests/conftest.py`: add Task fixtures for task lists
|
||||
- `tests/infrastructure/`: add repository fixtures for analytics aggregates
|
||||
|
||||
### Parameterized tests
|
||||
|
||||
- Task status transitions: open/done/dismissed
|
||||
- Analytics filters: project_id vs project_ids vs none
|
||||
|
||||
### Core test cases
|
||||
|
||||
- **Domain**: TaskStatus normalization + completion timestamp logic
|
||||
- **Service**: summary ingestion dedupe, analytics cache hits/misses
|
||||
- **API**: ListTasks pagination + filters, GetAnalyticsOverview range queries
|
||||
- **Integration**: task list after summary regenerate adds only new tasks
|
||||
|
||||
---
|
||||
|
||||
## Quality Gates
|
||||
|
||||
- [x] `pytest tests/application/test_task_service.py` passes (19 tests)
|
||||
- [x] `pytest tests/application/test_analytics_service.py` passes (10 tests)
|
||||
- [x] `pytest tests/grpc/test_tasks_mixin.py` passes (7 tests)
|
||||
- [x] `pytest tests/grpc/test_analytics_mixin.py` passes (6 tests)
|
||||
- [ ] `make quality` passes
|
||||
- [x] No type suppression comments or loose typing introduced
|
||||
|
||||
---
|
||||
|
||||
## Post-Sprint
|
||||
|
||||
- [ ] Add kanban view for tasks and inline editing
|
||||
- [ ] Add NER-based entity analytics (NamedEntityModel aggregates)
|
||||
- [ ] Materialized analytics tables if cache misses become expensive
|
||||