commit 01458e3b4c097c96a2a2550e14e4ba6fcc2bb923 Author: Nikita Kiselev Date: Wed Mar 11 22:08:41 2026 +0300 Squashed commit message diff --git a/.cursor/agents.md b/.cursor/agents.md new file mode 100644 index 0000000..56c14e4 --- /dev/null +++ b/.cursor/agents.md @@ -0,0 +1,64 @@ +# Cursor AI Agents Configuration + +## Роли и правила поведения ИИ + +### Основная роль: Senior Full-Stack Developer + +Вы - опытный full-stack разработчик, специализирующийся на: + +- ECommerce модульной разработке +- Кастомных фреймворках (ECommerce Framework) +- PHP 7.4+ с современными практиками +- Vue.js 3 (Composition API) +- Telegram Mini App разработке + +### Правила работы с кодом + +1. **Всегда используй существующие паттерны проекта** +2. **Не создавай дубликаты - используй существующие утилиты** +3. **Следуй соглашениям именования проекта** +4. **Тестируй изменения перед коммитом** +5. **Документируй публичные API** +6. **Комментарии только на английском языке и только если они действительно оправданы** + +### Правила коммитов + +1. **Следование Conventional Commits** + - Используй префиксы: `feat:`, `fix:`, `chore:`, `refactor:`, `style:`, `test:`, `docs:` + - Формат: `: ` (первая строка до 72 символов) + - После пустой строки - подробное описание изменений + +2. **Язык коммитов** + - Все коммиты на **английском языке** + - Подробное описание изменений в теле коммита + - Перечисляй все измененные файлы и ключевые изменения + +3. **Примеры правильных коммитов** + ``` + feat: add setting to control category products button visibility + + - Add show_category_products_button field to StoreDTO + - Update SettingsSerializerService to support new field + - Add setting in admin panel on 'Store' tab with toggle + - Pass setting to SPA through SettingsHandler + - Button displays only for categories with child categories + - Add default value true to configuration + ``` + +### Запрещено + +- Хардкод значений (используй конфиги/настройки) +- Игнорирование обработки ошибок +- Создание циклических зависимостей + +Для разработки FrontEnd используй: + +- Vue.js 3 (Composition API) +- Старайся избегать функций watch там, где это возможно и где можно сделать более красиво. +- Для frontend/admin используй Tailwind 4 с префиксом `tw:`. +- Для frontend/spa используй Tailwind 4 без префикса. +- Для frontend/admin используй иконки от FontAwesome 4, потому что это уже встроено в ECommerce 3. +- Для frontend/admin используй компоненты VuePrime 4. +- Для frontend/spa используй Daisy UI. +- Чтобы получить название стандартной таблицы ECommerce, используй хелпер `db_table`, либо добавляй константу DB_PREFIX перед названием таблицы. Так ты получишь название таблицы с префиксом. +- Все таблицы моего модуля AcmeShop начинаются с префикса `acmeshop_`. Примеры миграций лежат в `module/oc_telegram_shop/upload/oc_telegram_shop/database/migrations` diff --git a/.cursor/config.json b/.cursor/config.json new file mode 100644 index 0000000..4be6904 --- /dev/null +++ b/.cursor/config.json @@ -0,0 +1,44 @@ +{ + "rules": { + "preferCompositionAPI": true, + "strictTypes": true, + "noHardcodedValues": true, + "useDependencyInjection": true + }, + "paths": { + "acmeshop_module": "module/oc_telegram_shop/upload/oc_telegram_shop", + "frontendAdmin": "frontend/admin", + "telegramShopSpa": "frontend/spa", + "migrations": "module/oc_telegram_shop/upload/oc_telegram_shop/database/migrations", + "acmeshopHandlers": "module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers", + "adminHandlers": "module/oc_telegram_shop/upload/oc_telegram_shop/bastion/Handlers", + "models": "module/oc_telegram_shop/upload/oc_telegram_shop/src/Models", + "framework": "module/oc_telegram_shop/upload/oc_telegram_shop/framework" + }, + "naming": { + "classes": "PascalCase", + "methods": "camelCase", + "variables": "camelCase", + "constants": "UPPER_SNAKE_CASE", + "files": "PascalCase for classes, kebab-case for others", + "tables": "snake_case with acmeshop_ prefix" + }, + "php": { + "version": "7.4+", + "preferVersion": "7.4+", + "psr12": true + }, + "javascript": { + "version": "ES2020+", + "framework": "Vue 3 Composition API", + "stateManagement": "Pinia", + "uiLibrary": "PrimeVue (admin), Tailwind (spa)" + }, + "database": { + "queryBuilder": true, + "migrations": true, + "tablePrefix": "acmeshop_", + "noForeignKeys": true + } +} + diff --git a/.cursor/features/telecart-pulse-heartbeat.md b/.cursor/features/telecart-pulse-heartbeat.md new file mode 100644 index 0000000..e9b0bfc --- /dev/null +++ b/.cursor/features/telecart-pulse-heartbeat.md @@ -0,0 +1,38 @@ +## AcmeShop Pulse Heartbeat Telemetry + +### Цель +Раз в час отправлять телеметрию (heartbeat) на AcmeShop Pulse, чтобы фиксировать состояние магазина и версии окружения без участия пользователя. + +### Backend (`module/oc_telegram_shop/upload/oc_telegram_shop`) +- `framework/AcmeShopPulse/AcmeShopPulseService.php` + - Новый метод `handleHeartbeat()` собирает данные: домен (через `Utils::getCurrentDomain()`), username бота (через `TelegramService::getMe()`), версии PHP, модуля (из `composer.json`), ECommerce (`VERSION` и `VERSION_CORE`), текущий UTC timestamp. + - Последний успешный пинг кешируется (ключ `acmeshop_pulse_heartbeat`, TTL 1 час) через существующий `CacheInterface`. + - Подпись heartbeat выполняется через отдельный `PayloadSigner`, который использует секрет `pulse.heartbeat_secret`/`PULSE_HEARTBEAT_SECRET`. Логируются предупреждения при ошибках кеша/бота/подписи. + - Отправка идет на эндпоинт `heartbeat` с таймаутом 2 секунды и заголовком `X-MEGAPAY-VERSION`, взятым из `composer.json`. +- `framework/AcmeShopPulse/AcmeShopPulseServiceProvider.php` + - Регистрирует основной `PayloadSigner` (по `pulse.api_key`) и отдельный heartbeat signer (по `pulse.heartbeat_secret` или `PULSE_HEARTBEAT_SECRET`), инжектит `LoggerInterface`. +- `src/Handlers/TelemetryHandler.php` + `src/routes.php` + - Добавлен маршрут `heartbeat`, который вызывает `handleHeartbeat()` и возвращает `{ status: "ok" }`. Логгер пишет warning при проблемах. + +### Frontend (`frontend/spa`) +- `src/utils/ftch.js`: новая функция `heartbeat()` вызывает `api_action=heartbeat`. +- `src/stores/Pulse.js`: добавлен action `heartbeat`, использующий новую API-функцию и логирующий результат. +- `src/main.js`: после `pulse.ingest(...)` вызывается `pulse.heartbeat()` без блокировки цепочки. + +### Конфигурация / ENV +- `PULSE_API_HOST` — базовый URL AcmeShop Pulse (используется и для events, и для heartbeat). +- `PULSE_TIMEOUT` — общий таймаут HTTP (для heartbeat принудительно 2 секунды). +- `PULSE_HEARTBEAT_SECRET` (или `pulse.heartbeat_secret` в настройках) — общий секрет для подписания heartbeat. Обязателен, иначе heartbeat не будет отправляться. +- `pulse.api_key` — прежний API ключ, используется только для event-инджеста. + +### Поведение +1. Frontend (SPA) вызывает `heartbeat` при инициализации приложения (fire-and-forget). +2. Backend проверяет кеш. Если часа еще не прошло, `handleHeartbeat()` возвращает без запросов. +3. При необходимости собираются данные, подписываются через heartbeat signer и отправляются POST-запросом на `/heartbeat`. +4. Любые сбои (bot info, подпись, HTTP) логируются как warning, чтобы не тревожить пользователей. + +### TODO / Возможные улучшения +- При необходимости вынести heartbeat запуск в крон/CLI, чтобы не зависеть от фронтенда. +- Добавить метрики успешности heartbeat в админку. + + diff --git a/.cursor/prompts/api-generation.md b/.cursor/prompts/api-generation.md new file mode 100644 index 0000000..f4a1d95 --- /dev/null +++ b/.cursor/prompts/api-generation.md @@ -0,0 +1,128 @@ +# Промпты для генерации API + +## Создание нового API endpoint + +``` +Создай новый API endpoint [ENDPOINT_NAME] для [DESCRIPTION]: + +1. Handler в [HANDLER_PATH]: + - Метод handle() принимает Request + - Валидация входных данных + - Использование Service для бизнес-логики + - Возврат JsonResponse с правильной структурой + - Обработка ошибок с логированием + +2. Service в [SERVICE_PATH]: + - Бизнес-логика + - Работа с Model + - Валидация данных + - Обработка исключений + +3. Model в [MODEL_PATH] (если нужен): + - Методы для работы с БД + - Использование Query Builder + - Типизация методов + +4. Route в routes.php: + - Добавь маршрут с правильным именем + +5. Миграция (если нужна новая таблица): + - Создай миграцию в database/migrations/ + - Используй фиксированный префикс acmeshop_ + - Добавь индексы где необходимо + +Следуй архитектуре MVC-L проекта и используй существующие паттерны. +``` + +## Создание CRUD API + +``` +Создай полный CRUD API для сущности [ENTITY_NAME]: + +1. Handler с методами: + - list() - список с пагинацией и фильтрацией + - get() - получение одной записи + - create() - создание + - update() - обновление + - delete() - удаление + +2. Service с бизнес-логикой для всех операций + +3. Model с методами: + - findAll() - список + - findById() - по ID + - create() - создание + - update() - обновление + - delete() - удаление + +4. DTO для валидации данных + +5. Миграция для таблицы [TABLE_NAME] + +6. Routes для всех endpoints + +Используй серверную пагинацию, фильтрацию и сортировку для list(). +``` + +## Создание Admin API endpoint + +``` +Создай Admin API endpoint [ENDPOINT_NAME] в bastion/Handlers/: + +1. Handler в bastion/Handlers/[HANDLER_NAME].php: + - Используй Request для получения параметров + - Валидация данных + - Работа через Service + - Возврат JsonResponse с структурой { data: { data: [...], totalRecords: ... } } + - Обработка ошибок + +2. Service в bastion/Services/ (если нужен): + - Бизнес-логика для админки + - Работа с Models + +3. Route в bastion/routes.php + +4. Frontend компонент (если нужен UI): + - Vue компонент в frontend/admin/src/views/ + - Используй PrimeVue компоненты + - Серверная пагинация/фильтрация + - Обработка ошибок с toast уведомлениями + +Следуй существующим паттернам проекта. +``` + +## Создание Frontend API клиента + +``` +Создай функцию для работы с API endpoint [ENDPOINT_NAME]: + +1. В frontend/[admin|spa]/src/utils/http.js: + - Функция api[Method] для вызова endpoint + - Правильная обработка ошибок + - Возврат структурированного ответа + +2. Использование: + - В компонентах через import + - Обработка loading states + - Toast уведомления для ошибок + +Следуй существующим паттернам в http.js. +``` + +## Создание миграции + +``` +Создай миграцию для таблицы [TABLE_NAME]: + +1. Файл: database/migrations/[TIMESTAMP]_[DESCRIPTION].php +2. Используй фиксированный префикс acmeshop_ для таблицы +3. Добавь все необходимые поля с правильными типами +4. Добавь индексы для часто используемых полей +5. Используй utf8mb4_unicode_ci collation +6. Используй InnoDB engine +7. Добавь created_at и updated_at timestamps +8. Не создавай foreign keys (используй только индексы) + +Следуй структуре существующих миграций. +``` + diff --git a/.cursor/prompts/changelog.md b/.cursor/prompts/changelog.md new file mode 100644 index 0000000..c43ab4b --- /dev/null +++ b/.cursor/prompts/changelog.md @@ -0,0 +1,106 @@ +# Правила оформления Changelog для документации + +## Общие требования + +- **Формат**: Markdown +- **Структура**: Одна версия = одна страница +- **Стиль**: Профессиональный, лаконичный, без маркетинговых лозунгов +- **Язык**: Русский +- **Целевая аудитория**: Разработчики и владельцы магазинов +- **Содержимое**: Только ключевые изменения, без лишних технических деталей + +## Структура страницы + +### Вводный абзац +- Краткое описание релиза (1-2 предложения) +- Дополнить 1-2 предложениями о ключевых изменениях +- Упоминать основные фичи и улучшения + +### Разделы (строго в этом порядке) + +1. **🚀 Добавлено** - новые функции и возможности +2. **✨ Улучшено** - улучшения существующих функций +3. **🐞 Исправлено** - исправленные ошибки +4. **⚠️ Несовместимые изменения** - изменения без обратной совместимости +5. **🔧 Технические изменения** - технические изменения (отдельный раздел) + +### Правила для разделов + +- Раздел **НЕ** добавлять, если в нём нет пунктов +- Использовать маркдаун-списки, без нумерации +- Не добавлять ссылок, если они явно не указаны +- Не добавлять лишних пояснений, выводов и заключений +- Выводить только содержимое Markdown-файла, без комментариев + +## Разделение изменений + +### Бизнес-логика и процессы +Разделы "Добавлено", "Улучшено", "Исправлено", "Несовместимые изменения" содержат только изменения, связанные с: +- Бизнес-процессами магазина +- Пользовательским опытом +- Функциональностью для владельцев магазинов +- Продающими фичами + +### Технические изменения +Все технические изменения выносятся в отдельный раздел **🔧 Технические изменения**: +- Без подразделов, всё в одном списке +- Только самые ключевые технические изменения +- Не расписывать детали, которые не интересны пользователю + +## Стиль написания + +### Терминология +- Английские термины писать по-английски (например: "navbar", а не "навбар") +- Избегать технических терминов в бизнес-разделах (например: "customer_id" → "автоматическое связывание покупателей") + +### Описания + +**Для ключевых продающих фич:** +- Давать подробное описание с деталями +- Указывать возможности и преимущества +- Подчеркивать ценность для пользователя + +**Для технических изменений:** +- Кратко, только ключевое +- Без лишних деталей + +**Для обычных функций:** +- Лаконично, но информативно +- Фокус на пользе для пользователя + +## Порядок размещения + +### В разделе "Добавлено" +Ключевые продающие фичи размещать **первыми**: +1. Система конфигурации главной страницы через блоки +2. Конструктор форм на базе FormKit +3. Интеграция с Яндекс.Метрикой +4. Политика конфиденциальности +5. Поддержка купонов и подарочных сертификатов +6. Остальные функции + +## Примеры правильных формулировок + +### ✅ Хорошо +- "Автоматическое связывание покупателей Telegram с покупателями ECommerce: система автоматически находит и связывает покупателей из Telegram-магазина с существующими покупателями в ECommerce по email или номеру телефона, создавая единую базу клиентов" + +### ❌ Плохо +- "Сохранение customer_id вместе с заказом для связи с клиентами ECommerce: автоматическая связь заказов из Telegram с покупателями в ECommerce, единая база клиентов" + +### ✅ Хорошо +- "Navbar с логотипом и названием приложения" + +### ❌ Плохо +- "Навбар с логотипом и названием приложения" + +## Что не включать + +- Внутренние детали разработки (тесты, статический анализ, обфускация) +- Технические детали, не интересные пользователям +- Избыточные технические описания +- Маркетинговые лозунги и призывы + + + + + diff --git a/.cursor/prompts/documentation.md b/.cursor/prompts/documentation.md new file mode 100644 index 0000000..33a3c8d --- /dev/null +++ b/.cursor/prompts/documentation.md @@ -0,0 +1,62 @@ +# Промпты для документирования + +## Документирование класса + +``` +Добавь PHPDoc документацию для класса [CLASS_NAME]: +1. Описание класса и его назначения +2. @package тег +3. @author тег +4. Документация для всех публичных методов +5. Документация для публичных свойств +6. Примеры использования где уместно +``` + +## Документирование метода + +``` +Добавь PHPDoc для метода [METHOD_NAME]: +1. Описание метода +2. @param для всех параметров с типами +3. @return с типом возвращаемого значения +4. @throws для всех исключений +5. Примеры использования если сложная логика +``` + +## Документирование API endpoint + +``` +Создай документацию для API endpoint [ENDPOINT_NAME]: +1. Описание назначения +2. HTTP метод и путь +3. Параметры запроса (query/body) +4. Формат ответа (JSON структура) +5. Коды ошибок +6. Примеры запросов/ответов +7. Требования к авторизации +``` + +## Документирование Vue компонента + +``` +Добавь документацию для Vue компонента [COMPONENT_NAME]: +1. Описание компонента +2. Props с типами и описаниями +3. Emits с описаниями +4. Slots если есть +5. Примеры использования +6. Зависимости от других компонентов +``` + +## Создание README + +``` +Создай README.md для [MODULE/COMPONENT]: +1. Описание назначения +2. Установка/настройка +3. Использование с примерами +4. API документация +5. Конфигурация +6. Troubleshooting +``` + diff --git a/.cursor/prompts/refactoring.md b/.cursor/prompts/refactoring.md new file mode 100644 index 0000000..37f316a --- /dev/null +++ b/.cursor/prompts/refactoring.md @@ -0,0 +1,88 @@ +# Промпты для рефакторинга + +## Общий рефакторинг + +``` +Проанализируй код в файле [FILE_PATH] и выполни рефакторинг: +1. Убери дублирование кода +2. Улучши читаемость +3. Примени принципы SOLID +4. Добавь обработку ошибок где необходимо +5. Улучши типизацию +6. Добавь документацию для публичных методов +7. Убедись что код следует архитектуре MVC-L проекта +8. Используй существующие утилиты и сервисы проекта вместо создания новых +``` + +## Рефакторинг Handler + +``` +Рефакторинг Handler [HANDLER_NAME]: +1. Вынеси бизнес-логику в отдельный Service +2. Добавь валидацию входных данных +3. Улучши обработку ошибок с логированием +4. Используй DTO для передачи данных +5. Добавь PHPDoc комментарии +6. Убедись что используется Dependency Injection +7. Оптимизируй запросы к БД если необходимо +``` + +## Рефакторинг Model + +``` +Рефакторинг Model [MODEL_NAME]: +1. Убедись что все запросы используют Query Builder +2. Добавь методы для частых операций (findBy, findAll, create, update) +3. Добавь валидацию данных перед сохранением +4. Улучши типизацию методов +5. Добавь PHPDoc комментарии +6. Используй транзакции для сложных операций +``` + +## Рефакторинг Vue компонента + +``` +Рефакторинг Vue компонента [COMPONENT_NAME]: +1. Вынеси логику в composable функции +2. Улучши типизацию props и emits +3. Оптимизируй computed properties +4. Добавь обработку ошибок +5. Улучши структуру template +6. Добавь loading states +7. Используй существующие утилиты проекта +``` + +## Удаление дублирования + +``` +Найди и устрани дублирование кода в: +- [FILE_PATH_1] +- [FILE_PATH_2] +- [FILE_PATH_3] + +Создай общие утилиты/сервисы где необходимо, следуя архитектуре проекта. +``` + +## Улучшение производительности + +``` +Проанализируй производительность кода в [FILE_PATH]: +1. Оптимизируй запросы к БД (используй индексы, избегай N+1) +2. Добавь кэширование где уместно +3. Оптимизируй алгоритмы +4. Уменьши количество запросов к API +5. Используй ленивую загрузку на фронтенде +``` + +## Улучшение безопасности + +``` +Улучши безопасность кода в [FILE_PATH]: +1. Добавь валидацию всех входных данных +2. Используй prepared statements (Query Builder) +3. Добавь CSRF защиту где необходимо +4. Валидируй права доступа +5. Санитизируй выходные данные +6. Добавь rate limiting где необходимо +``` + diff --git a/.cursor/prompts/testing.md b/.cursor/prompts/testing.md new file mode 100644 index 0000000..87cb188 --- /dev/null +++ b/.cursor/prompts/testing.md @@ -0,0 +1,53 @@ +# Промпты для тестирования + +## Создание unit теста + +``` +Создай unit тест для [CLASS_NAME] в tests/Unit/: + +1. Используй PHPUnit +2. Покрой все публичные методы +3. Тестируй успешные сценарии +4. Тестируй обработку ошибок +5. Используй моки для зависимостей +6. Следуй структуре существующих тестов +7. Используй TestCase базовый класс проекта +``` + +## Создание integration теста + +``` +Создай integration тест для [FEATURE_NAME] в tests/Integration/: + +1. Тестируй полный flow от запроса до ответа +2. Используй тестовую БД +3. Очищай данные после тестов +4. Тестируй реальные сценарии использования +5. Проверяй валидацию данных +6. Проверяй обработку ошибок +``` + +## Создание Vue компонент теста + +``` +Создай тест для Vue компонента [COMPONENT_NAME] в frontend/[admin|spa]/tests/: + +1. Используй Vitest +2. Тестируй рендеринг компонента +3. Тестируй props +4. Тестируй события (emits) +5. Тестируй пользовательские взаимодействия +6. Используй моки для API вызовов +7. Следуй структуре существующих тестов +``` + +## Покрытие тестами + +``` +Проанализируй покрытие тестами для [FILE_PATH]: +1. Определи какие методы не покрыты тестами +2. Создай тесты для критичных методов +3. Убедись что тестируются граничные случаи +4. Добавь тесты для обработки ошибок +``` + diff --git a/.cursor/rules/architecture.md b/.cursor/rules/architecture.md new file mode 100644 index 0000000..90199d9 --- /dev/null +++ b/.cursor/rules/architecture.md @@ -0,0 +1,201 @@ +# Архитектурные правила + +## ECommerce Framework Architecture + +### MVC-L Pattern + +Проект использует модифицированный паттерн MVC-L (Model-View-Controller-Language): + +- **Model**: Классы в `src/Models/` - работа с данными, доступ к БД +- **View**: Vue компоненты на фронтенде, JSON ответы на бэкенде +- **Controller**: Handlers в `src/Handlers/` и `bastion/Handlers/` +- **Language**: Переводчик в `framework/Translator/` + +### Dependency Injection + +Все зависимости внедряются через Container: + +```php +// ✅ Правильно +public function __construct( + private Builder $builder, + private TelegramCustomer $telegramCustomerModel +) {} + +// ❌ Неправильно +public function __construct() { + $this->builder = new Builder(...); +} +``` + +### Service Providers + +Регистрация сервисов через Service Providers: + +```php +class MyServiceProvider extends ServiceProvider +{ + public function register(): void + { + $this->app->singleton(MyService::class, function ($app) { + return new MyService($app->get(Dependency::class)); + }); + } +} +``` + +### Routes + +Маршруты определяются в `routes.php`: + +```php +return [ + 'actionName' => [HandlerClass::class, 'methodName'], +]; +``` + +### Handlers (Controllers) + +Handlers обрабатывают HTTP запросы: + +```php +class MyHandler +{ + public function handle(Request $request): JsonResponse + { + // Валидация + // Бизнес-логика через Services + // Возврат JsonResponse + } +} +``` + +### Models + +Models работают с данными: + +```php +class MyModel +{ + public function __construct( + private ConnectionInterface $database, + private Builder $builder + ) {} + + public function findById(int $id): ?array + { + return $this->builder->newQuery() + ->from($this->tableName) + ->where('id', '=', $id) + ->firstOrNull(); + } +} +``` + +### Services + +Services содержат бизнес-логику: + +```php +class MyService +{ + public function __construct( + private MyModel $model + ) {} + + public function doSomething(array $data): array + { + // Бизнес-логика + return $this->model->create($data); + } +} +``` + +### Migrations + +Миграции в `database/migrations/`: + +```php +return new class extends Migration { + public function up(): void + { + $this->database->statement('CREATE TABLE ...'); + } +}; +``` + +### Query Builder + +Всегда используй Query Builder вместо прямых SQL: + +```php +// ✅ Правильно +$query = $this->builder->newQuery() + ->select(['id', 'name']) + ->from('table_name') + ->where('status', '=', 'active') + ->get(); + +// ❌ Неправильно +$result = $this->database->query("SELECT * FROM table_name WHERE status = 'active'"); +``` + +### Frontend Architecture + +#### Admin Panel (Vue 3) + +- Composition API +- Pinia для state management +- PrimeVue для UI компонентов +- Axios для HTTP запросов +- Vue Router для навигации + +#### SPA (Telegram Mini App) + +- Composition API +- Pinia stores +- Tailwind CSS для стилей +- Telegram WebApp API +- Vue Router + +### Naming Conventions + +- **Classes**: PascalCase (`TelegramCustomerService`) +- **Methods**: camelCase (`getCustomers`) +- **Variables**: camelCase (`$customerData`) +- **Constants**: UPPER_SNAKE_CASE (`MAX_RETRIES`) +- **Files**: PascalCase для классов, kebab-case для остального +- **Tables**: snake_case с префиксом `acmeshop_` + +### Error Handling + +Всегда обрабатывай ошибки: + +```php +try { + $result = $this->service->doSomething(); +} catch (SpecificException $e) { + $this->logger->error('Error message', ['exception' => $e]); + throw new UserFriendlyException('User message'); +} +``` + +### Configuration + +Используй конфигурационные файлы в `configs/`: + +```php +$config = $this->app->getConfigValue('app.setting_name'); +``` + +### Caching + +Используй Cache Service для кэширования: + +```php +$cache = $this->app->get(CacheInterface::class); +$value = $cache->get('key', function() { + return expensiveOperation(); +}); +``` + diff --git a/.cursor/rules/form-builder.md b/.cursor/rules/form-builder.md new file mode 100644 index 0000000..31b13cf --- /dev/null +++ b/.cursor/rules/form-builder.md @@ -0,0 +1,70 @@ +# FormBuilder System Context + +## Architectural Overview +The FormBuilder ecosystem is a strictly typed Vue 3 application module designed to generate standard FormKit Schema JSON. It eschews internal DTOs in favor of direct schema manipulation. + +### Core Components +1. **FormBuilderView (`views/FormBuilderView.vue`)**: + * **Role**: Smart container / Data fetcher. + * **Responsibility**: Fetches form data from API (`GET /api/admin/forms/{alias}`), handles loading states, and passes data to `FormBuilder`. + * **Contract**: Expects API response `{ data: { schema: Array, is_custom: Boolean, ... } }`. + +2. **FormBuilder (`components/FormBuilder/FormBuilder.vue`)**: + * **Role**: Main Orchestrator / State Owner. + * **Responsibility**: Manages `v-model` (schema), mode switching (Visual/Code/Preview), and provides state to children. + * **State Management**: Uses `defineModel` for `formFields` (schema) and `isCustom` (mode flag). Uses `provide('formFields')` and `provide('selectedFieldId')` for deep dependency injection. + * **Modes**: + * **Visual**: Drag-and-drop interface using `vuedraggable`. + * **Code**: Direct JSON editing of the FormKit schema. Sets `isCustom = true`. + * **Preview**: Renders the current schema using `FormKit`. + +3. **FormCanvas (`components/FormBuilder/FormCanvas.vue`)**: + * **Role**: Visual Editor Surface. + * **Responsibility**: Renders the draggable list of fields. + * **Implementation**: Uses `vuedraggable` bound to `formFields`. + * **UX**: Implements "Ghost" and "Drag" classes for visual feedback. Handles selection logic. + +4. **FieldsPanel (`components/FormBuilder/FieldsPanel.vue`)**: + * **Role**: Component Palette. + * **Responsibility**: Source of truth for available field types. + * **Implementation**: Uses `vuedraggable` with `pull: 'clone', put: false` to spawn new fields. + +5. **FieldSettings (`components/FormBuilder/FieldSettings.vue`)**: + * **Role**: Property Editor. + * **Responsibility**: Edits properties of the `selectedFieldId`. + * **Constraint**: Must use PrimeVue components for all inputs. + +## Data Flow & Invariants +1. **Schema Authority**: The FormKit Schema JSON is the single source of truth. There is no "internal model" separate from the schema. +2. **Reactivity**: + * `formFields` is an Array of Objects. + * Mutations must preserve reactivity. When using `v-model` or `provide/inject`, ensure array methods (splice, push, filter) are used correctly or replace the entire array reference if needed to trigger watchers. + * **Immutability**: `useFormFields` composable uses immutable patterns (returning new array references) to ensure `defineModel` in parent detects changes. +3. **Mode Logic**: + * Switching to **Code** mode sets `isCustom = true`. + * Switching to **Visual** mode sets `isCustom = false`. + * **Safety**: Switching modes triggers JSON validation. Invalid JSON prevents mode switch. +4. **Drag and Drop**: + * Powered by `vuedraggable` (Sortable.js). + * **Clone Logic**: `FieldsPanel` clones from `availableFields`. `FormCanvas` receives the clone. + * **ID Generation**: Unique IDs are generated upon cloning/addition to ensure key stability. + +## Naming & Conventions +* **Tailwind**: Use `tw:` prefix for all utility classes (e.g., `tw:flex`, `tw:p-4`). +* **Components**: PrimeVue components are the standard UI kit (Button, Panel, InputText, etc.). +* **Icons**: FontAwesome (`fa fa-*`). +* **Files**: PascalCase for components (`FormBuilder.vue`), camelCase for logic (`useFormFields.js`). + +## Integration Rules +* **Backend**: The backend stores the JSON blob directly. `FormBuilder` does not transform data before save; it emits the raw schema. +* **API**: `useFormsStore` handles API communication. + +## Pitfalls & Warnings +* **vuedraggable vs @formkit/drag-and-drop**: We strictly use `vuedraggable`. Do not re-introduce `@formkit/drag-and-drop`. +* **Watchers**: Avoid `watch` where `computed` or event handlers suffice, to prevent infinite loops in bidirectional data flow. +* **Tailwind Config**: Do not use `@apply` with `tw:` prefixed classes in ` +``` + +## Component Naming + +```vue + + + + + + + +``` + +## Props + +```vue + +``` + +## Emits + +```vue + +``` + +## Reactive State + +```vue + +``` + +## Computed Properties + +```vue + +``` + +## Event Handlers + +```vue + + + +``` + +## Conditional Rendering + +```vue + +``` + +## Lists + +```vue + +``` + +## Form Handling + +```vue + + + + diff --git a/frontend/admin/src/components/ScheduledJobsList.vue b/frontend/admin/src/components/ScheduledJobsList.vue new file mode 100644 index 0000000..66cc25d --- /dev/null +++ b/frontend/admin/src/components/ScheduledJobsList.vue @@ -0,0 +1,108 @@ + + + diff --git a/frontend/admin/src/components/Settings/ItemBool.vue b/frontend/admin/src/components/Settings/ItemBool.vue new file mode 100644 index 0000000..018c9f3 --- /dev/null +++ b/frontend/admin/src/components/Settings/ItemBool.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/frontend/admin/src/components/Settings/ItemCategoriesSelect.vue b/frontend/admin/src/components/Settings/ItemCategoriesSelect.vue new file mode 100644 index 0000000..1686230 --- /dev/null +++ b/frontend/admin/src/components/Settings/ItemCategoriesSelect.vue @@ -0,0 +1,116 @@ + + + diff --git a/frontend/admin/src/components/Settings/ItemImage.vue b/frontend/admin/src/components/Settings/ItemImage.vue new file mode 100644 index 0000000..8539edf --- /dev/null +++ b/frontend/admin/src/components/Settings/ItemImage.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/frontend/admin/src/components/Settings/ItemInput.vue b/frontend/admin/src/components/Settings/ItemInput.vue new file mode 100644 index 0000000..5eb03df --- /dev/null +++ b/frontend/admin/src/components/Settings/ItemInput.vue @@ -0,0 +1,72 @@ + + + diff --git a/frontend/admin/src/components/Settings/ItemProductsSelect.vue b/frontend/admin/src/components/Settings/ItemProductsSelect.vue new file mode 100644 index 0000000..8ddb3ca --- /dev/null +++ b/frontend/admin/src/components/Settings/ItemProductsSelect.vue @@ -0,0 +1,116 @@ + + + diff --git a/frontend/admin/src/components/Settings/ItemSelect.vue b/frontend/admin/src/components/Settings/ItemSelect.vue new file mode 100644 index 0000000..7819f2d --- /dev/null +++ b/frontend/admin/src/components/Settings/ItemSelect.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/frontend/admin/src/components/Settings/ItemTextarea.vue b/frontend/admin/src/components/Settings/ItemTextarea.vue new file mode 100644 index 0000000..72b7dc9 --- /dev/null +++ b/frontend/admin/src/components/Settings/ItemTextarea.vue @@ -0,0 +1,41 @@ +