# План работ RF4 Spotter Этот файл — единственный актуальный список задач. Завершённые аудиты сохранены как история в [PROJECT_AUDIT_2026-09-08.md](PROJECT_AUDIT_2026-09-08.md), [REGRESSION_AUDIT_2026-09-09.md](REGRESSION_AUDIT_2026-09-09.md) и [RECOVERY_PLAN_2026-09-10.md](RECOVERY_PLAN_2026-09-10.md); их старые чекбоксы не являются текущей очередью. Последняя сверка: **12 сентября 2026**. Подтверждено: - [x] пакет восстановления A01–A13 завершён; итог и доказательства собраны в [RECOVERY_FIXES_REPORT.md](RECOVERY_FIXES_REPORT.md); - [x] полный Python suite: **130 passed, 1 skipped**; skip относится к интеграционной проверке PostgreSQL и покрывается Docker-приёмкой; - [x] Astro check: 40 файлов, **0 errors / 0 warnings / 0 hints**; production build проходит; - [x] API после миграции healthy; `apps/api/tests/test_api.py`: **20 passed**; - [x] локальная БД и чистый bootstrap достигают Alembic head `20260910_recovery`; - [x] изолированный production bootstrap проходит Caddy adapt, scheduler validation и Playwright-сценарий отправки/модерации без обращения к внешним источникам; - [x] Astro + FastAPI + PostgreSQL остаются целевым стеком; Next.js и Vinext не используются. ## Ближайший пакет — без сервера Пункты выполняются сверху вниз, небольшими связанными коммитами. ### Брендинг и визуальная идентичность - [x] **B01 · Иерархия имени.** RF4 Spotter — единое имя продукта в UI, metadata, manifest и документации; «Ни хвоста, ни чешуи» — поддерживающий слоган. Обновлены wordmark в header/footer и подпись выпуска. - [x] **B02 · Дизайн-токены.** Добавлены семантические роли поверхностей, текста, границ, фокуса, success/warning/danger и всех источников. На токены переведены паспорта данных, status-карточки, skeleton и focus; контрастные пары зафиксированы в brand system. - [x] **B03 · Графическая грамматика.** Мотивы закреплены за функциями: крючок — бренд, поплавок — активность/ожидание, леска — время, радар — координаты, силуэт — сущность рыбы. Убраны ложная рябь неполных сигналов и дублирующие радар круги карточки лидера; неполнота теперь подчёркнута спокойной полевой меткой. - [x] **B04 · Компонентная подпись.** `SectionHeading`, `PageHero` и `StatePanel` унифицируют заголовки, hero и состояния; семантическая иерархия `data-action` согласует CTA публичных и admin-страниц. - [x] **B05 · Motion-система.** Смысловые микроанимации пульса, поплавка, загрузки и интерактивного отклика используют общие duration/easing-токены; декоративное движение empty-state удалено, reduced motion покрывает элементы и псевдоэлементы. - [x] **B06 · Brand QA.** Desktop/mobile-проверка усилила каталоги atlas-hero, счётчиками, береговыми контурами и выразительными карточками. Favicon/PWA PNG перегенерированы из SVG-мастера без размытия; `any` и полнофоновые `maskable`-иконки разделены, manifest и Caddy cache обновлены, OG подтверждён как 1200×630. - [x] **B07 · Аудит официальных изображений.** Текущий records-parser получает названия рыб/водоёмов и `title` приманки, но не image URL; официальные gallery/userguide содержат тематические медиа без устойчивого полного соответствия каноническим сущностям. Изображения не хотлинкать и не считать разрешение на данные автоматическим разрешением на медиапубликацию. - [x] **B08 · Семейства силуэтов рыб.** Три случайных hash-варианта заменены классификатором и отдельными формами `pike`, `salmonid`, `cyprinid`, `perch`, `catfish`, `eel`, `flatfish`, `marine`, плюс честный `generic`. Компонент допускает ручное переопределение family; название остаётся главным идентификатором. - [x] **B09 · Глифы снастей и приманок.** Добавлены SVG-глифы `spinner`, `wobbler`, `soft`, `boilie`, `worm`, `rig`, `unknown` и стабильная палитра по normalized name. Классификация срабатывает только по явным словам; глиф сопровождает текст в activity, лидере, уловах, рекордах и списке лучших приманок, не выдавая категорию за точную модель. - [x] **B10 · Визуальные отпечатки водоёмов.** Для каждого slug воспроизводимо выбираются один из восьми береговых контуров, число волн, положение точки и двухсимвольный индекс. Знак используется в каталоге и detail-hero; это явно абстрактный отпечаток, а не карта или игровая география. - [ ] **B11 · Разрешённый media pipeline — в работе.** Получено явное разрешение на локальный сбор. Добавлены allowlist, индекс кандидатов, provenance-manifest, очередь и content-addressed хранение без hotlink; первый официальный обход нашёл 69 кандидатов. Downloader проверяет реальный формат/MIME, лимит 40 Мп, сохраняет dimensions и не блокирует очередь постоянными `missing`/`blocked`/`invalid`. Review допускает `approved` только для сохранённого файла с типом и каноническим ключом сущности; доступен явный `rejected`. Осталось постепенно скачать очередь с общим cooldown 30 минут и проверить соответствия перед публикацией. - [x] **B12 · Эмблема сочетания.** Страница «водоём + рыба» получила составной атласный seal: собственный отпечаток водоёма пересекается со смысловым силуэтом рыбы. Так визуальная идентичность сопровождает всю иерархию каталога и не требует внешних изображений. - [x] **B13 · Навигационная леска атласа.** Разрозненные ссылки назад на detail-страницах заменены доступной breadcrumb-цепочкой с мотивом лески и узлов. Страница точки связывает главную, водоём и координаты; сочетание — каталог, водоём и рыбу. Текущий узел всегда подписан текстом и отмечен `aria-current`. - [x] **B14 · Атласные переходы сущностей.** Боковые списки рыб и водоёмов на detail-страницах получили компактные силуэты и отпечатки рядом с полным текстовым названием. Знаки продолжают систему каталога в рабочей навигации, а стрелка явно показывает переход к странице сочетания. - [x] **B15 · Целостность медиакаталога.** Локальный audit сводит статусы очереди и проверяет наличие файлов, SHA-256, фактические dimensions/MIME, каноническое соответствие approved-записей и бесхозные файлы. Проверка не обращается в сеть и может использоваться как pre-publication gate. - [ ] **Q01 · Документы источников.** Приложить или дать устойчивые ссылки на первичные разрешения RF4DB, RF4-STAT, RF4MAP и RF4 Posts; для каждого зафиксировать атрибуцию, точный production-лимит, срок хранения и процедуру удаления. - [ ] **Q02 · Управляемое удаление источника.** Добавить обнаружение изменённых/удалённых опубликованных записей без отдельного частого обхода: статус, журнал решения и безопасное исключение из активности после проверки. - [ ] **Q03 · Целостность ссылок.** Проверять исходные ссылки только во время разрешённого планового обращения к площадке, разделяя `missing`, `temporary_error` и `blocked`; не создавать дополнительный сетевой цикл. - [x] **Q04 · Состояния ожидания.** Асинхронные admin-очереди получили каркасные карточки, `aria-busy`, очистку при ошибке и поддержку `prefers-reduced-motion`. Публичные страницы остаются SSR и не показывают искусственный skeleton; форма уже блокирует повторную отправку и сообщает «Отправка…». - [x] **Q05 · Базовая визуальная матрица.** Главная проверена в браузере на 320/390/768/1280 px, ключевые public-маршруты — на 320 px; удалён корневой `min-width`, создававший горизонтальный scroll. Добавлен E2E-контракт для `/`, records, report, waterbodies, status и видимого skip-link. Ширина 320 px также покрывает reflow, эквивалентный 200% zoom для окна 640 px. Расширенная матрица наполненных/длинных/error-состояний остаётся постоянной частью приёмки UI, а не отдельным блокером. - [x] **Q06 · Performance baseline.** На локальной production-сборке после оптимизации hero: performance 100, LCP 1,66 с, FCP 1,15 с, CLS 0,023, TBT 9 мс. Устранены найденные Lighthouse проблемы контраста и accessible name; методика и бюджеты записаны в [performance-baseline.md](performance-baseline.md). Полевой INP измеряется только после запуска. - [x] **Q07 · Нагрузочная методика.** Добавлен read-only runner для activity, records, staging и moderation с warm-up, p50/p95/max, распределением HTTP-кодов и ограниченной concurrency. Методика фиксирует контекст запуска, ступени нагрузки и бюджеты, но не объявляет результатов до трёх прогонов на целевом сервере. - [x] **Q08 · Политика MinIO.** Production bootstrap создаёт bucket и отдельную policy только с bucket location/list и get/put/delete его объектов. App credentials проверяются через bucket stat и отрицательную проверку глобального list; API больше не требует `ListAllMyBuckets` и не пытается создавать bucket. Root credentials остаются только у init-задачи. - [ ] **Q09 · Release-процедура — код готов.** Миграции вынесены из API runtime в одноразовый `migrate` service; API запускается только после успешного Alembic upgrade. Документированы backup, rollout и два варианта отката. Осталось проверить upgrade с предыдущей ревизии на копии данных в изолированном Compose drill. - [ ] **Q10 · Документальная ревизия.** После каждого пакета обновлять этот файл и README, не возвращая закрытые R/A/T-задачи в активный backlog. ### Дополнения после ревизии PROJECT_AUDIT_2026-09-10 Аудит выполнен на старой базе `13e04e6`; рекомендации ниже повторно проверены по текущей ветке. Уже реализованные или неприменимые предложения не возвращаются в backlog. - [ ] **Q11 · Декомпозиция API.** Инкрементально разделить `apps/api/app/main.py` (638 строк, 26 маршрутов) на `APIRouter` по публичному каталогу/activity, submissions и admin/community. Сначала зафиксировать OpenAPI snapshot и сохранить URL, response models, middleware и dependency-поведение без функциональных изменений. - [ ] **Q12 · Query-plan gate.** В рамках Q07 снять `EXPLAIN (ANALYZE, BUFFERS)` для activity, records, spot detail и public spot pages на реалистичном наборе данных. Существующие индексы миграции `0011_query_indexes` не дублировать; индекс с `fish_id`, SQL-агрегацию или materialized view добавлять только по измеренному плану и p95. - [ ] **Q13 · Production bootstrap в CI.** Добавить отдельный ручной/плановый job для `deploy/test-production-bootstrap.sh`, не удваивая быстрый Compose E2E на каждом коммите; сохранять diagnostics при падении. - [ ] **Q14 · Полная CSP.** Расширить текущую CSP (`frame-ancestors`, `base-uri`, `object-src`) до `default-src`, `script-src`, `style-src`, `img-src`, `connect-src` и `form-action`. Сначала инвентаризировать inline scripts/styles Astro, затем внедрить nonce/hash или безопасное вынесение; проверить report/admin/OG без ослабления до произвольных внешних origin. - [ ] **Q15 · Частичная деградация главной.** Разделить получение activity, community signals и справочников так, чтобы отказ одного источника не превращал всю главную в общий 503. Для SSR не добавлять искусственный client-side loading/optimistic UI; показывать независимые `StatePanel` и корректный HTTP/cache статус. - [ ] **Q16 · Контракт OpenAPI.** Генерировать OpenAPI artifact из приложения в CI и проверять осознанные изменения контракта при декомпозиции API; не поддерживать вручную редактируемую копию. - [ ] **Q17 · Эксплуатационные документы.** Добавить короткие ADR по Astro/FastAPI/PostgreSQL, локальному cache и стратегии scheduler, а также incident runbook для заполнения диска/PostgreSQL, отказа MinIO, зависших импортов, ошибок миграции и компрометации секретов. - [ ] **Q18 · Минимальная observability.** До открытой альфы определить дешёвые метрики request count/latency/error rate, глубины moderation/staging и возраста последнего успешного импорта. Формат и exporter выбрать после выбора мониторинга сервера; полноценный tracing не внедрять без подтверждённой потребности. ## Готовность открытой альфы — требуется сервер или внешний сервис - [ ] Купить/подготовить Linux-сервер и подтвердить его публичный IPv4/IPv6. - [ ] Настроить DNS `rf4spotter.ru` и `files.rf4spotter.ru`, открыть только необходимые внешние порты и получить корректный TLS через Caddy. - [ ] Создать `.env.production`, заменить все демонстрационные секреты и выполнить `deploy/preflight.sh`. - [ ] Создать публичные контакты privacy/abuse и подключить их к сайту и alpha-баннеру. - [ ] Настроить внешний backup, выполнить восстановление с сервера и подключить реальный канал уведомлений. - [ ] Наполнить альфу небольшим разрешённым набором данных и провести финальную приёмку по [open-alpha-acceptance.md](open-alpha-acceptance.md). - [ ] После 24 часов стабильной работы пригласить первых игроков, собрать обратную связь и закрыть блокирующие проблемы пилота. - [ ] Подключить Search Console/Яндекс Вебмастер и проверить реальные canonical, sitemap, robots, OG и JSON-LD. - [ ] Снять серверные p95 и Lighthouse; скорректировать индексы, кэш и изображения только по измерениям. ## После пилота - [ ] Решить по обратной связи, нужны ли OCR, Telegram, профили и уведомления о клёве. - [ ] Рассмотреть cursor pagination при росте объёмов; текущая offset pagination достаточна для альфы. - [ ] Рассмотреть общую инвалидацию кэша при нескольких API-процессах; сейчас действует TTL и локальная инвалидация. - [ ] Рассмотреть Redis только при переходе к нескольким API-процессам или после измеренного дефицита локального cache; не добавлять отдельный stateful-сервис заранее. - [ ] Подготовить тематические обложки и индивидуальные OG для рыб/водоёмов, если страницы подтверждают поисковую ценность. ## Правила выполнения - Сетевой парсинг одной площадки — не чаще одного раза за 30 минут, включая ошибки и разные endpoint. - Каждая публичная запись обязана показывать источник; неполные данные — отдельную пометку и список отсутствующих полей. - Реальные источники не используются в тестах: только fixtures и изолированные Docker-сценарии. - Docker запускается одним общим прогоном для инфраструктурного пакета, а не после каждой правки. - Пункт закрывается только после адресной проверки; команда и результат фиксируются в коммите или отчёте. - Не менять целевой стек Astro + FastAPI + PostgreSQL.