prometeu-studio/docs/studio/pull-requests/PR-09-asset-move-action-and-relocate-wizard.md
2026-03-24 13:42:44 +00:00

165 lines
7.9 KiB
Markdown

# PR-09 Asset Move Action and Relocate Wizard
Domain owner: `docs/studio`
## Briefing
Adicionar a action `Move` na área de actions do asset selecionado e conectá-la a um wizard de relocação explícita.
O usuário deve escolher o destino do asset e revisar um resumo antes da execução.
Depois da confirmação, o Studio não move diretórios localmente.
Ele apenas envia um comando de relocação para o packer, que passa a ser o owner completo da mudança:
- atualiza o estado interno necessário;
- move o diretório do asset dentro da árvore `assets` do projeto;
- emite eventos operacionais até a conclusão.
Este plano também fecha uma regra operacional que precisa existir nas duas pontas:
- o diretório destino final do asset não pode já ser um root de asset;
- portanto, o root destino não pode conter `asset.json`.
Após a confirmação do resumo, o modal deve entrar em estado de espera com spinner, escutando o evento operacional do packer.
Quando a operação terminar:
- sucesso: o Studio dispara refresh, fecha o modal e reposiciona a seleção;
- falha: o modal sai do estado de espera e mostra a falha sem fechar silenciosamente.
## Objective
Entregar um fluxo de `Move` que seja explícito, previsível e compatível com o modelo em que o packer executa a mutação real e o Studio apenas comanda e observa.
Após este PR:
- a seção `Actions` do selected asset expõe `Move`;
- clicar em `Move` abre um wizard dedicado;
- o wizard coleta o parent de destino e o nome final do diretório;
- o wizard mostra um passo final de resumo antes do comando final;
- o Studio não aceita um destino cujo root já contenha `asset.json`;
- o packer também rejeita esse destino como regra de segurança e conformance;
- a confirmação final envia um comando de relocation para o packer via API;
- o modal entra em espera com spinner até receber o evento terminal da operação;
- o refresh estrutural só ocorre depois do evento de conclusão do packer.
## Dependencies
- [`./PR-05e-assets-staged-mutations-preview-and-apply.md`](./PR-05e-assets-staged-mutations-preview-and-apply.md)
- [`./PR-07c-asset-details-and-form-lifecycle.md`](./PR-07c-asset-details-and-form-lifecycle.md)
- [`./PR-07d-asset-mutation-and-structural-sync-orchestration.md`](./PR-07d-asset-mutation-and-structural-sync-orchestration.md)
- [`../specs/4. Assets Workspace Specification.md`](../specs/4.%20Assets%20Workspace%20Specification.md)
- cross-domain reference: [`../../packer/pull-requests/PR-05-sensitive-mutations-preview-apply-and-studio-write-adapter.md`](../../packer/pull-requests/PR-05-sensitive-mutations-preview-apply-and-studio-write-adapter.md)
- cross-domain reference: [`../../packer/pull-requests/PR-09-event-lane-progress-and-studio-operational-integration.md`](../../packer/pull-requests/PR-09-event-lane-progress-and-studio-operational-integration.md)
## Scope
- adicionar a action `Move` na seção `Actions` do details
- introduzir um `Relocate Wizard` efetivamente utilizável pelo selected asset atual
- coletar destino por:
- parent directory
- destination name
- target root derivado
- mostrar passo final de resumo antes da confirmação
- enviar um comando `RELOCATE_ASSET` com `targetRoot` explícito para o packer
- abrir estado modal de espera com spinner após confirmação
- correlacionar a operação via `operationId`
- escutar o evento operacional do packer até `ACTION_APPLIED` ou `ACTION_FAILED`
- publicar structural sync explícito apenas após conclusão bem-sucedida
- validar no Studio que `targetRoot/asset.json` não exista
- validar no packer que `targetRoot/asset.json` não exista, mesmo se o Studio falhar em bloquear antes
## Non-Goals
- não redesenhar o mutation preview panel inteiro
- não introduzir rename inline fora do wizard
- não adicionar batch move
- não redefinir semântica de identidade do asset
- não permitir fallback para target automático quando o usuário iniciou `Move`
- não mover diretórios diretamente pelo Studio fora do comando ao packer
## Execution Method
1. Expor `Move` na seção `Actions`.
O botão deve existir apenas quando houver asset selecionado e deve abrir o wizard a partir do `AssetReference` atual.
2. Implementar o wizard de relocação como fluxo explícito de destino.
O wizard deve reutilizar a linguagem já existente de `relocateWizard` e coletar:
- root atual
- diretório parent de destino
- nome final do diretório
- target root calculado
3. Adicionar validação local de destino.
O wizard deve bloquear avanço/confirmação quando:
- o target root for igual ao root atual;
- o target root sair da área válida esperada;
- o target root já contiver `asset.json`.
4. Adicionar passo final de resumo.
Antes do comando final, o usuário deve ver um resumo do:
- asset atual
- root atual
- parent de destino
- nome final
- target root resultante
5. Integrar o wizard ao fluxo de comando assíncrono do packer.
A saída do wizard deve virar `PackerMutationRequest(RELOCATE_ASSET, ..., targetRoot)`, sem usar target automático.
Depois do `OK`, o Studio inicia a operação, captura o `operationId` retornado e coloca o modal em estado de espera.
6. Esperar conclusão por evento, não por refresh cego.
O modal deve escutar `StudioPackerOperationEvent` correlacionado por `operationId`.
Regras:
- `ACTION_APPLIED`: disparar refresh estrutural, fechar modal e reselecionar o asset relocado;
- `ACTION_FAILED`: sair do spinner, manter modal aberto e mostrar a falha;
- eventos intermediários como `PROGRESS_UPDATED` podem atualizar a mensagem/estado visual, mas não fecham o modal.
7. Endurecer a regra no packer.
O preview/apply de relocation deve recusar destino cujo root já contenha `asset.json`, produzindo blocker claro e estável.
8. Orquestrar o pós-conclusão como mudança estrutural.
Relocation bem-sucedida deve acionar sync estrutural explícito e reposicionar a seleção para o asset movido no novo root.
## Acceptance Criteria
- `Move` aparece na seção `Actions` do asset selecionado
- clicar em `Move` abre wizard dedicado em vez de mutação imediata
- o wizard exige destino explícito escolhido pelo usuário
- existe passo final de resumo antes da conclusão
- `targetRoot/asset.json` bloqueia o fluxo já no Studio
- o packer também bloqueia `targetRoot/asset.json` como regra de segurança
- o `OK` final envia o comando ao packer e coloca o modal em espera com spinner
- o modal só fecha depois de `ACTION_APPLIED` para a mesma operação
- falha operacional não fecha o modal silenciosamente
- sucesso operacional executa structural sync explícito
- a seleção final aponta para o asset já movido, não para o root antigo
## Validation
- unit tests para validação de target root no wizard
- unit tests para derivação de `targetRoot` a partir de parent + destination name
- unit tests para correlação `operationId -> modal state`
- unit tests para sucesso/falha dirigidos por `StudioPackerOperationEvent`
- unit tests para publication/orchestration de relocation como structural sync
- packer tests para blocker quando `targetRoot/asset.json` já existe
- smoke test de UI para:
- abrir `Move`
- editar destino
- ver resumo final
- bloquear destino inválido
- confirmar operação
- ver spinner de espera
- fechar no evento de sucesso
- manter aberto no evento de falha
## Affected Artifacts
- `docs/studio/specs/4. Assets Workspace Specification.md` se a regra de destino inválido precisar ser tornada mais explícita
- `prometeu-studio/src/main/java/p/studio/workspaces/assets/details/actions/...`
- `prometeu-studio/src/main/java/p/studio/workspaces/assets/wizards/...`
- `prometeu-studio/src/main/java/p/studio/workspaces/assets/...` mutation orchestration wiring
- `prometeu-studio/src/main/java/p/studio/events/...`
- `prometeu-studio/src/main/resources/i18n/messages.properties`
- `prometeu-packer/src/main/java/p/packer/mutations/...`
- testes de Studio para wizard/flow
- testes de packer para relocation target validation