11 KiB
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 foutcodesService-laag: use-case logica (browse, file ops, tasks, bookmarks)Filesystem-laag: gecapsuleerde filesystem callsSecurity/path-guard: centrale pad-resolutie en whitelist enforcementTask-runner: background worker voor copy/move met persistente statusRepository-laag: SQLite toegang voor tasks/bookmarks/history
Datastroom copy/move:
- API ontvangt request en valideert payload.
path_guardvalideert source/destination tegen whitelist en security regels.- Service maakt task-record aan met status
queued. - Worker pakt task op, zet status op
running, voert operatie uit, werkt progress bij. - Bij afronding: status
completedoffailed; resultaat en fouten worden opgeslagen.
4. Voorgestelde backend projectstructuur
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=<root-relative>
File-operaties:
POST /api/files/renamePOST /api/files/deletePOST /api/files/mkdirPOST /api/files/copy(task-based)POST /api/files/move(task-based)
Tasks:
GET /api/tasks/{task_id}GET /api/tasks
Bookmarks:
GET /api/bookmarksPOST /api/bookmarksDELETE /api/bookmarks/{id}
6. Browse contract (v1 aangescherpt)
Padmodel:
- API accepteert in v1 alleen
root-relativepaden met expliciete root alias. - Voorstel requestvorm:
GET /api/browse?path=<root>/<subpath> - Voorbeelden:
storage1/,storage1/series,archive/docs/2026 - Absolute host paths worden niet geaccepteerd in publieke API om ambiguiteit te vermijden.
Succesresponse:
{
"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 modifiedals UTC ISO-8601 string- geen checksum/mime in v1
Hidden files beleid:
- default: hidden entries (
.-prefixed) niet tonen. - optioneel query-flag:
show_hidden=truevoor expliciete opname. .en..worden nooit teruggegeven.
Foutresponses:
400bij ongeldigepathparameter of malformed input403bij pad buiten whitelist / security-blokkade404als pad niet bestaat409als padtype mismatch (bijv. file i.p.v. directory)500bij onverwachte I/O fout
7. Delete gedrag (veiligheidsuitwerking v1)
Endpoint:
POST /api/files/delete- request:
{ "path": "<root-relative>", "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
- standaard alleen lege directory (
Non-empty directories:
- zonder recursive: blokkeren met heldere foutmelding
- met recursive: toegestaan binnen whitelist, met strikte guard tegen symlink escapes tijdens traversal
Foutafhandeling:
404target bestaat niet403security/path violations409directory non-empty zonder recursive of operation conflict500onverwachte 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_bytesen/oftotal_itemsblijvennull- 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_itemen foutdetails
Eindstatussen v1:
completedfailedqueuedenrunningals tussenstatussencancelednog niet in v1
9. Voorstel SQLite schema (v1)
Tabel tasks:
id TEXT PRIMARY KEYoperation TEXT NOT NULL(copy/move)source_path TEXT NOT NULLdestination_path TEXT NOT NULLstatus TEXT NOT NULL(queued/running/completed/failed)done_bytes INTEGER NULLtotal_bytes INTEGER NULLdone_items INTEGER NULLtotal_items INTEGER NULLcurrent_item TEXT NULLerror_code TEXT NULLerror_message TEXT NULLfailed_item TEXT NULLcreated_at TEXT NOT NULLstarted_at TEXT NULLfinished_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 AUTOINCREMENTlabel TEXT NOT NULLpath TEXT NOT NULL UNIQUEcreated_at TEXT NOT NULLupdated_at TEXT NOT NULL
Tabel history:
id INTEGER PRIMARY KEY AUTOINCREMENToperation TEXT NOT NULLpath TEXT NULLsource_path TEXT NULLdestination_path TEXT NULLstatus TEXT NOT NULLtask_id TEXT NULLerror_code TEXT NULLerror_message TEXT NULLcreated_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:
{
"error": {
"code": "path_outside_whitelist",
"message": "Requested path is outside allowed roots",
"details": {
"path": "storage1/../../etc"
}
}
}
Errorvelden:
code: machine-readable, stabiel voor clientlogicamessage: mens-leesbare samenvattingdetails: optioneel object met context (geen gevoelige hostpaths)
Voorgestelde error codes:
- security/path:
path_outside_whitelistpath_traversal_detectedsymlink_escape_detectedinvalid_root_alias
- not found/conflict/validation:
path_not_foundalready_existsdirectory_not_emptyinvalid_requestvalidation_error
- operationeel:
io_errorinternal_error
HTTP mapping:
400:invalid_request,validation_error403: security/path errors404:path_not_found,task_not_found,bookmark_not_found409:already_exists,directory_not_empty, type conflicts500: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 detailstatusBookmarks: snelle navigatie naar opgeslagen paden
Task polling:
- bij actieve taken elke 1-2 seconden
GET /api/tasks/{id}of batchGET /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.codebeslissen (bijv. specifieke melding voordirectory_not_empty) - destructive acties (delete, vooral recursive) krijgen expliciete confirm-dialog
12. Implementatieplan in kleine stappen
- Backend skeleton opzetten (FastAPI app, routers, config, logging).
path_guardimplementeren met root-alias model en centrale security checks.- Unit tests toevoegen voor whitelist/traversal/symlink scenario's.
- Browse endpoint bouwen volgens aangescherpt contract incl. hidden files beleid.
- Golden tests toevoegen voor browse success + browse error responses.
rename,mkdir,deleteimplementeren met veilig delete-gedrag (recursive policy).- Feature tests toevoegen voor file-operaties incl. non-empty directory fouten.
- SQLite schema (
tasks,bookmarks,history) toevoegen met repositories. - Task statusmachine en transitions implementeren + unit tests.
- Worker voor copy/move implementeren met bytes/items progress.
- Task endpoints implementeren (
create,get,list) met eindstatussen. - Feature tests voor copy/move + partial failure gedrag + polling flow.
- Bookmarks endpoints implementeren + basis tests.
- Regression tests voor path traversal, unicode, grote/nested directories.
- Frontend v1 basis flows koppelen (browse, acties, tasks polling, foutweergave).
- 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.