- Project.to_dict() now includes user_id and auto_summary
- Status validation unified to (active/completed/archived) on both
create and update project routes; update route previously had none
- Milestone routes: replace get_project (ownership-only) with
get_project_for_user so shared viewers/editors can access milestones
- Add get_milestone_in_project() to milestones service for project-
scoped lookup without user_id filter; all milestone routes use it
- Milestone PATCH now validates status as 'active'|'done'; fix tool
enum which was wrongly ['active','completed','cancelled']
- Write mutation routes (POST/PATCH/DELETE milestones) now check
can_write_project() and return 403 for read-only shared users
- update_project tool now exposes title and color fields so projects
can be renamed or recolored via chat
- create_project tool now exposes color field
- GET /api/projects?include_summary=true embeds summaries in one
backend pass; ProjectListView switches to this, eliminating N+1
per-project fetches
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
create_project and create_milestone hardcoded status="active" and
ignored any value passed by the MCP or API callers. Route, service,
and model construction now all thread the status field through.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>