Перейти к основному содержимому

GWPTD Analytics — mp.hyp.ru

Аналитический дашборд продаж Global Watch Parts Trading на маркетплейсах. Laravel 12 + Filament 3 + MySQL 8.0, два интерфейса на одном репозитории: /new (целевой) — Python Data API + kernel ETL, и /admin (legacy, заморожен).

Перед любой правкой кода — AGENTS.md: пайплайн local→s3→s2-по-OK, канон «всё через 1С», где что лежит. Этот README — только навигация; детали архитектуры и стратегии см. по ссылкам ниже.

Маркетплейсы

Реестр площадок, их идентификаторов и схем работы порождается из кодаdocs/backend/generated/MARKETPLACES-AND-IDENTITY.md. Там же порядок приведения внешних идентификаторов к нашему артикулу.

Полный перечень эндпоинтов сбора (81 спека: метод, путь, окно, постраничность, ограничения по частоте) — docs/backend/generated/ENDPOINTS-CATALOG.md.

Здесь список не дублируется намеренно: рукописная копия расходится с кодом — прежняя таблица в этом файле показывала одиннадцать площадок, тогда как в ядре их десять, а mp_id=7 отсутствует вовсе.

Стек

  • Laravel 12 + Filament 3 — один Laravel-репозиторий, два деплоя интерфейса (INTERFACE_VARIANT=admin|new, config/gwptd.php).
  • PHP 8.4/8.5, PhpSpreadsheet, Guzzle
  • Python 3.11 (data_api/, FastAPI) — HTTP API поверх kernel-слоя, читает gwptd_kernel.*
  • Python (marketplace-collector-v3/) — универсальный ProductSpec runtime: next_collector.pygwptd_intakekernel/etl/ (build_fact_*) → gwptd_kernel
  • MySQL 8.0lamoda_reports (legacy-схема, общая для обоих интерфейсов) + gwptd_intake / gwptd_kernel / gwptd_monitoring (новый контур, ADR-0008)
  • Docker (PHP-FPM + Nginx + Supervisor)
  • Google Drive API — синхронизация xlsx-отчётов (legacy, консервируется — не покрыто API)

Целевая архитектура — new-first (стратегия владельца, 2026-07-02)

Инвестируем в новое, старое замораживаем и в итоге выключаем.

  • /new — целевой интерфейс: 59 PageSpec и специализированные workflow-страницы читают данные через App\Services\DataApi\DataApiClient → HTTP → Python Data API (data_api/) → gwptd_kernel.*, наполняемый ETL из marketplace-collector-v3/kernel/etl/. Единственное текущее исключение — gwptd_kernel.shipments пишется из Laravel напрямую (осознанно, см. ADR-0014 (выведен в архив: docs/_archive/docs-archive-2026-08-legacy.zip)).
  • /admin — старый интерфейс (RatingService, TurnoverCalculationService, BitmapService, legacy-коллектор app/Services/Marketplace/* + marketplace-collector/, старые *Resource/*Page) — заморожен: не развивается, не чинится сверх P0-безопасности, оставлен только для сверки «было→стало». Старые страницы и Resources гейчены трейтом App\Filament\Concerns\OldInterfaceOnly (canAccess() только при INTERFACE_VARIANT=admin) — физически недоступны в /new.
  • Дальше: после контрольного окна сверки kernel↔legacy (ADR-0006: расхождение <0.5% × 14 дней) — выключение старого интерфейса и коллектора; в следующих итерациях — удаление старого кода из кодовой базы. База данных lamoda_reports (auth/users, warehouse_limits, часть shared-сервисов) переживает выключение интерфейса — cutover БД отдельный, не одномоментный с UI.
  • Полная стратегия, порядок волн и что уже сделано → docs/remediation/README.md
    • docs/remediation/_execution-log.md (выведен в архив: docs/_archive/docs-archive-2026-08-history.zip).

Быстрый старт (локально)

# 1. SSH-туннель к MySQL (Hetzner)
ssh -f -N -L 3307:127.0.0.1:3306 root@10.8.0.1

# 2. Установка
composer install && cp .env.example .env
php artisan key:generate && php artisan migrate

# 3. Создать пользователя
php artisan make:filament-user

# 4. Запуск
php artisan serve --port=8501
# Дашборд: http://localhost:8501/admin

Деплой S3 Next

Новый интерфейс опубликован через https://mp.hyp.ru/new* на S3. Перед любым действием сверять точный live SHA через mcp__gwptd__repo_status; S2 остаётся read-only production oracle, пока владелец отдельно не разрешит изменение.

# S3: только root-owned deploy wrapper и SHA, уже опубликованный в origin.
ssh s3-int /usr/local/sbin/gwptd-next-deploy --expected-sha <40-hex-commit>

# После deploy: read-only проверка checkout.
ssh s3-int 'cd /opt/gwptd-analytics/repo && git status --short --branch && git rev-parse HEAD'

Не использовать ручной git pull, bash deploy.sh, docker compose up, artisan migrate или ручную замену cron на S3. Эти действия обходят rollback, deploy lock и MCP reindex. S2 deploy возможен только по отдельному явному OK владельца.

Artisan-команды

php artisan mp:collect               # Остатки + заказы (все МП)
php artisan mp:collect --all # Всё: 8 типов данных
php artisan mp:collect --mp=ozon # Один МП
php artisan rating:calculate # Рейтинг
php artisan shipment:calculate --mp=NAME # Расчёт отгрузки
php artisan turnover:calculate # Оборачиваемость
php artisan import:reports [path] # Импорт XLSX
php artisan sync:supplier # Каталог gwptd.com

Документация

Вход — docs/README.md. Там документация разделена по роду: что порождается из кода, что написано человеком и охраняется проверкой, что выведено в архив. От рода зависит, можно ли файл править руками.

файлкогда читать
AGENTS.mdвсегда первым, до любого действия в коде — правила, границы, что заморожено
docs/README.mdвход в документацию — три рода, канон, генераторы, архив
for-ai-agents/START-HERE.mdпервая сессия ИИ-агента: порядок поиска, куда класть правку, грабли
docs/backend/generated/COLUMN-REGISTRY.md + generate_column_registry.pyреестр колонок и их происхождения — когда нужен точный разбор схемы
docs/remediation/HANDOFF-2026-08-04.mdпервым в новой сессии — состояние работ
docs/remediation/PLAN-SVEDENIE-2026-08-03.mdчто осталось сделать и что ждёт решения владельца
docs/remediation/POSTDEPLOY-CHECKLIST.mdдевять проверок после выкладки — после каждого S3 deploy
docs/remediation/OWNER-DECISIONS-PENDING.md16 решений, ожидающих владельца — перед owner-gated работой
docs/domain/до правки бизнес-логики — формулы, запреты, семантика статусов
docs/domain/METHOD-TABLE-REVIEW.mdметод проверки таблиц с данными — перед разбором качества и смысла данных
CLAUDE.mdобщая инфраструктура Laravel и прежний /admin-слой
data_api/README.mdработа с Python Data API
marketplace-collector-v3/README.mdколлектор и kernel ETL
scripts/docs/check_doc_links.pyсторож локальных Markdown-ссылок — после добавления или переноса документа
marketplace-collector-v3/scripts/check_intake_schema_contract.pyконтракт ProductSpec ↔ intake-схема — при изменении ProductSpec или миграций, с доступом к БД
marketplace-collector-v3/tests/test_returns_sign_invariant.pyсторож знака возвратов, включая известные xfail-пути — при правке проекции возвратов

Остальное перечислять здесь незачем: список файлов сам устаревает — это и была причина, по которой таблица разрослась до тридцати строк с мёртвыми ссылками.

Архитектура (кратко)

/new (целевой контур):

Маркетплейсы API

specs/products/*.yaml → next_collector.py → gwptd_intake.* (сырой слой)

marketplace-collector-v3/kernel/etl/* → gwptd_kernel.* (dim_*/fact_*, build_fact_rating/turnover/...)

data_api/ (FastAPI, HTTP/JSON) ← единственная дверь чтения kernel-данных

app/Services/DataApi/DataApiClient → PageSpec/SpecDrivenApiPage (Filament) → /new

https://mp.hyp.ru/new

Исключение из границы «PHP читает kernel только через Data API»: ShipmentCalcApiPage::saveBatch() пишет напрямую в gwptd_kernel.shipments (узаконено ADR-0014 (выведен в архив: docs/_archive/docs-archive-2026-08-legacy.zip)).

/admin (legacy, заморожен):

Маркетплейсы API

MarketplaceCollectorService (PHP artisan mp:collect) + Python marketplace-collector/

MySQL lamoda_reports: mp_stocks_daily, mp_orders_daily, mp_finances, ...

Services: RatingService, ShipmentCalculator, TurnoverCalculationService

Filament Dashboard (OldInterfaceOnly-гейт) + REST API (/api/*)

https://mp.hyp.ru/admin (nginx + Basic Auth + HSTS)

Override-паттерн (legacy): файлы в overrides/ перекрывают app/ через Docker volume mount. Изменения в логике старого коллектора вносить также в Python-коллектор (/opt/marketplace-collector/). Новый коллектор (marketplace-collector-v3/) от этого паттерна не зависит.

Безопасность

  • Nginx Basic Auth: задаётся через .env.production (не коммитятся в репо)
  • HSTS: max-age=31536000; includeSubDomains
  • Все credentials в .env (не в коде); прод-connection'ы без root/root-дефолтов (epic-09)
  • Старые SQL-инъекционные *Resource закрыты гейтом OldInterfaceOnly (недостижимы в /new)
  • Session UUID валидация в ChatController

Обновлено: 2026-07-03 | Стратегия: new-first (см. docs/remediation/)