Files
preland/README.md
T
Panfilov Konstantin 356eeb9806
deploy-preland / deploy barbariskatest (push) Skipped
deploy-preland / deploy zoomstage.online (push) Successful in 33s
deploy-preland / deploy zoompixel.online (push) Skipped
deploy-preland / deploy zoompixel.ru (push) Skipped
fix(config): enable explicit face focus
2026-10-17 19:25:05 +03:00

185 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Преленд zoomzilla
Одностраничный лендинг перед основным сайтом (`zoomzilla.ru`): посетитель с рекламы выбирает фото прямо на
преленде, файл сразу уходит в API сайта, а сам посетитель переходит на сайт — на страницу обработки этого фото.
Варианты страницы и сайта (A/B) задаются метками в адресе. Код — обычный PHP без фреймворка и сборки; переводы —
маленькая заглушка `Yii::t` в `i18n.php`.
Боевой экземпляр: `https://preland.anton.barbariskatest.ru` (хостинг beget). Пример ссылки входа:
`https://preland.anton.barbariskatest.ru/?indpic=1&theme=dark&degr=2&registration=after&bchoice=a&tp=1&utm_source=test&subid=CLICK1`.
## Как работает
### Метки
`index.php` разбирает параметры адреса по разделу `utm` из `config.json`. Для каждой настроенной метки:
- значение из адреса принимается, если оно есть в `weights`;
- `rnd` — случайное значение по весам (`weights`), так делится трафик между вариантами;
- неизвестное значение отбрасывается, отсутствующее — заменяется на `default`.
Ненастроенные параметры (`utm_source`, `keyword`, `subid` и любые другие) проходят как есть. Перед переходом
Preland всегда формирует полный resolved-набор своих восьми меток: явное допустимое значение остаётся, `rnd`
разрешается по весам, отсутствующее получает `default`. Вместе с внешними рекламными параметрами этот набор
уходит в `claim`, а затем сайт переносит его в `upscale`; ни один из семи параметров не должен пропадать только
потому, что был назначен default.
| Метка | Что задаёт | Где |
|---|---|---|
| `indpic` | картинка-пример на преленде | корневой каталог сета `/1/`, `/2/` и т. д. |
| `theme` | `light` / `dark` | преленд и сайт |
| `degr` | пресет ухудшения превью «До» | сайт (#42) |
| `registration` | `before` — PIN до оплаты, `after` — после | сайт, страница результата |
| `bchoice` | попап выбора банка (`a` — показать) | сайт, оплата (#44) |
| `chb` | галочки согласия на странице оплаты (`no` — не обязательны) | сайт, оплата |
| `tp` | группа тарифов | сайт, cpanel «Группы тарифов (tp)» |
| `focus` | первоначальная область лупы Join: `center`/`face` | сайт, cpanel после `tp` |
### Загрузка и переход на сайт
1. Браузер проверяет файл: изображение, не больше 6000 px по большей стороне.
2. XHR `POST https://<host>/api/images/public/create` (`multipart/form-data`: `file` и `client_key` — случайный UUID
загрузки, `crypto.randomUUID()`), `Accept: application/json`. Ответ — JSON с id обработки.
3. Браузер переходит на `https://<host>/api/images/public/claim?key=<client_key>&<метки>`. Сайт кладёт загрузку
в сессию посетителя и отвечает 302 на `/public/upscale?id=<обработка>&<метки>` (уже без ключа); страница сама
запускает обработку.
Почему не сразу `/public/upscale`: XHR с преленда кросс-доменный, и сессия, в которой сайт запомнил загрузку,
посетителю на сайте недоступна — браузеры изолируют или не принимают куки третьей стороны. Страница обработки
пускает только владельца загрузки, поэтому без передачи по ключу посетитель видел 404. Ключ одноразовый и годен
30 минут после загрузки.
`<host>` — домен сайта из `config.json`. API сайта принимает загрузку с любого домена (CORS отражает `Origin`), так
что для нового домена преленда на сайте ничего настраивать не нужно.
### Файлы
| Путь | Назначение |
|---|---|
| `index.php` | вход: конфиг, разбор меток, адреса API и перехода, общие переменные, `renderComponent()` |
| `template.php` | разметка страницы: шапка, блок загрузки, примеры, подвал с реквизитами |
| `components/form.php` | форма выбора файла и загрузка (XHR, `client_key`, переход на `claim`) |
| `components/preview.php`, `process.php`, `examples.php` | превью файла, индикатор загрузки, примеры «до/после» |
| `i18n.php`, `messages/{ru,en}/` | заглушка `Yii::t` и переводы; язык сейчас всегда `ru` (определение языка закомментировано) |
| `docs/` | `logo.svg`, `logo-alt.svg` и документы в PDF: тарифы, оферта, соглашение, политика |
| `requisites.html` | реквизиты для подвала (HTML), если в `config.json` нет `requisites`. Без обоих — **заглушка «ИП Иванов Иван Иванович»** из `template.php` |
| `images/`, `fonts/`, `favicon/`, `*.css` | статика; `style.min.css` встраивается в страницу |
| `.htaccess` | только сроки кэширования статики (Apache) |
| `config.json` | снимок актуального stage-конфига и схема. Рабочий конфиг на каждом хостинге настраивает владелец; deploy не заменяет его и меняет только явно согласованные в задаче ключи. После такого изменения актуальный stage-снимок забирают обратно в Git |
### `config.json`
| Ключ | Обязательный | Что задаёт |
|---|:---:|---|
| `host` | **да** | домен сайта, куда идут загрузка и переход (`zoomzilla.ru`). Без него берётся домен самого преленда — запросы уходят на преленд и получают 404 |
| `utm` | да | метки: `weights` (значение → доля трафика для `rnd`) и `default` |
| `requisites` | нет | реквизиты в подвале — список строк, каждая отдельным абзацем (текст экранируется). Важнее `requisites.html`; без обоих — заглушка «ИП Иванов» |
| `assetsUriPrefix` | нет | откуда брать статику. Пусто — из своего каталога; если на хостинге нет каталога `images`, статика берётся с сайта (`https://<host>`) |
| `fontsUrl`, `faviconUrl`, `spritePath` | нет | адреса шрифтов, иконок и SVG-спрайта, если они не в `assetsUriPrefix` |
| `logoAltExt` | нет | расширение второго логотипа (`svg` по умолчанию) |
| `title` | нет | заголовок страницы («Улучшение изображения») |
| `default_language` | нет | сейчас не действует: язык всегда `ru` |
### Демо-наборы
Preland хранит наборы ровно как Index, поэтому их можно переносить между проектами без переименования и
перекладывания файлов:
```text
1/01_desk_1-source.{jpg,webp,avif}
1/01_desk_2-result.{jpg,webp,avif}
1/01_desk_3-thumb.{jpg,webp,avif}
1/01_mob_1-source.{jpg,webp,avif}
1/01_mob_2-result.{jpg,webp,avif}
1/01_mob_3-thumb.{jpg,webp,avif}
...
1/05_...
2/01_...
...
N/05_...
```
`indpic=N` выбирает корневой каталог `/N/`. Набор копируется с Index в корень
домена целиком: без переименования, вложения в `images/` и промежуточных
каталогов. Устаревшие `images/demo*` не являются частью поставки.
## Деплой на произвольный домен
**Требования.** PHP 8.0+ (боевой хостинг — 8.2), веб-сервер с `index.php` в роли индексного файла и **HTTPS**:
`crypto.randomUUID()` работает только в защищённом контексте, а сайт отвечает по https.
1. **Домен.** Запись A (или CNAME) на хостинг, сертификат (Let's Encrypt или от хостинга); открыть `https://<домен>/`.
2. **Файлы.** Содержимое репозитория — в корень сайта, без `.git` и служебного (`README.md`, `.gitea/`):
```bash
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 конфиг пропал после заливки,
и преленд слал загрузку на собственный домен; это больше не допускается.
4. **nginx без Apache** (если хостинг не обрабатывает `.htaccess`):
```nginx
server {
server_name <домен>;
root /var/www/<домен>;
index index.php;
location ~ /(\.git|config\.json|README\.md) { deny all; }
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
}
location ~* \.(avif|webp|jpe?g|png|svg|ico|woff2?|css|js)$ { expires 1y; add_header Cache-Control "public, immutable"; }
}
```
5. **Сайт (по желанию).** Домен преленда сайт определяет сам — по `Referer` первого захода. Свои умолчания меток
для этого домена: cpanel → «Метки (UTM)» → «Умолчания по домену прелендинга».
6. **Проверка.**
```bash
curl -s 'https://<домен>/?nc=1' | grep -o 'const createApiUrl = [^;]*;\|const redirectUrlBase = [^;]*;'
# оба адреса — https://<host>/api/images/public/…, а не домен преленда
curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' 'https://<host>/api/images/public/claim?key=x'
# 302 на https://<host>/ — точка передачи на сайте есть
```
В браузере: открыть `https://<домен>/?indpic=1&theme=dark&subid=TEST`, выбрать фото — адрес сменится на
`https://<host>/public/upscale?id=…&indpic=1&theme=dark&subid=TEST…` (без `key=`), пойдёт обработка.
Это настоящая загрузка и обработка на сайте.
## Автодеплой (Gitea Actions)
`.gitea/workflows/deploy.yml`: после каждого коммита в `main` раннер заливает файлы репозитория на хостинги **всех
целей** по FTP с TLS и проверяет страницу каждой. Цель — домен со своим хостингом; список целей — `matrix` в workflow:
```yaml
- name: barbariskatest # имя цели (видно в списке прогонов: deploy barbariskatest)
url: https://preland.anton.barbariskatest.ru # адрес преленда — для проверки после заливки
prefix: PRELAND # секреты PRELAND_FTP_HOST, PRELAND_FTP_USER, PRELAND_FTP_PASS
dir: "" # каталог сайта на FTP: "" — корень FTP (beget), иначе, например, public_html
```
Цели выкатываются независимо (`fail-fast: false`): сбой одного хостинга не останавливает остальные.
**Новый домен на своём хостинге:**
1. Домен и HTTPS — как в «Деплой на произвольный домен», шаг 1.
2. Секреты `<ПРЕФИКС>_FTP_HOST`, `<ПРЕФИКС>_FTP_USER`, `<ПРЕФИКС>_FTP_PASS` (Gitea → настройки репозитория →
Actions → секреты; порт 21, FTP с TLS). В коде реквизитов нет.
3. Никаких ручных конфигов не создавать: единственный `config.json` приезжает вместе с кодом.
4. Запись в `matrix` — коммит в `main`, автодеплой выкатит все цели вместе с конфигом.
**Что заливается.** Каждый deploy получает файлы репозитория (`git ls-files`), кроме служебных
(`.gitea/`, `README.md`, `.gitignore`) и живущего на хостинге `requisites.html`. Единственный
версионируемый `config.json` всегда доставляется вместе с кодом.
На хостинге ничего не удаляется: файлы, убранные из репозитория, удалять вручную.
**Проверка после заливки.** На странице цели должен быть адрес загрузки на сайте, а не на самом преленде (иначе нет
`config.json` с `host`), и переход на `claim`. Иначе прогон этой цели падает.
**Откат** — `git revert` проблемного коммита в `main`: автодеплой зальёт прежнюю версию на все цели.
**SFTP.** Сейчас только FTP с TLS. Хостинг без FTP — поле `protocol` в цели и `lftp` вместо curl в шаге заливки.
**Откат вручную.** Перед заменой файлов — копия изменяемых файлов (`index.php`, `components/*`) с хостинга; вернуть их той же
загрузкой. Новый преленд требует на сайте `/api/images/public/claim` (api с 2026-10-05): со старым api переход
по ключу отдаст 404.