# PLAN.md Notitie: `project_docs/SPARRING_GPT_PROJECT_PROMPT.md` is niet gevonden in deze repository op 10 maart 2026. Dit plan is opgesteld op basis van de overige documenten in `project_docs/`. ## 1. Doel van de applicatie De applicatie is een webgebaseerde storage manager voor self-hosted omgevingen, met een veilige browserinterface om bestanden te beheren binnen strikt whitelisted root directories. Kernwaarde van v1: - veilige en voorspelbare filesystem-operaties binnen whitelist - transparant taakmodel voor langlopende copy/move acties - stabiele API-contracten die met golden tests bewaakt worden ## 2. V1 scope en out-of-scope In scope voor v1: - directory browsing binnen whitelist roots - file-operaties: `rename`, `delete`, `mkdir` - task-based operaties: `copy`, `move` - task status/progress polling - bookmarks CRUD (minimaal: list/create/delete) - history logging van uitgevoerde operaties - security path controls: canonicalisatie, traversal-blocking, symlink escape blocking Out-of-scope voor v1: - user management en authenticatie/autorisatie - fijnmazig permissions management - cloud storage integraties - distributed/multi-node storage - geavanceerde job scheduling (prioriteiten, parallel queue tuning, retry policy) - recycle bin/undo functionaliteit ## 3. Voorgestelde architectuur voor eerste versie Technische stack: - Backend: Python + FastAPI - Frontend: lichte JavaScript UI (zonder zwaar framework) - Opslag: SQLite voor tasks, bookmarks, history Architectuur v1 (monolithisch, modulair): - `API-laag` (FastAPI routes): validatie, response-shaping, HTTP foutcodes - `Service-laag`: use-case logica (browse, file ops, tasks, bookmarks) - `Filesystem-laag`: gecapsuleerde filesystem calls - `Security/path-guard`: centrale pad-resolutie en whitelist enforcement - `Task-runner`: background worker voor copy/move met persistente status - `Repository-laag`: SQLite toegang voor tasks/bookmarks/history Datastroom copy/move: 1. API ontvangt request en valideert payload. 2. `path_guard` valideert source/destination tegen whitelist en security regels. 3. Service maakt task-record aan met status `queued`. 4. Worker pakt task op, zet status op `running`, voert operatie uit, werkt progress bij. 5. Bij afronding: status `completed` of `failed`; resultaat en fouten worden opgeslagen. ## 4. Voorgestelde backend projectstructuur ```text backend/ app/ main.py config.py logging.py api/ schemas.py errors.py routes_browse.py routes_files.py routes_tasks.py routes_bookmarks.py services/ browse_service.py file_ops_service.py task_service.py bookmark_service.py history_service.py security/ path_guard.py fs/ filesystem_adapter.py tasks/ worker.py progress.py transitions.py db/ sqlite.py models.py migrations/ 001_init.sql repositories/ task_repo.py bookmark_repo.py history_repo.py tests/ unit/ test_path_guard.py test_task_transitions.py feature/ test_browse_flow.py test_file_ops_flow.py test_task_flow.py regression/ test_path_traversal_blocked.py test_unicode_filenames.py test_large_directory_listing.py golden/ test_api_browse_golden.py test_api_errors_golden.py ``` Richtlijnen: - security checks alleen via `path_guard.py` (geen ad-hoc checks in routes) - filesystem calls alleen via `filesystem_adapter.py` - API shapes blijven stabiel en worden bewaakt met golden tests ## 5. Belangrijkste API endpoints voor versie 1 Browse: - `GET /api/browse?path=` File-operaties: - `POST /api/files/rename` - `POST /api/files/delete` - `POST /api/files/mkdir` - `POST /api/files/copy` (task-based) - `POST /api/files/move` (task-based) Tasks: - `GET /api/tasks/{task_id}` - `GET /api/tasks` Bookmarks: - `GET /api/bookmarks` - `POST /api/bookmarks` - `DELETE /api/bookmarks/{id}` ## 6. Browse contract (v1 aangescherpt) Padmodel: - API accepteert in v1 alleen `root-relative` paden met expliciete root alias. - Voorstel requestvorm: `GET /api/browse?path=/` - Voorbeelden: `storage1/`, `storage1/series`, `archive/docs/2026` - Absolute host paths worden niet geaccepteerd in publieke API om ambiguiteit te vermijden. Succesresponse: ```json { "path": "storage1/series", "directories": [ { "name": "ShowA", "path": "storage1/series/ShowA", "modified": "2026-03-10T12:00:00Z" } ], "files": [ { "name": "episode.mkv", "path": "storage1/series/episode.mkv", "size": 734003200, "modified": "2026-03-10T11:30:00Z" } ] } ``` Metadata velden (v1): - voor directories: `name`, `path`, `modified` - voor files: `name`, `path`, `size`, `modified` - `modified` als UTC ISO-8601 string - geen checksum/mime in v1 Hidden files beleid: - default: hidden entries (`.`-prefixed) niet tonen. - optioneel query-flag: `show_hidden=true` voor expliciete opname. - `.` en `..` worden nooit teruggegeven. Foutresponses: - `400` bij ongeldige `path` parameter of malformed input - `403` bij pad buiten whitelist / security-blokkade - `404` als pad niet bestaat - `409` als padtype mismatch (bijv. file i.p.v. directory) - `500` bij onverwachte I/O fout ## 7. Delete gedrag (veiligheidsuitwerking v1) Endpoint: - `POST /api/files/delete` - request: `{ "path": "", "recursive": false }` Gedrag files vs directories: - file delete: direct verwijderen indien pad valide is - directory delete: - standaard alleen lege directory (`recursive=false`) - non-empty directory geeft `409 directory_not_empty` - recursive delete alleen bij expliciet `recursive=true` Non-empty directories: - zonder recursive: blokkeren met heldere foutmelding - met recursive: toegestaan binnen whitelist, met strikte guard tegen symlink escapes tijdens traversal Foutafhandeling: - `404` target bestaat niet - `403` security/path violations - `409` directory non-empty zonder recursive of operation conflict - `500` onverwachte filesystem fout Bevestigingsaannames: - backend voert geen interactieve confirm uit - frontend moet destructive acties bevestigen voordat endpoint wordt aangeroepen - voorstel frontend: extra bevestigingstekst voor recursive delete ## 8. Task/progress model (concreet v1) Progress model: - primaire metriek: bytes (`done_bytes`, `total_bytes`) voor copy/move van files - secundaire metriek voor directory-operaties: `done_items`, `total_items` - API retourneert beide waar beschikbaar Als totaal onbekend is: - `total_bytes` en/of `total_items` blijven `null` - client toont indeterminate progress state - `done_*` kan wel oplopen Partial failure gedrag: - v1 policy: fail-fast per task - eerste fatale fout zet task op `failed` - reeds verplaatste/gekopieerde items blijven staan (geen rollback in v1) - response bevat `failed_item` en foutdetails Eindstatussen v1: - `completed` - `failed` - `queued` en `running` als tussenstatussen - `canceled` nog niet in v1 ## 9. Voorstel SQLite schema (v1) Tabel `tasks`: - `id TEXT PRIMARY KEY` - `operation TEXT NOT NULL` (`copy`/`move`) - `source_path TEXT NOT NULL` - `destination_path TEXT NOT NULL` - `status TEXT NOT NULL` (`queued`/`running`/`completed`/`failed`) - `done_bytes INTEGER NULL` - `total_bytes INTEGER NULL` - `done_items INTEGER NULL` - `total_items INTEGER NULL` - `current_item TEXT NULL` - `error_code TEXT NULL` - `error_message TEXT NULL` - `failed_item TEXT NULL` - `created_at TEXT NOT NULL` - `started_at TEXT NULL` - `finished_at TEXT NULL` Indexen: - `idx_tasks_status_created_at(status, created_at DESC)` - `idx_tasks_created_at(created_at DESC)` Tabel `bookmarks`: - `id INTEGER PRIMARY KEY AUTOINCREMENT` - `label TEXT NOT NULL` - `path TEXT NOT NULL UNIQUE` - `created_at TEXT NOT NULL` - `updated_at TEXT NOT NULL` Tabel `history`: - `id INTEGER PRIMARY KEY AUTOINCREMENT` - `operation TEXT NOT NULL` - `path TEXT NULL` - `source_path TEXT NULL` - `destination_path TEXT NULL` - `status TEXT NOT NULL` - `task_id TEXT NULL` - `error_code TEXT NULL` - `error_message TEXT NULL` - `created_at TEXT NOT NULL` Indexen: - `idx_history_created_at(created_at DESC)` - `idx_history_operation_created_at(operation, created_at DESC)` - `idx_history_task_id(task_id)` ## 10. API error model (v1) Standaard error shape: ```json { "error": { "code": "path_outside_whitelist", "message": "Requested path is outside allowed roots", "details": { "path": "storage1/../../etc" } } } ``` Errorvelden: - `code`: machine-readable, stabiel voor clientlogica - `message`: mens-leesbare samenvatting - `details`: optioneel object met context (geen gevoelige hostpaths) Voorgestelde error codes: - security/path: - `path_outside_whitelist` - `path_traversal_detected` - `symlink_escape_detected` - `invalid_root_alias` - not found/conflict/validation: - `path_not_found` - `already_exists` - `directory_not_empty` - `invalid_request` - `validation_error` - operationeel: - `io_error` - `internal_error` HTTP mapping: - `400`: `invalid_request`, `validation_error` - `403`: security/path errors - `404`: `path_not_found`, `task_not_found`, `bookmark_not_found` - `409`: `already_exists`, `directory_not_empty`, type conflicts - `500`: `io_error`, `internal_error` ## 11. Minimale frontend-notitie voor v1 Hoofdschermen: - `Browser view`: directory listing + acties (rename/delete/mkdir/copy/move) - `Tasks view`: lijst met actieve/recente taken en detailstatus - `Bookmarks`: snelle navigatie naar opgeslagen paden Task polling: - bij actieve taken elke 1-2 seconden `GET /api/tasks/{id}` of batch `GET /api/tasks` - polling stopt automatisch bij eindstatus (`completed`/`failed`) - UI toont determinate progress bij bekende totalen, anders indeterminate indicator Foutweergave: - fouten tonen met `error.message` - client-logica kan op `error.code` beslissen (bijv. specifieke melding voor `directory_not_empty`) - destructive acties (delete, vooral recursive) krijgen expliciete confirm-dialog ## 12. Implementatieplan in kleine stappen 1. Backend skeleton opzetten (FastAPI app, routers, config, logging). 2. `path_guard` implementeren met root-alias model en centrale security checks. 3. Unit tests toevoegen voor whitelist/traversal/symlink scenario's. 4. Browse endpoint bouwen volgens aangescherpt contract incl. hidden files beleid. 5. Golden tests toevoegen voor browse success + browse error responses. 6. `rename`, `mkdir`, `delete` implementeren met veilig delete-gedrag (recursive policy). 7. Feature tests toevoegen voor file-operaties incl. non-empty directory fouten. 8. SQLite schema (`tasks`, `bookmarks`, `history`) toevoegen met repositories. 9. Task statusmachine en transitions implementeren + unit tests. 10. Worker voor copy/move implementeren met bytes/items progress. 11. Task endpoints implementeren (`create`, `get`, `list`) met eindstatussen. 12. Feature tests voor copy/move + partial failure gedrag + polling flow. 13. Bookmarks endpoints implementeren + basis tests. 14. Regression tests voor path traversal, unicode, grote/nested directories. 15. Frontend v1 basis flows koppelen (browse, acties, tasks polling, foutweergave). 16. Eindcontrole: volledige test run + golden contract verificatie. ## 13. Governance-notitie Volgens `CHANGE_POLICY.md` en `SAFE_FILES.md` vallen API-wijzigingen en DB schema-wijzigingen onder "eerst voorstel nodig". Deze aangescherpte `PLAN.md` is het voorstel dat eerst goedgekeurd moet worden. Na expliciete goedkeuring kan implementatie starten.