Files
photo-editor/docs/architecture/system-design-baseline.md
Coder 401969cfdb
Some checks failed
test / test (push) Failing after 24s
v2: модульный монолит — очередь, персистентность, безопасность, SSE, тесты
Реализация целевого дизайна (docs/architecture/target-design.md):
- src/: модульная структура (config, logger, errors, http, core: auth/history/jobs/engines/comfy/codex/images)
- Очередь заданий: FIFO, кониурентность codex=1 / comfy-upscale=2, MAX_QUEUED_JOBS=5, JSONL-журнал и восстановление после рестарта (running → interrupted, upscale requeue)
- Персистентные сессии (sha256-хеши токенов), scrypt-хеш пароля, rate-limit входа, Origin-проверка, magic-byte валидация аплоадов
- Атомарная запись манифеста истории, каскадное удаление, URL с фактическим расширением + 302-алиас /image.jpg, миграция history/ → data/history
- Даунскейл sharp до 1024px перед Codex + масштабирование области референса
- SSE /api/events с фолбэком на polling, фронтенд переведён на ES-модули (public/js/)
- Тесты node:test + supertest (27), CI workflow test.yml, Docker/деплой: том kadr-data
- Документация: README, docs/architecture/
2026-08-27 12:52:27 +07:00

98 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# System Design Baseline
**Вердикт:** READY
**Артефакт:** `docs/architecture/system-design-baseline.md`
**Статус:** 1.0, подтверждён по рабочей копии `main@1c36a21` (рабочее дерево чистое), дата наблюдения 2026-08-26.
**Язык:** русский (проект и владелец русскоязычные).
Этот документ — источник истины по **архитектуро-формирующим требованиям и ограничениям** проекта «Кадр». Он не описывает решение (см. `docs/architecture/target-design.md`). Каждый материал параметр имеет владельца, источник, дату и триггер пересмотра.
---
## 1. Идентичность и бизнес-контекст
| Параметр | Значение | Источник |
|---|---|---|
| Продукт | «Кадр» — локальный AI-фоторедактор: редактирование фотографии по текстовому промпту (Codex CLI) + 4× апскейл (ComfyUI RealESRGAN) | `README.md` |
| Владелец/оператор | Один человек («владелец»), доступ только ему | `README.md` разд. «Авторизация» |
| Развёртывание | Один контейнер Docker на хосте Portainer (`kadr-photo-editor`, порт 3000), LAN | `deploy/docker-compose.yml`, `README.md` |
| Окружение | Node.js 20+, Express 4, Codex CLI (OpenAI), ComfyUI `http://192.168.31.240:8188`, прокси `http://192.168.31.240:4067` для исходящего к OpenAI | `package.json`, `server.js`, `deploy/docker-compose.yml` |
| Читатели документа | Владелец; ИИ-агент, реализующий целевую архитектуру | — |
Критические сценарии (джорни):
1. Владелец загружает фото → видит превью → редактирует промптом (13 мин, фон) → результат в истории.
2. Владелец увеличивает разрешение версии (несколько секунд) → результат в истории.
3. Владелец возвращается к любой версии истории (дерево), продолжает правки с неё.
4. Владелец удаляет версию каскадно (с потомками).
5. Владелец получает подсказки промптов (из истории / от Codex).
Горизонт решений: **один пользователь, LAN, один хост, один контейнер**, горизонт планирования 612 месяцев. Выход за эти рамки — триггер пересмотра (см. реестр).
---
## 2. Область и не-цели
**В области:** редактирование по промпту, апскейл 4×, история версий с деревом и каскадным удалением, авторизация одного владельца, референс с областью, подсказки промптов, мультизагрузка, деплой Docker/Portainer, CI на Gitea Actions.
**Вне области (не-цели):** многопользовательность; публичный интернет-доступ; мобильные приложения; пакетная обработка; генерация изображений «с нуля»; онлайн-редактор с кистями/слоями; платёжные интеграции; облачный хостинг. Всё перечисленное — кандидаты на отдельное решение, не для текущего горизонта.
---
## 3. Драйверы и ограничения (реестр)
Легенда: **Крит.** — DRIVER / SUPPORTING / INFORMATIONAL; **Статус** — CONFIRMED (из кода/документов), ASSUMED, UNKNOWN.
| # | Тема | Параметр | Крит. | Статус | Значение/мера | Источник и владелец | Триггер пересмотра |
|---|---|---|---|---|---|---|---|
| D1 | Бизнес | Один владелец, закрытый доступ | DRIVER | CONFIRMED | Ровно один логин (`APP_USER`/`APP_PASSWORD`), cookie-сессия `kadr_session`, 7 суток, sliding | `server.js:119-218`, `README.md` | Появление второго пользователя |
| D2 | Бизнес | Редактирование по промпту — ядро продукта | DRIVER | CONFIRMED | Обработка 6082 с на 512×512, 13 мин на больших; узкое место — вызов image-модели | `README.md` разд. «Тест скорости» | Смена движка редактирования |
| D3 | Бизнес | История версий — непрерывная ветка правок | DRIVER | CONFIRMED | Дерево по `parentId`, до 50 версий, каскадное удаление, переживает перезапуск | `server.js:820-900, 1765-1826`, `README.md` | Рост лимита истории |
| D4 | Demand | Нагрузка | SUPPORTING | CONFIRMED | Один пользователь, 1 редактирование + 1 апскейл одновременно; опрос статуса каждые 3 с; лимит аплоада 25 МБ, промпт ≤ 1000 симв. | `server.js:24, 1876`, `README.md` | Параллельные правки разных фотографий |
| D5 | Demand | Объём данных | SUPPORTING | CONFIRMED | ≤ 50 версий × ≤ 25 МБ исходник; реальные файлы 16 МБ | `history/history.json`, `server.js:34` | Лимит 50 перестаёт устраивать |
| D6 | Качество | Время ответа API | SUPPORTING | CONFIRMED | `POST /api/edit`, `/api/upscale`, `/api/suggest` отвечают мгновенно (< 1 с) с `jobId`; тяжёлая работа фоном | `README.md` стр. 25-29 | — |
| D7 | Качество | Завершение редактирования | DRIVER | CONFIRMED | Codex: таймаут 420 с; ComfyUI: таймаут 300 с; сбои отображаются в UI, задание помечается `error` | `server.js:22, 29, 465-541, 1489-1534` | — |
| D8 | Данные | Переживание перезапуска | DRIVER | CONFIRMED | История переживает перезапуск; **сессии и задания — нет** (память, `sessions`/`jobs` Map); `.codex-jobs` очищается при старте | `server.js:141-153, 2259`, `README.md` стр. 98 | Цель перепроектирования: переживание заданий |
| D9 | Данные | Согласованность истории | DRIVER | CONFIRMED | Один писатель (`historyWriteChain`), полная перезапись `history.json` при каждом изменении, файлы `history/<uuid>.<ext>` | `server.js:830-868` | Переход на SQLite при > 500 версий |
| D10 | Безопасность | Аутентификация | DRIVER | CONFIRMED | Сравнение пароля — `constantTimeEqual` по **открытому** значению env-переменной; без хеширования, без rate-limit на вход | `server.js:155-159, 1641` | Редизайн: хешировать (scrypt) |
| D11 | Безопасность | Уязвимости | SUPPORTING | CONFIRMED | Только UUID в путях (`JOB_ID_PATTERN`); MIME+расширение проверяются, но без проверки сигнатуры файла; SameSite=Lax; без Secure (HTTP LAN); без Origin-проверки | `server.js:234-267, 2116` | Появление внешнего доступа |
| D12 | Операции | Деплой | SUPPORTING | CONFIRMED | Образ `node:22-bookworm-slim` (glibc обязателен для Codex); том `kadr-history`; секреты `APP_USER`/`APP_PASSWORD` из Gitea; Codex через прокси `:4067` | `Dockerfile`, `deploy/docker-compose.yml`, `.gitea/workflows/*.yml` | Смена хостинга |
| D13 | Операции | Наблюдаемость | SUPPORTING | CONFIRMED | Только лог в stdout (уровни debug/info/warn/error), без requestId, без метрик | `server.js:50-79`, `README.md` разд. «Логирование» | — |
| D14 | Экономика | Стоимость | INFORMATIONAL | CONFIRMED | Стоимость = токены Codex (ChatGPT API), редактирование ~1552k токенов/операция | `README.md` разд. «Тест скорости» | Смена тарифа |
| D15 | Эволюция | Скорость редактирования | SUPPORTING | CONFIRMED | Время растёт с разрешением исходника (1200×800 медленнее 512×512); замерено: `CODEX_REASONING_EFFORT=low` даёт ~17% | `README.md` разд. «Тест скорости» | Внедрение предварительного даунскейла |
| D16 | Ограничение | Внешние сервисы | DRIVER | CONFIRMED | ComfyUI API (upload/workflow/history/view), модель `sdxl_turbo.safetensors`, upscale `RealESRGAN_x4plus.safetensors`; Codex CLI `codex exec` с флагами `-i`, `-o last_message.txt`, `--ephemeral`, bypass sandbox | `server.js:15-17, 397-411`, `README.md` | Обновление ComfyUI/Codex |
| D17 | Ограничение | Исходящий egress | DRIVER | CONFIRMED | Прямой выход к OpenAI блокируется (403 cf-ray HEL); обязателен прокси `http://192.168.31.240:4067`, `NO_PROXY` для внутренних адресов | `deploy/docker-compose.yml:20-27`, `README.md` п.5 разд. Portainer | Смена сети/провайдера |
---
## 4. Ключевые сценарии (source/stimulus/environment/artifact/response/measure)
1. **Редактирование с сохранением в историю.** Источник: владелец. Стимул: `POST /api/edit` с фото/`sourceId` + промпт. Окружение: один контейнер, Codex доступен. Артефакт: сервис `/api/edit`. Реакция: ответ < 1 с с `jobId`; ≤ 420 с — новая версия `kind=edit` в истории; мера: версия видна в `GET /api/history` и по `job.status=done`.
2. **Апскейл.** Стимул: `POST /api/upscale`. Реакция: ≤ 300 с — версия `kind=upscale` (PNG), исходник масштабируется до ≤ 2048 px до подачи в ComfyUI. Мера: `job.status=done`.
3. **Переживание перезапуска (цель).** Стимул: перезапуск контейнера во время `running`-задания. Реакция (целевая): задание помечается прерванным с понятной ошибкой; очередь-задания и сессии переживают рестарт; история не теряется. Мера: после рестарта `GET /api/jobs/:id/status` возвращает `interrupted`/`error`, а не 404; сессия владельца жива.
4. **Безопасный вход.** Стимул: 10 неудачных попыток логина за 15 мин с одного IP. Реакция: блокировка с `Retry-After`; пароль не хранится в открытом виде. Мера: rate-limit срабатывает, в логах нет паролей.
---
## 5. Допущения и неизвестные
- **ASSUMED:** ComfyUI и Codex доступны из сети владельца (рабочее состояние подтверждается историей и `.bench/`).
- **ASSUMED:** целевой читатель (ИИ-агент) реализует сервер на Node.js/Express и фронтенд без сборки (vanilla ES-модули) — см. решения в target-design.md.
- **UNKNOWN:** точные объёмы будущего использования (нет метрик) — не влияет: горизонтальный запас огромен для одного пользователя.
- **UNKNOWN:** SLA внешних сервисов (Codex/ComfyUI) — обрабатываются таймаутами и понятными ошибками.
## 6. Триггеры пересмотра baseline
- Второй пользователь или внешний доступ (D1, D11).
- Лимит истории 50 или объём > 500 версий (D3, D5, D9).
- Параллельные правки разных фотографий (D4).
- Смена движка редактирования (D2, D16).
- Смена хостинга/сети (D12, D17).
- Переход на SQLite или другое хранилище (D9).
---
# System Design Baseline
**Checklist: 5/5 complete**<br>
**Incomplete: None** — все пункты чек-листа (объём и назначение; реестр доказательств; драйверы; написание; валидация) выполнены; изменены только документы `docs/architecture/*.md`, код не трогался.