Files
interview-demo-code/docs/features/settings/CLAUDE.md
Nikita Kiselev adcca7cbc4 docs: document settings framework and telecart-pulse feature
Каркас системы настроек (docs/features/settings) и фича TeleCart Pulse
с heartbeat (docs/features/telecart-pulse); спека синхронизирована с opt-in.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 15:08:05 +03:00

89 lines
6.7 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.
# Настройки модуля
## Назначение
Сквозная подсистема настроек модуля: форма в админ-панели, хранение значений и чтение их
на backend. Это **каркас**, в который встраиваются остальные фичи — когда фиче нужен свой
флаг/параметр, она добавляет поле в этот пайплайн, а не строит собственный механизм.
## Точки входа
| action | Метод | Где объявлен |
|--------------------|------------------------------------|---------------------|
| `getSettingsForm` | `SettingsHandler::getSettingsForm` | `bastion/routes.php` |
| `saveSettingsForm` | `SettingsHandler::saveSettingsForm`| `bastion/routes.php` |
| `resetCache` | `SettingsHandler::resetCache` | `bastion/routes.php` |
| `getSystemInfo` | `SettingsHandler::getSystemInfo` | `bastion/routes.php` |
## Ключевые файлы по слоям
- **Дефолты:** `module/oc_telegram_shop/upload/oc_telegram_shop/configs/app.php` — структура
всех настроек с дефолтными значениями (секции `app`, `telegram`, `metrics`, `store`,
`orders`, `texts`, `sliders`, `mainpage_blocks`, `pulse`, `cron`).
- **Handler (админка):** `module/.../bastion/Handlers/SettingsHandler.php`
`getSettingsForm()` отдаёт срез конфига (`Arr::getWithKeys` по списку секций),
`saveSettingsForm()` сохраняет тот же срез.
- **Сохранение:** `module/.../bastion/Services/SettingsService.php``update()` пишет в
OpenCart-таблицу `oc_setting` через `model_setting_setting->editSetting('module_telecart',
['module_telecart_settings' => $data])`, синхронизирует статус модуля `module_tgshop` и
очищает кэш.
- **Чтение (backend):** `Openguru\OpenCartFramework\Config\Settings``get('a.b.c')` /
`getAll()`. Расширение для витрины — `App\Services\SettingsService` (наследует `Settings`)
и DTO в `src/DTO/Settings/` с типизированными геттерами (`is*()`, `get*()`).
- **Сборка конфига:** `module/.../bastion/ApplicationFactory.php` (и точка входа
`admin/controller/extension/module/tgshop.php`) — дефолты из `configs/app.php` мержатся с
сохранёнными `module_telecart_settings` через `Arr::mergeArraysRecursively`, результат
отдаётся в `Application`.
- **Фронтенд (стор):** `frontend/admin/src/stores/settings.js` — Pinia setup-store: дефолтный
state, `fetchSettings()` (`getSettingsForm`), `saveSettings()` (`saveSettingsForm`).
- **Фронтенд (поля):** `frontend/admin/src/components/Settings/``ItemBool` (toggle),
`ItemInput`, `ItemSelect`, `ItemImage`, `ItemToggleButton`. `ItemBool`
`Switcher``ToggleSwitch` (PrimeVue). Используются во `views/*View.vue`.
## Поток данных
Чтение формы:
`getSettingsForm``Settings::getAll()` (уже смерженный конфиг) → срез по секциям →
JSON → стор `fetchSettings()` → поля во `*View.vue`.
Сохранение:
поле (`v-model`) → стор `saveSettings()``saveSettingsForm``SettingsService::update()`
`oc_setting` (`module_telecart_settings`) + сброс кэша.
Чтение на backend:
дефолты `configs/app.php` ⊕ сохранённые значения → `Application``Config\Settings` / DTO
→ сервисы (через DI-провайдеры, которые инжектят `getConfigValue('...')` в конструкторы).
## Как добавить новый toggle (чек-лист)
1. **Дефолт:** добавить ключ в нужную секцию `configs/app.php` (для булева — `true`/`false`).
2. **Backend-потребитель:** прочитать значение там, где оно нужно. Идиома модуля — читать в
ServiceProvider (`$app->getConfigValue('секция.ключ')`) и **инжектить** в конструктор
сервиса (не дёргать конфиг из глубины класса). При наличии DTO — добавить геттер.
3. **Стор:** добавить ключ с дефолтом в соответствующую секцию state в
`frontend/admin/src/stores/settings.js`.
4. **View:** добавить компонент поля (для тумблера — `<ItemBool label="…"
v-model="settings.items.<секция>.<ключ>">…текст-подсказка…</ItemBool>`) в нужный
`*View.vue`.
5. Убедиться, что секция уже перечислена в списках `Arr::getWithKeys` в `getSettingsForm`/
`saveSettingsForm` (если добавляешь поле в новую секцию — добавить и саму секцию в оба
списка).
## Связанные фичи
- [telecart-pulse](../telecart-pulse/CLAUDE.md) — heartbeat использует этот каркас:
флаг `pulse.heartbeat_enabled` проходит весь путь от формы до backend-гейта.
## Нюансы и подводные камни
- **PHP 7.4** в backend-коде (без `match`, промоушена свойств, union-типов и т.п.).
- `getSettingsForm`/`saveSettingsForm` работают строго по **белому списку секций**
(`Arr::getWithKeys`). Поле вне перечисленных секций не отдастся и не сохранится.
- Секция `cron` содержит read-only поля (`cli_path`, `last_run`), которые добавляются при
выдаче и вырезаются перед сохранением — не сохраняй вычисляемые значения.
- `saveSettingsForm` сейчас вызывает пустой `validate()` — серверной валидации значений
настроек по сути нет; не полагайся на неё.
- После сохранения кэш сбрасывается целиком (`SettingsService::update` → `cache->clear()`).
- Существующие установки не имеют сохранённого значения нового ключа — оно берётся из
дефолта `configs/app.php` (мерж). Выбирай дефолт так, чтобы поведение «как было».