diff --git a/.cursor/agents.md b/.cursor/agents.md new file mode 100644 index 0000000..23e58de --- /dev/null +++ b/.cursor/agents.md @@ -0,0 +1,39 @@ +# Cursor AI Agents Configuration + +## Роли и правила поведения ИИ + +### Основная роль: Senior Full-Stack Developer + +Вы - опытный full-stack разработчик, специализирующийся на: + +- OpenCart модульной разработке +- Кастомных фреймворках (OpenCart Framework) +- PHP 7.4+ с современными практиками +- Vue.js 3 (Composition API) +- Telegram Mini App разработке + +### Правила работы с кодом + +1. **Всегда используй существующие паттерны проекта** +2. **Не создавай дубликаты - используй существующие утилиты** +3. **Следуй соглашениям именования проекта** +4. **Тестируй изменения перед коммитом** +5. **Документируй публичные API** + +### Запрещено + +- Хардкод значений (используй конфиги/настройки) +- Игнорирование обработки ошибок +- Создание циклических зависимостей + +Для разработки FrontEnd используй: + +- Vue.js 3 (Composition API) +- Старайся избегать функций watch там, где это возможно и где можно сделать более красиво. +- Для frontend/admin используй Tailwind 4 с префиксом `tw:`. +- Для frontend/spa используй Tailwind 4 без префикса. +- Для frontend/admin используй иконки от FontAwesome 4, потому что это уже встроено в OpenCart 3. +- Для frontend/admin используй компоненты VuePrime 4. +- Для frontend/spa используй Daisy UI. +- Чтобы получить название стандартной таблицы OpenCart, используй хелпер `db_table`, либо добавляй константу DB_PREFIX перед названием таблицы. Так ты получишь название таблицы с префиксом. +- Все таблицы моего модуля TeleCart начинаются с префикса `telecart_`. Примеры миграций лежат в `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..c7970c6 --- /dev/null +++ b/.cursor/config.json @@ -0,0 +1,44 @@ +{ + "rules": { + "preferCompositionAPI": true, + "strictTypes": true, + "noHardcodedValues": true, + "useDependencyInjection": true + }, + "paths": { + "telecart_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", + "telecartHandlers": "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 telecart_ 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": "telecart_", + "noForeignKeys": true + } +} + diff --git a/.cursor/prompts/api-generation.md b/.cursor/prompts/api-generation.md new file mode 100644 index 0000000..68b9fab --- /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/ + - Используй фиксированный префикс telecart_ + - Добавь индексы где необходимо + +Следуй архитектуре 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. Используй фиксированный префикс telecart_ для таблицы +3. Добавь все необходимые поля с правильными типами +4. Добавь индексы для часто используемых полей +5. Используй utf8mb4_unicode_ci collation +6. Используй InnoDB engine +7. Добавь created_at и updated_at timestamps +8. Не создавай foreign keys (используй только индексы) + +Следуй структуре существующих миграций. +``` + 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..9464a3e --- /dev/null +++ b/.cursor/rules/architecture.md @@ -0,0 +1,201 @@ +# Архитектурные правила + +## OpenCart 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 с префиксом `telecart_` + +### 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/javascript.md b/.cursor/rules/javascript.md new file mode 100644 index 0000000..6672b3e --- /dev/null +++ b/.cursor/rules/javascript.md @@ -0,0 +1,332 @@ +# JavaScript/TypeScript Code Style Rules + +## JavaScript Version + +- ES2020+ features +- Modern async/await +- Optional chaining (`?.`) +- Nullish coalescing (`??`) +- Template literals + +## Code Style + +### Variable Declarations + +```javascript +// ✅ Используй const по умолчанию +const customers = []; +const totalRecords = 0; + +// ✅ let только когда нужно переназначение +let currentPage = 1; +currentPage = 2; + +// ❌ Не используй var +var oldVariable = 'bad'; +``` + +### Arrow Functions + +```javascript +// ✅ Предпочтительно для коротких функций +const filtered = items.filter(item => item.isActive); + +// ✅ Для методов объектов +const api = { + get: async (url) => { + return await fetch(url); + } +}; + +// ✅ Для сложной логики - обычные функции +function complexCalculation(data) { + // много строк кода + return result; +} +``` + +### Template Literals + +```javascript +// ✅ Предпочтительно +const message = `User ${userId} not found`; +const url = `${baseUrl}/api/${endpoint}`; + +// ❌ Не используй конкатенацию +const message = 'User ' + userId + ' not found'; +``` + +### Optional Chaining + +```javascript +// ✅ Используй optional chaining +const name = user?.profile?.name; +const count = data?.items?.length ?? 0; + +// ❌ Избегай длинных проверок +const name = user && user.profile && user.profile.name; +``` + +### Nullish Coalescing + +```javascript +// ✅ Используй ?? для значений по умолчанию +const page = params.page ?? 1; +const name = user.name ?? 'Unknown'; + +// ❌ Не используй || для чисел/булевых +const page = params.page || 1; // 0 будет заменено на 1 +``` + +### Destructuring + +```javascript +// ✅ Используй деструктуризацию +const { data, totalRecords } = response.data; +const [first, second] = items; + +// ✅ В параметрах функций +function processUser({ id, name, email }) { + // ... +} + +// ✅ С значениями по умолчанию +const { page = 1, limit = 20 } = params; +``` + +### Async/Await + +```javascript +// ✅ Предпочтительно +async function loadCustomers() { + try { + const response = await apiGet('getCustomers', params); + return response.data; + } catch (error) { + console.error('Error:', error); + throw error; + } +} + +// ❌ Избегай .then() цепочек +function loadCustomers() { + return apiGet('getCustomers', params) + .then(response => response.data) + .catch(error => console.error(error)); +} +``` + +## Vue.js 3 Composition API + +### Script Setup + +```vue + +``` + +### Reactive State + +```javascript +// ✅ Используй ref для примитивов +const count = ref(0); +const name = ref(''); + +// ✅ Используй reactive для объектов +import { reactive } from 'vue'; +const state = reactive({ + customers: [], + loading: false +}); + +// ✅ Или ref для объектов (предпочтительно) +const state = ref({ + customers: [], + loading: false +}); +``` + +### Computed Properties + +```javascript +// ✅ Используй computed для производных значений +const filteredCustomers = computed(() => { + return customers.value.filter(c => c.isActive); +}); + +// ❌ Не используй методы для вычислений +function filteredCustomers() { + return customers.value.filter(c => c.isActive); +} +``` + +### Props + +```vue + +``` + +### Emits + +```vue + +``` + +## Pinia Stores + +```javascript +// ✅ Используй setup stores +import { defineStore } from 'pinia'; +import { ref, computed } from 'vue'; + +export const useCustomersStore = defineStore('customers', () => { + const customers = ref([]); + const loading = ref(false); + + const totalRecords = computed(() => customers.value.length); + + async function loadCustomers() { + loading.value = true; + try { + const result = await apiGet('getCustomers'); + customers.value = result.data || []; + } finally { + loading.value = false; + } + } + + return { + customers, + loading, + totalRecords, + loadCustomers + }; +}); +``` + +## Error Handling + +```javascript +// ✅ Всегда обрабатывай ошибки +async function loadData() { + try { + const result = await apiGet('endpoint'); + if (result.success) { + return result.data; + } else { + throw new Error(result.error); + } + } catch (error) { + console.error('Failed to load data:', error); + toast.error('Не удалось загрузить данные'); + throw error; + } +} +``` + +## Naming Conventions + +### Variables and Functions + +```javascript +// ✅ camelCase +const customerData = {}; +const totalRecords = 0; +function loadCustomers() {} + +// ✅ Константы UPPER_SNAKE_CASE +const MAX_RETRIES = 3; +const API_BASE_URL = '/api'; +``` + +### Components + +```vue + + + +``` + +### Files + +```javascript +// ✅ kebab-case для файлов +// customers-view.vue +// http-utils.js +// customer-service.js +``` + +## Imports + +```javascript +// ✅ Группируй импорты +// 1. Vue core +import { ref, computed, onMounted } from 'vue'; + +// 2. Third-party +import { apiGet } from '@/utils/http.js'; +import { useToast } from 'primevue'; + +// 3. Local components +import CustomerCard from '@/components/CustomerCard.vue'; + +// 4. Types (если TypeScript) +import type { Customer } from '@/types'; +``` + +## TypeScript (где используется) + +```typescript +// ✅ Используй типы +interface Customer { + id: number; + name: string; + email?: string; +} + +function getCustomer(id: number): Promise { + return apiGet(`customers/${id}`); +} +``` + diff --git a/.cursor/rules/php.md b/.cursor/rules/php.md new file mode 100644 index 0000000..7d8b3e1 --- /dev/null +++ b/.cursor/rules/php.md @@ -0,0 +1,243 @@ +# PHP Code Style Rules + +## PHP Version + +Проект поддерживает PHP 7.4+ + +## PSR Standards + +- **PSR-1**: Basic Coding Standard +- **PSR-4**: Autoloading Standard +- **PSR-12**: Extended Coding Style + +## Code Style + +### Type Declarations + +```php +// ✅ Правильно - строгая типизация +public function getCustomers(Request $request): JsonResponse +{ + $id = (int) $request->get('id'); + return new JsonResponse(['data' => $customers]); +} + +// ❌ Неправильно - без типов +public function getCustomers($request) +{ + return ['data' => $customers]; +} +``` + +### Nullable Types + +```php +// ✅ Правильно +public function findById(?int $id): ?array +{ + if ($id === null) { + return null; + } + return $this->query->where('id', '=', $id)->firstOrNull(); +} +``` + +### Strict Types + +Всегда используй `declare(strict_types=1);`: + +```php + 'value']; + +// ❌ Не использовать +$array = array('key' => 'value'); +``` + +### String Interpolation + +```php +// ✅ Предпочтительно +$message = "User {$userId} not found"; + +// ✅ Альтернатива +$message = sprintf('User %d not found', $userId); +``` + +### Arrow Functions (PHP 7.4+) + +```php +// ✅ Для простых операций +$filtered = array_filter($items, fn($item) => $item->isActive()); + +// ❌ Для сложной логики - используй обычные функции +``` + +### Nullsafe Operator (PHP 8.0+) + +```php +// ✅ Для PHP 7.4 +$name = $user && $user->profile ? $user->profile->name : null; +``` + +## Naming Conventions + +### Classes + +```php +// ✅ PascalCase +class TelegramCustomerService {} +class UserRepository {} +``` + +### Methods + +```php +// ✅ camelCase +public function getCustomers(): array {} +public function saveOrUpdate(array $data): array {} +``` + +### Variables + +```php +// ✅ camelCase +$customerData = []; +$totalRecords = 0; +``` + +### Constants + +```php +// ✅ UPPER_SNAKE_CASE +private const MAX_RETRIES = 3; +public const DEFAULT_PAGE_SIZE = 20; +``` + +### Private Properties + +```php +// ✅ camelCase с модификатором доступа +private string $tableName; +private Builder $builder; +``` + +## Documentation + +### PHPDoc + +```php +/** + * @throws ValidationException Если параметры невалидны + */ +public function getCustomers(Request $request): JsonResponse +{ + // ... +} +``` + +### Inline Comments + +```php +// ✅ Полезные комментарии +// Применяем фильтры для подсчета общего количества записей +$countQuery = $this->buildCountQuery($filters); + +// ❌ Очевидные комментарии +// Получаем данные +$data = $this->getData(); +``` + +## Error Handling + +### Exceptions + +```php +// ✅ Специфичные исключения +if (!$userId) { + throw new InvalidArgumentException('User ID is required'); +} + +// ✅ Логирование +try { + $result = $this->service->process(); +} catch (Exception $e) { + $this->logger->error('Processing failed', [ + 'exception' => $e, + 'context' => $context, + ]); + throw new ProcessingException('Failed to process', 0, $e); +} +``` + +## Query Builder Usage + +### Always Use Query Builder + +```php +// ✅ Правильно +$customers = $this->builder->newQuery() + ->select(['id', 'name', 'email']) + ->from('telecart_customers') + ->where('status', '=', 'active') + ->orderBy('created_at', 'DESC') + ->get(); + +// В крайних случаях можно использовать прямые SQL +$result = $this->database->query("SELECT * FROM telecart_customers"); +``` + +### Parameter Binding + +```php +// ✅ Query Builder автоматически биндит параметры +$query->where('name', 'LIKE', "%{$search}%"); + +// ❌ Никогда не конкатенируй значения в SQL, избегай SQL Injection. +``` + +## Array Access + +### Safe Array Access + +```php +// ✅ Используй Arr::get() +use Openguru\OpenCartFramework\Support\Arr; + +$value = Arr::get($data, 'key', 'default'); + +// ❌ Небезопасно +$value = $data['key']; // может вызвать ошибку +``` + +## Return Types + +```php +// ✅ Всегда указывай return type +public function getData(): array {} +public function findById(int $id): ?array {} +public function process(): void {} + +// ❌ Без типа +public function getData() {} +``` + +## Visibility Modifiers + +```php +// ✅ Всегда указывай модификатор доступа +private string $tableName; +protected Builder $builder; +public function getData(): array {} +``` + diff --git a/.cursor/rules/vue.md b/.cursor/rules/vue.md new file mode 100644 index 0000000..e501897 --- /dev/null +++ b/.cursor/rules/vue.md @@ -0,0 +1,370 @@ +# Vue.js 3 Rules + +## Component Structure + +### Template + +```vue + +``` + +### Script Setup + +```vue + +``` + +### Styles + +```vue + +``` + +## Component Naming + +```vue + + + + + + + +``` + +## Props + +```vue + +``` + +## Emits + +```vue + +``` + +## Reactive State + +```vue + +``` + +## Computed Properties + +```vue + +``` + +## Event Handlers + +```vue + + + +``` + +## Conditional Rendering + +```vue + +``` + +## Lists + +```vue + +``` + +## Form Handling + +```vue +