Files
multica/server/pkg
Naiyuan Qing f94d98b0de feat(projects): guard removing a space from a project when it still has issues
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>
2026-07-09 13:35:43 +08:00
..