← все проекты

Хвосты (цифровой след)

Сервис проверки цифрового следа: находим где засветились твои данные и помогаем убрать. Next 15 + FastAPI + ARQ, стенд на cfru:3140. Результат скана только после подтверждения владения кодом.

repo: E:/Проекты для Гитхаба/Хвостыserver: cfru, docker compose, web 3140, домена пока нет, работаем по IPdocs: docs/
готовS1 · Каркас6/7

Цель: Монорепо, compose, миграции, сид источников, CI, стенд на cfru по IP

Монорепо и конфиги
apps/web, apps/api, apps/worker, packages/shared, infra. Линт, типы, форматирование, .env.example
Монорепо apps/web, apps/api, apps/worker, packages/core, infra. Ruff и mypy настроены, .env.example на месте, секретов в репозитории нет.
feature
docker-compose со всеми сервисами
postgres 16, redis, api, worker, web. Лимиты памяти: cfru занят на 40 процентов и свопит. Внутренние сервисы только на 127.0.0.1, web на 3140
Compose на 5 сервисов плюс разовый мигратор. Лимиты памяти выставлены (postgres 768M, остальные по 256-512M), фактическое потребление всего стека около 180 МБ. Redis с maxmemory и allkeys-lru, чтобы не повторить историю с noeviction. Наружу только 3140, база и redis на 127.0.0.1.
feature
Alembic и первая миграция
Вся схема из docs/02-data-model.md одной миграцией, повторный прогон идемпотентен
Alembic на asyncpg (второй драйвер ради миграций не нужен). Одна миграция 0001 со всей схемой: 14 таблиц плюс alembic_version. Проверено: накат с нуля, повторный накат, откат до base и накат заново дают ту же схему.
feature
Сид справочника источников
Только бесплатная группа A0 из docs/03-collectors.md, у каждого removal_method и cost_per_call_rub = 0
Сид пяти бесплатных источников, идемпотентный через on conflict do update. Сверх задачи: в базе стоит ограничение free_tier_costs_nothing, платный источник в бесплатном тарифе не вставится физически.
feature
Health-check и структурные логи
/health у api и web с раздельным состоянием postgres и redis, JSON-логи со scan_id, без секретов
/health у api отдаёт состояние postgres и redis раздельно (6 мс), у web состояние себя и api (18 мс). Логи JSON, uvicorn и arq затянуты в тот же конвейер, есть затирание секретов и ПДн по имени поля и по виду значения, scan_id проставляется из контекста. 14 тестов, включая проверку что пароль и код не попадают в лог.
feature
CI: линт, типы, тесты
GitHub Actions, сборка образов
Workflow написан (линт, типы, тесты, отдельная job на прогон миграций с нуля и откат, сборка веба). Проверить нельзя: репозиторий на GitHub не заведён, нужен ответ владельца.
chore
Стенд на cfru
Деплой, проверка что открывается по IP:3140. npm через прокси aitodo:8888 с ipv4first, иначе сборка не пройдёт
Стенд живёт на cfru в /opt/hvosty, открывается по http://80.90.184.203:3140. Проверено с другой машины: 3140 открыт, 5443, 6393 и 8000 закрыты. Все контейнеры healthy, перезапусков ноль.
chore
готовS2 · Скан по бесплатным источникам8/8

Цель: 5 бесплатных коллекторов, ARQ-оркестрация, SSE, капча и лимиты

Базовый класс коллектора и реестр
BaseCollector, автосбор подклассов, CollectorContext, RawFinding, нормализация телефона в E.164 и почты в нижний регистр
BaseCollector с автосбором реестра по подклассам, CollectorContext с бюджетом времени и кэшем, RawFinding с обязательной чисткой доказательств от секретов прямо в конструкторе. Нормализация вынесена в ядро: телефон в E.164, почта в нижний регистр, ник из части почты до собачки. safe_collect ловит всё, падение источника не выходит за пределы своей задачи.
feature
Коллектор nickname_scan
Около 150 сайтов по шаблонам ссылок. Код свой: у maigret GPL-3.0, копировать нельзя, берём только список сайтов
50 сайтов по шаблонам ссылок, код свой (у maigret GPL-3.0). Главная работа была не в обходе списка, а в калибровке: прогнали заведомо несуществующий ник и нашли 7 сайтов, которые отвечают 200 на любой запрос. Каждый разобран поимённо: Steam переводит заголовок по языку запроса, у Dailymotion заголовок лежит на 47-й тысяче байт, PyPI закрыт антиботом и выброшен. Итог: по фейковому нику ноль находок вместо тридцати.
feature
Коллекторы gravatar, github_commits, whois, telegram_username
Четыре бесплатных источника, у каждого мок-тест на фикстуре, в сеть из тестов не ходим
gravatar (аватар, имя, город, связанные аккаунты), github_commits (почта в публичных коммитах и профиль), telegram_username (публичная страница), leaks_public. whois из бесплатной группы убран: обратный поиск доменов по почте есть только в платных API. Вместо него подключена бесплатная проверка утечек, она отдаёт факт компрометации, названия баз и даты без паролей.
feature
Оркестрация через ARQ
Отдельная задача на каждый коллектор, частичные результаты, таймауты, scan_tasks со статусами и длительностью
Отдельная задача на каждый источник, scan_tasks со статусом и длительностью, общий дедлайн и страховочная задача закрытия скана. Скан по живой почте: 14.6 секунды, все пять источников ok. До оптимизации было 51 секунда, помог частичный сбор по бюджету времени вместо ожидания всех сайтов.
feature
SSE-канал прогресса
Redis pub/sub, находки и статусы источников потоком. Проверить что прокси и Next не буферизуют поток
Redis pub/sub, поток через Next без буферизации, проверен живьём: события scan_started, source_state и finding приходят по мере готовности, в конце scan_finished. В событиях намеренно нет ни ссылок, ни значений, только категория и серьёзность, поэтому поток безопасен до подтверждения владения.
feature
Капча и ограничение по адресу
3 бесплатных скана в сутки с одного адреса, понятный человеку текст при отказе
Ограничение 3 скана в сутки на адрес через Redis, проверено живьём: четвёртый запрос получает 429 с человеческим текстом. Капча: слой готов под три провайдера, но провайдер не выбран, поэтому проверка пока пропускает. На боевом окружении запуск без провайдера запрещён кодом.
feature
Вырезание паролей до записи
Тест на фикстуре с паролем: его нет ни в базе, ни в логах, ни в ответе API
Чистка стоит в ядре, а не в коллекторах: полагаться на аккуратность автора нового источника нельзя. Вырезаются поля по именам и строки, похожие на хеши (bcrypt, argon2, md5). Проверено на живой базе: ноль находок со словом password в доказательствах, при этом список утёкших полей сохранён, человеку важно знать, что утёк именно пароль.
test
Дедупликация находок
Уникальность user_id + source_key + url + value_hash, повторный скан обновляет last_seen_at вместо дубля
Уникальность по пользователю, источнику, ссылке и хешу значения. Проверено на базе: две одинаковые находки одного пользователя дают одну строку и сдвигают last_seen_at. У анонимных сканов дедупликации нет намеренно, каждый такой скан живёт сам по себе.
feature
готовS3 · Подтверждение владения и результат7/8

Цель: Код на почту и телефон, блокировка перебора, экран скана с живой лентой, экран результата с пейволом

Слой отправки уведомлений
Провайдеры: console для стенда, SMTP для почты, SMS отдельным решением (платно). Шаблон письма с кодом, тон на ты
Слой готов: провайдер выбирается настройкой, письмо с кодом написано, на стенде код уходит в журнал и человеку об этом честно сказано на экране.
Нужен почтовый ящик и доступ к SMTP для настоящей отправки писем. Для проверки по телефону нужен платный провайдер SMS, это отдельное решение по деньгам.
feature
Выдача и проверка кода
Хранится только хеш кода, срок 15 минут, 3 попытки, дальше блокировка на 10 минут. Подстановка чужого scan_id не открывает результат
Шестизначный код, хранится только хешем на секрете приложения, сравнение за постоянное время. Срок 15 минут, повторная отправка не чаще раза в минуту, три попытки и блокировка на десять минут. Проверено живьём: после блокировки не проходит даже верный код, чужой scan_id отдаёт 404.
feature
Риск-скор
Считается кодом, не моделью: веса по серьёзности плюс бонусы за полный набор данных. Модель подключим в спринте 6
Считается кодом, не моделью: веса по серьёзности плюс бонусы за полный набор данных и за пароль в нескольких утечках. Находки «возможно твой профиль» намеренно весят ноль, чтобы не пугать человека цифрой на пустом месте. 7 тестов на границы уровней.
feature
Человеческие названия источников
Долг спринта 2: в поток событий уходили технические ключи вместо названий из справочника
Названия берутся из справочника источников и идут в поток событий и в ответ API. На экране теперь «Утечки баз данных» вместо leaks_public.
chore
Экран сканирования
Живая лента находок через SSE, список источников с состоянием, прогресс, ввод кода параллельно скану
Живая лента через SSE: список источников с состоянием, прогресс, счётчик найденного. Поймал гонку: страница подписывается на поток уже после старта скана, поэтому источник, ответивший из кэша мгновенно, навсегда оставался в состоянии «ждёт». Лечится тем, что после завершения состояние берётся из базы, а не из потока.
feature
Экран результата с пейволом
Крупная цифра риска, до кода только агрегат, после кода три находки и размытый остаток, одна кнопка без таймеров
Крупная цифра риска с дугой, до кода только агрегат, после кода три находки и размытый остаток с одной кнопкой без таймеров. Проверено скриншотами на живом стенде в обеих темах и на телефоне.
feature
Дизайн-система в коде
Токены двух тем, типографика, компоненты кнопки, карточки, поля. Мобильная вёрстка
Токены двух тем, типографика, кнопки, карточки, поля, значки серьёзности. Красный только у критичной находки и только тонкой рамкой. Тексты на ты, без канцелярита. Мобильный порядок блоков переставлен: прогресс, риск, находки, и только потом длинный список источников.
feature
package-lock.json для веба
Долг спринта 1: сборка без лока уже ломалась на версиях Tailwind
Долг спринта 1 закрыт: лок сгенерирован, сборка идёт через npm ci. Именно из-за его отсутствия ломалась сборка на несовпадении версий Tailwind.
chore
готовS4 · Лендинг и продвижение6/6

Цель: Все блоки лендинга, живой счётчик из базы, страницы источников, карта сайта, разметка, llms.txt

Публичная статистика
Эндпоинт со счётчиками из базы: проверок, находок, источников. Никаких персональных данных, только агрегат
Эндпоинты статистики и справочника источников, только агрегаты, персональных данных не отдают. Счётчик убранных записей есть в API, но на лендинге не показывается, пока удаление не работает: придумывать число для социального доказательства нельзя.
feature
Блоки лендинга
Первый экран с формой, живой счётчик, что находим, как это работает, чего не можем, тарифы, вопросы
Все семь блоков: первый экран с формой, живой счётчик из базы, что находим, как работает, где смотрим, чего не можем, тарифы, вопросы. Блок про честность написан прямо: утечку не удалить, гарантий нет, данные возвращаются через месяцы, чужие данные не ищем.
feature
Страницы источников
Генерятся из справочника: что за источник, какие данные там лежат, как удаляться. Обновляются сами при изменении справочника
Собираются из справочника: добавили источник в базу, страница и ссылка появились сами. На каждой форма проверки и разметка HowTo. Это будущий основной приток из поиска: человек ищет «как удалить анкету с сайта X», а не наш бренд.
feature
Карта сайта и robots
sitemap.xml из базы, robots управляется настройкой: стенд закрыт, прод открыт
Карта строится из базы, сейчас 7 страниц. Индексация управляется окружением: стенд закрыт, прод открыт, страницы результатов проверок закрыты всегда. Поймал грабли: страницы рендерились на сборке образа, когда API ещё не поднят, и карта уезжала без источников, а llms.txt с нулями. Перевёл на рендер по запросу.
feature
Разметка и llms.txt
schema.org Organization, Service, FAQPage, HowTo. llms.txt с фактами для ИИ-выдачи
schema.org Organization, Service и FAQPage на главной, HowTo на страницах источников. llms.txt отдаёт живые цифры и честный список того, чего сервис не делает, чтобы ассистенты цитировали правду, а не рекламу.
feature
Тексты и вычитка
Тон на ты, без канцелярита и длинных тире. Честный блок про то, чего не можем
Тексты на ты, без канцелярита и длинных тире. Отдельно поправил честность: пока код подтверждения не спрашивают, форма не обещает его прислать. Текст берётся из состояния сервиса, а не зашит.
chore
готовS5 · Кабинет6/6

Цель: Регистрация и вход, обзор, находки с фильтрами, мои данные, честное удаление аккаунта

Регистрация и вход
Пароль через argon2, сессия в куке, привязка анонимных проверок к аккаунту после входа
Пароль через argon2, сессия хранится в базе и отзывается, в куке только случайный токен. На неверную почту и неверный пароль один и тот же ответ, иначе по разнице собирают список существующих аккаунтов. Проверка, сделанная до регистрации, забирается в кабинет, но чужую привязать нельзя: нужно подтверждённое владение или тот же адрес. По дороге нашёл дефект: проверка, запущенная уже из кабинета, оставалась анонимной и не попадала в историю. Починено.
feature
Обзор
Риск в динамике, счётчики по статусам, что делать дальше
Риск, счётчики находок и проверок, история со ссылками на каждую проверку. Пока последняя проверка идёт, вместо нуля показывается «считаем»: иначе человек видит «пока чисто» и решает, что всё в порядке, хотя источники ещё отвечают.
feature
Находки с фильтрами
Таблица с фильтрами по категории, серьёзности, статусу. Массовые действия
Фильтры по серьёзности без перезагрузки, сортировка по важности своя, потому что в базе порядок алфавитный. Массовое действие пока одно: отложить находку. Отправки на удаление намеренно нет, обещать кнопкой то, за чем ничего не стоит, нельзя.
feature
Мои данные
Идентификаторы, подтверждение владения, история проверок
Список проверяемых данных в замаскированном виде и статус подтверждения. Плюс выгрузка всего, что о человеке храним, одним файлом: право забрать свои данные идёт в комплекте с правом их удалить.
feature
Честное удаление аккаунта
Кнопка стирает всё по-настоящему: после неё в базе не остаётся строк. Проверяется запросом
Именно удаление, а не пометка. Проверено запросом в базу: до удаления 1 пользователь, 1 проверка, 5 находок, 1 идентификатор, 1 сессия; после удаления везде ноль, старая кука отвечает 401. Сессии лежат в базе как раз ради этого: иначе кука продолжала бы работать после того, как человек попросил стереть всё.
feature
Пустые состояния
У каждого раздела экран пустоты, который объясняет что делать, а не выглядит поломкой
У каждой вкладки свой экран пустоты, который объясняет что делать: «проверок ещё не было» с кнопкой проверки, «по этому фильтру находок нет», «данные добавляются, когда запускаешь проверку».
feature
готовS6 · Разбор находок моделью6/6

Цель: Промпты файлами, sanitize перед вызовом, сводка и приоритеты, учёт стоимости

Клиент OpenRouter через прокси
Ключ и прокси из Контент Завода. Каждый вызов пишет токены и стоимость в api_cost_log
Ключ и прокси взяты из Контент Завода: из России провайдеры отвечают отказом по региону, поэтому запросы идут через тот же tinyproxy, что и сборка веба. Каждый вызов пишет токены и фактическую стоимость в api_cost_log, цену берём из ответа OpenRouter, а не считаем сами.
feature
Санитайзер перед моделью
В модель не уходят ссылки, ники, значения и пароли: только категории, серьёзность и состав полей
В модель уходит только ключ источника, категория, серьёзность и состав открытых полей. Ни ссылок, ни ников, ни значений, ни паролей. Находки по производному нику помечаются как неподтверждённые, чтобы модель не выдавала их за факт. Проверяется тестом, который ищет в запросе ссылки и адреса.
feature
Промпт разбора файлом
Отдельный файл с версией в имени, строгий JSON на выходе, валидация через Pydantic, фолбэк на шаблон
Промпт отдельным файлом с версией в имени, версия пишется в базу вместе с ответом. Строгий JSON, валидация через Pydantic, при провале шаблонный текст вместо ошибки. Разбор ответа выдержал три формы, включая markdown-обёртку, которую модель ставит вопреки строгому формату.
feature
Задача обогащения
Запускается после скана, пишет сводку и порядок действий в базу
Задача ставится после скана и только если есть что разбирать, один раз на скан. Находки группируются по источнику, чтобы не платить за пятьдесят однотипных строк. Результат в базе вместе с моделью и временем.
feature
Разбор на экране результата
Человеческая сводка и конкретные шаги вместо голого списка находок
Блоки «Что это значит» и «С чего начать» на экране результата, догружаются событием из живого потока, руками обновлять не надо. Текст получился человеческий: модель сама помечает необязательные действия и честно говорит, что находка может быть не про тебя.
feature
Контроль стоимости
Видно фактическую цену разбора на скан, приёмка требует не выше 8 рублей
Разбор одного скана стоит 1.24 рубля при потолке приёмки в 8. Видно в api_cost_log вместе с токенами. Всего на отладку спринта ушло 4.16 рубля за 3 вызова.
chore
готовS7 · Портрет вместо списка5/6

Цель: Человек вводит несколько данных и получает картину, как его видит интернет, а не перечень ссылок

Мульти-ввод идентификаторов
Несколько почт, ников, имя с городом в одной проверке. Сейчас поддерживается ровно один идентификатор
До шести данных в одной проверке: почты, ники, имя с городом. Город приклеивается к имени, потому что «Иван Петров» и «Иван Петров Казань» дают в поиске совершенно разную выдачу. Подтверждение владения теперь выбирает из нескольких данных подходящее, предпочитая почту.
feature
Коллектор поиска Яндекса
Ключ из монитора тендеров, Cloud Search API v2. Ловушка: folderid со строчной d и l10N ru, иначе Permission denied. Ищем по нику, имени с городом, почте, телефону
Работает на ключе из монитора тендеров. Две ловушки формата, на которых потерял время: folderid со строчной d и l10N ru, иначе Permission denied, который выглядит как проблема с правами. Главное в коллекторе не запрос, а фильтр: результат засчитывается, только если искомое есть в ссылке или заголовке. До фильтра поиск по адресу почты тащил страницы самого Gmail, мусора было больше половины (29 находок против 10 честных).
feature
Коллектор DaData
Телефон даёт оператора и регион, ФИО ищет ИП с ОКВЭД, email определяет тип. Бесплатный тариф: 10000 подсказок и 100 проверок в день
Ключ из LeadForge, бесплатный тариф. По телефону показывает оператора и регион, по имени ищет предпринимателя с ОКВЭД и статусом, по почте отличает корпоративную. Предприниматель по имени всегда предположение: однофамильцев много, обжигались на этом в досье на лида.
feature
Портрет вместо списка
Разделы: кем тебя считает интернет, где ты живёшь в сети, что скомпрометировано, что стоит подчистить. Выводы модели, а не перечисление
Промпт v2: разделы «кем тебя считает интернет», «где ты живёшь в сети», «что скомпрометировано». Модель получает типы площадок (профиль соискателя, профиль разработчика), но не ссылки и не значения, и делает вывод о профессии. Когда данных мало, честно пишет «понять, чем ты занимаешься, нельзя», а не выдумывает. Отдельно запретил советовать чужие сервисы проверки утечек: в первом прогоне модель отправляла человека к конкурентам.
feature
Экран портрета
Форма с несколькими полями и результат в виде картины, а не таблицы находок
Форма разворачивается по мере заполнения: заполнил первое поле, появилось следующее, отдельно город. На экране результата блок «Каким тебя видит интернет» идёт первым, выше сводки и находок.
feature
Активность соцсетей
Отличать живой профиль от заброшенного там, где дата последней активности видна публично
Даты последней активности публично видны не везде: у части площадок нужен токен, у части их нет вовсе. Отложено до спринта с мониторингом.
feature
готовS8 · Домен, админка, дорогой вид7/7

Цель: Подключить 24хвосты.рф, сделать админку с метриками, юрдокументы, блог для поиска и переделать посадочную под дорогой сервис

Подготовка под поиск и ИИ-выдачу
Общие шапка и подвал, разборы в навигации, разметка организации, статей, крошек и инструкции, картинка для соцсетей, боты ассистентов в robots
Шапка и подвал стали общими компонентами вместо двенадцати копий: разборов не было ни в одной шапке, подвал жил только на главной. Разметка собрана в lib/schema.ts и стоит на всех публичных страницах. Картинка для соцсетей отдаётся везде, ловушка Next: свой блок openGraph заменяет родительский целиком. Ботам ассистентов вход разрешён отдельными правилами, личные разделы закрыты. Статей стало пять, у каждой короткие ответы в конце, они же в llms.txt.
feature
Фавиконка и иконка для телефона
Иконок не было ни одной. Сделаны из знака логотипа: хвост клиньями вместо штрихов, потому что в шестнадцати пикселях штрихи сливались в кашу. Логотип в шапке приведён к той же геометрии, знак должен быть один. Плашка тёмная: на прозрачном фоне оранжевый знак теряется на светлой вкладке.
feature
Домен и TLS
24хвосты.рф (xn--24-flc2cpgr6c.xn--p1ai), Caddy или nginx с автоматическим сертификатом, HVOSTY_ENV=prod и открытие индексации
24хвосты.рф делегирован, A-запись на 80.90.184.203. Nginx отдаёт домен в веб на 3140, отдельная секция для /api/scans/ с выключенной буферизацией, иначе живой поток проверки копится и экран стоит. Сертификат Lets Encrypt до 3 ноября, продлевается сам, http и www уводят на https. Адрес сайта прокинут в сборку образа: карта сайта и canonical пекутся на билде. Индексация закрыта до появления доставки кода подтверждения.
24хвосты.рф куплен, но не делегирован: ни NS, ни A записей на момент работы. Punycode xn--24-flc2cpgr6c.xn--p1ai, сервер 80.90.184.203. Как DNS доедет, работы на десять минут.
feature
Редизайн посадочной
Дорогой вид: сложные цвета, глубина, переливы, анимация, визуал. Без вида шаблона и без следов ИИ-генерации
Тёмная тема по умолчанию, глубина через радиальные подсветки и сетку вместо плоского фона, крупная типографика с плотным трекингом, градиент в заголовке, счётчики оживают при загрузке, карточки приподнимаются при наведении. Иллюстраций намеренно нет: стоковые картинки в теме приватности выглядят дешевле, чем их отсутствие. Отдельно по замечанию владельца: на лендинге теперь четыре понятных направления (утечки, выдача, аккаунты, справочники), а не технические названия сборщиков.
feature
Админка с метриками
Сколько зарегистрировалось, сколько бесплатных проверок, расходы, конверсии. Вход по флагу администратора
Себестоимость одной проверки, расходы по провайдерам, воронка от проверки до оплаты, статистика по источникам (находки, ошибки, среднее время, цена вызова), список людей, проверки по дням. Доступ только по флагу администратора, посторонним отвечает 404, а не «нет прав»: существование админки не должно подтверждаться. Живые цифры: 25 проверок, 237 находок, себестоимость 0.20 рубля.
feature
Юридические документы
Политика, оферта, согласия. Структуру берём с 24contentzavod.ru, адаптируем под сервис проверки данных
Политика обработки, согласие (отдельно на обработку и отдельно на действия от имени человека), оферта. Структуру взял с Контент Завода, тексты написал под наш сервис: у нас обработка чужих ПДн и обращения от имени человека, там этого нет. Пока нет реквизитов и проверки юристом, на страницах стоит честная пометка о черновике.
feature
Блог для поиска и ИИ-выдачи
Статьи о том, как утекают базы и как защищать данные. Под запросы с реальным спросом, с разметкой
Три разбора под реальные запросы: как утекают базы, как удалить свои данные, откуда мошенники знают имя. В каждом короткий ответ первым абзацем и разметка сразу двух типов: статья для поиска и вопрос с ответом для ИИ-выдачи. Карта сайта собрала 18 страниц.
feature
готовS9 · Мониторинг и подписка7/7

Цель: Планировщик, дедупликация, алерты, перепроверка убранного через 90 дней

Отметка новых и вернувшихся находок
Запись находки различает вставку и обновление. Новая находка после первого скана даёт событие, убранная и снова найденная переводится в статус вернулось
Запись находки различает вставку и обновление через xmax, отдельного запроса перед записью не нужно. Новая находка даёт событие, но только если у человека уже был завершённый скан: иначе кабинет заводится и сразу приносит три десятка сообщений про то, что и так на экране. Убранное и снова найденное получает статус вернулось и второе обращение рядом со старым. Проверено на живой базе: повтор не плодит дублей, третье обращение при следующем повторе не создаётся.
feature
Планировщик перепроверок
Cron раз в час: подписки с наступившим сроком ставят скан по сохранённым идентификаторам, срок сдвигается по частоте
Крон раз в час поднимает подписки с наступившим сроком, ставит обычный скан по сохранённым данным и сдвигает срок по частоте. Берёт до пятидесяти за заход, чтобы очередь не легла на источники разом. Подписка без данных выключается сама, иначе будила бы планировщик вечно, проверено на живой базе.
feature
Лента изменений в кабинете
Раздел что изменилось: новые и вернувшиеся находки, отметка прочитанного, счётчик непрочитанных
Вкладка Что изменилось в кабинете: новые и вернувшиеся находки, счётчик непрочитанного прямо на закладке, отметка прочтения при открытии ленты.
feature
Управление подпиской из кабинета
Включение слежения, частота, список идентификаторов под наблюдением, дата следующей проверки
Включение слежения, три частоты, число данных под наблюдением и дата следующей проверки. Включить без сохранённых данных нельзя, кривая частота отбивается на входе.
feature
Перепроверка убранного через 90 дней
Успешное удаление ставит срок перепроверки. Если данные вернулись, статус вернулось и новое обращение
Успешное удаление ставит срок перепроверки через 90 дней, ночной крон запускает обычный скан. Отдельного похода на страницу нет намеренно: иначе появится вторая, расходящаяся с основной, логика проверки.
feature
Слой доставки уведомлений
Очередь отправки с каналами. Канал кабинет работает сразу, почта включается одной настройкой когда появится ящик
Создание события отделено от отправки. События копятся в кабинете уже сейчас, задача доставки просыпается дважды в час и пока только считает, сколько писем ушло бы. Включается настройкой NOTIFICATIONS_ENABLED, когда появится ящик на домене.
chore
Дополнение проверки и возврат в кабинет
Дополнение работало в API с шестого спринта, но в интерфейс выведено не было. Блок стоит на экране результата после находок и показывает, сколько следов принесли новые данные. Проверено на живой базе: проверка по нику подняла три источника, добавление телефона подняло другие три, первые повторно не запускались. С экрана проверки появился путь назад в кабинет для вошедших.
feature
В РАБОТЕS10 · Машина продвижения7/8

Цель: Страницы источников из базы, статьи, регионы, проверка попадания в ИИ-выдачу

Разборы и живая статистика на страницах источников
У каждого из семи источников свой текст, написанный руками: что смотрим, как ты сюда попал, что делать, чего не можем, короткие ответы. Плюс цифры из базы на каждый показ: доля проверок с находкой, какие поля раскрываются чаще, разбивка по серьёзности, дата последней находки. По утечкам вышло 84 процента проверок с находкой. До этого страницы отличались только названием, что запрещено критерием приёмки.
feature
Региональные страницы: решение не делать
Не делаем сознательно. За региональными страницами нет региональных данных: источники общие, законы федеральные, сроки одинаковые везде. Отличались бы только названием города, а это дорвеи, за которые понижается весь домен. Решение записано в DECISIONS.md, пересмотреть, если появится региональная практика операторов.
chore
Ещё два разбора
Как удалить заброшенный аккаунт без доступа и что делать в первые часы после утечки. Всего семь статей, карта сайта выросла до 22 ссылок, llms.txt до 111 строк.
feature
Проверка попадания в ИИ-выдачу
chore
Свои данные: дедупликация и управление
Каждая проверка заводила данные заново: тридцать записей на пять уникальных, подтверждение владения цеплялось к случайной копии. Проверка и дополнение теперь сверяются со всеми данными человека и переиспользуют существующую запись, на будущее стоит частичный уникальный индекс. Накопленное схлопнуто миграцией 0005: сначала переписаны ссылки в проверках и подписках, потом удалены лишние, битых ссылок ноль, подтверждение перенесено. В кабинете появились кнопки убрать чужое и добавить своё, добавление не запускает проверку само.
fix
Письма и обращения об удалении
Автоотправку не делаем: у каждого сайта свой адрес и манера отвечать, плюс посреднику нужна доверенность, а требование от самого человека юридически чище. Третий шаблон, требование к сайту, подставляет адрес страницы из находки. Документ docx собирается без зависимостей, формат это zip с XML. Обращение живёт и без находки для случая звонков с ненайденного номера. Кнопка на находке, вкладка Письма со статусами, инструкция из пяти шагов с привязкой к закону. Отметка об удалении ставит перепроверку через 90 дней.
feature
Проверка по имени отдельно от почты
Поля подробной формы шли каскадом: чтобы добраться до имени, надо было заполнить два поля до него. Переделано на независимые подписанные поля, запустить можно по любому одному. Если введено только имя без города, показывается предупреждение про однофамильцев.
fix
Письма по текстам законов: паспорт, четыре шаблона, Word и PDF
Шаблоны переписаны по текстам законов. Часть 3 статьи 14 закона 152-ФЗ требует номер документа, дату выдачи, выдавший орган и сведения о связи с оператором, без них отказывают законно. Право на забвение по статье 10.3 закона 149-ФЗ требует того же плюс основание и согласие на обработку. Для отказа от рекламных звонков паспорт не нужен, идентификация по номеру. Паспорт нигде не сохраняется: обращение хранит параметры без личных данных, документ собирается заново при скачивании, проверено запросом к базе. Четвёртый шаблон для поисковика. Два формата: Word и PDF с системным шрифтом DejaVu. Тексты интерфейса переписаны человеческим языком.
feature
планS11 · Админка0/0

Цель: Дашборд, пользователи, источники, очередь оператора, расходы, аудит-лог

задач нет

планS12 · Деньги и юрконтур0/0

Цель: ЮKassa, вебхуки, чеки, PDF-отчёт, документы, уведомление в РКН

задач нет

планS13 · Браузерный агент0/0

Цель: Playwright-runner, политика доменов, бюджет шагов, фолбэк с коллектора

задач нет

планS14 · Нагрузка и прод0/0

Цель: Кэш на сутки, бэкапы, мониторинг, тест на 100 сканов, домен и TLS

задач нет

Ворклог (места остановки)

05.08.2026, 09:00:45 · · claude

Спринт 10, продвижение. Главное: страницы источников перестали быть одинаковыми. У каждого из семи свой разбор, написанный руками, и свои цифры из базы на каждый показ: доля проверок с находкой, какие поля раскрываются чаще, разбивка по серьёзности. По утечкам 84 процента проверок находят хоть что-то, такой статистики нет больше ни у кого, это наши собственные наблюдения. Добавлены два разбора, всего семь статей, карта сайта 22 ссылки, llms.txt 111 строк. Региональные страницы решено не делать: за ними нет региональных данных, отличались бы только названием города, а это дорвеи, за которые понижается весь домен. Тесты 104 зелёные.

Проверка попадания в ИИ-выдачу заблокирована индексацией: десять контрольных вопросов и методика записаны в docs, проверка руками сразу после открытия. Следующие спринты 11 админка и 13 браузерный агент. Спринт 12, деньги и юрконтур, отложен владельцем до закрытия остальных.

05.08.2026, 08:39:05 · · claude

По замечаниям владельца: с экрана проверки не было пути назад в кабинет и не было видно, как дополнить свои данные. Возврат добавлен для вошедших, им же убрано предложение сохранить уже сохранённый результат. Дополнение проверки выведено в интерфейс: блок после находок, добавляешь телефон или ещё почту, найденное не перепроверяется. Проверено на живой базе: дополнение телефоном подняло только те источники, которым телефон нужен, три источника по нику повторно не запускались. Скан с дополнением обошёлся в 36 копеек.

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

05.08.2026, 07:36:38 · · claude

Закрыт спринт 9, наблюдение. Планировщик раз в час поднимает подписки с наступившим сроком и ставит обычный скан. Запись находки различает вставку и обновление, поэтому событие создаётся только про новое. Первый скан событий не даёт: иначе кабинет заводится и сразу приносит три десятка сообщений. Убранное и снова найденное получает статус вернулось и второе обращение рядом со старым, прежнее не переоткрывается. В кабинете вкладка Что изменилось со счётчиком непрочитанного и настройкой частоты. Отправка наружу отделена от создания события: события копятся, канал включится настройкой. Проверено на живой базе, 104 теста зелёные, тестовый аккаунт удалён без сирот. Отдельно сделаны фавиконка и иконка для телефона, логотип приведён к той же геометрии.

Спринт 9 закрыт не полностью честно: письмо о новой находке не уходит, потому что ящика на домене нет. Это же держит индексацию и боевое окружение. Следующий по роадмапу спринт 10, машина продвижения: региональные страницы, ещё статьи, проверка попадания в ИИ-выдачу по контрольным вопросам.

05.08.2026, 06:54:10 · · claude

Домен 24хвосты.рф подключён с TLS, сайт готов под поиск и ИИ-выдачу. Nginx отдаёт домен в веб на 3140, для живого потока проверки буферизация выключена отдельной секцией. Сертификат до 3 ноября, продлевается сам. Адрес сайта уходит в сборку образа: карта сайта, robots и canonical пекутся на билде и в рантайме не меняются. Шапка и подвал стали общими компонентами вместо двенадцати копий, разборы наконец появились в навигации. Разметка организации, статей, крошек и инструкции собрана в lib/schema.ts и стоит на всех публичных страницах. Написаны две статьи под живые запросы: как проверить утечку и как запретить рекламные звонки, всего пять. У каждой короткие ответы в конце, они же уезжают в llms.txt для ассистентов. Три новые картинки в Kie на 9 рублей: две обложки и баннер для соцсетей, всего потрачено 18 из 30 рублей бюджета. Обложка в статье больше не занимает весь экран.

Индексация закрыта осознанно: боевое окружение принудительно требует подтверждения владения адресом, а отправлять код нечем. Порядок такой: почта или SMS, затем боевое окружение, затем robots. Дальше по роадмапу спринт 9, мониторинг и подписка: планировщик перепроверок, алерты о новых находках, перепроверка убранного через 90 дней.

05.08.2026, 06:08:13 · 8 · claude

Добавлены фирменный знак, превью отчёта и картинки. Лого сделал вектором, а не картинкой от модели: след из трёх штрихов, растворяющийся к точке, читается даже в фавиконе и перекрашивается под тему одной переменной. Превью отчёта на лендинге свёрстано интерфейсом, а не скриншотом: скриншот устаревает в день изменения экрана, а это живёт вместе с продуктом и остаётся чётким на любом экране. Цифры в превью из настоящей проверки, данные человека убраны. Через Kie сгенерированы три обложки для блога в тёмном стиле с янтарными акцентами (база рассыпается в частицы, тающий цифровой след, портрет из точек данных): 18 кредитов, примерно 9 рублей из выделенных 30. Картинки пришли по 2 МБ, что убило бы скорость загрузки, поэтому сжаты в webp: 2012 КБ стали 121 КБ, суммарно 300 КБ на три обложки. Стоковых иллюстраций намеренно нет: в теме приватности они удешевляют.

Домен 24хвосты.рф проверен трижды, включая RDAP и публичные резолверы: в зоне .рф его нет, NS у регистратора не прописаны. Нужно действие владельца в панели регистратора: A-запись на 80.90.184.203. Как появится, поднимаю TLS и переключаю окружение в боевое.

05.08.2026, 05:53:16 · 8 · claude

Сделан весь список владельца, кроме домена. Посадочная переделана под дорогой вид: тёмная тема, глубина подсветкой и сеткой, оживающие счётчики, приподнимающиеся карточки. По замечанию владельца убрал с лендинга технические названия сборщиков, теперь там четыре понятных направления. Собрана админка: себестоимость проверки, расходы по провайдерам, воронка, статистика источников, люди. Написаны юридические документы под наш сервис (политика, согласие на обработку и на действия от имени человека, оферта) с честной пометкой о черновике до проверки юристом. Запущен блог: три разбора под реальные запросы, с коротким ответом первым абзацем и разметкой для поиска и для ИИ-ответов. Карта сайта выросла до 18 страниц. 92 теста зелёные.

Домен 24хвосты.рф ждёт делегирования: как появятся NS, поднимаю TLS и переключаю окружение в боевое. Дальше по решению владельца: поиск по фото, HIBP (даст международный слой, но две из пяти найденных баз у него отсутствуют), почта и SMS для подтверждения, оплата и юрконтур.

05.08.2026, 05:20:39 · 7 · claude

Доделано по плану владельца: утечки теперь показываются по каждому сервису отдельно (название, дата, состав утёкшего), а не одной строкой «нашли в пяти базах». Формулировка честная: источник отдаёт состав полей общим списком по всем базам, поэтому пишем «суммарно по твоим утечкам», а не приписываем чужие поля конкретному сервису. Починен учёт расходов: раньше в журнал попадала только цена модели, теперь пишется и стоимость поиска, скан честно стоит 0.19 рубля. Сделан генератор готовых требований: прекратить рекламные звонки по части 1 статьи 18 закона о рекламе плюс отзыв согласия по 152-ФЗ, и отдельно заявление об удалении данных с сайта. Юридический каркас в шаблоне, модель к этим письмам не подпускается: выдуманная ссылка на статью хуже, чем отсутствие письма. Сделано дополнение проверки: добавил телефон к готовому скану, запустился только DaData по новому номеру, старое не перегонялось.

Оценка HIBP по фактам: у него 1022 базы, но из пяти найденных по нашей почте двух российских (Level.travel, dns-shop.ru) там нет. Пересечение около двух третей, HIBP добавит международный слой за 4.39 доллара в месяц, но не перевернёт картину.

05.08.2026, 04:32:44 · 7 · claude

Стенд передан владельцу на тестирование. Заведён аккаунт для входа, вход проверен. Порядок теста: заходить в кабинет и запускать проверку изнутри него, тогда она попадает в историю; с главной без входа проверка остаётся анонимной. Кода подтверждения на стенде не спрашивают, находки открываются сразу. Ограничение: три проверки в сутки с адреса, дальше 429. Портрет появляется отдельно, через 20-40 секунд после конца проверки, страница дорисовывает его сама.

Ждём обратную связь по портрету: что попало мимо, каких блоков не хватает, где формулировки врут. Дальше по решению владельца: поиск по фото (2-4 рубля за запрос, нужна граница с распознаванием лиц) и активность соцсетей. Платное (почта, SMS, оплата, юрконтур) отложено до готовности к проду.

04.08.2026, 17:39:20 · 7 · claude

Продукт развёрнут по описанию владельца: не список находок, а портрет, каким человека видит интернет. В одну проверку принимается несколько данных, подключены поиск Яндекса и справочники DaData, результат выдаётся разделами с выводами о профессии и занятиях. Поиск сразу показал силу: по одному нику нашлись профиль на Хабр Карьере, профиль в Тинькофф Инвестициях, форум, страница игрока в бадминтон, отзывы на Флампе, агрегатор соцпрофилей с именем и городом. Ничего из этого наш ник-скан не видел. Главная работа была не в подключении, а в фильтрации: без правила «искомое должно быть в ссылке или заголовке» поиск по адресу почты тащил страницы самого Gmail, мусора было больше половины. Отдельно поправил правило продукта: запрет на платные источники в бесплатном скане заменён бюджетом, потому что поиск стоит 15 копеек, а без него продукт не показывает главного. Скан с поиском 15 копеек, разбор портрета 2.6 копейки. 92 теста зелёные.

Осталось из описанного владельцем: поиск по фото (2-4 рубля за запрос, нужно решение по деньгам и по границе с распознаванием лиц) и определение активности соцсетей. Государственные реестры сознательно вычеркнуты: API ФССП закрыт, а долги человек про себя и так знает. Полный разбор источников в docs/11-istochniki-issledovanie.md.

04.08.2026, 16:17:30 · 5 · claude

Спринт 5 закрыт: кабинет работает. Регистрация и вход, обзор с историей проверок, находки с фильтрами, свои данные, выгрузка и удаление аккаунта. Главный критерий приёмки проверен запросом в базу: удаление аккаунта стирает всё по-настоящему, после него ноль строк во всех таблицах и старая кука мертва. Ради этого сессии хранятся в базе, а не только в подписанной куке. Два дефекта нашёл и починил: проверка, запущенная из кабинета, оставалась анонимной и не попадала в историю; и обзор показывал «пока чисто» с нулевым риском, пока последняя проверка ещё шла. Честно записал продуктовое расхождение: кабинет показывает все находки, а на экране проверки стоит пейвол, то есть пейвол обходится регистрацией. Городить ограничение, которое нельзя снять деньгами, до появления оплаты нечестно. 89 тестов зелёные.

Всё бесплатное по роадмапу сделано: каркас, скан, подтверждение владения, лендинг с продвижением, кабинет, разбор моделью. Дальше по плану идёт платное и требует решений владельца: движок удаления (нужна доменная почта и SMTP), российские источники (часть платная), оплата и юрконтур, SMS. Долги в docs/SCOPE-CUTS-LOG.md, среди важных: нет восстановления пароля, нет разделов удалений и мониторинга, CI не проверен без репозитория на GitHub.

04.08.2026, 15:56:27 · 6 · claude

Модель переведена с claude-sonnet-5 на deepseek/deepseek-v4-flash по решению владельца. Замер на одном и том же скане: 1.24 рубля против 0.03 рубля, то есть в сорок раз дешевле, качество текста сопоставимое. Разбор находок это пересказ готовой структуры человеческим языком, а не рассуждение, поэтому дорогая модель тут не нужна. Проверено живьём: тон на ты сохранился, длинных тире нет, находки по нику честно помечены как «может быть просто совпадение».

Начат спринт 5: кабинет. Регистрация, обзор, находки с фильтрами, мои данные, честное удаление аккаунта.

04.08.2026, 15:48:21 · 6 · claude

Спринт 6 закрыт: находки разбирает модель. Ключ OpenRouter и прокси взяты из Контент Завода, запросы идут через tinyproxy, иначе провайдер отказывает по региону. На экране результата появились сводка «Что это значит» и нумерованный порядок действий с оценками времени. Текст вышел живой: модель сама помечает необязательные действия и честно пишет, что находка по нику может быть не про тебя. Принципиально: цифру риска модель не считает, ей отдают готовое число, иначе одинаковые находки давали бы разный результат. Две вещи починил кодом, а не промптом: модель оборачивает JSON в markdown вопреки строгому формату (разбор теперь выдерживает три формы ответа), и ставит длинные тире вопреки прямому запрету (чистится валидатором). Первый прогон упал на разборе и отработал запасной текст, то есть страховка тоже проверена живьём. Стоимость разбора 1.24 рубля на скан при потолке 8. Вся отладка спринта стоила 4.16 рубля.

Осталось из бесплатного: спринт 5 (кабинет: регистрация, разделы, история проверок, честное удаление аккаунта). Платное отложено по решению владельца до готовности к проду: почта и SMS, платные источники, оплата, юрконтур. Долги спринта в docs/SCOPE-CUTS-LOG.md: нет кнопки переразобрать, объяснения по источникам хранятся, но не показываются, курс доллара зашит числом.

04.08.2026, 15:20:50 · 4 · claude

Спринт 4 закрыт. По решению владельца подтверждение владения на стенде выключено настройкой, чтобы не ждать доменной почты и SMS. Важно: в бою настройка игнорируется, выключить подтверждение при HVOSTY_ENV=prod нельзя даже случайно, иначе сервис превращается в пробивалку. Интерфейс тоже честен: пока код не спрашивают, форма его не обещает. Собран лендинг целиком: семь блоков, живой счётчик из базы (12 проверок, 48 следов, 5 источников), тарифы, вопросы с разметкой. Сделаны страницы источников, которые собираются из справочника сами, карта сайта из базы на 7 страниц, robots и индексация по окружению, llms.txt с живыми фактами для ИИ-ответов. Грабли спринта: страницы рендерились на этапе сборки образа, когда API ещё не поднят, и уезжали с нулями, а карта сайта без источников. Перевёл на рендер по запросу. Лендинг отдаётся за 39 мс. 75 тестов зелёные.

Всё бесплатное по плану сделано. Дальше по роадмапу спринт 5 (кабинет: регистрация, разделы, честное удаление аккаунта) и спринт 6 (разбор находок моделью через OpenRouter, это уже платно и требует ключа). Платные развилки ждут решения владельца: почта и SMTP, провайдер SMS, ключ OpenRouter, платные источники, репозиторий на GitHub для CI.

04.08.2026, 14:52:01 · 3 · claude

Спринт 3 закрыт: собран полный путь от главной до пейвола, проверен вживую в браузере. Человек вводит почту, видит живую ленту источников, вводит код и получает три находки, остальное за пейволом. Подтверждение владения работает как задумано: до кода API не отдаёт ни ссылок, ни значений, только счётчики. Код хранится хешем, три попытки, блокировка на десять минут, после неё не проходит и верный код. Риск считает код, а не модель. Три дефекта нашёл и починил по скриншотам: кнопка ломалась в две строки, форма кода ждала конца скана вместо параллельного ввода, и гонка в живом потоке, из-за которой быстрый источник навсегда оставался в состоянии «ждёт». Закрыт долг первого спринта: package-lock.json есть, сборка идёт через npm ci. 71 тест зелёный.

Развилка для владельца: нужен почтовый ящик и SMTP, иначе письма с кодом не уходят и наружу сервис открывать нельзя. Отдельно решение по SMS, это платно, без него проверка по телефону не завершается. Дальше спринт 4: полный лендинг со всеми блоками, живой счётчик убранных записей, каркас продвижения (карта сайта, разметка, llms.txt, страницы под источники). CI по-прежнему ждёт репозитория на GitHub.

04.08.2026, 13:53:44 · 2 · claude

Спринт 2 закрыт: скан работает на живых данных. Пять бесплатных источников, оркестрация через очередь, живой поток событий, ограничение по адресу, дедупликация. Скан по реальной почте: 14.6 секунды, критичная находка по утечкам (5 баз, среди них dns-shop.ru, Level.travel, Bookmate) и четыре аккаунта по нику. Себестоимость ноль. Три вещи, которые нашли и починили по факту, а не по догадке: User-Agent с кириллицей ронял вообще все запросы (заголовки HTTP только ascii, поймал тест); скан занимал 51 секунду вместо 20, вылечено частичным сбором по бюджету времени; и главное, ложные находки, коллектор по нику давал 30 несуществующих профилей, потому что часть сайтов отвечает 200 на любой ник. Прогнали калибровку заведомо несуществующим ником, разобрали каждый сайт поимённо, теперь по фейку ноль находок. Отдельно: находки по нику, выведенному из почты, помечаются как «возможно твой», выдавать их за подтверждённые нечестно. 57 тестов зелёные, линт чистый.

Спринт 3: подтверждение владения кодом на почту и телефон, блокировка перебора, экран сканирования с живой лентой и экран результата с пейволом. Сейчас ответ API уже разделён на «до кода» и «после кода», но кода никто не шлёт, поэтому находки закрыты всегда. Долги в docs/SCOPE-CUTS-LOG.md: капча без провайдера, нет package-lock.json у веба, названия источников в потоке событий техническими ключами. CI по-прежнему не проверен: репозитория на GitHub нет, gh не авторизован, нужен вход владельца.

04.08.2026, 12:49:34 · 1 · claude

Спринт 1 (каркас) собран и поднят на cfru: http://80.90.184.203:3140. Монорепо: packages/core (модели, настройки, логи), apps/api (FastAPI), apps/worker (ARQ), apps/web (Next 15, Tailwind 4, две темы), infra (compose, два Dockerfile, deploy.sh). Схема 14 таблиц одной миграцией, включая добавленную verification_codes под подтверждение владения и audit_log. Сид пяти бесплатных источников идемпотентный. 14 тестов зелёные. По дороге починили четыре реальные вещи: Alembic просил psycopg2 (перевели на asyncpg вместо второго драйвера), Tailwind 4.0.0 конфликтовал со свежим нативным модулем (синхронизировали на 4.3.3), логи uvicorn и arq шли мимо JSON и мимо затирания секретов (затянули в общий конвейер через ProcessorFormatter), healthcheck веба падал из-за резолва localhost в ::1 при сервере на IPv4 (адрес явный). Приёмка спринта закрыта по всем пунктам кроме CI.

Открыт один пункт приёмки: CI не проверен, репозиторий на GitHub не заведён, нужно решение владельца заводить ли и приватным ли. Дальше спринт 2: базовый класс коллектора, реестр, пять бесплатных коллекторов, оркестрация ARQ, SSE-канал, капча и лимиты. Долг из спринта 1 записан в docs/SCOPE-CUTS-LOG.md: нет package-lock.json у веба (уже обожглись на версиях), mypy в CI не блокирует, один образ на api и worker, бэкапов базы нет.

04.08.2026, 12:12:35 · 1 · claude

Разобрали пакет ТЗ из 10 документов, нашли 8 дыр и противоречий. Согласованы решения: название Хвосты; результат скана открывается только после подтверждения владения кодом, иначе сервис работает как пробивка по чужому номеру и противоречит собственному legal; бесплатный скан только на бесплатных источниках, платные API обсуждаются отдельно с ценами; текст через OpenRouter claude-sonnet-5 вместо прямого Anthropic (в ТЗ была несуществующая модель claude-sonnet-4-6); право на забвение в три ветки на выбор пользователя; деньги и юрконтур в конец; две темы переключателем, светлая на лендинге и тёмная в кабинете; SEO и GEO оба контура с первого дня; maigret не копируем из-за GPL-3.0. Собран репозиторий: CLAUDE.md, docs/DECISIONS.md с 12 решениями, docs/ACCEPTANCE.md с поведенческими критериями по всем спринтам, docs/10-seo-geo.md, переписаны 06-frontend (дизайн-система, токены, тон на ты) и 08-roadmap (14 спринтов). Роадмап заведён в дашборд, задачи расписаны по спринтам 0 и 1.

Ждём ок владельца на план спринта 0, дальше код каркаса. Открыто: домен (hvosty.ru занят, нужна альтернатива), состав платных API с ценами, проверка доступности российских источников перед спринтом 7.