# 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. Владелец загружает фото → видит превью → редактирует промптом (1–3 мин, фон) → результат в истории. 2. Владелец увеличивает разрешение версии (несколько секунд) → результат в истории. 3. Владелец возвращается к любой версии истории (дерево), продолжает правки с неё. 4. Владелец удаляет версию каскадно (с потомками). 5. Владелец получает подсказки промптов (из истории / от Codex). Горизонт решений: **один пользователь, LAN, один хост, один контейнер**, горизонт планирования 6–12 месяцев. Выход за эти рамки — триггер пересмотра (см. реестр). --- ## 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 | Обработка 60–82 с на 512×512, 1–3 мин на больших; узкое место — вызов 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 МБ исходник; реальные файлы 1–6 МБ | `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/.` | `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), редактирование ~15–52k токенов/операция | `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**
**Incomplete: None** — все пункты чек-листа (объём и назначение; реестр доказательств; драйверы; написание; валидация) выполнены; изменены только документы `docs/architecture/*.md`, код не трогался.