# 2026-04-20 — Dedicated storage-service with pluggable backends **Timestamp:** 2026-04-20T00:00:00Z ## Summary Introduced a dedicated `storage-service` container (port 8020) as the single file/blob persistence layer for the entire stack. All services now route file and config I/O through this service's HTTP API. The service supports pluggable storage backends (local filesystem by default; S3-compatible and WebDAV built in) with a zero-data-loss migration flow. The `doc_data` and `app_config` Docker volumes were removed. ## Files Added - `features/storage-service/app/main.py` — FastAPI app, lifespan (backend init) - `features/storage-service/app/core/config.py` — Settings (DATA_DIR, STORAGE_BACKEND, S3_*, WEBDAV_*) - `features/storage-service/app/routers/health.py` — GET /health - `features/storage-service/app/routers/objects.py` — PUT/GET/DELETE /objects/{bucket}/{key:path}, GET /objects/{bucket} - `features/storage-service/app/routers/migrate.py` — POST/GET/DELETE /migrate, PATCH /backend-config - `features/storage-service/app/services/backend_manager.py` — Driver factory, singleton, atomic switch - `features/storage-service/app/services/migration.py` — Async migration: copy → verify → switch → cleanup - `features/storage-service/app/services/backends/base.py` — AbstractStorageBackend ABC - `features/storage-service/app/services/backends/local.py` — LocalFSBackend (path traversal guard) - `features/storage-service/app/services/backends/s3.py` — S3Backend (aiobotocore, endpoint_url configurable) - `features/storage-service/app/services/backends/webdav.py` — WebDAVBackend (aiohttp + defusedxml) - `features/storage-service/scripts/start.sh` — prod uvicorn start - `features/storage-service/scripts/start_dev.sh` — dev uvicorn --reload start - `features/storage-service/pyproject.toml` — Dependencies - `features/storage-service/Dockerfile` — python:3.12-slim, non-root user 1001, port 8020 - `features/storage-service/CLAUDE.md` — API reference, bucket docs, driver docs - `features/storage-service/STATUS.md` — Service status - `backend/app/core/config_storage.py` — Thin async helpers: read_json/write_json/delete_key/list_keys - `backend/app/routers/storage_config.py` — Admin proxy endpoints for storage config + migration - `features/doc-service/alembic/versions/0008_rename_file_path_to_storage_key.py` — DB migration - `frontend/src/pages/StorageAdminPage.tsx` — Admin UI: backend status, driver form, migration progress - `tests/storage-service_tests.md` — §20 storage-service test suite ## Files Modified - `docker-compose.yml` — Added storage-service, storage_data volume; removed doc_data, app_config; added depends_on service_healthy - `docker-compose.dev.yml` — Added storage-service dev override - `backend/app/core/config.py` — Added STORAGE_SERVICE_URL - `backend/app/core/app_config.py` — Full async rewrite using config_storage HTTP helpers (no filesystem) - `backend/app/routers/settings.py` — Removed all asyncio.to_thread wrappers; direct await calls - `backend/app/main.py` — Register storage_config router; update register_services call - `backend/app/services/service_health.py` — Register storage-service - `features/doc-service/app/core/config.py` — Added STORAGE_SERVICE_URL - `features/doc-service/app/models/document.py` — file_path → storage_key - `features/doc-service/app/services/storage.py` — Complete rewrite: HTTP client calls to storage-service - `features/doc-service/app/services/config_reader.py` — Complete rewrite: reads/writes via storage-service config bucket - `features/doc-service/app/services/file_watcher.py` — Uses save_upload() → storage-service - `features/doc-service/app/routers/documents.py` — storage_key refs, pdfplumber(io.BytesIO), streaming from storage-service - `features/ai-service/app/core/config.py` — Added STORAGE_SERVICE_URL; removed CONFIG_PATH - `features/ai-service/app/services/config_reader.py` — Complete rewrite: reads/writes via storage-service config bucket - `frontend/src/api/client.ts` — Added StorageStatus, MigrationStatus, StorageBackendConfig interfaces + 5 API functions - `frontend/src/App.tsx` — Added /admin/storage route (AdminRoute → StorageAdminPage) - `tests/ALL_TESTS.md` — Updated to 20 feature areas; added §20 storage-service tests - `CLAUDE.md` — Added storage-service to Services/Volumes/Networks tables; storage enforcement rule; §20 test file - `backend/CLAUDE.md` — Added config_storage.py, storage_config.py to tree; added admin storage endpoints - `frontend/CLAUDE.md` — Added StorageAdminPage to tree; added /admin/storage route - `features/doc-service/CLAUDE.md` — Updated storage.py description; file_path → storage_key; added migration 0008 - `features/ai-service/CLAUDE.md` — Added config_reader.py description - `backend/STATUS.md` — Added storage-config endpoints; updated settings persistence note - `frontend/STATUS.md` — Added /admin/storage route; added StorageAdminPage description