# ПЛАН: универсальный файловый сервис на ВМ (API) _Дата: 2026-08-21. Статус: РЕАЛИЗОВАНО И ЗАДЕПЛОЕНО (v1.0.0), см. `README.md` сервиса `/home/naeel/nubes/vmfiles/` и `2026-08-21-vm-upload-implemented.md`._ ## Цель Один внутренний (НЕ публичный) сервис на ВМ `5.172.178.213` (`contracts.kube5s.ru`) для приёма/временного хранения/выдачи файлов. Потребители: **drhider**, **contracts**, **SQS IoT**. Заменяет сырой nginx-dav `/drhider-upload/` на задокументированный, версионированный API, чтобы любому сервису было ясно, как им пользоваться. ## Потребители и режимы - **drhider** — браузер (PUT файла) + сервер (pull). Нужен CORS для браузера. - **contracts** — сервер-к-серверу, много файлов из локали. - **SQS IoT** — сервер-к-серверу. ## Технология **FastAPI + uvicorn** (Python уже есть на ВМ). Почему FastAPI: автогенерация OpenAPI/Swagger (`/docs`) → «как юзать» видно из коробки; нативный streaming для больших тел. ## API v1 (контракт) | Метод | Путь | Вход | Ответ | |---|---|---|---| | `POST` | `/api/v1/files` | тело=файл (raw или multipart `file`), header `X-App-Key` | `201 {"id","url","size","expires_at"}` | | `GET` | `/api/v1/files/{id}` | header `X-App-Key` | байты файла | | `DELETE` | `/api/v1/files/{id}` | header `X-App-Key` | `204` | | `GET` | `/api/v1/health` | — | `{"ok":true,"version":...}` | | `GET` | `/api/v1/docs` | — | Swagger UI (авто) | Единые ошибки: `{"error": "...", "code": "unauthorized|not_found|too_large|expired|quota_exceeded"}`. ## Авторизация Заголовок `X-App-Key`, по одному секрету на приложение. Ключи — в конфиге на ВМ (файл `apps.yml`/`.env`): `drhider`, `contracts`, `sqs-iot`. Без валидного ключа — `401`. ## Хранилище и метаданные - Файлы: `/var/lib/vmfiles/` (или `/var/www/vmfiles/`, владелец — пользователь сервиса). - Метаданные: SQLite (`id, app, name, size, created_at, expires_at`). - id — серверный UUID (или клиентский токен — см. «открытые вопросы»). ## Лимиты и TTL - `max_file_size` (по умолчанию 1024m) и `quota` на приложение. - TTL по умолчанию 30 мин (на приложение можно переопределить). - Чистка — встроенная фоновая задача сервиса (вместо текущего cron-`find`). ## Деплой на ВМ 1. Код сервиса — в отдельной папке на ВМ (или отдельный репозиторий). 2. systemd-юнит `vmfiles.service` → `uvicorn app:app --host 127.0.0.1 --port 8769`. 3. nginx: новый `location /api/v1/ { proxy_pass http://127.0.0.1:8769; ... }` + `proxy_request_buffering off` (стримить большие тела) + `client_max_body_size 1024m`. CORS — отдать сервису (FastAPI), не nginx. 4. Проверка: `nginx -t` → reload. ## Миграция drhider - Пока сервис поднимается — `/drhider-upload/` оставить как есть (не ломать текущее). - После готовности — перевести `uploadFiles()` и `/api/upload_refs` на `/api/v1/files`, убрать dav-location и cron-`find`. ## Порядок работ 1. Скелет FastAPI + health + `/docs`. 2. `POST/GET/DELETE /files` + SQLite-метаданные + TTL-чистка. 3. `X-App-Key` авторизация + квоты. 4. systemd + nginx `proxy_pass`. 5. Тесты: curl (raw + multipart), большие файлы, expiry, quota. 6. Перевести drhider на новый API, выпилить старый dav. 7. Документ-спека (`README`/`API.md`) + примеры для contracts/SQS. ## Открытые вопросы (до «делай») 1. Язык: FastAPI (рекомендую) или Flask? 2. id файла: сервер генерирует (POST) или клиент приносит токен (PUT)? Влияет на браузерный поток drhider. 3. Загрузка: только raw-тело или поддерживать multipart тоже? 4. Где живёт код сервиса — отдельный репозиторий на gitea или папка на ВМ? 5. Ключи приложений — придумать сейчас или сервис сгенерирует при первом старте?