From 3e85635a65cdd122dd8a7ea5c79031b1b6692684 Mon Sep 17 00:00:00 2001 From: hightemp Date: Tue, 27 Oct 2026 16:36:20 +0300 Subject: [PATCH] docs: every document in English and Russian, the plan translated IMPROVEMENT_PLAN.md is now the English translation of the plan and the Russian original moved to IMPROVEMENT_PLAN.ru.md; both keep the same sections, checkboxes and decision numbers. CONTRIBUTING, ROADMAP, SECURITY, desktop/README and the READMEs of spec/ got Russian versions. Every pair has a language switcher at the top, and the links of each version lead to documents in the same language. CONTRIBUTING says a change updates both versions of a document. Co-Authored-By: Claude Opus 5.5 --- CONTRIBUTING.md | 6 +- CONTRIBUTING.ru.md | 97 ++ IMPROVEMENT_PLAN.md | 1438 +++++++++++---------- IMPROVEMENT_PLAN.ru.md | 934 +++++++++++++ README.md | 2 +- README.ru.md | 6 +- ROADMAP.md | 4 +- ROADMAP.ru.md | 49 + SECURITY.md | 2 + SECURITY.ru.md | 30 + desktop/README.md | 2 + desktop/README.ru.md | 41 + server/internal/spec/logformat_v2_test.go | 2 +- spec/README.md | 2 + spec/README.ru.md | 16 + spec/db/README.md | 2 + spec/db/README.ru.md | 23 + spec/fixtures/v1/README.md | 2 + spec/fixtures/v1/README.ru.md | 23 + spec/fixtures/v2/README.md | 2 + spec/fixtures/v2/README.ru.md | 18 + spec/frozen/README.md | 2 + spec/frozen/README.ru.md | 31 + spec/logformat/README.md | 2 + spec/logformat/README.ru.md | 75 ++ 25 files changed, 2085 insertions(+), 726 deletions(-) create mode 100644 CONTRIBUTING.ru.md create mode 100644 IMPROVEMENT_PLAN.ru.md create mode 100644 ROADMAP.ru.md create mode 100644 SECURITY.ru.md create mode 100644 desktop/README.ru.md create mode 100644 spec/README.ru.md create mode 100644 spec/db/README.ru.md create mode 100644 spec/fixtures/v1/README.ru.md create mode 100644 spec/fixtures/v2/README.ru.md create mode 100644 spec/frozen/README.ru.md create mode 100644 spec/logformat/README.ru.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e2d91d4..bac8bf2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,10 +1,12 @@ # Contributing -The plan and all decisions are in [IMPROVEMENT_PLAN.md](IMPROVEMENT_PLAN.md) (in Russian): section 8 is the order of work, section 10 the decisions. +**English** · [Русский](CONTRIBUTING.ru.md) + +The plan and all decisions are in [IMPROVEMENT_PLAN.md](IMPROVEMENT_PLAN.md): section 8 is the order of work, section 10 the decisions. ## Language -The project is open source and **English is the base language**: code, comments, identifiers, commit messages, CLI output, API error messages, specifications and documentation. Russian is the second language: the UI is translated (`ui/src/lib/i18n`) and user documentation has a Russian version (`README.ru.md`). A change to user-facing docs updates both versions. +The project is open source and **English is the base language**: code, comments, identifiers, commit messages, CLI output, API error messages, specifications and documentation. Russian is the second language: the UI is translated (`ui/src/lib/i18n`) and every document comes in a pair: `X.md` in English and `X.ru.md` in Russian, with a language switcher at the top of both. A change to a document updates both versions, and the links of each version lead to documents in the same language. The plan is no exception: `IMPROVEMENT_PLAN.md` and `IMPROVEMENT_PLAN.ru.md` are kept in sync, and an item done is ticked in both. ## Repository layout diff --git a/CONTRIBUTING.ru.md b/CONTRIBUTING.ru.md new file mode 100644 index 0000000..10c6541 --- /dev/null +++ b/CONTRIBUTING.ru.md @@ -0,0 +1,97 @@ +# Участие в разработке + +[English](CONTRIBUTING.md) · **Русский** + +План и все решения — в [IMPROVEMENT_PLAN.ru.md](IMPROVEMENT_PLAN.ru.md): раздел 8 — порядок работ, раздел 10 — решения. + +## Язык + +Проект открытый, и **базовый язык — английский**: код, комментарии, идентификаторы, сообщения коммитов, вывод CLI, сообщения об ошибках API, спецификации и документация. Русский — второй язык: UI переведён (`ui/src/lib/i18n`), а каждый документ существует в паре: `X.md` на английском и `X.ru.md` на русском, с переключателем языка вверху обоих. Правка документа меняет обе версии, а ссылки каждой версии ведут на документы на том же языке. План — не исключение: `IMPROVEMENT_PLAN.md` и `IMPROVEMENT_PLAN.ru.md` ведутся вместе, сделанный пункт отмечается в обоих. + +## Устройство репозитория + +| Каталог | Что | Язык | +|---|---|---| +| `client-php/` | PHP-библиотека (отладчик), Composer-пакет, PHP 7.4+; `v1/` — прежняя библиотека, только срочные исправления, вне линтеров | PHP | +| `server/` | Просмотрщик: CLI, сервер, импорт логов, точка входа десктопа | Go 1.26+ | +| `ui/` | Веб-интерфейс, встраивается в Go-бинарник | Svelte 5 + TypeScript | +| `desktop/` | Заметки о сборке десктопа на Wails | — | +| `spec/` | Контракты: фикстуры, JSON Schema, OpenAPI | — | + +## Команды + +Все проверки запускаются через `make`; CI вызывает те же цели: + +```sh +make doctor # что установлено, чего не хватает +make tools # закреплённые версии линтеров в .tools/bin +make deps # зависимости всех компонентов +make test # все тесты +make lint # все линтеры +make ci # всё, что делает CI +make e2e # браузерные тесты (Playwright) собранного просмотрщика на фикстурах логов +make e2e-visual # снимки каждой темы против ui/e2e/__screenshots__ (Docker) +make ssh-e2e # просмотрщик против настоящего OpenSSH-сервера в Docker +make help # все остальные цели +``` + +`make e2e` один раз нужен Chromium для Playwright: `cd ui && npx playwright install chromium`. + +`make e2e-visual` снимает скриншоты внутри Docker-образа Playwright, поэтому шрифты одинаковые на любой машине и в CI. После задуманного изменения внешнего вида `make e2e-visual-update` снимает их заново; посмотрите новые файлы в `ui/e2e/__screenshots__`, прежде чем коммитить. Витрина компонентов, `#/dev/components` (или «Витрина компонентов» в `Ctrl+K`), показывает каждый компонент в каждой встроенной теме. + +Цвета живут только в `ui/src/styles/theme.css` как токены; Stylelint не пропустит цвет в любом другом месте. + +## TDD + +Новый код пишется с теста: + +1. Тест, который описывает поведение, — и падает (красный). +2. Минимальная реализация, с которой он проходит (зелёный). +3. Рефакторинг при зелёных тестах. + +Код без теста, который его потребовал, не принимается. Баг, найденный вручную, сначала воспроизводится тестом, потом исправляется. + +| Компонент | Тесты | Где | +|---|---|---| +| `client-php` | PHPUnit 9.6, матрица PHP 7.4–8.4 в CI | `client-php/tests/` | +| `server` | `go test -race` | рядом с кодом, `*_test.go` | +| `ui` | Vitest + Testing Library | рядом с кодом, `*.test.ts` | + +Тесты разбора логов используют фикстуры из `spec/fixtures/`, а не придуманные строки. + +## Контракты и сгенерированный код + +Сначала меняется контракт в `spec/` (форматы логов, OpenAPI), потом код. Типы Go (`server/internal/api`, `server/internal/libclient`) и TypeScript (`ui/src/lib/api/schema.gen.d.ts`) генерируются из OpenAPI командой `make generate`; файлы `*.gen.*` руками не правятся. CI проверяет, что сгенерированный код совпадает с закоммиченным (`make generate-check`). + +## Именование + +Венгерская нотация во всём новом коде запрещена: никаких префиксов типа вроде `a`, `s`, `i`, `b`, `o`, `m`, `f`, `fn` (`$aVars`, `$sMessage`, `fnDebugLog`, `oSelectedProject`). Тип выражает система типов. + +| Где | Стиль | Пример | +|---|---|---| +| PHP | PSR-12: классы `PascalCase`, методы и свойства `camelCase`, константы `UPPER_SNAKE` | `$projectRoot`, `log()`, `Level::ERROR` | +| Go | идиоматичный Go (`MixedCaps`) | `Project.LogDir()` | +| TypeScript / Svelte | `camelCase`, компоненты `PascalCase` | `selectedRequest`, `RequestList.svelte` | +| Формат логов, конфиг, API, база данных | `snake_case` | `request_id`, `is_cli`, `messages.level` | + +Поля DTO из OpenAPI остаются в TypeScript `snake_case` (без слоя конвертации). + +Это проверяется автоматически: `client-php/tools/bin/check-naming` для PHP и правило ESLint `naming-convention` для TS/Svelte. Строку с устаревшей обёрткой, которая сохраняет старое имя, можно исключить комментарием `// naming-check:ignore`. + +## Тексты UI + +Каждая видимая пользователю строка проходит через `i18n.t('key')`. Ключ добавляется в оба словаря в `ui/src/lib/i18n/messages.ts`; тесты проверяют, что у `en` и `ru` одинаковые ключи, одинаковые подстановки и все формы множественного числа (`Intl.PluralRules`). Нативные диалоги браузера (`alert`, `confirm`, `prompt`), `` / combobox | форма проекта (`link_type`) | `Select` / `Combobox` с поиском | -| Атрибут `title` (нативные подсказки) | кнопки тулбаров без подписей | `Tooltip` с задержкой и горячей клавишей в тексте | -| Контекстное меню браузера | списки файлов и сообщений | `ContextMenu` (копировать, открыть в IDE, удалить, сравнить, закрепить) | -| Нативные скроллбары | все панели | Тонкие стилизованные скроллбары через CSS (`scrollbar-width`, `::-webkit-scrollbar`), без JS-эмуляции. ❓ *п. 10.5* | -| `` | фильтры | `Checkbox`, `Switch`, `SegmentedControl` | -| `` | фильтр по времени (новый) | `DateRangePicker` с пресетами («последние 15 мин», «сегодня») | -| `` | импорт JSONL/ZIP (новый) | Зона Drag&Drop + кнопка | -| Web Notifications API | заготовка в `notification_manager.js` | Внутренние `Toast`; системные уведомления только по явному согласию в настройках | -| Нативный drag разделителей | `split:true` в EasyUI | `SplitPane` с запоминанием размеров | -| Нативный поиск по странице (Ctrl+F) в виртуализированных списках не работает | — | Свой поиск `/` + командная палитра `Ctrl+K` | -| Нативный `` и выбор шрифта | — | Собственный редактор темы (п. 6.4) | - -- [x] Собрать набор компонентов в `ui/src/lib/components` и сделать витрину для разработки (страница `/dev/components` или Storybook). ❓ *Писать всё самому или взять headless-библиотеку (Bits UI / Melt UI) и стилизовать — п. 10.4.* — *v0.9: компоненты свои (в `ui/src/components`); витрина — `#/dev/components` (и «Витрина компонентов» в `Ctrl+K`): каждый компонент во всех встроенных темах рядом, живой. Добавлен `ColorField` вместо ``.* - -### 6.4 Темы оформления - -**Архитектура:** - -- [x] Дизайн-токены как CSS custom properties: цвета (`--bg`, `--surface`, `--text`, `--muted`, `--border`, `--accent`, `--danger`, `--warning`, `--info`, `--success`), цвета уровней сообщений (`--level-error`, `--level-warning`, `--level-info`, `--level-message`), подсветка синтаксиса и JSON (`--syntax-key`, `--syntax-string`, `--syntax-number`, `--syntax-null` …), радиусы, тени, отступы, шрифты. -- [x] Ни одного захардкоженного цвета в компонентах. Проверка в CI через Stylelint (`color-no-hex` вне файлов тем, `declaration-property-value-allowed-list`). — *v0.9: Stylelint в `make ui-lint` запрещает hex, именованные цвета и цветовые функции (`rgb()`, `hsl()` …) везде, кроме `src/styles/theme.css`; затемнение под диалогом стало токеном `--backdrop`.* -- [x] Тема — это файл токенов (TS/JSON → CSS-переменные на `:root[data-theme="…"]`). Переключение мгновенное, без перезагрузки. -- [x] Без «вспышки» неверной темы при загрузке: маленький inline-скрипт в `index.html` выставляет `data-theme` до монтирования приложения. — *выполнено иначе: не inline, а блокирующий `theme-init.js` — inline-скрипты запрещены CSP (фаза 5).* -- [x] Подсветка кода (Shiki) и JSON-дерево берут цвета из той же темы. Для каждой темы задаётся пара: тема UI + тема подсветки. — *JSON-дерево и подсветка кода — токены `--syntax-*` каждой темы (v0.5).* - -**Набор тем:** - -- [x] Встроенные: **Светлая**, **Тёмная**, **Системная** (следует `prefers-color-scheme`), **Высокий контраст**. ❓ *Нужны ли дополнительные пресеты (Solarized, Nord, Dracula, Monokai и т. п.) — п. 10.24.* -- [x] Акцентный цвет выбирается отдельно поверх любой темы. — *v0.9: «Оформление» → акцентный цвет (свой выбор цвета или «Как в теме»), предупреждение, если контраст с фоном темы меньше 3:1.* -- [x] Цвет окружения поверх темы: полоса или рамка `stage`/`prod` (п. 7.5) видна в любой теме и не перекрывается акцентом. — *v0.9: рамка вокруг всего окна цвета `--env-stage`/`--env-prod`, когда выбран проект или лента сервера stage/prod; не перехватывает клики; выключается в «Оформлении».* - -**Настройки отображения (вместе с темой):** - -- [x] Плотность: компактная / обычная (высота строк в списках запросов и сообщений). — *v0.9: токены `--row-padding-y`, `--row-line-height`; виртуальные списки перемеряют строку при смене плотности и шрифта.* -- [x] Размер шрифта интерфейса и моноширинный шрифт для кода и переменных (системный стек по умолчанию; при выборе своих шрифтов — локальные файлы, без внешних CDN). — *v0.9: размер 12–18 px; шрифт кода — имя шрифта, установленного на компьютере (только имена, кавычки и запятые), за ним системный моноширинный стек; файлы шрифтов не загружаются.* -- [x] Уважать `prefers-reduced-motion` и `prefers-contrast`. — *v0.9: «Системная» тема при `prefers-contrast: more` — высококонтрастная, следует за ОС без перезагрузки.* - -**Пользовательские темы:** - -- [x] Редактор темы в настройках: правка токенов с живым предпросмотром на макете (список запросов, сообщение, JSON, код), сброс к базовой теме. — *v0.9: «Оформление» → «Редактор тем»: цвета поверх светлой, тёмной или контрастной основы по группам, макет просмотрщика в самой правке (тема работает на любом элементе с `data-theme`), контраст всех пар WCAG AA вживую, сброс токена и всей темы; до 20 тем.* -- [x] Экспорт и импорт темы JSON-файлом; валидация схемы при импорте. ❓ *Хранить пользовательские темы на сервере (в настройках Go-сервера, общие для всех браузеров) или только в браузере — п. 10.25.* — *v0.9: файл `.theme.json` — объект `CustomTheme` из `spec/openapi.yaml`; импорт проверяет имя, основу и цвета, токены новых версий пропускает. Темы и все настройки оформления — на сервере (`GET/PUT /api/v1/settings`, событие `settings_updated` в другие окна), `localStorage` — кэш для первого кадра (`theme-init.js`).* - -**Качество:** - -- [x] Автотест контраста: для каждой встроенной темы проверять пары «текст/фон», «уровень/фон», «подсветка/фон» на WCAG AA (4.5:1 для текста, 3:1 для крупных элементов и иконок). -- [x] Визуальные снапшоты Playwright основных экранов во всех встроенных темах. — *v0.9: `make e2e-visual` сравнивает просмотрщик во всех темах, витрину, «Оформление» и редактор тем с `ui/e2e/__screenshots__` в Docker-образе Playwright (одни шрифты локально и в CI); `make e2e-visual-update` — снять заново.* -- [x] Витрина компонентов (п. 6.3) с переключателем темы. — *v0.9: все темы рядом или одна на выбор.* -- [x] Переключение темы из командной палитры (`Ctrl+K` → «Тема: …») и горячей клавишей. — *v0.6: из палитры; отдельной клавиши нет.* - -### 6.5 Доработка функционала в новом UI - -Кроме функций из п. 5.1, которые реализуются сразу в новом UI: - -- [ ] Раскладка: серверы → проекты → запросы → сообщения → детали (п. 7.5). Панели можно изменять по размеру и сворачивать; есть компактный режим для узкого экрана. — *частично: проекты → запросы → сообщение → детали есть; серверов в дереве и изменяемых панелей нет.* -- [ ] Вкладки деталей сообщения: **Сообщение**, **Переменные** (JSON-дерево с типами, поиском, копированием пути и значения), **Бэктрейс** (с превью исходника), **Сырой JSON**. -- [ ] Вкладки деталей запроса: **Обзор** (URL, метод, код, время, память, пользователь), **Timeline**, **SQL**, **Ошибки**, **Суперглобалы**. — *частично (v0.5): «Сообщения», «Шкала времени», «SQL», «Суперглобальные»; обзор — в шапке запроса; отдельной вкладки ошибок нет.* -- [x] Командная палитра (`Ctrl+K`): переход к проекту или запросу, действия, настройки. — *v0.6: проекты, серверы, закреплённые и ошибочные запросы, окна, темы, языки, настройки, фильтр ленты.* -- [x] Горячие клавиши для всего (j/k, Enter, `/`, `Esc`, `g p` — проекты), справка по `?`. — *v0.6: j/k, Shift+J/K, Esc, /, g p, ?, Ctrl/⌘+K.* -- [x] Строка фильтров с синтаксисом (`type:error tag:sql duration>500 url:/api/*`) и автодополнением. Сейчас похожий синтаксис `type:error` есть только в PHP-библиотеке. — *v0.6.* -- [x] Несколько открытых запросов во вкладках и режим сравнения двух запросов бок о бок. — *v0.7: до восьми вкладок над запросом; кнопка ⇄ сравнивает вкладку с открытым запросом.* -- [ ] Страница настроек проекта вместо модального окна: сервер, пути, маппинг путей (сервер/контейнер ↔ локальная копия для IDE) с проверкой «путь существует», выбор редактора, ретеншн. -- [ ] Страница серверов: добавление SSH-подключения (хост из `~/.ssh/config`, ключ, jump-хост), кнопка «Проверить подключение», статус и задержка (п. 7.4). -- [ ] Индикатор состояния: подключение к live-потоку и к каждому серверу (online/offline/переподключение), количество неимпортированных файлов (сейчас `#project-files-info`), место на диске. -- [ ] Пустые состояния и онбординг: «нет проектов → как подключить `Debugger.class.php`» с готовым сниппетом. — *частично: пустая лента подсказывает, что делать; онбординга нет.* -- [x] i18n (ru/en). ❓ *п. 10.11.* - -### 6.6 Порядок работ - -1. [x] Зафиксировать **API-контракт v1** (OpenAPI): REST-ресурсы `servers`, `projects`, `requests`, `messages`, `context`, `stream`. Этот контракт реализует Go-бэкенд (п. 7); имена полей без венгерской нотации (п. 4.4). — *сделано (фазы 3–5).* -2. [x] Создать проект `ui/` с нуля (Vite + Svelte 5 + TS), настроить линтеры, тесты и сборку в `server/web/` для `//go:embed`. — *сделано (фазы 3–5).* -3. [x] Дизайн-токены и темы (п. 6.4), затем набор компонентов (п. 6.3) с витриной. — *сделано (фазы 3–5).* -4. [x] Экраны и функции **вертикальными срезами**: эндпоинт в Go + экран в UI + e2e-тест за один подход (один исполнитель, п. 10.34). Данные — Go-сервер на фикстурах; мок-сервер по OpenAPI не нужен. — *сделано (фазы 3–5).* -5. [x] Обязательный минимум функций, которые есть в старом интерфейсе и должны быть в новом (используется как чек-лист, не как образец для переноса кода): список проектов, поиск новых логов, список запросов, сообщения, бэктрейс, переменные, очистка логов, ссылки в IDE, счётчик неимпортированных файлов. — *сделано (фазы 3–5).* -6. [x] Удалить старый UI целиком, без переходного режима `/legacy`: `index.php`, `includes/`, `static/app/` (EasyUI, jQuery, `node_modules`, `modules/*.js`, `icons.css` на 4000 строк, иконки famfamfam, `easymde`, `jspanel3`, `speadsheet.js`), `screenshots/` (заменить новыми). Иконки в новом UI — SVG-набор (например, Lucide). — *сделано (фазы 3–5).* +| `alert` / `confirm` / `prompt` (now through `$.messager`) | `lib.js:15`, `debug_files.js:140`, `projects.js:124`, `debug_messages.js:126`, `tags.js:154` | `Dialog` / `ConfirmDialog` with a promise API (`await confirm(...)`), a focus trap, Esc/Enter | +| The system dialog "Open the vscode:// application?" | `editor_url` links | Our own "Open in…" popover (VS Code / PhpStorm / Cursor / copy the path) that remembers the choice | +| `` | filters | `Checkbox`, `Switch`, `SegmentedControl` | +| `` | a time filter (new) | `DateRangePicker` with presets ("last 15 min", "today") | +| `` | JSONL/ZIP import (new) | A drag & drop zone + a button | +| Web Notifications API | the stub in `notification_manager.js` | In-app `Toast`; system notifications only with explicit consent in the settings | +| Native dragging of dividers | `split:true` in EasyUI | `SplitPane` that remembers sizes | +| Native in-page search (Ctrl+F) does not work in virtualized lists | — | Our own search `/` + a command palette `Ctrl+K` | +| Native `` and font picking | — | Our own theme editor (section 6.4) | + +- [x] Collect the components in `ui/src/lib/components` and make a showcase for development (a `/dev/components` page or Storybook). ❓ *Write everything ourselves or take a headless library (Bits UI / Melt UI) and style it — section 10.4.* — *v0.9: the components are our own (in `ui/src/components`); the showcase is `#/dev/components` (and "Component showcase" in `Ctrl+K`): every component in all built-in themes side by side, live. `ColorField` was added instead of ``.* + +### 6.4 Themes + +**Architecture:** + +- [x] Design tokens as CSS custom properties: colors (`--bg`, `--surface`, `--text`, `--muted`, `--border`, `--accent`, `--danger`, `--warning`, `--info`, `--success`), colors of message levels (`--level-error`, `--level-warning`, `--level-info`, `--level-message`), syntax and JSON highlighting (`--syntax-key`, `--syntax-string`, `--syntax-number`, `--syntax-null` …), radii, shadows, spacing, fonts. +- [x] Not a single hard-coded color in components. Checked in CI by Stylelint (`color-no-hex` outside theme files, `declaration-property-value-allowed-list`). — *v0.9: Stylelint in `make ui-lint` forbids hex, named colors and color functions (`rgb()`, `hsl()` …) everywhere except `src/styles/theme.css`; the shade under a dialog became the `--backdrop` token.* +- [x] A theme is a file of tokens (TS/JSON → CSS variables on `:root[data-theme="…"]`). Switching is instant, without a reload. +- [x] No "flash" of a wrong theme on load: a small inline script in `index.html` sets `data-theme` before the application mounts. — *done differently: not inline but a blocking `theme-init.js` — inline scripts are forbidden by the CSP (phase 5).* +- [x] Code highlighting (Shiki) and the JSON tree take their colors from the same theme. Every theme defines a pair: a UI theme + a highlighting theme. — *the JSON tree and code highlighting — the `--syntax-*` tokens of each theme (v0.5).* + +**Set of themes:** + +- [x] Built in: **Light**, **Dark**, **System** (follows `prefers-color-scheme`), **High contrast**. ❓ *Whether extra presets are needed (Solarized, Nord, Dracula, Monokai and so on) — section 10.24.* +- [x] The accent color is chosen separately over any theme. — *v0.9: "Appearance" → accent color (a color of your own or "As in the theme"), a warning when the contrast with the theme background is below 3:1.* +- [x] The environment color over the theme: a `stage`/`prod` stripe or frame (section 7.5) is visible in any theme and is not covered by the accent. — *v0.9: a frame around the whole window in the `--env-stage`/`--env-prod` color when a project or the feed of a stage/prod server is selected; it does not catch clicks; turned off in "Appearance".* + +**Display settings (together with the theme):** + +- [x] Density: compact / regular (row height in the request and message lists). — *v0.9: the `--row-padding-y`, `--row-line-height` tokens; virtual lists re-measure a row when density and font change.* +- [x] The interface font size and a monospace font for code and variables (the system stack by default; with fonts of your own — local files, no external CDNs). — *v0.9: size 12–18 px; the code font is the name of a font installed on the computer (only names, quotes and commas), followed by the system monospace stack; no font files are loaded.* +- [x] Respect `prefers-reduced-motion` and `prefers-contrast`. — *v0.9: the "System" theme with `prefers-contrast: more` is the high-contrast one, it follows the OS without a reload.* + +**Custom themes:** + +- [x] A theme editor in the settings: editing tokens with a live preview on a mock-up (the request list, a message, JSON, code), a reset to the base theme. — *v0.9: "Appearance" → "Theme editor": colors over a light, dark or high-contrast base by group, a mock-up of the viewer inside the editor itself (a theme works on any element with `data-theme`), WCAG AA contrast of all pairs live, resetting a token and the whole theme; up to 20 themes.* +- [x] Export and import of a theme as a JSON file; schema validation on import. ❓ *Keep custom themes on the server (in the Go server settings, shared by all browsers) or only in the browser — section 10.25.* — *v0.9: the `.theme.json` file is a `CustomTheme` object from `spec/openapi.yaml`; the import checks the name, the base and the colors, and skips tokens of newer versions. Themes and all appearance settings are on the server (`GET/PUT /api/v1/settings`, a `settings_updated` event to other windows), `localStorage` is a cache for the first frame (`theme-init.js`).* + +**Quality:** + +- [x] An automatic contrast test: for every built-in theme check the pairs "text/background", "level/background", "highlighting/background" against WCAG AA (4.5:1 for text, 3:1 for large elements and icons). +- [x] Playwright visual snapshots of the main screens in all built-in themes. — *v0.9: `make e2e-visual` compares the viewer in all themes, the showcase, "Appearance" and the theme editor with `ui/e2e/__screenshots__` in the Playwright Docker image (the same fonts locally and in CI); `make e2e-visual-update` takes them again.* +- [x] A component showcase (section 6.3) with a theme switch. — *v0.9: all themes side by side or one of your choice.* +- [x] Switching the theme from the command palette (`Ctrl+K` → "Theme: …") and with a shortcut. — *v0.6: from the palette; no separate key.* + +### 6.5 Improving the functionality in the new UI + +Besides the features from section 5.1, which are implemented in the new UI right away: + +- [ ] Layout: servers → projects → requests → messages → details (section 7.5). Panels can be resized and collapsed; there is a compact mode for a narrow screen. — *partly: projects → requests → message → details are there; no servers in the tree and no resizable panels.* +- [ ] Tabs of message details: **Message**, **Variables** (a JSON tree with types, search, copying the path and the value), **Backtrace** (with a source preview), **Raw JSON**. +- [ ] Tabs of request details: **Overview** (URL, method, code, time, memory, user), **Timeline**, **SQL**, **Errors**, **Superglobals**. — *partly (v0.5): "Messages", "Timeline", "SQL", "Superglobals"; the overview is in the request header; no separate errors tab.* +- [x] A command palette (`Ctrl+K`): going to a project or a request, actions, settings. — *v0.6: projects, servers, pinned and failed requests, windows, themes, languages, settings, the feed filter.* +- [x] Keyboard shortcuts for everything (j/k, Enter, `/`, `Esc`, `g p` — projects), help on `?`. — *v0.6: j/k, Shift+J/K, Esc, /, g p, ?, Ctrl/⌘+K.* +- [x] A filter line with syntax (`type:error tag:sql duration>500 url:/api/*`) and autocompletion. Right now a similar `type:error` syntax exists only in the PHP library. — *v0.6.* +- [x] Several open requests in tabs and a mode comparing two requests side by side. — *v0.7: up to eight tabs above a request; the ⇄ button compares a tab with the open request.* +- [ ] A project settings page instead of a modal window: the server, paths, path mapping (server/container ↔ a local copy for the IDE) with a "the path exists" check, the editor choice, retention. +- [ ] A servers page: adding an SSH connection (a host from `~/.ssh/config`, a key, a jump host), a "Test connection" button, the status and latency (section 7.4). +- [ ] A status indicator: the connection to the live stream and to every server (online/offline/reconnecting), the number of files not yet imported (now `#project-files-info`), disk space. +- [ ] Empty states and onboarding: "no projects → how to include `Debugger.class.php`" with a ready snippet. — *partly: an empty feed hints at what to do; no onboarding.* +- [x] i18n (ru/en). ❓ *section 10.11.* + +### 6.6 Order of work + +1. [x] Fix the **API contract v1** (OpenAPI): REST resources `servers`, `projects`, `requests`, `messages`, `context`, `stream`. The Go backend implements this contract (section 7); field names without Hungarian notation (section 4.4). — *done (phases 3–5).* +2. [x] Create the `ui/` project from scratch (Vite + Svelte 5 + TS), set up linters, tests and the build into `server/web/` for `//go:embed`. — *done (phases 3–5).* +3. [x] Design tokens and themes (section 6.4), then the component set (section 6.3) with a showcase. — *done (phases 3–5).* +4. [x] Screens and features as **vertical slices**: an endpoint in Go + a screen in the UI + an e2e test in one go (one developer, section 10.34). The data comes from the Go server on fixtures; a mock server from OpenAPI is not needed. — *done (phases 3–5).* +5. [x] The required minimum of features that the old interface has and the new one must have (used as a checklist, not as a model for carrying code over): the list of projects, finding new logs, the list of requests, messages, the backtrace, variables, clearing logs, links to the IDE, the counter of files not yet imported. — *done (phases 3–5).* +6. [x] Delete the old UI entirely, without a transitional `/legacy` mode: `index.php`, `includes/`, `static/app/` (EasyUI, jQuery, `node_modules`, `modules/*.js`, the 4000-line `icons.css`, the famfamfam icons, `easymde`, `jspanel3`, `speadsheet.js`), `screenshots/` (to be replaced with new ones). Icons in the new UI are an SVG set (for example, Lucide). — *done (phases 3–5).* --- -## 7. Бэкенд просмотрщика на Go +## 7. Viewer backend in Go -> ✅ **Решено.** На Go переписывается **сервер просмотра** (`index.php`, `ajax.php`, `controllers/*`, `sse.php`, `bin.php`, RedBean/SQLite). **Отладчик `Debugger.class.php` остаётся на PHP**: он работает внутри отлаживаемого PHP-проекта. +> ✅ **Decided.** The **viewing server** is rewritten in Go (`index.php`, `ajax.php`, `controllers/*`, `sse.php`, `bin.php`, RedBean/SQLite). **The debugger `Debugger.class.php` stays in PHP**: it runs inside the PHP project being debugged. -### 7.1 Что даёт Go +### 7.1 What Go gives -- **Один бинарник** `wapp-debugger` со встроенным Svelte-UI (`embed.FS`): не нужны PHP-FPM, nginx и Docker с 15 расширениями. Запуск: `wapp-debugger serve --projects ./projects`. -- **Фоновые процессы**: наблюдение за папками логов через `fsnotify`, инкрементальный импорт растущих файлов и настоящий SSE/WebSocket. В PHP-FPM долгоживущие соединения держат воркеры, в Go это дёшево. -- **Скорость и память**: потоковый разбор JSONL по гигабайтным логам, батчевые вставки, параллельный импорт нескольких проектов. -- **Приём логов по HTTP/UDP** (п. 5.2) реализуется естественно, без общей файловой системы. -- Кроссплатформенные сборки через goreleaser (Linux/macOS/Windows) и маленький Docker-образ (distroless/scratch). -- Десктоп-приложение на Wails из того же Go-ядра и того же Svelte-UI (п. 7.8). +- **One binary** `wapp-debugger` with the Svelte UI embedded (`embed.FS`): no PHP-FPM, nginx and Docker with 15 extensions needed. Run: `wapp-debugger serve --projects ./projects`. +- **Background processes**: watching log folders with `fsnotify`, incremental import of growing files and real SSE/WebSocket. In PHP-FPM long-lived connections hold workers; in Go this is cheap. +- **Speed and memory**: streaming JSONL parsing over gigabyte logs, batched inserts, parallel import of several projects. +- **Receiving logs over HTTP/UDP** (section 5.2) comes naturally, without a shared file system. +- Cross-platform builds through goreleaser (Linux/macOS/Windows) and a small Docker image (distroless/scratch). +- A desktop application on Wails from the same Go core and the same Svelte UI (section 7.8). -### 7.2 Минусы и риски +### 7.2 Downsides and risks -- Второй язык в проекте: библиотека остаётся на PHP, сервер становится на Go. Порог входа для контрибьюторов-PHP-разработчиков выше. -- Работы в PHP-сервере и старом UI будут выброшены, поэтому их развитие **замораживается**. Исправляются только критичные баги и дыры безопасности (п. 1.2, 2.2), пока Go-сервер и новый UI не готовы. После этого PHP-сервер и EasyUI удаляются одновременно. -- Нужно аккуратно перенести логику маппинга путей Docker ↔ хост (`path`, `global_path`, `relative_path`, `lib.php:fnGetProject*Path`) и ссылок в редактор. +- A second language in the project: the library stays in PHP, the server becomes Go. The entry barrier for contributors who are PHP developers is higher. +- Work on the PHP server and the old UI will be thrown away, so their development is **frozen**. Only critical bugs and security holes are fixed (sections 1.2, 2.2) until the Go server and the new UI are ready. After that the PHP server and EasyUI are removed at the same time. +- The logic of path mapping Docker ↔ host (`path`, `global_path`, `relative_path`, `lib.php:fnGetProject*Path`) and of editor links must be carried over carefully. -### 7.3 Стек и устройство +### 7.3 Stack and structure -- [x] ✅ Go 1.26 (`go.mod`; на момент фазы 2 поддерживаются 1.26 и 1.27, старый локальный Go сам скачивает нужный toolchain), `net/http` с новым роутингом (или `chi`), `log/slog`. Линтер — golangci-lint v2 (v1 не поддерживается текущим `golangci-lint-action`), версия закреплена в Makefile. -- [x] ✅ SQLite: **`modernc.org/sqlite`** (п. 10.6): чистый Go, серверный бинарник собирается без CGO под все ОС одной командой, FTS5 включён, отладчику логов скорости хватает с запасом. Драйвер подключается только через `database/sql` в `internal/store`, поэтому при проблемах с производительностью замена на `mattn/go-sqlite3` — правка одного файла. Десктопу CGO всё равно нужен (WebKit/WebView2), но это не мешает. Миграции встроены в бинарник (`goose` или свой раннер на `embed`). -- [x] Доступ к БД через `sqlc` или `database/sql` с ручными запросами, без ORM. -- [ ] Пакеты: - - `cmd/wapp-debugger` — CLI: `serve`, `import`, `watch`, `projects add/list`, `purge`; - - `internal/logformat` — парсер форматов v1 (текущий, с заголовком 1000 байт) и v2 (п. 4.2); - - `internal/source` — абстракция источника логов: `LocalSource` (fsnotify), `SSHSource` (SFTP), `HTTPPullSource` (легаси HTTP-режим библиотеки, п. 7.4a), позже `PushSource` (агент, п. 7.6); общий интерфейс `List/Stat/ReadFrom(offset)/Remove/SetEnabled`; - - `internal/ssh` — пул SSH-подключений, `~/.ssh/config`, agent, known_hosts, ProxyJump, keepalive и переподключение; - - `internal/ingest` — планировщик импорта по всем источникам, импорт с offset, HTTP-приёмник; - - `internal/store` — SQLite, FTS5, ретеншн; - - `internal/api` — REST по контракту из п. 6.6 + SSE; - - `internal/pathmap` — маппинг путей и ссылок в IDE; - - `internal/codeview` — безопасное чтение исходников проекта для превью (локально или по SFTP; только внутри корня проекта, `filepath.Rel` + `EvalSymlinks`/`realpath` на удалённой стороне); - - `web/` — собранный Svelte, `//go:embed`. -- [ ] Конфиг: YAML/TOML-файл + флаги + env. Серверы и проекты задаются в конфиге или добавляются через UI (п. 7.5). — *частично: пока флаги и env (`WAPP_DEBUGGER_TOKEN`), проекты — в БД через UI/API; файла конфига нет.* -- [x] Безопасность по умолчанию: слушать `127.0.0.1`, токен для API и приёма логов, CORS выключен, мутации только POST/DELETE. -- [x] Тесты: unit-тесты парсера на реальных образцах (`tmp/message.json`, `tmp/head.json`), интеграционные тесты API (`httptest`), fuzz-тест парсера JSONL, интеграционные тесты SSH-источника против тестового SSH-сервера (`gliderlabs/ssh` или контейнер `openssh-server` в CI). -- [x] CI и релизы — через Makefile и GitHub Actions (п. 3.1, 3.2). +- [x] ✅ Go 1.26 (`go.mod`; at the time of phase 2 versions 1.26 and 1.27 are supported, an old local Go downloads the needed toolchain itself), `net/http` with the new routing (or `chi`), `log/slog`. The linter is golangci-lint v2 (v1 is not supported by the current `golangci-lint-action`), its version is pinned in the Makefile. +- [x] ✅ SQLite: **`modernc.org/sqlite`** (section 10.6): pure Go, the server binary builds without CGO for every OS with one command, FTS5 is on, and the speed is more than enough for a log debugger. The driver is used only through `database/sql` in `internal/store`, so if performance becomes a problem, switching to `mattn/go-sqlite3` is a change of one file. The desktop needs CGO anyway (WebKit/WebView2), but that does not get in the way. Migrations are embedded into the binary (`goose` or our own runner on `embed`). +- [x] Database access through `sqlc` or `database/sql` with hand-written queries, no ORM. +- [ ] Packages: + - `cmd/wapp-debugger` — the CLI: `serve`, `import`, `watch`, `projects add/list`, `purge`; + - `internal/logformat` — the parser of formats v1 (the current one, with the 1000-byte header) and v2 (section 4.2); + - `internal/source` — an abstraction of a log source: `LocalSource` (fsnotify), `SSHSource` (SFTP), `HTTPPullSource` (the legacy HTTP mode of the library, section 7.4a), later `PushSource` (an agent, section 7.6); a common interface `List/Stat/ReadFrom(offset)/Remove/SetEnabled`; + - `internal/ssh` — a pool of SSH connections, `~/.ssh/config`, agent, known_hosts, ProxyJump, keepalive and reconnection; + - `internal/ingest` — the import scheduler over all sources, import from an offset, the HTTP receiver; + - `internal/store` — SQLite, FTS5, retention; + - `internal/api` — REST by the contract from section 6.6 + SSE; + - `internal/pathmap` — path mapping and IDE links; + - `internal/codeview` — safe reading of project sources for previews (locally or over SFTP; only inside the project root, `filepath.Rel` + `EvalSymlinks`/`realpath` on the remote side); + - `web/` — the built Svelte, `//go:embed`. +- [ ] Config: a YAML/TOML file + flags + env. Servers and projects are set in the config or added through the UI (section 7.5). — *partly: flags and env so far (`WAPP_DEBUGGER_TOKEN`), projects — in the database through the UI/API; no config file.* +- [x] Secure by default: listen on `127.0.0.1`, a token for the API and for receiving logs, CORS off, mutations only through POST/DELETE. +- [x] Tests: unit tests of the parser on real samples (`tmp/message.json`, `tmp/head.json`), integration tests of the API (`httptest`), a fuzz test of the JSONL parser, integration tests of the SSH source against a test SSH server (`gliderlabs/ssh` or an `openssh-server` container in CI). +- [x] CI and releases — through the Makefile and GitHub Actions (sections 3.1, 3.2). -### 7.4 Подключение к проектам по SSH +### 7.4 Connecting to projects over SSH -Сейчас просмотрщик читает логи только из локальной папки или Docker-маунта. Отсюда маппинг `path`/`global_path`/`path_to_debug_log`/`global_debug_log_path` и персональный маунт в `docker-compose.yaml`. SSH-подключение позволяет смотреть логи на любом dev/stage-сервере без общих папок и без открытия HTTP-портов. +Right now the viewer reads logs only from a local folder or a Docker mount. Hence the mapping `path`/`global_path`/`path_to_debug_log`/`global_debug_log_path` and the personal mount in `docker-compose.yaml`. An SSH connection lets you look at logs on any dev/stage server without shared folders and without opening HTTP ports. -**Подключение и аутентификация:** +**Connection and authentication:** -- [x] Клиент на `golang.org/x/crypto/ssh` + `github.com/pkg/sftp`. -- [x] Чтение `~/.ssh/config` (`Host`, `HostName`, `User`, `Port`, `IdentityFile`, `ProxyJump`), чтобы сервер можно было добавить просто по алиасу. -- [ ] Аутентификация: ssh-agent (`SSH_AUTH_SOCK`), ключи из файлов (с passphrase через запрос в UI). ❓ *Пароли и хранение секретов — п. 10.19.* — *частично: ssh-agent и ключи, сначала ключи из `IdentityFile`, `IdentitiesOnly` (фаза 7); для ключа с паролем — подсказка добавить его в ssh-agent, ввода пароля в UI нет.* -- [x] **Проверка ключа хоста** через `~/.ssh/known_hosts` (`knownhosts`). Никакого `InsecureIgnoreHostKey`. Новый хост подтверждается в UI с показом отпечатка (TOFU). — *фаза 7: known_hosts пользователя + свой файл; новый ключ подтверждается в UI по отпечатку с типом и подсказкой, какой файл сверить на сервере; ключ доверяется, только если сервер всё ещё показывает его; изменившийся — отказ; запрашивается известный тип ключа, для новых — ED25519.* -- [x] Jump-хосты / бастионы (`ProxyJump`, цепочка). -- [x] Keepalive, переподключение с экспоненциальной задержкой, статус подключения в UI. — *фаза 7: keepalive, переподключение, задержка 1 с → 1 мин, состояние в UI вживую по `server_status`.* -- [x] Одно SSH-подключение на сервер, мультиплексирование сессий (SFTP + exec) для всех проектов этого сервера. +- [x] A client on `golang.org/x/crypto/ssh` + `github.com/pkg/sftp`. +- [x] Reading `~/.ssh/config` (`Host`, `HostName`, `User`, `Port`, `IdentityFile`, `ProxyJump`), so that a server can be added just by its alias. +- [ ] Authentication: ssh-agent (`SSH_AUTH_SOCK`), keys from files (with a passphrase asked for in the UI). ❓ *Passwords and storing secrets — section 10.19.* — *partly: ssh-agent and keys, keys from `IdentityFile` first, `IdentitiesOnly` (phase 7); for a key with a passphrase — a hint to add it to ssh-agent, no passphrase input in the UI.* +- [x] **Host key verification** through `~/.ssh/known_hosts` (`knownhosts`). No `InsecureIgnoreHostKey`. A new host is confirmed in the UI with its fingerprint shown (TOFU). — *phase 7: the user's known_hosts + our own file; a new key is confirmed in the UI by its fingerprint with the type and a hint about which file to compare on the server; the key is trusted only if the server still shows it; a changed one is refused; a known key type is requested, ED25519 for new hosts.* +- [x] Jump hosts / bastions (`ProxyJump`, a chain). +- [x] Keepalive, reconnection with exponential backoff, the connection status in the UI. — *phase 7: keepalive, reconnection, a delay of 1 s → 1 min, the state in the UI live through `server_status`.* +- [x] One SSH connection per server, multiplexing sessions (SFTP + exec) for all projects of that server. -**Чтение логов:** +**Reading logs:** -- [x] Листинг папки логов и `stat` по SFTP, дочитывание файлов с сохранённого offset (`ReadAt`). Состояние (файл, размер, offset, mtime) хранится в SQLite, чтобы после рестарта не читать всё заново. -- [ ] Режим live tail. ❓ *Опрос SFTP раз в N секунд или `exec` команды `inotifywait`/`tail -F` на удалённой стороне — п. 10.18.* — *частично: опрос SFTP раз в 2 с (п. 10.18, фаза 7); ускорение через `inotifywait` — нет.* -- [ ] Сжатие трафика (SSH compression) и лимит скорости на сервер, чтобы большие логи не забивали канал. -- [x] Логи внутри Docker на удалённом сервере: читать через путь volume на хосте. ❓ *Или через `docker exec … cat` — п. 10.21.* — *по п. 10.21 — путь volume на хосте: это обычная папка логов, отдельного кода не нужно.* +- [x] Listing the log folder and `stat` over SFTP, reading the rest of files from the saved offset (`ReadAt`). The state (file, size, offset, mtime) is kept in SQLite, so that nothing is read again after a restart. +- [ ] Live tail mode. ❓ *Polling SFTP every N seconds or `exec` of `inotifywait`/`tail -F` on the remote side — section 10.18.* — *partly: polling SFTP every 2 s (section 10.18, phase 7); no speed-up through `inotifywait`.* +- [ ] Traffic compression (SSH compression) and a speed limit per server, so that big logs do not clog the link. +- [x] Logs inside Docker on a remote server: read through the volume path on the host. ❓ *Or through `docker exec … cat` — section 10.21.* — *per section 10.21 — the volume path on the host: it is a regular log folder, no separate code needed.* -**Управление и операции:** +**Control and operations:** -- [x] ✅ Включение и выключение отладчика на удалённом проекте записью `dws_debugger.json` через SFTP (атомарно: временный файл + `rename`). Это основной способ управления (п. 10.22); HTTP — только легаси-режим (п. 7.4a). — *временный файл рядом + `posix-rename`, права сохраняются.* -- [x] Очистка и удаление логов на удалённой стороне только внутри папки логов проекта (проверка через `realpath`), с подтверждением в UI. — *фаза 7: удаляются только файлы папки логов по имени (без путей, ссылок и каталогов); очистка — общая кнопка проекта с подтверждением, через источник сервера; запрещена на серверах «только чтение» и без права удаления.* -- [x] Режим «только чтение» для сервера: запрещает удаление и изменение конфига, например для stage. — *права сервера (фаза 5), задаются при добавлении SSH-сервера (фаза 7).* -- [x] Превью исходников по SFTP (п. 5.1) с кэшем по `mtime`. — *v0.5, без кэша: читается только окно вокруг строки из файла до 1 МБ.* -- [x] Проверка подключения: доступность хоста, права на папку логов, наличие `Debugger.class.php`/конфига, версия PHP (через `exec php -v`, если разрешено). — *фаза 7: по шагам — настройки, подключение, SFTP, для каждого проекта папка логов (чтение; запись — пробным файлом, кроме серверов «только чтение»), конфиг библиотеки; `php -v`. Конфиг и PHP — предупреждения, проверку не валят.* -- [x] Ссылки в IDE для удалённых проектов: маппинг «удалённый путь → локальная копия» (`/var/www/app` → `~/work/app`), а при её отсутствии — ссылка для VS Code Remote-SSH (`vscode://vscode-remote/ssh-remote+/:`). — *фаза 7: и для Cursor; PhpStorm и Sublime без локальной копии ссылку не получают.* +- [x] ✅ Turning the debugger on and off on a remote project by writing `dws_debugger.json` over SFTP (atomically: a temporary file + `rename`). This is the main way of control (section 10.22); HTTP is only the legacy mode (section 7.4a). — *a temporary file next to it + `posix-rename`, permissions are kept.* +- [x] Clearing and deleting logs on the remote side only inside the log folder of the project (checked through `realpath`), with a confirmation in the UI. — *phase 7: only files of the log folder are deleted, by name (no paths, links or directories); clearing is a common button of the project with a confirmation, through the source of the server; forbidden on "read only" servers and without the delete permission.* +- [x] A "read only" mode for a server: it forbids deleting and changing the config, for example for stage. — *server permissions (phase 5), set when an SSH server is added (phase 7).* +- [x] Source previews over SFTP (section 5.1) with a cache by `mtime`. — *v0.5, without a cache: only a window around the line is read, from a file of up to 1 MB.* +- [x] Connection test: host reachability, permissions on the log folder, presence of `Debugger.class.php`/the config, the PHP version (through `exec php -v`, if allowed). — *phase 7: step by step — settings, connection, SFTP, for every project the log folder (reading; writing — with a trial file, except on "read only" servers), the library config; `php -v`. The config and PHP give warnings and do not fail the test.* +- [x] IDE links for remote projects: a mapping "remote path → local copy" (`/var/www/app` → `~/work/app`), and without one — a link for VS Code Remote-SSH (`vscode://vscode-remote/ssh-remote+/:`). — *phase 7: and for Cursor; PhpStorm and Sublime get no link without a local copy.* -### 7.4a Легаси HTTP-режим (опционально) +### 7.4a Legacy HTTP mode (optional) -Для серверов, куда нет SSH-доступа (старый shared-хостинг, чужая инфраструктура), просмотрщик может работать через HTTP-режим PHP-библиотеки (п. 4.1). +For servers without SSH access (old shared hosting, someone else's infrastructure) the viewer can work through the HTTP mode of the PHP library (section 4.1). -- [x] Тип сервера `http`: базовый URL проекта + токен (хранится в системном хранилище секретов, как SSH-пароли, п. 10.19). — *фаза 7: до системного хранилища (п. 10.19) токен лежит в `secrets.json` рядом с базой (права 0600), в API только на запись; один сервер — одно приложение и один проект.* -- [x] `HTTPPullSource`: опрос `list` и `read` с offset по расписанию, live tail — частым опросом; `enable`/`disable`/`clear` из UI. — *фаза 7: `source.HTTP`, опрос раз в 2 с; проходит общий контракт `sourcetest` и тест против настоящей библиотеки под `php -S`.* -- [x] Только HTTPS (HTTP — с явным предупреждением в UI), проверка сертификата, таймауты, ограничение частоты запросов со стороны просмотрщика. — *фаза 7: сертификат проверяется всегда, таймаут 30 с, запросы не чаще раза в 50 мс, после 429 — пауза по `Retry-After`; `http://` — предупреждение в форме и в проверке.* -- [ ] Возможности, недоступные в этом режиме (превью исходников, автообнаружение проектов), в UI скрыты с пояснением. — *частично: у HTTP-проекта скрыты папка логов и конфиг; превью исходников и автообнаружения пока нет ни в каком режиме (фазы 8, 10).* -- ✅ Старый HTTP API (`?debug_msg=…`) просмотрщик не поддерживает (п. 10.36): для HTTP-режима на сервере ставится библиотека 2.x. +- [x] Server type `http`: the base URL of the project + a token (kept in the system secret store, like SSH passwords, section 10.19). — *phase 7: until the system store (section 10.19) the token lives in `secrets.json` next to the database (permissions 0600), write-only in the API; one server — one application and one project.* +- [x] `HTTPPullSource`: polling `list` and `read` with an offset on a schedule, live tail — by frequent polling; `enable`/`disable`/`clear` from the UI. — *phase 7: `source.HTTP`, polling every 2 s; it passes the common `sourcetest` contract and a test against the real library under `php -S`.* +- [x] HTTPS only (HTTP — with an explicit warning in the UI), certificate verification, timeouts, a request rate limit on the viewer side. — *phase 7: the certificate is always verified, a 30 s timeout, requests no more often than once per 50 ms, after a 429 — a pause by `Retry-After`; `http://` — a warning in the form and in the test.* +- [ ] Features not available in this mode (source previews, project discovery) are hidden in the UI with an explanation. — *partly: an HTTP project has the log folder and the config hidden; source previews and discovery do not exist in any mode yet (phases 8, 10).* +- ✅ The viewer does not support the old HTTP API (`?debug_msg=…`) (section 10.36): for the HTTP mode library 2.x is installed on the server. -### 7.5 Несколько серверов и проектов +### 7.5 Several servers and projects -**Модель данных:** +**Data model:** -✅ **Решено (п. 10.20):** много серверов, на каждом свои проекты. Проект принадлежит ровно одному серверу; кластерные проекты (один проект на нескольких нодах) не поддерживаются. +✅ **Decided (section 10.20):** many servers, each with its own projects. A project belongs to exactly one server; cluster projects (one project on several nodes) are not supported. ``` -Server (local | ssh | http) — тип подключения, параметры, метка окружения, права (read-only и т. д.) - └─ Project — имя, корень, папка логов, маппинг путей для IDE, редактор, ретеншн - └─ Request — один файл лога / один HTTP- или CLI-запрос - └─ Message — событие внутри запроса +Server (local | ssh | http) — connection type, parameters, environment label, permissions (read-only and so on) + └─ Project — name, root, log folder, path mapping for the IDE, editor, retention + └─ Request — one log file / one HTTP or CLI request + └─ Message — an event inside a request ``` -**Задачи:** +**Tasks:** -- [x] Таблицы `servers`, `projects` (`server_id`), `requests`, `messages` (без венгерской нотации, п. 4.4). Вместо прежнего `tprojects` с четырьмя путями — `projects` с одним корнем и папкой логов на своём сервере + маппинг для IDE. **Схема и интерфейс `Source` проектируются сразу в фазе 3 и реализуются в MVP** (даже если в MVP есть только локальный сервер), чтобы SSH и несколько серверов не требовали переделки схемы и API. -- [ ] Конфиг-файл со списком серверов и проектов (YAML), который можно редактировать вручную и через UI, а также импортировать и экспортировать (без секретов). — *частично (фаза 8): экспорт и импорт YAML без секретов (API `GET/POST /config`, окно «Экспорт / импорт»): импорт добавляет недостающее, файл с ошибкой или секретом отклоняется целиком; токен HTTP-сервера задаётся потом в окне серверов. Источник правды — база, а не файл: правка файла применяется импортом.* -- [x] Автообнаружение проектов на сервере: поиск `dws_debugger.json` или папок логов по маске в заданных корнях (аналог текущего `scan_projects`, но для любого сервера). — *фаза 8: «Найти проекты» у локального и SSH-сервера: корни, до 4 уровней и 5000 папок, без ссылок, `vendor`/`node_modules`/`.git` пропускаются; пути — по правилам библиотеки (с ключами v1); уже добавленные отмечены; проверено и на настоящем OpenSSH.* -- [ ] Параллельные коннекторы: по горутине на сервер, общий лимит одновременных импортов, изоляция ошибок (один недоступный сервер не мешает остальным). — *частично: по циклу импорта на проект (фаза 5); общего лимита нет.* -- [x] UI: дерево «серверы → проекты» в сайдбаре; статусы; цветные метки окружений (`local`, `dev`, `stage`, `prod`) и предупреждение при деструктивных действиях на `stage`/`prod`. — *фаза 8: группы по серверам на панели проектов, состояние подключения вживую, полоса окружения выбранного проекта; на `stage`/`prod` очистка и удаление — вводом имени проекта.* -- [x] Сводные представления: «все ошибки по всем проектам», «последние запросы везде», фильтр по серверу и окружению. — *фаза 8: общая лента с «только с ошибками», лента сервера по клику на его имя (`#/servers/N`), фильтр окружения, «проект · сервер» в строке.* -- [x] Учёт сдвига часов между серверами (важно для сводных лент): хранить время сервера и время получения, показывать предупреждение при большом расхождении. — *фаза 8: `received_at` рядом с `ts`; сдвиг часов сервера (SSH — `date` при подключении, HTTP — заголовок `Date`) в `clock_offset_ms` статуса; больше 2 с — предупреждение у сервера в UI.* -- [ ] Ретеншн и квоты на уровне сервера и проекта (сколько хранить в локальной БД и сколько оставлять на удалённой стороне). -- [x] Права на уровне сервера: read-only, разрешение удаления, разрешение управления отладчиком. +- [x] Tables `servers`, `projects` (`server_id`), `requests`, `messages` (without Hungarian notation, section 4.4). Instead of the former `tprojects` with four paths — `projects` with one root and a log folder on its server + a mapping for the IDE. **The schema and the `Source` interface are designed right in phase 3 and implemented in the MVP** (even if the MVP has only the local server), so that SSH and several servers do not require reworking the schema and the API. +- [ ] A config file with the list of servers and projects (YAML) that can be edited by hand and through the UI, and imported and exported (without secrets). — *partly (phase 8): export and import of YAML without secrets (API `GET/POST /config`, the "Export / import" window): the import adds what is missing, a file with an error or a secret is rejected entirely; the token of an HTTP server is set afterwards in the servers window. The source of truth is the database, not the file: a change of the file is applied by importing it.* +- [x] Discovering projects on a server: looking for `dws_debugger.json` or log folders by a mask in given roots (like the current `scan_projects`, but for any server). — *phase 8: "Find projects" at a local and an SSH server: roots, up to 4 levels and 5000 folders, no links, `vendor`/`node_modules`/`.git` are skipped; paths — by the rules of the library (with v1 keys); already added ones are marked; checked on a real OpenSSH too.* +- [ ] Parallel connectors: a goroutine per server, a common limit of simultaneous imports, isolation of errors (one unreachable server does not get in the way of the others). — *partly: an import loop per project (phase 5); no common limit.* +- [x] UI: a "servers → projects" tree in the sidebar; statuses; colored environment labels (`local`, `dev`, `stage`, `prod`) and a warning on destructive actions on `stage`/`prod`. — *phase 8: groups by server on the projects panel, the connection state live, the environment stripe of the selected project; on `stage`/`prod` clearing and deleting require typing the project name.* +- [x] Combined views: "all errors across all projects", "latest requests everywhere", a filter by server and environment. — *phase 8: a common feed with "only with errors", the feed of a server on a click on its name (`#/servers/N`), an environment filter, "project · server" in the row.* +- [x] Handling clock skew between servers (important for combined feeds): keep the server time and the time of receipt, show a warning on a big difference. — *phase 8: `received_at` next to `ts`; the clock offset of the server (SSH — `date` on connect, HTTP — the `Date` header) in the `clock_offset_ms` of the status; more than 2 s — a warning at the server in the UI.* +- [ ] Retention and quotas at the server and project level (how much to keep in the local database and how much to leave on the remote side). +- [x] Permissions at the server level: read-only, allowing deletion, allowing control of the debugger. -### 7.6 Опционально: Go-агент рядом с PHP-проектом +### 7.6 Optional: a Go agent next to the PHP project -- [x] Лёгкий агент `wapp-debugger agent` для случаев, когда SSH недоступен (облачные контейнеры, Kubernetes-поды): читает папку логов PHP-библиотеки и отправляет события на центральный сервер (`HTTPSource`). При наличии SSH агент не нужен. — *v0.8: `wapp-debugger agent --logs-dir … --push …` (токен — `WAPP_DEBUGGER_PUSH_TOKEN`): новые строки v2 по мере записи, повтор после сбоя, после перезапуска — заново без дублей; файлы v1 пропускает.* +- [x] A light agent `wapp-debugger agent` for cases where SSH is not available (cloud containers, Kubernetes pods): it reads the log folder of the PHP library and sends events to the central server (`HTTPSource`). With SSH available the agent is not needed. — *v0.8: `wapp-debugger agent --logs-dir … --push …` (the token — `WAPP_DEBUGGER_PUSH_TOKEN`): new v2 lines as they are written, a retry after a failure, after a restart — again without duplicates; v1 files are skipped.* -### 7.7 Переход +### 7.7 Transition -1. [ ] Спецификации: формат логов, API-контракт v1, схема БД с `servers/projects` (фаза 3). -2. [ ] Walking skeleton (фаза 4), затем MVP для локального источника: проекты, импорт, запросы, сообщения, переменные (фаза 5). -3. [ ] SSH-источник (п. 7.4, фаза 7), затем функции нескольких серверов (п. 7.5, фаза 8). -4. [ ] Миграция данных: ❓ *переносить старую `db/dbfile.db` или просто переимпортировать JSONL-файлы (проще, рекомендуется) — п. 10.10.* -5. [ ] Удалить PHP-сервер (`index.php`, `ajax.php`, `controllers/`, `models/`, `lib.php`, `database.php`, `rb.php`, `sse.php`, `docker/nginx`, `docker/php-workspace`). В репозитории остаются `client-php/` (отладчик), `server/` (Go) и `ui/` (Svelte). +1. [ ] Specifications: the log format, the API contract v1, the database schema with `servers/projects` (phase 3). +2. [ ] Walking skeleton (phase 4), then the MVP for the local source: projects, import, requests, messages, variables (phase 5). +3. [ ] The SSH source (section 7.4, phase 7), then the features of several servers (section 7.5, phase 8). +4. [ ] Data migration: ❓ *carry over the old `db/dbfile.db` or just re-import the JSONL files (simpler, recommended) — section 10.10.* +5. [ ] Delete the PHP server (`index.php`, `ajax.php`, `controllers/`, `models/`, `lib.php`, `database.php`, `rb.php`, `sse.php`, `docker/nginx`, `docker/php-workspace`). The repository keeps `client-php/` (the debugger), `server/` (Go) and `ui/` (Svelte). -### 7.8 Десктоп-версия (Wails) +### 7.8 Desktop version (Wails) -✅ **Решено:** десктоп нужен. Делается на **Wails**: Go-ядро (`internal/*`) и Svelte-UI (п. 6) общие с серверной версией, отдельного кода UI для десктопа нет. +✅ **Decided:** a desktop is needed. It is built with **Wails**: the Go core (`internal/*`) and the Svelte UI (section 6) are shared with the server version, there is no separate UI code for the desktop. -**Устройство:** +**Structure:** -- [x] Структура: `cmd/wapp-debugger` (сервер/CLI) и `desktop/` (Wails-приложение) поверх одних и тех же пакетов `internal/*`. -- [x] ✅ **Wails v3** (п. 10.26) с проверкой в walking skeleton (фаза 4). Версия закрепляется точно (`go.mod`), обновления — отдельными PR после прогона CI на трёх ОС. Весь код, зависящий от Wails, держится в `desktop/` тонким слоем (окно, трей, события, deep links), чтобы откат на v2 затрагивал только его. -- [x] **Критерии отката на v2** (проверяются в фазе 4): не собирается или не проходит smoke-тест на одной из ОС в CI; не работает отдача REST через asset handler или live-поток (п. 10.27); блокирующие баги трея, frameless-окна, single instance или deep links без обходного пути. При откате — v2 + отдельная библиотека трея. -- [x] Связь UI ↔ ядро: тот же REST API, что в серверной версии. HTTP-обработчик Go отдаётся через asset handler Wails (`AssetOptions.Handler` в v3), поэтому сетевой порт не открывается. Live-поток через события Wails, если SSE через asset handler работает ненадёжно. В UI это прячется за одним интерфейсом `transport` (HTTP+SSE в браузере, Wails в десктопе). ❓ *Подтвердить прототипом — п. 10.27.* -- [ ] Режим «десктоп + доступ из браузера»: опционально поднять тот же сервер на `127.0.0.1:<порт>` с токеном, чтобы открыть UI ещё и в браузере. -- [ ] Данные и конфиг в стандартных каталогах ОС (`os.UserConfigDir`, `os.UserCacheDir`); общий формат конфига с серверной версией, импорт и экспорт. — *частично: БД в `os.UserConfigDir`; общего файла конфига нет.* -- [ ] SSH в десктопе: ssh-agent на Linux/macOS (`SSH_AUTH_SOCK`), на Windows — OpenSSH agent (named pipe) и Pageant; секреты в системном хранилище (Keychain / Credential Manager / Secret Service), п. 10.19. +- [x] Layout: `cmd/wapp-debugger` (the server/CLI) and `desktop/` (the Wails application) on top of the same `internal/*` packages. +- [x] ✅ **Wails v3** (section 10.26), checked in the walking skeleton (phase 4). The version is pinned exactly (`go.mod`), updates come as separate PRs after a CI run on three OSes. All code that depends on Wails is kept in `desktop/` as a thin layer (the window, the tray, events, deep links), so that a fallback to v2 touches only it. +- [x] **Criteria for falling back to v2** (checked in phase 4): it does not build or does not pass the smoke test on one of the OSes in CI; serving REST through the asset handler or the live stream does not work (section 10.27); blocking bugs of the tray, the frameless window, single instance or deep links without a workaround. On fallback — v2 + a separate tray library. +- [x] UI ↔ core communication: the same REST API as in the server version. The Go HTTP handler is served through the Wails asset handler (`AssetOptions.Handler` in v3), so no network port is opened. The live stream goes through Wails events if SSE through the asset handler is unreliable. In the UI this hides behind one `transport` interface (HTTP+SSE in the browser, Wails in the desktop). ❓ *To be confirmed by a prototype — section 10.27.* +- [ ] A "desktop + browser access" mode: optionally start the same server on `127.0.0.1:` with a token, to open the UI in a browser as well. +- [ ] Data and config in the standard OS directories (`os.UserConfigDir`, `os.UserCacheDir`); a config format shared with the server version, import and export. — *partly: the database is in `os.UserConfigDir`; no shared config file.* +- [ ] SSH in the desktop: ssh-agent on Linux/macOS (`SSH_AUTH_SOCK`), on Windows — the OpenSSH agent (named pipe) and Pageant; secrets in the system store (Keychain / Credential Manager / Secret Service), section 10.19. -**Возможности десктопа:** +**Desktop features:** -- [ ] Свой заголовок окна (frameless) в стиле текущей темы: продолжение п. 6.3 про замену дефолтного UI. На macOS — нативные «светофоры», на Windows/Linux — свои кнопки. -- [x] Иконка в трее/меню-баре со счётчиком новых ошибок, быстрое меню (пауза live, последние ошибки, открыть окно). — *фаза 9: счётчик непросмотренных запросов с ошибками (сбрасывается при фокусе окна), меню: открыть, последние 5 ошибок с переходом, выход; закрытие окна прячет его в трей (настройка). Паузы live в меню нет.* -- [x] Системные уведомления о новых ошибках (по согласию в настройках, с фильтром по проекту и уровню). — *фаза 9: о запросе — один раз, при первой ошибке (или предупреждении — по настройке), в выбранных проектах; всплеск — одной сводкой «ещё N»; клик открывает запрос; язык — как в UI.* -- [x] Deep links `wapp-debugger://open?project=…&request=…` из браузера, IDE или чата. — *частично: разбор ссылки (только `open` с числовыми id) и переход в UI, из аргументов (Windows, Linux) и события macOS (фаза 9); регистрация схемы — в `.desktop` (Linux), реестре HKCU (Windows), `Info.plist` (macOS).* -- [x] Один экземпляр приложения (повторный запуск активирует окно и передаёт deep link). — *фаза 9: Wails SingleInstance, ссылка из второго запуска открывается в первом окне.* -- [ ] Автозапуск при входе в систему (опция), запоминание размера и положения окна и раскладки панелей. — *частично: автозапуск (настройка) и размер, положение, развёрнутость окна (фаза 9); раскладка панелей не запоминается.* -- [ ] Нативное меню приложения (macOS) с горячими клавишами, совпадающими с UI. — *частично: стандартные меню macOS (приложение, правка, вид, окно) с их сочетаниями (фаза 9); своих горячих клавиш в UI пока нет.* -- [ ] Перетаскивание JSONL/ZIP из файлового менеджера в окно для импорта. -- [ ] Автообновление. ❓ *Нужно ли и каким способом — п. 10.29.* — *по п. 10.29: без самообновления; уведомление о новой версии (фаза 9): GitHub Releases не чаще раза в сутки, в десктопе — по настройке (включено), в сервере — флагом `--update-check`; ссылка на релиз в шапке UI, в десктопе открывается в системном браузере.* +- [ ] Our own window title bar (frameless) in the style of the current theme: a continuation of section 6.3 about replacing the default UI. On macOS — the native "traffic lights", on Windows/Linux — our own buttons. +- [x] A tray/menu bar icon with a counter of new errors, a quick menu (pause live, latest errors, open the window). — *phase 9: a counter of unseen requests with errors (reset when the window gets focus), the menu: open, the latest 5 errors with navigation, quit; closing the window hides it in the tray (a setting). No live pause in the menu.* +- [x] System notifications about new errors (with consent in the settings, with a filter by project and level). — *phase 9: about a request — once, at its first error (or warning — by a setting), in the chosen projects; a burst — one summary "N more"; a click opens the request; the language — as in the UI.* +- [x] Deep links `wapp-debugger://open?project=…&request=…` from a browser, an IDE or a chat. — *partly: parsing the link (only `open` with numeric ids) and navigation in the UI, from arguments (Windows, Linux) and the macOS event (phase 9); the scheme is registered in `.desktop` (Linux), the HKCU registry (Windows), `Info.plist` (macOS).* +- [x] A single instance of the application (a second launch activates the window and passes the deep link). — *phase 9: Wails SingleInstance, a link from the second launch opens in the first window.* +- [ ] Autostart at login (an option), remembering the size and position of the window and the panel layout. — *partly: autostart (a setting) and the size, position and maximized state of the window (phase 9); the panel layout is not remembered.* +- [ ] A native application menu (macOS) with shortcuts matching the UI. — *partly: the standard macOS menus (application, edit, view, window) with their shortcuts (phase 9); the UI has no shortcuts of its own there yet.* +- [ ] Dragging JSONL/ZIP from a file manager into the window to import. +- [ ] Auto-update. ❓ *Whether it is needed and how — section 10.29.* — *per section 10.29: no self-update; a notice about a new version (phase 9): GitHub Releases at most once a day, in the desktop — by a setting (on), in the server — by the `--update-check` flag; a link to the release in the UI header, in the desktop it opens in the system browser.* -**Сборка и поставка:** +**Build and delivery:** -- [x] `make desktop-dev`, `make desktop-build`, `make desktop-package` (п. 3.1). — *все три; `make icons` рисует иконки из SVG.* -- [x] Установщики: macOS `.dmg` (universal: arm64 + amd64), Windows NSIS `.exe` (WebView2 — bootstrapper в установщике), Linux AppImage и `.deb` (зависимость `libwebkit2gtk`). ❓ *Нужны ли `.rpm`, Flatpak, Homebrew cask, winget, Scoop — п. 10.32.* — *фаза 9 (`make desktop-package`, `scripts/desktop-package.sh`): Linux — `.deb` (nfpm через `wails3 tool package`) и AppImage, Windows — NSIS `setup.exe` для пользователя без прав администратора (проверка WebView2 со ссылкой на загрузку, без встроенного bootstrapper), macOS — universal `.app` в `.dmg` (ad-hoc подпись); везде — схема `wapp-debugger://`. Каналы — только GitHub Releases (п. 10.32).* -- [ ] Подпись и нотаризация (macOS Developer ID + notarytool, Windows Authenticode) в release workflow (п. 3.2). ❓ *п. 10.28.* -- [x] Тесты: unit-тесты слоя `transport`, smoke-тест запуска собранного приложения в CI на трёх ОС (стартует, отдаёт UI, закрывается). +- [x] `make desktop-dev`, `make desktop-build`, `make desktop-package` (section 3.1). — *all three; `make icons` renders the icons from SVG.* +- [x] Installers: macOS `.dmg` (universal: arm64 + amd64), Windows NSIS `.exe` (WebView2 — a bootstrapper in the installer), Linux AppImage and `.deb` (depends on `libwebkit2gtk`). ❓ *Whether `.rpm`, Flatpak, a Homebrew cask, winget, Scoop are needed — section 10.32.* — *phase 9 (`make desktop-package`, `scripts/desktop-package.sh`): Linux — `.deb` (nfpm through `wails3 tool package`) and AppImage, Windows — an NSIS `setup.exe` for a user without administrator rights (a WebView2 check with a download link, no bundled bootstrapper), macOS — a universal `.app` in a `.dmg` (ad-hoc signed); everywhere — the `wapp-debugger://` scheme. Channels — GitHub Releases only (section 10.32).* +- [ ] Signing and notarization (macOS Developer ID + notarytool, Windows Authenticode) in the release workflow (section 3.2). ❓ *section 10.28.* +- [x] Tests: unit tests of the `transport` layer, a smoke test launching the built application in CI on three OSes (it starts, serves the UI, closes). --- -## 8. Порядок работ: фазы и вехи +## 8. Order of work: phases and milestones -### 8.1 Что было не так в предыдущей версии порядка +### 8.1 What was wrong with the previous version of the order -1. **Работа впустую по коду, который будет удалён.** Этапы 1–4 включали починку и оптимизацию старого PHP-сервера и EasyUI (RedBean, индексы, импорт, теги, мёртвый код, Dockerfile), хотя оба удаляются. Теперь в старом коде только hotfix (🔥), остальное ↪ — требования к Go. -2. **Двойная работа в PHP-библиотеке.** Баги чинились в старом файле, а потом тот же код переписывался. Теперь в старом файле только дешёвые правки фатальных ошибок и уязвимостей. -3. **HTTP-управление строилось дважды** (токены в старом коде и в новом). Теперь в hotfix — только «выключено по умолчанию + обязательный токен», а полноценный опциональный HTTP-режим делается один раз в новой библиотеке. -4. **Схема для нескольких серверов шла последней (7в)**, хотя она определяет БД и API. Теперь схема проектируется в фазе 3 вместе с контрактами. -5. **Главные технические риски проверялись в конце**: встраивание UI в Go, SSE внутри Wails (п. 10.27), сборка на трёх ОС, CGO/WebKit на Linux. Теперь их снимает walking skeleton в фазе 4. -6. **Нет вех и MVP.** Релизный workflow стоял после всего, первый релиз — неизвестно когда. Теперь у каждой фазы есть версия. -7. **Монорепо не было отдельным шагом**, хотя от него зависят Makefile и CI; в п. 4.1 было `packages/client`, в остальных местах `client-php/`. -8. **Параллельность «Go и UI одновременно»** реальна только при двух исполнителях. ✅ Исполнитель один (п. 10.34), поэтому фазы идут последовательно, MVP — вертикальными срезами, а PHP-библиотека v2 перенесена после MVP. +1. **Wasted work on code that will be deleted.** Stages 1–4 included fixing and optimizing the old PHP server and EasyUI (RedBean, indexes, import, tags, dead code, Dockerfile), although both are being removed. Now the old code gets only hotfixes (🔥), the rest ↪ are requirements for Go. +2. **Double work in the PHP library.** Bugs were fixed in the old file, and then the same code was rewritten. Now the old file gets only cheap fixes of fatal errors and vulnerabilities. +3. **HTTP control was built twice** (tokens in the old code and in the new one). Now the hotfix has only "off by default + a required token", and a full optional HTTP mode is built once in the new library. +4. **The schema for several servers came last (7c)**, although it defines the database and the API. Now the schema is designed in phase 3 together with the contracts. +5. **The main technical risks were checked at the end**: embedding the UI into Go, SSE inside Wails (section 10.27), building on three OSes, CGO/WebKit on Linux. Now the walking skeleton in phase 4 removes them. +6. **No milestones and no MVP.** The release workflow came after everything, the first release — who knows when. Now every phase has a version. +7. **The monorepo was not a separate step**, although the Makefile and CI depend on it; section 4.1 had `packages/client`, other places `client-php/`. +8. **Doing "Go and UI at the same time"** is realistic only with two developers. ✅ There is one developer (section 10.34), so the phases go one after another, the MVP — as vertical slices, and PHP library v2 was moved after the MVP. -### 8.2 Фазы +### 8.2 Phases -Номер фазы = порядок выполнения (один исполнитель). +The phase number = the order of work (one developer). -| Фаза | Содержание | Результат / веха | Оценка | +| Phase | Content | Result / milestone | Estimate | |---|---|---|---| -| **0. Решения** | ✅ Выполнено: 10.6, 10.13, 10.17, 10.20, 10.22, 10.23, 10.26, 10.34 | Зафиксированные решения | — | -| **1. Hotfix текущей версии** ✅ код готов, проверен на PHP 7.4 и 8.4; осталось закоммитить и поставить тег | 🔥 из п. 1.1, 2.1, 2.2 (см. п. 9); синтаксис не выше уже используемого в файле, без PHP 8-функций | тег `legacy-hotfix` (не SemVer, чтобы не путать с версиями нового продукта): библиотеку безопасно держать в проектах | 1–2 дня | -| **2. Основа репозитория** ✅ | Монорепо (`legacy/` для старого кода), `.env`, фикстуры v1, каркас Makefile (`help`, `doctor`, `lint`, `test`, `ci`) и `ci.yml`, CONTRIBUTING с правилами именования (п. 4.4) | Пустые, но собираемые `client-php/`, `server/`, `ui/`, `desktop/`; зелёный CI | 2 дня | -| **3. Спецификации** ✅ | JSON Schema формата v1 и v2 (п. 4.2), OpenAPI v1 — включая легаси HTTP-режим библиотеки (п. 4.1), схема БД `servers/projects/requests/messages` и интерфейс `Source` (п. 7.5), генерация типов (`make generate`) | `spec/` — единый контракт для PHP, Go, UI | 2–3 дня | -| **4. Walking skeleton** | Go `serve`: парсер v1 на фикстурах, 2–3 эндпоинта + SSE; Svelte: один экран со списком запросов, токены и переключатель светлой/тёмной темы; **Wails v3**-оболочка с тем же UI и проверкой live-потока (критерии отката — п. 7.8); CI собирает server+ui+desktop на трёх ОС; `make release-snapshot` | Сквозной путь «лог → Go → UI → десктоп → артефакт» работает; решения 10.26/10.27 подтверждены или откат на v2 | 3–5 дней | -| **5. MVP просмотрщика** | Шаги в п. 8.2d: английский как базовый язык и i18n; парсер v2 и импорт с offset; fsnotify; детали запроса и сообщения в API и UI; проекты и управление отладчиком; поиск и фильтры; безопасность по умолчанию; удаление `legacy/`; `release.yml` | **v0.1.0** — первый релиз нового продукта; старый сервер и EasyUI удалены | 15–22 дня | -| **6. PHP-библиотека v2** ✅ код готов; публикация 2.0.0 ждёт владельца | Пакет для PHP 7.4+ (п. 4.1), формат v2 (`snake_case`), именование (п. 4.4), deprecated-обёртки (п. 10.23), маскировка, error/exception handler, ротация, PSR-3/Monolog обеих линий, опциональный HTTP-режим | `client-php` **2.0.0** в Packagist (через split, п. 3.2); просмотрщик сразу показывает v2-логи | 6–8 дней | -| **7. SSH** ✅ тег v0.2.0 | п. 7.4: подключение, known_hosts, SFTP-чтение с offset, live tail, управление отладчиком через конфиг, read-only; затем легаси HTTP-режим (п. 7.4a) | **v0.2.0** | 5–8 дней | -| **8. Несколько серверов** ✅ тег v0.3.0 | п. 7.5: дерево «серверы → проекты», автообнаружение проектов, сводные ленты, окружения и предупреждения, сдвиг часов, права (схема уже есть с фазы 3) | **v0.3.0** | 3–4 дня | -| **9. Десктоп полностью** ✅ код готов; тег v0.4.0 — после подтверждения | п. 7.8: трей, уведомления, deep links, single instance, автозапуск, установщики, подпись (по 10.28), уведомление о новой версии | **v0.4.0** | 4–6 дней | -| **10. Развитие** | Возможности UI (п. 5.1, 6.5: timeline, SQL, сравнение, палитра, редактор тем); HTTP-приёмник + `HttpWriter` + JS-клиент (п. 5.2); агент (п. 7.6); интеграции с фреймворками и хелперы SQL/Guzzle (п. 5.3) | итеративные минорные версии → **v1.0.0** | итеративно | - -**Критерии v1.0.0:** стабильный формат v2 и API v1 (дальше только обратно совместимые изменения), SSH, легаси HTTP-режим и несколько серверов, десктоп на трёх ОС, документация по установке и интеграции, нет известных уязвимостей. +| **0. Decisions** | ✅ Done: 10.6, 10.13, 10.17, 10.20, 10.22, 10.23, 10.26, 10.34 | Recorded decisions | — | +| **1. Hotfix of the current version** ✅ the code is ready, checked on PHP 7.4 and 8.4; left to commit and tag | 🔥 from sections 1.1, 2.1, 2.2 (see section 9); syntax no newer than already used in the file, no PHP 8 functions | the `legacy-hotfix` tag (not SemVer, not to be confused with versions of the new product): the library is safe to keep in projects | 1–2 days | +| **2. Repository foundation** ✅ | Monorepo (`legacy/` for the old code), `.env`, v1 fixtures, a Makefile skeleton (`help`, `doctor`, `lint`, `test`, `ci`) and `ci.yml`, CONTRIBUTING with the naming rules (section 4.4) | Empty but buildable `client-php/`, `server/`, `ui/`, `desktop/`; green CI | 2 days | +| **3. Specifications** ✅ | JSON Schema of formats v1 and v2 (section 4.2), OpenAPI v1 — including the legacy HTTP mode of the library (section 4.1), the database schema `servers/projects/requests/messages` and the `Source` interface (section 7.5), type generation (`make generate`) | `spec/` — one contract for PHP, Go, UI | 2–3 days | +| **4. Walking skeleton** | Go `serve`: the v1 parser on fixtures, 2–3 endpoints + SSE; Svelte: one screen with the list of requests, tokens and a light/dark theme switch; a **Wails v3** shell with the same UI and a check of the live stream (fallback criteria — section 7.8); CI builds server+ui+desktop on three OSes; `make release-snapshot` | The end-to-end path "log → Go → UI → desktop → artifact" works; decisions 10.26/10.27 confirmed or a fallback to v2 | 3–5 days | +| **5. Viewer MVP** | Steps in section 8.2d: English as the base language and i18n; the v2 parser and import from an offset; fsnotify; request and message details in the API and UI; projects and control of the debugger; search and filters; secure by default; removing `legacy/`; `release.yml` | **v0.1.0** — the first release of the new product; the old server and EasyUI removed | 15–22 days | +| **6. PHP library v2** ✅ the code is ready; publishing 2.0.0 waits for the owner | A package for PHP 7.4+ (section 4.1), format v2 (`snake_case`), naming (section 4.4), deprecated wrappers (section 10.23), masking, error/exception handler, rotation, PSR-3/Monolog of both lines, the optional HTTP mode | `client-php` **2.0.0** on Packagist (through a split, section 3.2); the viewer shows v2 logs right away | 6–8 days | +| **7. SSH** ✅ tag v0.2.0 | Section 7.4: connection, known_hosts, SFTP reading from an offset, live tail, control of the debugger through the config, read-only; then the legacy HTTP mode (section 7.4a) | **v0.2.0** | 5–8 days | +| **8. Several servers** ✅ tag v0.3.0 | Section 7.5: the "servers → projects" tree, project discovery, combined feeds, environments and warnings, clock skew, permissions (the schema has been there since phase 3) | **v0.3.0** | 3–4 days | +| **9. Full desktop** ✅ the code is ready; tag v0.4.0 — after confirmation | Section 7.8: tray, notifications, deep links, single instance, autostart, installers, signing (per 10.28), a notice about a new version | **v0.4.0** | 4–6 days | +| **10. Growth** | UI features (sections 5.1, 6.5: timeline, SQL, comparison, palette, theme editor); the HTTP receiver + `HttpWriter` + the JS client (section 5.2); the agent (section 7.6); framework integrations and the SQL/Guzzle helpers (section 5.3) | iterative minor versions → **v1.0.0** | iterative | + +**Criteria of v1.0.0:** a stable format v2 and API v1 (only backward compatible changes after that), SSH, the legacy HTTP mode and several servers, a desktop on three OSes, documentation on installation and integration, no known vulnerabilities. -### 8.2a Итоги фазы 2 - -Сделано (ветка `phase-2-foundation`): - -- **Монорепо**: старый сервер, EasyUI и библиотека v1 перенесены в `legacy/` без изменения поведения (проверено запуском `php -S`); `.env` удалён, есть `legacy/.env.example`, персональный маунт заменён на `PROJECTS_PATH`. -- **`client-php/`**: Composer-пакет (PHP ≥ 7.4), PHPUnit 9.6, PHPStan 2 (уровень 8, `phpVersion: 70400`), PHP-CS-Fixer (`@PSR12`, `@PHP74Migration`). Первый код через TDD — проверка имён `tools/bin/check-naming` (запрет венгерской нотации, п. 4.4): 22 теста, зелёные на PHP 7.4 и 8.4; на `legacy/Debugger.class.php` находит 466 имён. -- **`server/`**: Go-модуль (Go 1.26), CLI `wapp-debugger version|help` и пакет `internal/version` через TDD, golangci-lint v2. -- **`ui/`**: Vite 8 + Svelte 5 + TypeScript 6, Vitest + Testing Library, ESLint (с правилом против венгерской нотации, `snake_case` для свойств разрешён), Prettier, `svelte-check`; через TDD — выбор темы (`resolveTheme`, `parseThemePreference`, п. 6.4). Сборка — в `server/web/dist`. Компоненты пишутся с `