Работы по сайту, CRM, ботам и интеграциям пошагово и постоянно сохраняются на этой странице.
Последнее обновление: Записей: 24
Безопасность и RBAC
Усилены границы уведомлений, заказов, интеграций и полномочий
Выполнено
Финальный аудит чтения и записи API/CRM выявил дополнительные строгие границы для уведомлений dashboard, приватности заказа, профиля курьера, делегирования полномочий сотрудников и публичных callback Instagram. Исправления опираются на серверные permissions, а UI больше не показывает и не вызывает действия без действующего права.
API уведомлений отдаёт только канал DASHBOARD и безопасные поля без recipient; аудитории admin, manager и receptionist разделены
Текст WebSocket-уведомления не транслируется: только код события уходит в комнату соответствующего permission
Колокольчик CRM без dashboard.view скрыт и не вызывает API уведомлений
Мастер получает только заказ, назначенный напрямую, через stage или task; ОТК — только заказы своей очереди и истории задач ОТК
Для мастера и ОТК сервер удаляет телефон/каналы/адрес клиента, delivery-details, payments и клиентские цены
Order search, карточка, allowed transitions, этапы и event feed используют одну row-level проверку; финансовые события не попадают в feed без права
Excel-экспорт привязан к reports.finance, PDF — к receipts.print, payment-link — к orders.finance, каталог и прайс — к price.view
Карточка заказа открывается после загрузки прав и показывает только разрешённые finance/status/assign/courier/payment/discount/document блоки
Приёмщик сохраняет список курьеров и заявки доставки; создание, редактирование и деактивация профиля курьера требуют routes.manage
Точка доставки проверяется DTO и service по существующему заказу, ISO-дате, слоту, координатам, stage и активному курьеру; завершённая точка не редактируется
Делегированный users.manage не может выдать роль или permission выше собственных; защищены SUPERADMIN и последний активный владелец
Instagram POST webhook закрыт без HMAC raw-body; public manual/mock fallback удалён, OAuth state хранится хешем, живёт 10 минут и одноразовый
Сервисные ключи PBX, ботов и tracking используют общее constant-time сравнение
Новый и сменяемый пароль валидируется как 8–128 символов на DTO и service; существующие логин и пароль не менялись
Успешно: 34 backend suites, 265/265; все production-сборки, Prisma validate, npm audit 0 и Flutter format/analyze/test
Production RBAC API-приёмка 19/19: проверены поля notification, scope/redaction мастера, 403 приёмщика и unsigned webhook без записи в БД
Общая read-only production-приёмка 17/17: работают API/DB health, HTTPS и fail-closed интеграции
Browser smoke через реальный HTTPS 73/73: разрешённые и запрещённые страницы 8 активных ролей, persistence resize заказа и 3 публичные страницы
API, CRM, сайт и оба бота online в PM2; milestone виден в публичном отчёте, код отправлен в удалённую Git-ветку
Roadmap P1–P3
Завершены мобильный рабочий поток, порядок маршрута и удобство таблицы
Выполнено
Мастера получили в мобильном приложении приём этапа, возврат с причиной, безопасное внутреннее фото из камеры или галереи, завершение только после фото и просмотр собственного заработка. CRM атомарно сохраняет drag-and-drop порядок внутри маршрута, а ширина колонок заказов меняется мышью, касанием или клавиатурой и сохраняется в браузере. Одновременно закрыто несоответствие ownership, позволявшее сотруднику другой роли обратиться к действию чужой задачи или курьерской точки.
Действия этапа в мобильном приложении используют существующую role/owner-защиту backend и безопасное декодирование/перекодирование изображений
Экран заработка за месяц или всё время получает только профиль мастера из JWT; границы дат строго проверяются как полные локальные дни
Production API задан по HTTPS; release-manifest запрещает cleartext-трафик и не содержит ненужного разрешения геолокации
Android scaffold, Gradle wrapper и pubspec.lock добавлены в Git для воспроизводимой сборки; local property, key и keystore остаются секретными
Release AAB проверен с настоящим non-debug upload-key; при неполной настройке signing release-сборка завершается fail-closed
Внутренний порядок маршрута принимает только полный актуальный список UUID и записывает все sortOrder одной транзакцией
Точки TO_MASTER/FROM_MASTER включены в алгоритм и карту; завершение продолжает нужный stage и не переводит заказ ошибочно в статус «выдан»
Callback внешнего мастера сделан retry-safe: открытая задача не дублируется, этап повторно не уходит в ОТК, а при ошибке callback статус точки компенсируется
Ручной перенос не отменяет выбранного курьера повторным запуском алгоритма; старый и новый списки последовательно нормализуются
Действия курьера защищены по роли, владельцу точки, статусу, причине и сумме; чужой маршрут и action закрыты для остальных ролей tasks.my
Колонки заказов меняются в пределах 64–480 px мышью/клавиатурой, повреждённые значения storage очищаются, доступен reset
Успешно: 27 backend suites, 240/240; Flutter format/analyze/test, все production-сборки, Prisma validate и npm audit 0
Production read-only acceptance 17/17: подтверждены API health, БД, HTTPS, auth и fail-closed интеграции
Browser smoke через реальные HTTPS-домены 24/24: 20 страниц CRM, resize→reload persistence и 3 публичные страницы
Production API мастера: earnings 200, телефон клиента скрыт; чужие route/action дают 403, неполный order отклонён 400 без записи в БД
API, CRM, сайт и оба бота online в PM2; новый milestone виден в публичном отчёте, commit отправлен в удалённую Git-ветку
Production-приёмка
Доступная без внешних данных часть roadmap передана в production
Выполнено
Сайт, CRM, API, боты, media CMS, зависимости и fail-closed интеграции прошли единый финальный цикл приёмки. Старые acceptance/smoke-скрипты, записывавшие данные в production, заменены read-only проверками, устаревшие заявления о mock и открытых LAN-портах исправлены. Оставшиеся пункты требуют только внешних credentials, реальных медиа или sudo-доступа владельца.
Успешно: 230/230 backend-тестов, четыре production-сборки и npm audit 0
Read-only production acceptance: 17/17; тестовые user, lead, order, payment или call не создавались
Read-only browser smoke через реальные HTTPS-домены: 20 страниц CRM и 3 публичные, успешно 23/23
CRM→API→public media E2E: PNG→WebP, настоящий MP4, публичная выдача и полный cleanup БД/файлов
Два старых 4×4 тестовых PNG без связи с БД перемещены в восстанавливаемую Корзину; БД и каталог галереи чисты
Prisma 6.19.3 работает в production: health, 15 migrations и нулевой schema-diff
Финальный atomic snapshot: 339 объектов БД и 9 медиа; изолированный restore: 45 таблиц и 9/9 медиа
API, CRM, сайт и оба бота online в PM2; публичный сайт, отчёт и CRM отвечают HTTP 200
3000/3001/3002 только на 127.0.0.1; payment mock/webhook 503, PBX без ключа 403, delivery 503 без изменения БД
Все commits кода и отчёта отправлены в удалённую Git-ветку
Слой данных
Prisma контролируемо обновлена с 5.22 до 6.19.3
Выполнено
Prisma ORM и Client переведены на единую версию 6.19.3. Официальный список breaking changes проверен по schema и коду, CLI-конфигурация перенесена в отдельный prisma.config.ts. К production-БД не применялось неизвестных изменений schema.
Node 22.14 и TypeScript 5.6 соответствуют требованиям Prisma 6
Не найдены Bytes-поля, старый NotFoundError, middleware $use и неявные PostgreSQL many-to-many связи
Prisma Client 6.19.3 успешно сгенерирован, schema валидна
Все 15 миграций production-БД актуальны, schema-diff: “No difference detected”
prisma.config.ts детерминированно задаёт root .env, schema, migration path и seed-команду
Пройдены 230 backend-тестов, все production-сборки и аудит с 0 уязвимостей
Prisma 7 одновременно меняет ESM, output клиента, PostgreSQL driver adapter и pool-семантику, поэтому вынесена в отдельную архитектурную миграцию
Безопасность интеграций
Delivery, АТС и платёжные адаптеры переведены в честный fail-closed режим
Выполнено
Пока нет договора и проверенного реального адаптера, production больше не создаёт фиктивный трек Yandex, запись «звонок отвечен» или результат упрощённого webhook Payme/Click/Uzum. CRM явно показывает состояние интеграции; собственные курьеры, подтверждённые вручную звонки и наличный/терминальный поток продолжают работать.
DELIVERY_PROVIDER в production установлен в disabled; mock возможен только в test/development
Один токен Yandex без реального API-вызова не может перевести задачу в статус «в пути»
Payme, Click и Uzum сохранены в CRM, показаны как «не подключены» и недоступны для выбора
Упрощённые методы invoice/webhook реальных платежей удалены и закрыты до contract-тестов
Ключ АТС отделён от bot-key, имеет минимум 32 символа и принимается только через заголовок X-PBX-Key
Click-to-call без АТС больше не создаёт ложный ANSWERED; открывается набор номера устройства
Безопасность credentials
Безопасно ротированы production JWT и ключ внутреннего сервиса
Выполнено
Строгая проверка после deploy обнаружила, что в старой конфигурации сохранился шаблон ключей, характерный для development. Без публикации значений они были атомарно заменены отдельными криптографически случайными ключами; все сервисы одновременно перезагружены с новой конфигурацией. Ради безопасности прежние сессии CRM аннулированы, логин и пароль не менялись.
JWT и ключ bot-service раздельно созданы из 48 криптографически случайных байт
Замена выполнена через временный файл и atomic rename без вывода значений в терминал
Validator теперь отклоняет шаблоны local/development/sample/test и совпадение двух ключей
Проверено без показа значений, что активный процесс API загрузил именно обновлённые ключи
API, CRM, сайт и оба Telegram-бота online; health и публичные страницы отвечают 200
Основной сайт и CMS
Сайт дополнен, в CRM добавлено безопасное управление реальными медиа
Выполнено
На главную добавлены направления услуг, советы по уходу, удобная навигация, блок видео реальных работ, SEO structured data и улучшения accessibility. CRM теперь управляет текстами RU/UZ, парами «до/после», их порядком и видео процесса. Пока подтверждённых реальных медиа нет, сайт честно помечает текущую графику как иллюстрацию.
Главная дополнена 6 направлениями услуг, 4 советами по уходу и понятными CTA
В CRM создано управление двуязычными текстами сайта, галереей и видео
Изображения галереи декодируются на сервере, очищаются от EXIF/метаданных, уменьшаются до 2000 px и переводятся в WebP
Видео процесса принимается только по сигнатуре MP4/WebM, под UUID-именем и с лимитом 30 МБ
Для публикации финального фото заказа требуется реальное фото «до» и клиентский уровень видимости медиа
Проверены URL, координаты карты, lazy-loading, skip-link для клавиатуры, JSON-LD и двуязычные alt/aria-тексты
Успешно пройдены 222 backend-теста, все production-сборки и аудит зависимостей; уязвимостей: 0
Безопасность зависимостей
Next.js и NestJS контролируемо обновлены до безопасных версий
Выполнено
Сайт и CRM переведены на Next.js 15.5.20, API — на NestJS 11.1.28 и линию Express 5. Каждое breaking-изменение адаптировано в коде; аудит framework, upload и транзитивных пакетов доведён до нуля уязвимостей.
Исходный npm audit: 29 записей; итоговый аудит: 0
Все публичные страницы адаптированы к async API route-параметров Next.js
Peer-пакеты NestJS объединены в единый dependency-граф 11.1.28
Установлена production-линия Multer 2.2 и Express 5
Срок JWT проверяется в строгом формате и преобразуется в безопасное числовое значение
Успешно пройдены 216 backend-тестов и production-сборки всех четырёх приложений
Границы сервера
Закрыты внутренние порты и усилена production-конфигурация
Выполнено
API, CRM и сайт теперь слушают только loopback-интерфейс сервера; единственным внешним входом остаётся Nginx. PM2 детерминированно загружает root env и принудительно задаёт production, а backend не запускается с опасной конфигурацией.
Порты 3000, 3001 и 3002 слушают только адрес 127.0.0.1
NODE_ENV=production проверен у всех пяти сервисов PM2
Удалены development-fallback для JWT и внутренних сервисных ключей
Production CORS сокращён до официальных HTTPS-origin
Публичный домен возвращает 404 для внутренних stage-медиа и 200 для галереи
CSP/headers и границы uploads для Nginx готовы в Git; применение требует root-доступ сервера
Резервное копирование
Внедрены атомарный backup БД и медиа и реальный restore-тест
Выполнено
Ежедневная задача systemd объединяет PostgreSQL и локальные медиа в единый версионированный snapshot, проверяет SHA-256 и применяет daily/weekly/monthly retention. Еженедельный тест восстанавливает копию в отдельную временную БД и каталог.
В реальном snapshot сохранены 339 объектов БД и 11 медиафайлов
Изолированный тест успешно восстановил 45 таблиц и все 11 медиафайлов
Сервисы systemd backup и restore повторно проверены с exit-code 0
Добавлены lock от параллельного запуска и атомарный staging
Offsite не запускается без полного набора данных; готовый поток шифрует AES-256 и проверяет обратную расшифровку
Безопасность входа
Безопасно восстановлен SUPERADMIN-доступ владельца системы
Выполнено
После подтверждения владельца для единственной активной учётной записи SUPERADMIN установлен новый сильный временный пароль. Секретные данные не добавлялись в отчёт или код.
Сброс применён только к одной точно найденной активной учётной записи SUPERADMIN
Операция записана в audit-log сервера без секретных данных
Новые данные успешно проверены через реальный API входа
Безопасность медиа
Все потоки загрузки файлов переведены на единые безопасные правила
Выполнено
Медиа этапов, клиентов, галереи, Telegram и звонков больше не доверяют присланному имени или MIME. Сервер проверяет тип по содержимому, создаёт безопасное UUID-имя и применяет строгий лимит размера.
Изображения принимаются только с сигнатурой JPEG, PNG или WebP
Фото этапа может загрузить только назначенный мастер или администратор
Аудио проверяется и хранится только как MP3, WAV, OGG или M4A
Записи АТС загружаются только с отдельно разрешённого HTTPS-хоста, без redirect и до 50 МБ
Документы Telegram хранятся в неисполняемом бинарном формате, исходное имя — только для безопасного отображения
Локальный snapshot БД+медиа, retention и реальный restore-тест завершены. Осталось включить AES-256 offsite-копию после получения внешнего S3 endpoint, bucket, access key и отдельного пароля шифрования.
БД и медиа включены в единый атомарный цикл копирования
Дневное/недельное/месячное хранение работает
Тест восстановления выполнен без воздействия на production-данные
Данные доступа к внешнему storage пока отсутствуют на сервере
Безопасность сервера
Усиление портов, security-заголовков и production-конфигурации
В работе
Loopback-порты, строгая production env-проверка и граница публичных медиа уже работают. Конфигурация CSP и дополнительных заголовков Nginx готова, но для установки в `/etc/nginx` требуется root-доступ.
Состояние портов и firewall повторно проверено
API, CRM и сайт переведены на loopback и прошли smoke-тест
Конфигурация Nginx подготовлена с rollback через Git
Осталось: установка с root, nginx -t, reload и smoke-тест заголовков
Технический долг
Контролируемое обновление framework и библиотек
Выполнено
Next.js, NestJS, Express, Multer и транзитивные пакеты обновлены до безопасных линий; миграция Prisma 6.19.3 завершена со schema-diff. Уязвимостей в аудите не осталось. Prisma 7 вынесена в безопасный отдельный цикл из-за архитектурных изменений ESM и driver-adapter.
29 записей аудита сокращены до 0
Миграция Next.js и NestJS завершена с тестами и build
Миграция Prisma 6.19.3 завершена: 15 актуальных migrations и нулевой schema-diff
Зафиксирована безопасная граница отдельной архитектурной миграции Prisma 7
Основной сайт
Наполнение, развитие и улучшение удобства Restoria.uz
В работе
База контента, UX, SEO и CMS сайта завершена. Безопасный технический поток галереи и видео готов; оставшийся контентный этап — загрузить через CRM реальные фото «до/после» и видео процесса с разрешением клиентов.
Дополнены услуги, цены, сроки, уход, CTA Telegram/телефон и путь к отслеживанию
Готово управление RU/UZ-контентом, WebP-галереей, video poster и видео процесса из CRM
Проверены SEO structured data, lazy-loading и основные требования accessibility
Осталось: загрузить одобренные владельцем реальные медиа с описанием и категорией
Интеграции
Подключение реальных платёжных провайдеров и АТС по договору
В работе
Fail-closed защита production завершена: неподключённые Payme, Click, Uzum, Yandex Delivery и АТС не создают фиктивный результат. Оставшийся внешний этап — договоры с выбранными провайдерами, официальные credentials, sandbox и contract-тесты подписи/idempotency.
Неподключённые провайдеры видны в CRM, но недоступны для выбора
Production mock/fallback для payments, delivery и АТС закрыт
Осталось: официальные credentials провайдеров и sandbox contract-тесты
Защита данных
Защищены realtime-канал и границы публичного API
Выполнено
WebSocket CRM проверяет JWT, активность аккаунта и индивидуальные права. События отправляются только в соответствующие permission-room. Публичный endpoint текстов возвращает только необходимые сайту поля org.
WebSocket без токена не получает события
Событие звонка получают только роли с правом просмотра клиентов
Настройки AI и каналов исключены из public texts
Демо-отзывы и внутренние поля review исключены из публичного ответа
Безопасность Telegram
Защищены идентификация ботов и поток медиа
Выполнено
Клиентский и служебный боты теперь связывают профиль только через собственный Telegram-контакт пользователя. Существующая привязка не заменяется незаметно. Фото больше не сохраняются URL-адресом с токеном Telegram — они проверяются и копируются в хранилище Restoria.
Владелец контакта проверяется по Telegram user ID
К endpoint дохода сотрудника добавлена проверка сервисного ключа
Задачи и точки курьера проверяются на принадлежность исполнителю
Закрытие многоэтапной работы через бот без обязательного фото заблокировано
Тип изображения определяется по реальной сигнатуре байтов, а не имени файла
Безопасность платежей
Тестовые онлайн-платежи закрыты в production
Выполнено
Mock-ссылка и вебхуки без проверенной подписи больше не могут подтверждать оплату в production. До полноценных тестов подписи и транзакций реальных адаптеров Payme/Click система остаётся fail-closed.
Production PAYMENT_PROVIDER переведён в disabled
Mock-режим работает только вне production
В CRM провайдеры видны как неподключённые и заблокированы; Telegram-бот не выдаёт ссылку
С сайта удалены несоответствующие обещания Payme/Click
Безопасность входа
Закрыт публичный вход демо-администратора
Выполнено
С формы входа CRM удалены готовые телефон и пароль. Старый публично известный аккаунт отключён, его прежние сессии стали недействительными, а пароль заменён невосстанавливаемым значением.
Перед блокировкой проверено наличие другого активного SUPERADMIN
Старый демо-вход возвращает 401 на уровне API
Production-данные входа удалены из seed- и тестовых скриптов
Операция записана в серверный audit-log
Прозрачность
Создан постоянный отчёт о развитии
Выполнено
Внедрён постоянный двуязычный журнал, в котором по шагам сохраняются безопасные изменения сайта, CRM и интеграций.
Источник отчёта сохраняется в истории Git
Страница работает на русском и узбекском языках
Секреты и инструкции по эксплуатации уязвимостей не публикуются
Безопасное начало
Начат контролируемый процесс изменений
Выполнено
Остановлена автоматическая отправка непроверенного кода. До изменений созданы снимки базы данных и локальных медиа, работа вынесена в отдельную ветку.
Production-сервисы продолжили работать
Резервная копия БД успешно создана
Снимок медиа проверен контрольной суммой
Аудит
Проведён полный read-only аудит сайта и CRM
Выполнено
Проверены архитектура, API, конвейер заказов, боты, платежи, маршруты, резервное копирование, SEO и конфигурация сервера. Исправления расставлены по уровню риска.