# AGENTS.md — рабочие инструкции pnd8_app Версия: 2026-08-10 Кодировка: UTF-8 ## Назначение - Этот файл — входная карта проекта для AI-ассистентов и разработчиков. - Перед нетривиальной правкой сначала изучить затрагиваемый модуль, соседний модуль того же типа и связанные XML/шаблоны/миграции. - Новые устойчивые правила проекта добавлять сюда. Не превращать файл в журнал реализации отдельных задач. - Не удалять и не откатывать чужие изменения в dirty worktree без явного запроса. - Не хранить в этом файле пароли, токены, API-ключи и другие секреты. ## Контекст проекта `pnd8_app` — веб-приложение для поиска участка обслуживания ПНД по адресу и показа врачей с расписанием приёма. Основной пользовательский сценарий: 1. Пользователь вводит адрес на публичной странице. 2. Яндекс Карты определяют координаты. 3. Приложение находит содержащий точку полигон `pnd_zone_geometry`. 4. Через `zone_id` загружаются участок `pnd_zones` и врачи `pnd_doctors`. 5. Расписание врача читается из JSON-поля `schedule` и отображается/печатается. Данные врачей, участков и расписаний синхронизируются из внешней старой МИС cron-скриптом. FAQ, документы и статические страницы управляются через собственный движок и админку. ## Стек - PHP 7.4 FPM и Composer 2. - Собственный legacy PHP-фреймворк: `module`, `cat`, `cobject`, XML-компоновка, legacy `.htm` и BladeOne. - MariaDB 10.6.21 в текущем `docker-compose.yml`; слой доступа к БД — собственный `db`/`cobject` поверх `mysqli`. - Nginx 1.24, Docker Compose, phpMyAdmin. - Публичный frontend: Bootstrap 4, jQuery 3.4.1, Font Awesome 5, Яндекс Карты и Suggest API. - PHP CS Fixer подключён как Composer-зависимость; автоматизированного тестового набора в репозитории сейчас нет. Не применять синтаксис и API PHP 8.x. Не обновлять версии runtime, Composer-зависимостей или frontend-библиотек попутно с прикладной задачей. ## Карта проекта - `app/` — код приложения; в контейнерах монтируется в `/var/www/html`. - `app/public_html/` — фактический web root и публичная точка входа `index.php`. - `app/public_html/admin/` — точка входа админки. - `app/public_html/assets/` — публичные CSS, JS, SCSS, шрифты и генератор статических include-файлов. - `app/engine/bootstrap.php` — общая загрузка конфигурации, БД, ядра и BladeOne. - `app/engine/core/` — ядро, `cobject`, БД, формы, фильтры, роутинг и типы атрибутов. - `app/engine/www/modules/` — контроллеры публичной части. - `app/engine/www/bladetpl/` — Blade-шаблоны публичной части. - `app/engine/www/tpls/` — legacy-шаблоны и XML include-файлы публичной части. - `app/engine/www/xml/` — XML-компоновка публичных категорий. - `app/engine/admin/modules/`, `bladetpl/`, `tpls/`, `xml/` — соответствующие части админки. - `app/engine/migrations/` — плоский каталог SQL-миграций и исполнитель `_migrate.php`. - `app/engine/cron/data_sync/` — импорт врачей, участков и расписания из внешней МИС. - `app/config/` — конфигурация и подключения приложения; считать содержимое чувствительным. - `config/`, `docker/`, `docker-compose.yml` — инфраструктура контейнеров. - `db/`, `logs/`, `sessions/` — runtime-данные; не редактировать и не добавлять в Git. - `Договор/`, архивы и дампы в корне — не код приложения; не открывать и не изменять без прямой необходимости задачи. README унаследован от Bambolo и местами устарел: в этом репозитории web root называется `public_html`, а текущий Compose содержит только `php`, `nginx`, `mariadb` и `phpmyadmin`. Проверять фактическую конфигурацию, а не слепо следовать README или `deploy.cmd`. ## Архитектурные правила - Сначала искать аналогичный существующий модуль и сохранять принятый проектом паттерн. - У модуля параметры запроса явно перечислять в `$_get_vars`, `$_post_vars` и `$_loc_vars`; внутри action использовать `$this->имяПараметра`. - Action этого движка реализуются методами `_on_*`/`_ajax_*`; не смешивать несвязанные action и представления в одном шаблоне. - Для Blade использовать общий `$blade` через `global $blade` и `$blade->run($this->getBladeTempl(...), $data)`. - Для текущей категории использовать `global $cat` и `$cat->cat`, для редиректа — `_redirect()`. - Не использовать `$GLOBALS[...]` и не добавлять новый прямой доступ к `$_REQUEST`. - Бизнес-вычисления и SQL готовить в PHP-модуле; в Blade оставлять преимущественно отображение. При доработке существующего шаблона постепенно выносить сложную подготовку данных, если это входит в задачу. - Не вводить новый фреймворк, ORM или сборщик ради локальной правки. - Сохранять обратную совместимость публичных URL, XML-категорий и связки `module -> XML/category -> template`. ## База данных и миграции - Перед изменением сущности проверить таблицу, `_sys_datatypes`, использующие её модули и предыдущие миграции. - Любое изменение схемы или системных метаданных оформлять новым `.sql` в `app/engine/migrations/`; уже применённые миграции не переписывать. - Имена новых миграций продолжать в существующем формате `YYYYMMDD-HHMM-description.sql` и обеспечивать уникальность имени. - Исполнитель миграций примитивно делит SQL по `;` перед переводом строки. Не добавлять процедуры, триггеры или конструкции с внутренними `;` без предварительной доработки/проверки runner. - SQL строить с приведением числовых значений через `(int)`/`intval()` и экранированием строк через `db_escape_string()`. Предпочитать методы `cobject`, когда они покрывают операцию. - Не использовать `REPLACE INTO`; для upsert применять `INSERT ... ON DUPLICATE KEY UPDATE` либо явные `UPDATE`/`INSERT`. - Геометрия зон хранится как MySQL spatial `POLYGON`. Сохранять действующий порядок координат и замыкать контур; проверять поиск точки через `ST_WITHIN`. - Не запускать миграции на production и не импортировать дампы без явного запроса. ## Синхронизация с МИС - `sync_doctors_and_zones.php` — потенциально разрушительная операция: она создаёт временные таблицы, очищает основные `pnd_zones`/`pnd_doctors`, переносит данные и удаляет временные таблицы. - Не запускать этот скрипт автоматически для проверки. Сначала использовать режим dry-run или отдельную тестовую БД и явно проверить подключения. - После миграции МИС рабочие слоты врачей находятся в `SimpleSchedule`; старую цепочку `Event`/`Action`/`ActionProperty_Time` для расписания не использовать. - Рабочее время дня вычислять по всем действующим амбулаторным слотам `SimpleSchedule`, независимо от `ticket`. Исключать удалённые, отключённые, сверхурочные и нулевые слоты, а также строки с `absence_reason`. - `SimpleSchedule.ticket` ссылается на `TicketInfo.id`; `NULL` означает свободный слот. Для синхронизации только рабочих часов `TicketInfo` не читать и пациентские данные не переносить. - ID врачей и участков сейчас совпадают с внешними ID старой МИС. Не менять эту семантику без миграционного плана. - Поле `pnd_doctors.schedule` содержит JSON вида `YYYY-MM-DD => {start, end}` либо `null`; при изменениях сохранять обратную совместимость формата. - Расписание формируется на 10 дней, включая текущий. Проверять границы дат, отсутствие приёма и часовой пояс `Europe/Moscow`. - Не добавлять новые реквизиты подключения в код. Обнаруженные hardcoded-пароли и API-ключи не копировать в логи, ответы, документацию или новые файлы; при отдельной задаче переносить их в переменные окружения. ## UI и шаблоны - Админка и публичная часть используют Bootstrap 4; не применять классы и `data-bs-*` из Bootstrap 5. - Использовать существующие jQuery/Bootstrap/Font Awesome 5 и визуальные паттерны соседних шаблонов. - Сохранять адаптивность крупного адресного поля, списка подсказок, модального результата и печати. - Для изменений карты проверять оба сценария: выбор адреса по координатам и клик по полигону. - Пользовательские и внешние строки не конкатенировать в HTML без экранирования. В Blade по умолчанию использовать `{{ ... }}`, а `{!! ... !!}` — только для заранее подготовленного доверенного содержимого. - Не коммитить скомпилированные файлы из `app/engine/*/bladetpl/cache/`, если задача прямо не требует обновления уже отслеживаемых артефактов. - После изменения перечня CSS/JS или исходной статики пересобрать include-файлы соответствующим `static_optimization.php` и проверить diff сгенерированных файлов. ## Кодировка и стиль - Все новые и изменённые текстовые файлы сохранять в UTF-8 без порчи русских строк. - В старых файлах уже встречается повреждённая кириллица. Не распространять её копированием и не делать массовое исправление кодировки вне отдельной задачи. - Следовать стилю ближайшего файла; не проводить широкий форматирующий рефакторинг вместе с функциональной правкой. - PHP-файлы проверять на синтаксис под PHP 7.4. Форматтер запускать только для файлов в области задачи и внимательно просматривать diff. ## Рабочие команды Из корня проекта: ```powershell docker compose up -d docker compose ps docker compose logs --tail=100 php docker compose exec php composer install docker compose exec php php -l engine/www/modules/site_index.php docker compose exec php sh -lc "cd engine/migrations && php _migrate.php" ``` Последнюю команду запускать только когда задача действительно требует применения миграций к выбранной локальной БД. Проверка синтаксиса всех изменённых PHP-файлов должна выполняться адресно. `app/php-cs-fixer.cmd` с `fix` изменяет много файлов, поэтому не запускать его по всему проекту без отдельного согласования. ## Минимальная проверка перед завершением - Просмотреть `git status --short` и `git diff`; убедиться, что изменены только файлы задачи. - Для каждого изменённого PHP-файла выполнить `php -l` в PHP 7.4 контейнере. - Для SQL проверить совместимость с MariaDB 10.6.21 и ограничения `_migrate.php`. - Для изменений публичного сценария вручную проверить: загрузку карты, подсказки адресов, поиск зоны, карточки врачей, пустое расписание, модальное окно и печать. - Для изменений полигонов проверить создание/редактирование/удаление в админке и попадание точки внутрь зоны на публичной странице. - Для cron сначала проверить dry-run/тестовую БД; убедиться, что временные таблицы и основные данные остаются согласованными при ошибке. - После массовых замен отдельно проверить русские строки на «кракозябры». - Не считать отсутствие автоматических тестов основанием пропустить адресную проверку.