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>
This commit is contained in:
88
docs/features/settings/CLAUDE.md
Normal file
88
docs/features/settings/CLAUDE.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Настройки модуля
|
||||
|
||||
## Назначение
|
||||
|
||||
Сквозная подсистема настроек модуля: форма в админ-панели, хранение значений и чтение их
|
||||
на 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` (мерж). Выбирай дефолт так, чтобы поведение «как было».
|
||||
Reference in New Issue
Block a user