feat(artist): move a source into another artist (#130 step 4)
CI / lint (push) Successful in 3s
CI / frontend-build (push) Successful in 20s
CI / backend-lint-and-test (push) Successful in 28s
CI / integration (push) Successful in 3m36s

Operator ask: a surface to merge new sources into existing artists (consolidate
the singleton artist a fresh add spins up). Enabled by the #130 slug decoupling —
the storage path is immutable, so re-attribution moves NO files. SourceService
.reassign moves the source, re-points its posts (Post.source_id==S) and the
images it contributed (ImageProvenance via S, scoped to the old artist so shared
images aren't stolen), and deletes the old artist if it's left fully empty (else
clears its subscription flag). POST /api/sources/<id>/reassign. Frontend: a
'Move…' action per source on the artist Management tab → artist-autocomplete
picker → confirm → routes to the target (whose slug is stable).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CDgx8bQS5YrGRK76v8HUnM
This commit is contained in:
2026-07-04 22:15:38 -04:00
parent 87d53db0cb
commit a69bd1baa8
5 changed files with 283 additions and 5 deletions
+10 -1
View File
@@ -84,6 +84,15 @@ export const useSourcesStore = defineStore('sources', () => {
return await api.get('/api/artists/autocomplete', { params: { q: query, limit } })
}
// #130: move a source (+ its content) to another artist. Files don't move
// (slug is immutable); the backend re-attributes source/posts/images and
// deletes the old artist if it's left empty.
async function reassign(id, targetArtistId) {
return await api.post(`/api/sources/${id}/reassign`, {
body: { target_artist_id: targetArtistId },
})
}
async function loadScheduleStatus() {
scheduleStatus.value = await api.get('/api/sources/schedule-status')
return scheduleStatus.value
@@ -177,7 +186,7 @@ export const useSourcesStore = defineStore('sources', () => {
recoverSource,
recaptureSource,
previewSource,
findOrCreateArtist, autocompleteArtist,
findOrCreateArtist, autocompleteArtist, reassign,
loadScheduleStatus,
sourcesByArtistGrouped,
}