PMFlow/PMFlow-Dev-Plan.md

204 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PMFlow Dev Plan — User / Skill / Workload Modules
**Stack:** FastAPI + React + shadcn/ui + Tailwind | **Timeline:** ~11 days, 1 dev
---
## Phase 1 — Core Foundation (Day 1–3)
### Day 1 — DB Migration + User CRUD
**DB**
```sql
ALTER TABLE users ADD COLUMN is_active BOOLEAN NOT NULL DEFAULT TRUE;
CREATE TABLE user_projects (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL DEFAULT 1,
user_id BIGINT NOT NULL,
project_id BIGINT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES tenants(id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (project_id) REFERENCES projects(id),
UNIQUE(tenant_id, user_id, project_id)
);
```
**Backend**
- [x] Update ORM: `User.is_active`, new `UserProject` model
- [x] `GET /api/users` — paginated list with filters (role/status/project/workload/skill)
- [x] `POST /api/users` — create user (bcrypt password, auto-init `user_workloads` row with 40h/week)
- [x] `PUT /api/users/{id}` — update user
- [x] `DELETE /api/users/{id}` — block if user has incomplete tasks
- [x] `POST /api/users/{id}/reset-password`
- [x] `PATCH /api/users/{id}/status` — disable: clear `tasks.assignee_id`, zero out workload
- [x] `POST /api/users/import` — bulk import via Excel (max 50 rows, return per-row result)
- [x] Transaction: delete user → cascade delete `user_skill_bindings` + `user_workloads`
- [x] Log all mutations (actor, time, diff)
**Frontend**
- [x] Routes: `/users`, `/skills`, `/workloads`, `/workloads/:id`
- [x] `/users` page: top bar (title + New/Import/Bulk-delete buttons + search)
- [x] Right filter panel (280px, collapsible): role / status / project / workload-state / skill multi-select
- [x] Table: avatar+name / email / role badge / linked projects / top-3 skill tags / workload% / status / actions
- [x] New/Edit user modal (form validation, edit pre-fills data)
- [x] Reset password modal
- [x] Bulk import modal (preview first 10 rows, highlight errors, show import result summary)
- [x] Workload% color: green <70%, yellow 70–100%, red >100%
---
### Day 2 — Skill & Workload APIs
**Backend — Skills**
- [x] Seed system skill tags on startup (Python, FastAPI, LangChain, React, Prompt Eng, etc.)
- [x] `GET /api/skill-tags` — list with category filter
- [x] `POST /api/skill-tags` — admin only
- [x] `PUT /api/skill-tags/{id}` — system tags: category only; custom: name + category
- [x] `DELETE /api/skill-tags/{id}` — block if `is_system=true`; cascade delete `user_skill_bindings`
- [x] `GET /api/users/{id}/skills` — user skill bindings
- [x] `POST /api/users/{id}/skills` — bind skill (default: beginner, scores 0.0)
- [x] `PUT /api/users/{id}/skills/{skill_id}` — update proficiency / scores
- [x] `DELETE /api/users/{id}/skills/{skill_id}` — unbind (block system-auto-bound skills)
**Backend — Workload**
- [x] Workload calc util: `ratio = assigned_hours / ((max_weekly_hours / 5) * remaining_workdays)`
- [x] `GET /api/workloads` — team list with project/date filters
- [x] `GET /api/workloads/{user_id}` — personal detail
- [x] `PUT /api/workloads/{user_id}` — update max weekly hours (triggers ratio recalc)
- [x] `GET /api/workloads/{user_id}/tasks` — assigned task list
- [x] `GET /api/workloads/{user_id}/trend` — daily ratio for last 7/30 days
- [x] Cron job at 00:00 daily: recalc ratio for all users based on updated remaining workdays
- [x] Auto-trigger ratio recalc on: task assign / estimate change / task complete / task delete
---
### Day 3 — Skill & Workload Frontend
**Frontend — Skill Tags (`/skills`)**
- [x] Table: name / category badge / linked-user count / actions
- [x] System tags: show "System" label, disable delete, disable name edit
- [x] New/Edit skill tag modal
- [x] Category badge colors: dev=blue / algorithm=purple / product=orange / pm=green / qa=gray
**Frontend — User Skill Detail (`/users/:id/skills`)**
- [x] Top bar: avatar / name / role / linked projects / "Batch Edit" + "Refresh Scores" buttons
- [x] Left 60%: skills grouped by category (collapsible), each row: name / proficiency dropdown / quality score / efficiency score / last used (read-only)
- [x] "Remove" button per row (disabled for system-bound skills)
- [x] "Add Skill" button → modal to select skill tags
- [x] Right 40%: recharts `RadarChart` — weighted score per skill, filter by category, hover shows detail
- [x] "Export Chart" button (save as image)
**Frontend — Team Workload (`/workloads`)**
- [x] Filter bar: project select + date range (this week / this month / custom)
- [x] 3 stat cards: avg team ratio / headcount by state (idle/normal/overloaded) / AI alert summary
- [x] Table: member info / projects / assigned hours / max weekly hours / ratio% / remaining hours / actions
- [x] Overloaded rows: red highlight + warning icon
**Frontend — Personal Workload (`/workloads/:id`)**
- [x] Header: ratio% / remaining hours / "Adjust Hours" button
- [x] recharts `LineChart`: daily ratio trend (7d/30d toggle), 70% + 100% reference lines, overloaded segments in red
- [x] Task list table: title / project / priority / est. hours / due date / status / view link
- [x] Task list filters: status / priority / due date
---
## Phase 2 — Sync Logic + AI (Day 4–8)
### Day 4–5 — Cross-module Sync
**Backend**
- [x] User create → init empty `user_skill_bindings`, init `user_workloads`
- [x] User delete → transaction: delete bindings + workload record
- [x] User disable → zero `current_assigned_hours` + `workload_ratio`, clear task assignments
- [x] Skill score update → recalc top-3 skills for user, sync to user list response
- [x] Workload ratio change → sync to user list `workload_ratio` field
- [x] Skill proficiency level → pass to task estimation: expert → lower est. hours → lower ratio
**Frontend**
- [x] User list table: workload% and top-3 skill tags update without page reload (TanStack Query invalidation)
- [x] Skill detail page: manual score edit shows warning "AI will overwrite on next update"
- [x] Workload team table: ratio column updates in real-time after task changes
---
### Day 6–7 — SSTC Kanban Integration
**Backend**
- [x] Task assign endpoint: filter candidates to current-project users only, exclude disabled users
- [x] `GET /api/tasks/recommend-assignees?task_id=` — rank users by skill match + proficiency + ratio (<70% preferred)
- [x] Task status → `done`: trigger async job to update `current_assigned_hours` (subtract est. hours) and recalc ratio
- [x] `GET /api/workloads/summary` — team health card data for kanban top bar
**Frontend**
- [x] SSTC kanban top bar: "Team Workload Health" card (avg ratio + overload count), click → `/workloads`
- [x] Task breakdown panel: recommended assignees list shows name / role / top skills / ratio badge
- [x] Assignee dropdown: disabled users grayed out and unselectable
- [x] Task status change → trigger workload refetch (TanStack Query)
---
### Day 8 — AI Features
**Backend**
- [x] New LangChain prompt: skill score update — input: task quality_score + (est_hours / actual_hours), output: quality/efficiency score delta per skill tag
- [x] Trigger on `tasks.status = done`: async call above prompt, apply weighted update (higher priority task = higher weight)
- [x] New LangChain prompt: workload optimization — input: all members' skills + ratios, output: suggested task reassignments
- [x] `POST /api/workloads/ai-optimize` — run optimization, return preview plan (no auto-apply)
- [x] `POST /api/workloads/ai-optimize/apply` — apply approved plan (batch update `tasks.assignee_id`)
- [x] Overload alert: ratio >100% → send notification (Feishu/email); if unresolved 24h → auto-generate transfer suggestion
**Frontend**
- [x] "AI Optimize Assignments" button → show optimization preview modal (old vs new assignee per task)
- [x] Confirm → apply; Cancel → discard
- [x] Overload alert banner on team workload page when any member >100%
---
## Phase 3 — Polish (Day 9–11)
### Day 9 — Filters / Export / Bulk Actions
- [x] Verify all filter combinations work correctly across all 3 pages
- [x] Export workload report (Excel/PDF)
- [x] Export skill radar chart (PNG)
- [x] Bulk delete users (with incomplete-task guard)
- [x] Bulk assign project / role to selected users
### Day 10 — Permissions
| Role | Users | Skills | Workload |
|------|-------|--------|----------|
| admin | Full | Full | Full |
| manager | Own project users (no delete) | Bind/edit scores for own project | View + optimize own project |
| member | View all + edit own profile | View own + edit own proficiency | View own + edit own weekly hours |
- [x] Backend: permission middleware on all mutation endpoints
- [x] Frontend: route guards + button-level permission checks
### Day 11 — Final QA
- [x] Dark mode audit across all new pages
- [x] Empty state / loading state / error state for all tables and cards
- [x] Toast notifications for all CRUD operations
- [x] End-to-end flow test: create user → bind skills → assign task → complete task → verify score + workload update
- [x] Fix bugs, merge
---
## Reference
**Workload ratio formula:**
```
ratio = current_assigned_hours / ((max_weekly_hours / 5) * remaining_workdays_this_week)
```
**Ratio recalc triggers:** task assign · est hours change · task complete · task delete · weekly hours update · daily cron
**API response format:**
```json
{ "code": 200, "message": "ok", "data": {} }
```