|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## КРИТИЧЕСКИ ВАЖНО: Запреты при разработке |
| 6 | + |
| 7 | +**КАТЕГОРИЧЕСКИ ЗАПРЕЩЕНО:** |
| 8 | +1. **Изменять файлы вне директории модуля** - никогда не модифицировать файлы в `/offload/`, `/usr/www/src/`, или других системных директориях MikoPBX |
| 9 | +2. **Использовать rsync, cp -r или tar для установки модуля** - это может перезаписать системные файлы MikoPBX |
| 10 | +3. **Удалять директорию модуля целиком** (`rm -rf /storage/.../ModuleAmoCrm`) - это удалит базу данных модуля |
| 11 | +4. **Затирать `Lib/AmoCrmMainBase.php` при установке модуля** — этот файл содержит реальные OAuth-credentials (`CLIENT_ID`, `CLIENT_SECRET`, `REDIRECT_URL`), которые подставляются CI при сборке. В репозитории хранятся только плейсхолдеры (`%CLIENT_ID%` и т.д.). **Перед обновлением/установкой модуля на сервере необходимо сделать бэкап этого файла и восстановить его после установки.** |
| 12 | + |
| 13 | +## Требования к коду |
| 14 | + |
| 15 | +**Совместимость:** |
| 16 | +- Код должен быть совместим с **PHP 7.4** и **PHP 8.x** |
| 17 | +- Код должен работать с **Phalcon 4.x** и **Phalcon 5.x** |
| 18 | + |
| 19 | +**Избегайте (только PHP 8+):** |
| 20 | +- `match` выражения → используйте `switch` |
| 21 | +- Union types `function foo(): int|string` → используйте PHPDoc |
| 22 | +- Named arguments `foo(name: $value)` |
| 23 | +- Constructor property promotion |
| 24 | +- Nullsafe operator `?->` |
| 25 | +- `str_contains()`, `str_starts_with()`, `str_ends_with()` → используйте `strpos() !== false` |
| 26 | + |
| 27 | +## Project Overview |
| 28 | + |
| 29 | +ModuleAmoCrm — модуль-расширение для MikoPBX, интегрирующий телефонную систему с AmoCRM. Синхронизирует звонки (CDR), контакты, сделки, компании и задачи между АТС и CRM. |
| 30 | + |
| 31 | +- **Namespace**: `Modules\ModuleAmoCrm\` (PSR-4 от корня) |
| 32 | +- **Стек:** PHP 7.4+, Phalcon MVC, Beanstalk (очереди), Asterisk AMI |
| 33 | +- **Module ID**: `ModuleAmoCrm` |
| 34 | + |
| 35 | +## Команды |
| 36 | + |
| 37 | +```bash |
| 38 | +# Установка PHP-зависимостей |
| 39 | +composer install |
| 40 | + |
| 41 | +# Проверка синтаксиса |
| 42 | +php -l <file.php> |
| 43 | + |
| 44 | +# Фоновые воркеры (запускаются на PBX-системе) |
| 45 | +php bin/WorkerAmoCrmAMI.php # AMI-слушатель событий Asterisk |
| 46 | +php bin/AmoCdrDaemon.php # Синхронизация CDR |
| 47 | +php bin/ConnectorDb.php # IPC-диспетчер, все операции с БД |
| 48 | +php bin/WorkerAmoHTTP.php # HTTP-запросы к AmoCRM API |
| 49 | +php bin/SyncDaemon.php # Синхронизация контактов/компаний/сделок |
| 50 | +``` |
| 51 | + |
| 52 | +## Build & CI |
| 53 | + |
| 54 | +GitHub Actions workflow (`.github/workflows/build.yml`) срабатывает на push в `master`/`develop` и использует reusable workflow из `mikopbx/.github-workflows`: |
| 55 | +```yaml |
| 56 | +jobs: |
| 57 | + build: |
| 58 | + uses: mikopbx/.github-workflows/.github/workflows/extension-publish.yml@master |
| 59 | + with: |
| 60 | + initial_version: "1.84" |
| 61 | + secrets: inherit |
| 62 | +``` |
| 63 | +
|
| 64 | +Тестов в проекте нет (нет phpunit.xml, нет каталога tests/). |
| 65 | +
|
| 66 | +## Сборка и установка модуля |
| 67 | +
|
| 68 | +### Сборка архива (локально) |
| 69 | +
|
| 70 | +```bash |
| 71 | +cd /Volumes/DevDisk/apor/Developement/MikoPBX/Extensions/ModuleAmoCrm |
| 72 | +zip -r ../ModuleAmoCrm.zip . -x "*.git*" -x "*tasks.md*" -x "*.DS_Store*" -x "*CLAUDE.md*" |
| 73 | +``` |
| 74 | + |
| 75 | +### Установка через WorkerModuleInstaller (ЕДИНСТВЕННЫЙ РАЗРЕШЁННЫЙ СПОСОБ) |
| 76 | + |
| 77 | +```bash |
| 78 | +# На сервере: создать settings.json |
| 79 | +cat > /tmp/settings.json << 'EOF' |
| 80 | +{ |
| 81 | + "currentModuleDir": "/storage/usbdisk1/mikopbx/custom_modules/ModuleAmoCrm", |
| 82 | + "filePath": "/home/user/ModuleAmoCrm.zip", |
| 83 | + "uniqid": "ModuleAmoCrm" |
| 84 | +} |
| 85 | +EOF |
| 86 | + |
| 87 | +# Установить модуль (сохраняет БД!) |
| 88 | +php -f /usr/www/src/PBXCoreREST/Workers/WorkerModuleInstaller.php start /tmp/settings.json |
| 89 | +``` |
| 90 | + |
| 91 | +## Инициализация в скриптах |
| 92 | + |
| 93 | +Все PHP скрипты (bin/) должны начинаться с: |
| 94 | + |
| 95 | +```php |
| 96 | +#!/usr/bin/php |
| 97 | +<?php |
| 98 | +require_once('Globals.php'); |
| 99 | +``` |
| 100 | + |
| 101 | +**Важно:** `Globals.php` должен быть симлинком на `/usr/www/src/Core/Config/Globals.php` |
| 102 | + |
| 103 | +## Сборка JavaScript |
| 104 | + |
| 105 | +Исходники: `public/assets/js/src/` — **редактировать только файлы в `src/`**. |
| 106 | +Скомпилированные файлы в `public/assets/js/*.js` — автогенерируемые, не редактировать вручную. |
| 107 | + |
| 108 | +Сборка через Babel (пресет `airbnb`, source maps включены). |
| 109 | +PHPStorm File Watcher: https://docs.mikopbx.com/mikopbx-development/prepare-ide-tools/mac#phpstorm-setup-babel |
| 110 | + |
| 111 | +Ручная сборка: |
| 112 | +```bash |
| 113 | +cd /Users/apor/Developement/MikoPBX/MikoPBXUtils && \ |
| 114 | +cp babel.config.json babel.config.json.bak && \ |
| 115 | +echo '{"presets":[["@babel/preset-env",{"targets":{"chrome":50,"ie":11,"firefox":45}}]]}' > babel.config.json && \ |
| 116 | +./node_modules/.bin/babel \ |
| 117 | + /Volumes/DevDisk/apor/Developement/MikoPBX/Extensions/ModuleAmoCrm/public/assets/js/src/module-amo-crm-index.js \ |
| 118 | + --out-dir /Volumes/DevDisk/apor/Developement/MikoPBX/Extensions/ModuleAmoCrm/public/assets/js/ \ |
| 119 | + --source-maps && \ |
| 120 | +mv babel.config.json.bak babel.config.json |
| 121 | +``` |
| 122 | + |
| 123 | +## Architecture |
| 124 | + |
| 125 | +### Worker-Based Async System |
| 126 | + |
| 127 | +Модуль работает через набор фоновых демонов (workers), взаимодействующих через Beanstalk-очереди: |
| 128 | + |
| 129 | +| Worker | Файл | Тип проверки | Назначение | |
| 130 | +|--------|------|-------------|------------| |
| 131 | +| `WorkerAmoCrmAMI` | `bin/WorkerAmoCrmAMI.php` | AMI | Слушает события Asterisk (перехват, звонки) | |
| 132 | +| `AmoCdrDaemon` | `bin/AmoCdrDaemon.php` | PID | Синхронизация CDR → AmoCRM (батчами по 50) | |
| 133 | +| `ConnectorDb` | `bin/ConnectorDb.php` | PID | RPC-сервис для операций с БД через Beanstalk | |
| 134 | +| `WorkerAmoHTTP` | `bin/WorkerAmoHTTP.php` | Beanstalk | HTTP-запросы к API AmoCRM (throttle: 7 req/s) | |
| 135 | +| `SyncDaemon` | `bin/SyncDaemon.php` | PID | Синхронизация контактов/компаний/сделок | |
| 136 | + |
| 137 | +Все workers наследуют `WorkerBase` из MikoPBX. `ConnectorDb::invoke()` — универсальный паттерн RPC-вызова к БД-воркеру из других процессов. |
| 138 | + |
| 139 | +### Inter-Process Communication Flow |
| 140 | + |
| 141 | +``` |
| 142 | +AMI Events → WorkerAmoCrmAMI → Beanstalk → ConnectorDb (DB ops) |
| 143 | + → WorkerAmoHTTP (API calls) |
| 144 | +CDR records → AmoCdrDaemon → ConnectorDb → WorkerAmoHTTP → AmoCRM API |
| 145 | +Webhooks → ApiController → ConnectorDb → обработка |
| 146 | +``` |
| 147 | + |
| 148 | +### MVC Layer (Phalcon) |
| 149 | + |
| 150 | +- **Controller**: `App/Controllers/ModuleAmoCrmController.php` — CRUD для настроек модуля |
| 151 | +- **Models** (`Models/`): 6 моделей, все наследуют `ModulesModelsBase`. Таблицы имеют префикс `m_ModuleAmo*` |
| 152 | +- **Forms** (`App/Forms/`): формы для настроек и правил обработки звонков |
| 153 | +- **Views** (`App/Views/`): Volt-шаблоны (`index.volt`, `modify.volt`) |
| 154 | + |
| 155 | +### Module Configuration (`Lib/AmoCrmConf.php`) |
| 156 | + |
| 157 | +Центральный класс конфигурации, наследует `ConfigClass`. Отвечает за: |
| 158 | +- Регистрацию workers в `getModuleWorkers()` |
| 159 | +- REST-маршруты в `getPBXCoreRESTAdditionalRoutes()` |
| 160 | +- Генерацию dialplan-контекстов (extensions.conf) для перехвата звонков |
| 161 | +- Nginx-локации для WebRTC-телефона и воспроизведения записей |
| 162 | +- Cron-задачи: очистка tmp (каждую минуту), начальная синхронизация (01:00 ежедневно) |
| 163 | +- Реакцию на изменения в БД через `modelsEventChangeData()` |
| 164 | + |
| 165 | +### REST API |
| 166 | + |
| 167 | +Маршруты зарегистрированы в `AmoCrmConf::getPBXCoreRESTAdditionalRoutes()`. Контроллер: `Lib/RestAPI/Controllers/ApiController.php`. |
| 168 | + |
| 169 | +Базовый путь: `/pbxcore/api/amo-crm/v1/` |
| 170 | + |
| 171 | +| Endpoint | Метод | Назначение | |
| 172 | +|----------|-------|------------| |
| 173 | +| `/callback` | POST | Инициация звонка из AmoCRM | |
| 174 | +| `/listener` | GET/POST | OAuth2 авторизация | |
| 175 | +| `/command` | POST | Команды управления (hangup и др.) | |
| 176 | +| `/change-settings` | POST | Сохранение настроек из виджета | |
| 177 | +| `/find-contact` | POST | Поиск контакта по телефону | |
| 178 | +| `/panel-enable` | GET | Проверка статуса панели | |
| 179 | +| `/entity-update` | POST | Webhook от AmoCRM при изменении сущностей | |
| 180 | + |
| 181 | +Авторизация API — через файл-токен в `/var/etc/auth/`. |
| 182 | + |
| 183 | +### Call Processing Rules |
| 184 | + |
| 185 | +Модель `ModuleAmoEntitySettings` определяет правила для 7 типов звонков: |
| 186 | +`INCOMING_UNKNOWN`, `MISSING_UNKNOWN`, `INCOMING_KNOWN`, `MISSING_KNOWN`, `OUTGOING_UNKNOWN`, `OUTGOING_KNOWN`, `OUTGOING_KNOWN_FAIL` |
| 187 | + |
| 188 | +Каждое правило задаёт: ответственного, создание контакта/сделки/задачи/unsorted, шаблоны имён, воронку и статус. Defaults хранятся в `db/default-entity-settings.json`. |
| 189 | + |
| 190 | +### OAuth2 & AmoCRM API |
| 191 | + |
| 192 | +- `Lib/AmoCrmMain.php` — основной API-клиент AmoCRM (v4 API) |
| 193 | +- `Lib/AuthToken.php` — управление OAuth2 токенами (refresh с буфером 1 час) |
| 194 | +- `Lib/ClientHTTP.php` — HTTP-обёртка (POST, PATCH, GET) |
| 195 | +- Поддержка приватного виджета с отдельными client_id/secret |
| 196 | + |
| 197 | +### Widget (`widget/`) |
| 198 | + |
| 199 | +AmoCRM-виджет для встраивания в интерфейс CRM: WebRTC-телефон через iframe, event-driven коммуникация (PubSub), настройки в `manifest.json`. |
| 200 | + |
| 201 | +### Database Models |
| 202 | + |
| 203 | +- `ModuleAmoCrm` — главные настройки (OAuth-токены, домен, параметры интеграции) |
| 204 | +- `ModuleAmoEntitySettings` — правила обработки звонков per DID/type |
| 205 | +- `ModuleAmoUsers` — маппинг PBX extension ↔ AmoCRM user |
| 206 | +- `ModuleAmoPhones` — маппинг телефонных номеров |
| 207 | +- `ModuleAmoLeads` — кеш сделок |
| 208 | +- `ModuleAmoPipeLines` — кеш воронок |
| 209 | + |
| 210 | +## Пути на сервере |
| 211 | + |
| 212 | +| Путь | Описание | |
| 213 | +|------|----------| |
| 214 | +| `/storage/usbdisk1/mikopbx/custom_modules/ModuleAmoCrm/` | Директория модуля | |
| 215 | +| `/storage/usbdisk1/mikopbx/custom_modules/ModuleAmoCrm/db/` | Персистентные данные (БД) | |
| 216 | +| `/usr/www/src/Core/Config/Globals.php` | MikoPBX bootstrap | |
| 217 | + |
| 218 | +## Key Conventions |
| 219 | + |
| 220 | +- Модели: наследовать `ModulesModelsBase`, таблицы с префиксом `m_Module*` |
| 221 | +- Workers: наследовать `WorkerBase`, регистрировать в `AmoCrmConf::getModuleWorkers()` |
| 222 | +- REST-маршруты: добавлять в `AmoCrmConf::getPBXCoreRESTAdditionalRoutes()` |
| 223 | +- Логи: через `Lib/Logger.php` с ротацией (cesargb/php-log-rotation) |
| 224 | +- Локализация: файлы переводов в `Messages/` (31 язык, управляется через Weblate) |
| 225 | +- Схема БД создаётся из аннотаций Phalcon-моделей при `PbxExtensionSetup::installDB()` |
| 226 | +- CSS-фреймворк — Semantic UI |
0 commit comments