# DIRECTORY_MOVE_V1_DESIGN.md ## 1. Scope Doel van Directory Move v1 is om directory-verplaatsing toe te voegen binnen het bestaande move/task/securitymodel, zonder het huidige veiligheidsniveau of de voorspelbaarheid van de backend te verzwakken. In scope voor v1: - directory move als expliciete uitbreiding van de bestaande move-operatie - task-based uitvoering - conflictcontrole op destination - beveiligde padvalidatie via bestaand `path_guard` - duidelijke foutstatussen bij ongeldige of gevaarlijke moves Out of scope voor v1: - geen rollbackmechanisme - geen cancel/retry - geen gedeeltelijke recovery van half-voltooide cross-root moves - geen symlink-following buiten whitelist - geen speciale merge- of overwrite-semantiek - geen multi-select directory move als aparte batch-semantiek buiten bestaande sequentiële task-aanmaak --- ## 2. Same-root versus cross-root ### Directory move binnen dezelfde root Dit is de veiligste en simpelste stap. Kenmerken: - kan meestal native via `rename()`/`move` op directoryniveau - snel en atomair binnen hetzelfde filesystem/root - geen inhoudelijke recursieve file copy nodig - veel minder kans op partial failure ### Directory move tussen verschillende roots Dit is aanzienlijk complexer. Kenmerken: - vereist recursieve copy van directory tree - daarna delete van source tree - progressmeting en foutafhandeling worden lastiger - partial failure is realistischer - rollback is ingewikkeld en in v1 ongewenst ### Aanbevolen scopekeuze Aanbevolen v1: - **alleen same-root directory move ondersteunen** - **cross-root directory move nog niet ondersteunen** Reden: - sluit goed aan op bestaand taskmodel zonder grote complexiteitsexplosie - beperkt regressierisico - voorkomt een half-robuste recursieve copy+delete-implementatie zonder rollback --- ## 3. Semantiek ### Wanneer is het een echte move Directory move is van toepassing als: - source een directory is - destination een volledig doelpad is - destination nog niet bestaat Binnen same-root: - de operatie gebruikt native rename/move op directoryniveau - dit geldt zowel voor verplaatsen naar andere parent als voor directory move binnen dezelfde root met andere naam ### Destination bestaat al Gedrag v1: - destination mag niet bestaan - response: `already_exists` Geen merge in v1. ### Nested destinations Verboden gevallen: - source naar een child van zichzelf - source naar een pad in eigen subtree Voorbeeld: - source: `/Volumes/8TB/Shows` - destination: `/Volumes/8TB/Shows/Archive/Shows` Dit moet direct geblokkeerd worden. Aanbevolen fout: - `invalid_request` met duidelijke boodschap zoals `Destination cannot be inside source` ### Verplaatsen van map in zichzelf Ook verboden: - destination exact gelijk aan source - destination onder source subtree Dit moet vóór task-creatie worden afgewezen. --- ## 4. Taskmodel Directory move blijft task-based, ook voor same-root moves. ### Progressmeting Voor same-root native directory move is echte byte-progress meestal niet beschikbaar. Aanbevolen v1: - gebruik vooral `done_items` / `total_items` - voor same-root kan dat minimaal zijn: - `total_items = 1` - `done_items = 0 -> 1` - `done_bytes` / `total_bytes` mogen `null` blijven in v1 voor same-root directory move ### Fail-fast gedrag Aanbevolen v1: - fail-fast - zodra de move-operatie faalt, task -> `failed` ### Partial failure Voor same-root native directory move is partial failure veel minder waarschijnlijk. - of de rename slaagt - of de rename faalt Dus v1-model: - geen expliciete partial-successstatus - eindstatus blijft: - `completed` - `failed` ### Rollback Geen rollback in v1. Voor same-root native rename is dat meestal niet nodig. Voor cross-root zou rollback wel relevant worden, maar die scope wordt niet aanbevolen voor v1. --- ## 5. Security ### Symlinkgedrag in directory trees Aanbevolen v1-beleid: - source directory zelf mag geen symlink zijn - bij same-root native rename wordt de tree niet recursief gevolgd of gekopieerd, dus child-symlinks hoeven niet actief gevolgd te worden voor uitvoering - toch blijft containmentcontrole op source en destination verplicht ### Traversal en containment - bron- en destination-pad blijven via bestaand `path_guard` - destination binnen whitelist verplicht - destination mag niet buiten root escapen - nested destination-in-source moet expliciet extra gevalideerd worden ### PathGuard-impact Bestaand `path_guard` blijft basis voor: - whitelistvalidatie - traversalblokkade - symlink containment check op bron/destination-resolutie Aanvullend nodig voor directory move: - helper of servicecheck om te bepalen of destination in subtree van source ligt ### Escapes buiten whitelist voorkomen Bij same-root-only v1: - containment blijft relatief eenvoudig - geen recursieve copy over child nodes nodig - dus ook minder attack surface dan cross-root recursieve tree copy --- ## 6. Backend-impact Waarschijnlijk te wijzigen delen: - `webui/backend/app/services/move_task_service.py` - `webui/backend/app/tasks_runner.py` - `webui/backend/app/fs/filesystem_adapter.py` - mogelijk `webui/backend/app/api/schemas.py` alleen als taskdetail-documentatie wordt aangescherpt - mogelijk kleine aanvulling in `path_guard.py` of move-service validatiehelpers ### Bestaande move-logica die hergebruikt kan worden Herbruikbaar: - task-creatie - repository-persistency - statusflow `queued -> running -> completed/failed` - destination-exists checks - parent directory validation - algemene error mapping Nieuw voor directory move: - source typecheck moet directory toestaan in same-root-case - same-root task runner moet directory rename kunnen uitvoeren - nested-destination-validatie ### Rename binnen zelfde parent blijft apart Ja. Aanbevolen scheiding: - `rename` endpoint blijft aparte, directe single-path operatie - `move` blijft task-based voor echte moves - ook als een same-root directory move technisch op rename lijkt, blijft het semantisch onderdeel van `move` Dat houdt UI- en API-rollen duidelijk. --- ## 7. UI-impact ### Move-knop en F6 bij exact 1 directory Aanbevolen gedrag: - F6 / Move-knop blijven dezelfde popupflow gebruiken - exact 1 directory geselecteerd: - zelfde parent + andere naam -> huidige `rename` route blijft toegestaan - andere parent binnen dezelfde root -> task-based directory move toegestaan in v1 - cross-root destination -> blokkeren met duidelijke melding, bijvoorbeeld: - `Cross-root directory move is not supported in v1` ### Multi-select met directories Aanbevolen v1: - geen gemengde halfslimme batchflow - als multi-select directories bevat: - alleen toestaan als alle geselecteerde directories voldoen aan same-root move-semantiek, of - eenvoudiger en veiliger voor v1: nog blokkeren met duidelijke melding Aanbevolen eerste stap: - **multi-select met directories nog blokkeren** - melding: - `Batch directory move is not supported in v1` Reden: - beperkt scope en regressierisico - houdt UI-flow voorspelbaar --- ## 8. Teststrategie ### Golden tests Toe te voegen voor move-API: - same-root directory move success - directory destination exists -> `already_exists` - directory source not found - directory source is symlink -> blokkade - nested destination blocked - exact same source/destination blocked - cross-root directory move blocked ### Regressietests - file move success same-root blijft werken - file move success cross-root blijft werken als huidige scope dat al ondersteunt - rename endpoint blijft ongewijzigd - browse en delete blijven ongewijzigd ### Securitytests - traversal source - traversal destination - symlink source rejection - destination inside source rejection - destination outside whitelist rejection ### Runtime edge cases - rename/move van lege directory - rename/move van directory met inhoud binnen same-root - permission failure -> `io_error` - destination parent ontbreekt -> bestaande foutmapping --- ## 9. Aanbeveling Aanbevolen v1-richting: - **alleen same-root directory move ondersteunen** - **cross-root directory move nog niet ondersteunen** Korte motivatie: - laagste complexiteit - beste aansluiting op bestaand taskmodel - minimale partial-failure kans - veel kleiner regressie- en securityrisico dan recursieve cross-root tree copy+delete Praktische v1-scope: - exact 1 directory - same-root move task-based - nested destination geblokkeerd - destination exists geblokkeerd - cross-root directory move expliciet geweigerd - batch directory move nog niet Dat is de veiligste eerste stap met duidelijke semantiek en goede testbaarheid.