# Как собирается корпус

Каждый сайт принимает замеры **сам, на свой домен**. Ничего постоянно
работающего на серверах не появляется.

```
браузер посетителя           тот же сайт                  ваш макбук
  probe.js ──маячок──▶ /corpus/collect ──scp──▶ mantia corpus-ingest
   (по клику)          пишет тело в лог
```

## Три решения и их причины

**Приём на своём домене, а не на общем.** Соблазн собрать всё в одно место
велик, но тогда магазин при каждом визите стучится на посторонний сайт: лишняя
связь между проектами прямо в браузере посетителя и лишняя точка отказа на
чужой отрисовке. Адрес в зонде относительный (`/corpus/collect`), домены не
зашиты нигде. Побочно исчезает CORS — свой домен не требует ни разрешений, ни
предварительных запросов.

**Запуск по первому действию человека**, а не по загрузке страницы. Дело не в
разрешениях: всё, что зонд снимает, доступно и без жеста. Дело в выборке — в
журналах сетки от 10 до 25 процентов запросов делают сканеры, и они грузят
страницу. Корпус, разбавленный чужими серверами, врёт о распределениях именно
там, где должен быть точен. Проверено замером: без действия человека спустя
шесть секунд ноль замеров, после клика — полный.

**Принимает уже стоящий веб-сервер.** Замер — это одна строка тела запроса, и
nginx умеет записать её сам. Своя служба была бы третьей вещью, которую надо
ставить, обновлять и держать живой, ради одной директивы.

## Установка

### Сайты с nginx: legitdress, cansphere, spoofexpert, rareamour, emirates

Взять `nginx-corpus.conf`, перенести `log_format` и пустышку на `9977` в блок
`http`, а `location = /corpus/collect` — в блок `server` сайта. Затем:

```bash
nginx -t && systemctl reload nginx
```

### exifexpert — без nginx

Трафик идёт туннелем Cloudflare прямо в Next.js на `127.0.0.1:3000`, и записать
тело некому. Приёмник уже лежит в самом приложении:
`src/app/corpus/collect/route.ts` (исходник — `nextjs-route.ts` рядом). Пишет
ту же строку, что и nginx: формат общий, потому что разбор один на всю сетку.

### Все шесть

Выкатить обычными `deploy.sh`.

## Разбор

```bash
scp legitdress:/var/log/nginx/corpus.log /tmp/legitdress.log
mantia corpus-ingest /tmp/legitdress.log
# …и так по каждому сайту; корпус общий
mantia corpus-summary
```

Повторный разбор того же файла безопасен: замеры схлопываются по хешу
сочетания, вырастет только счётчик. Пересечение файлов при ротации не страшно.

## Если замеров нет

1. `wc -l /var/log/nginx/corpus.log` на сервере — доходит ли вообще;
2. открыть сайт, **щёлкнуть по странице**, «Сеть» в инструментах разработчика,
   фильтр `collect` — уходит ли маячок и с каким кодом. Без действия человека
   зонд молчит намеренно, и это не поломка;
3. `nginx -T | grep -A5 corpus` — на месте ли конфиг.

Три ловушки, все проверены замером и все молчаливые:

* **Тип содержимого.** `application/json` не входит в список безопасных для
  CORS, требует предварительного `OPTIONS`, которого маячок делать не умеет —
  браузер отбрасывает отправку целиком, и в консоли пусто. Зонд шлёт
  `text/plain`. Не «чинить» обратно.
* **Пустой лог при `return 204`.** Без `proxy_pass` nginx не читает тело, и
  `$request_body` пуст: файл создаётся и остаётся нулевым. Пустышка на
  `127.0.0.1:9977` существует ровно ради этого.
* **Удалённый лог.** Стереть файл после перезагрузки nginx — значит заставить
  его писать в удалённый inode: снаружи «ничего не пишется», хотя пишется.
  Сначала удалить, потом перезагрузить.
