mirror of
https://github.com/multica-ai/multica.git
synced 2026-08-06 19:00:01 +02:00
Project↔space had an asymmetry: attaching an issue whose space isn't in a project's space set is intercepted (add the space, or move the issue), but the reverse — removing a space from a project's set while the project still has issues filed under it — was completely unguarded, silently stranding those issues under a space the project no longer lists. UpdateProject now checks every space_ids removal against the project's actual issues (CountProjectIssuesBySpace). A removal with no issues under it proceeds as before. A removal with issues is rejected with a structured 409 (project_space_has_issues, listing each conflicting space + its issue count) unless the request's space_reassignments maps every one of them to a space the project still lists — in which case the affected issues are moved (renumbered, old identifier aliased) in the same transaction as the space_ids update, and each gets its own issue:updated broadcast so realtime-filtered lists reconcile like a manual move would. Extracted the single-issue move-to-space logic out of UpdateIssue into service.MoveIssueToSpace so the batch path reuses it instead of duplicating the counter/position/alias sequence. Frontend: project's 3-dot menu gets a "Manage spaces" entry opening a new two-step dialog (pick spaces → resolve conflicts with a per-space move-target picker), replacing the disabled space property row that project-detail.tsx carried since the space rollout. Dropped the now-dead table.spaces locale key that row was the only user of. Verification: new Go tests for the accept/reject/reassign/invalid-target cases (server/internal/handler/project_space_reconcile_test.go) against an isolated worktree database; full internal/... and cmd/migrate suites pass. New dialog tests (packages/views/spaces/components/manage-project-spaces-dialog.test.tsx) cover the no-conflict, empty-selection, conflict-step, confirm-move, and malformed-409 cases. core/views/web/desktop typecheck clean; views locale parity test passes for en/ja/ko/zh-Hans. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>