Files
multica/server/internal/handler/space_resolve.go
Naiyuan Qing df00c59239 refactor(spaces): decouple project↔space; drop alignment enforcement
Issue/project/autopilot each declare their own space(s) with no
cross-validation — an issue's space need not belong to its project's
space set. Removes:
- backend: ProjectSpaceAmbiguous error, the EnsureProjectHasSpace side
  effect, the 409 space_reassignments reconcile + renumber, and the
  now-orphaned CountProjectIssuesBySpace / ListIssuesByProjectAndSpace
  queries; ResolveSpace falls back to the workspace default for a
  multi-space project instead of erroring.
- frontend: both SpaceProjectConflictDialog wirings and the project-side
  ProjectSpaceReassignDialog, plus the conflict schema/types/i18n.

Data structures unchanged (project_space, issue.space_id,
autopilot.space_id); multi-space projects stay, managed inline via
SpaceMultiPicker on the project detail.

Also bundled from this branch's working tree:
- create-space: derive the key from the name, no silent "T" prefix
- space detail: normal-colour description, shadcn members trigger
- invitations: space_ids so invitees join chosen spaces on accept
  (migration 149)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 16:00:49 +08:00

44 lines
1.3 KiB
Go

package handler
import (
"errors"
"net/http"
"github.com/multica-ai/multica/server/internal/service"
)
// Unified, transport-facing messages for the service-layer space-resolution
// errors. Every issue-producing handler (create, quick-create, autopilot,
// project space lists) maps the same typed error to the same string so callers
// see one wording per condition.
const (
spaceNotFoundMessage = "space not found in this workspace"
spaceArchivedMessage = "space is archived"
)
// spaceResolveMessage maps a service space-resolution error to its unified
// message. Returns "" for errors that are not space-resolution errors.
func spaceResolveMessage(err error) string {
switch {
case errors.Is(err, service.ErrSpaceNotFound):
return spaceNotFoundMessage
case errors.Is(err, service.ErrSpaceArchived):
return spaceArchivedMessage
default:
return ""
}
}
// writeSpaceResolveError writes a 400 with the unified message for a
// space-resolution error and returns true. It returns false (writing nothing)
// for errors it does not recognize so callers can fall through to their own
// handling.
func writeSpaceResolveError(w http.ResponseWriter, err error) bool {
msg := spaceResolveMessage(err)
if msg == "" {
return false
}
writeError(w, http.StatusBadRequest, msg)
return true
}