diff --git a/History/2026-08-21-vm-files-api-plan.md b/History/2026-08-21-vm-files-api-plan.md new file mode 100644 index 0000000..9d4e66e --- /dev/null +++ b/History/2026-08-21-vm-files-api-plan.md @@ -0,0 +1,75 @@ +# ПЛАН: универсальный файловый сервис на ВМ (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. Ключи приложений — придумать сейчас или сервис сгенерирует при первом старте?