From 9835bb0ef8235572a2dd33b180bf97de39823a6e Mon Sep 17 00:00:00 2001 From: Panfilov Konstantin Date: Sat, 17 Oct 2026 10:56:08 +0300 Subject: [PATCH] feat(utm): propagate join focus mode --- README.md | 27 +++++++----- config.json | 7 +++ tests/check-utm-redirect-contract.php | 59 ++++++++++++++++++++++++++ tests/check-versioned-stage-config.php | 1 + 4 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 tests/check-utm-redirect-contract.php diff --git a/README.md b/README.md index bd6c7d9..5da2c52 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,11 @@ - `rnd` — случайное значение по весам (`weights`), так делится трафик между вариантами; - неизвестное значение отбрасывается, отсутствующее — заменяется на `default`. -Ненастроенные параметры (`utm_source`, `keyword`, `subid` и любые другие) проходят как есть. Все метки уходят дальше -в адрес сайта: сайт сохраняет их на воронку и шлёт в Keitaro. +Ненастроенные параметры (`utm_source`, `keyword`, `subid` и любые другие) проходят как есть. Перед переходом +Preland всегда формирует полный resolved-набор своих восьми меток: явное допустимое значение остаётся, `rnd` +разрешается по весам, отсутствующее получает `default`. Вместе с внешними рекламными параметрами этот набор +уходит в `claim`, а затем сайт переносит его в `upscale`; ни один из восьми параметров не должен пропадать только +потому, что был назначен default. | Метка | Что задаёт | Где | |---|---|---| @@ -30,6 +33,7 @@ | `bchoice` | попап выбора банка (`a` — показать) | сайт, оплата (#44) | | `chb` | галочки согласия на странице оплаты (`no` — не обязательны) | сайт, оплата | | `tp` | группа тарифов | сайт, cpanel «Группы тарифов (tp)» | +| `focus` | первоначальная область лупы Join: `center`/`face` | сайт, cpanel после `tp` | ### Загрузка и переход на сайт @@ -61,7 +65,7 @@ | `requisites.html` | реквизиты для подвала (HTML), если в `config.json` нет `requisites`. Без обоих — **заглушка «ИП Иванов Иван Иванович»** из `template.php` | | `images/`, `fonts/`, `favicon/`, `*.css` | статика; `style.min.css` встраивается в страницу | | `.htaccess` | только сроки кэширования статики (Apache) | -| `config.json` | единственный версионируемый рабочий конфиг всех прилендов: точная проверенная конфигурация stage `zoomstage.online`; каждый deploy доставляет его на целевой хост | +| `config.json` | зафиксированный Git-снимок актуального stage-конфига; runtime-файл хоста является источником истины и обычным deploy не заменяется | ### `config.json` @@ -87,10 +91,10 @@ git clone http://git.dira89kv.beget.tech:3000/anton/preland.git && cd preland # дальше — загрузка на хостинг: rsync/scp по SSH или FTP-клиент ``` -3. **Конфиг и реквизиты.** Рабочий `config.json` уже лежит в репозитории и обязателен к доставке на каждый - приленд. Его не заменяют локальным вариантом и не исключают из синхронизации. Реквизиты задаются ключом - `requisites` в нём либо runtime-файлом `requisites.html`. 2026-10-05 конфиг пропал после заливки, - и преленд слал загрузку на собственный домен; это больше не допускается. +3. **Конфиг и реквизиты.** Runtime `config.json` создаётся при первичной настройке хоста и не заменяется + обычной синхронизацией. Менять в нём можно только ключи, явно согласованные в задаче; после такого выпуска + актуальный stage-снимок фиксируется в Git. Реквизиты задаются ключом `requisites` либо runtime-файлом + `requisites.html`. 4. **nginx без Apache** (если хостинг не обрабатывает `.htaccess`): ```nginx server { @@ -137,12 +141,13 @@ 1. Домен и HTTPS — как в «Деплой на произвольный домен», шаг 1. 2. Секреты `<ПРЕФИКС>_FTP_HOST`, `<ПРЕФИКС>_FTP_USER`, `<ПРЕФИКС>_FTP_PASS` (Gitea → настройки репозитория → Actions → секреты; порт 21, FTP с TLS). В коде реквизитов нет. -3. Никаких ручных конфигов не создавать: единственный `config.json` приезжает вместе с кодом. -4. Запись в `matrix` — коммит в `main`, автодеплой выкатит все цели вместе с конфигом. +3. Один раз создать runtime `config.json` с нужными значениями: последующие обычные deploy его не перезапишут. +4. Запись в `matrix` — коммит в `main`, автодеплой выкатит код на все цели, сохраняя их конфиги. **Что заливается.** Каждый deploy получает файлы репозитория (`git ls-files`), кроме служебных -(`.gitea/`, `README.md`, `.gitignore`) и живущего на хостинге `requisites.html`. Единственный -версионируемый `config.json` всегда доставляется вместе с кодом. +(`.gitea/`, `README.md`, `.gitignore`), а также живущих на хостинге `requisites.html` и `config.json`. +Перед разрешённым изменением конкретного конфигурационного ключа workflow считывает текущий host-файл и +патчит только этот ключ. На хостинге ничего не удаляется: файлы, убранные из репозитория, удалять вручную. **Проверка после заливки.** На странице цели должен быть адрес загрузки на сайте, а не на самом преленде (иначе нет diff --git a/config.json b/config.json index 62063b9..c31a200 100644 --- a/config.json +++ b/config.json @@ -57,6 +57,13 @@ "2": 1 }, "default": "1" + }, + "focus": { + "weights": { + "center": 1, + "face": 0 + }, + "default": "center" } } } diff --git a/tests/check-utm-redirect-contract.php b/tests/check-utm-redirect-contract.php new file mode 100644 index 0000000..a068466 --- /dev/null +++ b/tests/check-utm-redirect-contract.php @@ -0,0 +1,59 @@ + 'stage-ad', + 'subid' => 'click-42', + 'key' => 'must-not-replace-client-key', +]; +$_SERVER['HTTP_HOST'] = 'zoomstage.online'; + +ob_start(); +require dirname(__DIR__) . '/index.php'; +$html = (string) ob_get_clean(); + +if (!preg_match('/const redirectUrlUtm = (.+);/', $html, $match)) { + fwrite(STDERR, "FAIL: Preland не отдал redirectUrlUtm.\n"); + exit(1); +} + +$query = json_decode($match[1], true); +if (!is_string($query)) { + fwrite(STDERR, "FAIL: redirectUrlUtm должен быть JSON-строкой.\n"); + exit(1); +} + +parse_str($query, $params); +$expected = [ + 'indpic' => '1', + 'theme' => 'dark', + 'degr' => '1', + 'registration' => 'after', + 'bchoice' => 'a', + 'chb' => 'b', + 'tp' => '1', + 'focus' => 'center', + 'utm_source' => 'stage-ad', + 'subid' => 'click-42', +]; + +ksort($params); +ksort($expected); + +if ($params !== $expected) { + fwrite(STDERR, "FAIL: claim URL обязан нести все resolved UTM и внешние параметры.\n"); + exit(1); +} + +if (isset($params['key'])) { + fwrite(STDERR, "FAIL: внешний key не должен подменять одноразовый ключ загрузки.\n"); + exit(1); +} + +fwrite(STDOUT, "OK: preland redirects resolved UTM and external parameters\n"); diff --git a/tests/check-versioned-stage-config.php b/tests/check-versioned-stage-config.php index 6664953..dc04f3d 100644 --- a/tests/check-versioned-stage-config.php +++ b/tests/check-versioned-stage-config.php @@ -25,6 +25,7 @@ if (!is_array($config)) { 'bchoice' => ['a' => 1, 'b' => 0, 'default' => 'a'], 'chb' => ['a' => 1, 'b' => 0, 'default' => 'b'], 'tp' => ['1' => 0, '2' => 1, 'default' => '1'], + 'focus' => ['center' => 1, 'face' => 0, 'default' => 'center'], ]; if (($config['host'] ?? null) !== $expected['host']) {