# 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=<root-relative>`

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=<root>/<subpath>`
- 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": "<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`

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.
