Compare commits
2
Commits
a37b1c2b8b
...
16e4c071d1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16e4c071d1 | ||
|
|
24b33695b2 |
@@ -6,7 +6,7 @@ RF4 Spotter — неофициальный сервис свежих точек
|
|||||||
|
|
||||||
## Статус разработки
|
## Статус разработки
|
||||||
|
|
||||||
Функциональный MVP и локальный production-контур готовы к закрытой альфе: официальный импорт, пользовательские заявки, модерация, объяснимый индекс, staging внешних источников, адаптивный Astro UI, миграции, резервное копирование, retention, мониторинг и security/accessibility-проверки реализованы. Автоматические импорты внешних источников выключены. Публичный запуск блокируют покупка и настройка сервера, DNS/TLS, реальные секреты, внешний backup и канал уведомлений.
|
Функциональный MVP и локальный production-контур готовятся к открытой альфе: официальный импорт, пользовательские заявки, модерация, объяснимый индекс, staging внешних источников, адаптивный Astro UI, миграции, резервное копирование, retention, мониторинг и security/accessibility-проверки реализованы. Автоматические импорты внешних источников выключены. Публичный запуск блокируют покупка и настройка сервера, DNS/TLS, реальные секреты, внешний backup, канал уведомлений и публичные страницы правил/privacy.
|
||||||
|
|
||||||
RF4DB/RF4-STAT/RF4MAP/RF4 Posts принимаются только в изолированный staging и не влияют на индекс без ручного сопоставления и публикации. Для разрешённых community-источников действует интервал не менее 30 минут на источник.
|
RF4DB/RF4-STAT/RF4MAP/RF4 Posts принимаются только в изолированный staging и не влияют на индекс без ручного сопоставления и публикации. Для разрешённых community-источников действует интервал не менее 30 минут на источник.
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ Host-side мониторинг контейнеров, readiness, диска, р
|
|||||||
Ежедневный systemd timer создаёт проверяемую копию до retention-очистки, а production Compose ограничивает рост JSON-логов контейнеров.
|
Ежедневный systemd timer создаёт проверяемую копию до retention-очистки, а production Compose ограничивает рост JSON-логов контейнеров.
|
||||||
|
|
||||||
Фактическое состояние DNS/TLS домена и серверный чек-лист ведутся в [`docs/deployment-status.md`](docs/deployment-status.md).
|
Фактическое состояние DNS/TLS домена и серверный чек-лист ведутся в [`docs/deployment-status.md`](docs/deployment-status.md).
|
||||||
Результаты security review и остаточные ограничения закрытой альфы записаны в [`docs/security-review.md`](docs/security-review.md).
|
Результаты security review и остаточные риски открытой альфы записаны в [`docs/security-review.md`](docs/security-review.md).
|
||||||
|
|
||||||
## Архитектура
|
## Архитектура
|
||||||
|
|
||||||
|
|||||||
@@ -62,4 +62,28 @@ for (const viewport of [{ name: "desktop", width: 1280, height: 900 }, { name: "
|
|||||||
const dimensions = await page.evaluate(() => ({ width: document.documentElement.clientWidth, scroll: document.documentElement.scrollWidth }));
|
const dimensions = await page.evaluate(() => ({ width: document.documentElement.clientWidth, scroll: document.documentElement.scrollWidth }));
|
||||||
expect(dimensions.scroll).toBeLessThanOrEqual(dimensions.width);
|
expect(dimensions.scroll).toBeLessThanOrEqual(dimensions.width);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test(`external staging queue is safe on ${viewport.name}`, async ({ page }) => {
|
||||||
|
await page.setViewportSize(viewport);
|
||||||
|
let mutations = 0;
|
||||||
|
await page.route("**/api/v1/**", async route => {
|
||||||
|
const request = route.request();
|
||||||
|
if (request.method() !== "GET") mutations += 1;
|
||||||
|
const path = new URL(request.url()).pathname;
|
||||||
|
if (path.endsWith("/fishes")) return route.fulfill({ json: [{ slug: "pike", name_ru: "Щука" }] });
|
||||||
|
if (path.endsWith("/waterbodies")) return route.fulfill({ json: [{ slug: "kuori", name_ru: "Куори" }] });
|
||||||
|
if (path.endsWith("/admin/external-observations")) return route.fulfill({ json: [{ id: "10000000-0000-0000-0000-000000000001", source_system: "rf4db", source_external_id: "fixture-1", source_url: "https://rf4db.com/fixture-1", fish_name: "Pike", waterbody_name: "Kuori", x: 72, y: 84, weight_g: null, status: "staged", fish_slug: null, waterbody_slug: null, review_note: null }] });
|
||||||
|
return route.fulfill({ status: 404 });
|
||||||
|
});
|
||||||
|
await page.goto("/admin/external-sources");
|
||||||
|
await page.getByLabel("Административный токен").fill("test-token-not-sent");
|
||||||
|
await page.getByRole("button", { name: "Открыть очередь" }).click();
|
||||||
|
const card = page.locator(".moderation-card");
|
||||||
|
await expect(card).toContainText("rf4db");
|
||||||
|
await expect(card.getByLabel("Каноническая рыба")).toContainText("Щука");
|
||||||
|
await expect(card.getByRole("button", { name: "Опубликовать" })).toBeDisabled();
|
||||||
|
expect(mutations).toBe(0);
|
||||||
|
const dimensions = await page.evaluate(() => ({ width: document.documentElement.clientWidth, scroll: document.documentElement.scrollWidth }));
|
||||||
|
expect(dimensions.scroll).toBeLessThanOrEqual(dimensions.width);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -1,4 +1,4 @@
|
|||||||
# Развёртывание закрытой альфы rf4spotter.ru
|
# Развёртывание открытой альфы rf4spotter.ru
|
||||||
|
|
||||||
Production-контур рассчитан на один Linux-сервер с Docker Compose. Наружу публикуются только Caddy `80/443`; PostgreSQL, FastAPI и MinIO не имеют host-портов. Административные страницы защищены одновременно Caddy Basic Auth и API bearer token.
|
Production-контур рассчитан на один Linux-сервер с Docker Compose. Наружу публикуются только Caddy `80/443`; PostgreSQL, FastAPI и MinIO не имеют host-портов. Административные страницы защищены одновременно Caddy Basic Auth и API bearer token.
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ Production-контур рассчитан на один Linux-сервер с D
|
|||||||
|
|
||||||
Создайте A-записи `rf4spotter.ru` и `files.rf4spotter.ru` на публичный IPv4 сервера. При наличии рабочего IPv6 добавьте AAAA для обоих имён. До запуска убедитесь, что извне доступны TCP 80/443 и UDP 443; SSH ограничьте своим IP или VPN. Порты 4321, 8000, 9000, 9001 и 5432 открывать нельзя.
|
Создайте A-записи `rf4spotter.ru` и `files.rf4spotter.ru` на публичный IPv4 сервера. При наличии рабочего IPv6 добавьте AAAA для обоих имён. До запуска убедитесь, что извне доступны TCP 80/443 и UDP 443; SSH ограничьте своим IP или VPN. Порты 4321, 8000, 9000, 9001 и 5432 открывать нельзя.
|
||||||
|
|
||||||
Минимум для закрытой альфы: 2 vCPU, 4 ГБ RAM и 40 ГБ SSD. Рекомендуется 4 vCPU, 8 ГБ RAM и отдельное внешнее место для резервных копий.
|
Минимум для открытой альфы: 2 vCPU, 4 ГБ RAM и 40 ГБ SSD. Рекомендуется 4 vCPU, 8 ГБ RAM и отдельное внешнее место для резервных копий.
|
||||||
|
|
||||||
## 2. Секреты
|
## 2. Секреты
|
||||||
|
|
||||||
@@ -145,10 +145,12 @@ systemctl list-timers rf4spotter-maintenance.timer
|
|||||||
|
|
||||||
Проверка контролирует контейнеры, `/ready`, диск, свежесть backup и срок TLS. Установка systemd timer, пороги и порядок реакции описаны в [`docs/production-monitoring.md`](../docs/production-monitoring.md). До подключения реального канала уведомлений одного журнала systemd недостаточно.
|
Проверка контролирует контейнеры, `/ready`, диск, свежесть backup и срок TLS. Установка systemd timer, пороги и порядок реакции описаны в [`docs/production-monitoring.md`](../docs/production-monitoring.md). До подключения реального канала уведомлений одного журнала systemd недостаточно.
|
||||||
|
|
||||||
## 9. Что ещё блокирует приглашение альфа-пользователей
|
## 9. Что ещё блокирует публичное открытие альфы
|
||||||
|
|
||||||
- подключение уведомлений о сбоях мониторинга;
|
- подключение уведомлений о сбоях мониторинга;
|
||||||
- проверка DNS/TLS и полного запуска на целевом сервере;
|
- проверка DNS/TLS и полного запуска на целевом сервере;
|
||||||
- внешнее зашифрованное хранилище резервных копий.
|
- внешнее зашифрованное хранилище резервных копий.
|
||||||
|
- действующие `privacy@rf4spotter.ru` и `abuse@rf4spotter.ru`, публичные правила и privacy notice;
|
||||||
|
- проверка rate limit и очереди модерации под ожидаемой публичной нагрузкой.
|
||||||
|
|
||||||
До закрытия этих пунктов контур можно поднять для технической проверки домена, но не следует открывать форму реальным пользователям.
|
До закрытия этих пунктов контур можно поднять для технической проверки домена, но не следует открывать форму без ограничения доступа.
|
||||||
|
|||||||
+6
-3
@@ -78,7 +78,7 @@
|
|||||||
- [x] Упростить форму улова, добавить помощь форматов, валидацию и сохранение значений при ошибке (пакет C UI/UX-аудита).
|
- [x] Упростить форму улова, добавить помощь форматов, валидацию и сохранение значений при ошибке (пакет C UI/UX-аудита).
|
||||||
- [x] Заменить slug-фильтры справочниками, добавить сброс и самодостаточные мобильные строки рекордов (пакет D UI/UX-аудита; detail уже адаптивен).
|
- [x] Заменить slug-фильтры справочниками, добавить сброс и самодостаточные мобильные строки рекордов (пакет D UI/UX-аудита; detail уже адаптивен).
|
||||||
- [x] Завершить accessibility/admin safety пакет с воспроизводимыми axe/Lighthouse-командами (пакет E).
|
- [x] Завершить accessibility/admin safety пакет с воспроизводимыми axe/Lighthouse-командами (пакет E).
|
||||||
- [ ] Добавить smoke-проверку административной очереди внешних источников на desktop/mobile без публикации реальных записей.
|
- [x] Добавить smoke-проверку административной очереди внешних источников на desktop/mobile: API-фикстура, неполная запись, disabled publish, ноль mutation-запросов и отсутствие overflow.
|
||||||
- [x] Обновить README: актуальный статус, архитектура, группы переменных окружения, импорт, модерация, backup/restore, эксплуатация логов и известные ограничения.
|
- [x] Обновить README: актуальный статус, архитектура, группы переменных окружения, импорт, модерация, backup/restore, эксплуатация логов и известные ограничения.
|
||||||
- [x] Выбрать лицензию кода `AGPL-3.0-only` и оформить отдельную политику использования, минимизации, хранения и удаления данных (`LICENSE`, `docs/data-policy.md`).
|
- [x] Выбрать лицензию кода `AGPL-3.0-only` и оформить отдельную политику использования, минимизации, хранения и удаления данных (`LICENSE`, `docs/data-policy.md`).
|
||||||
- [ ] Завершить production-профиль для `rf4spotter.ru`: приложение и `deploy/preflight.sh` готовы; внешняя проверка 7 сентября не установила соединение с обоими доменами, требуются IP целевого сервера, DNS, запуск и канал уведомлений (`docs/deployment-status.md`).
|
- [ ] Завершить production-профиль для `rf4spotter.ru`: приложение и `deploy/preflight.sh` готовы; внешняя проверка 7 сентября не установила соединение с обоими доменами, требуются IP целевого сервера, DNS, запуск и канал уведомлений (`docs/deployment-status.md`).
|
||||||
@@ -107,6 +107,9 @@
|
|||||||
|
|
||||||
## Этап 5 — пилот
|
## Этап 5 — пилот
|
||||||
|
|
||||||
|
- [ ] Опубликовать правила открытой альфы и privacy notice, добавить явное согласие перед отправкой улова.
|
||||||
|
- [ ] Создать и проверить ящики `privacy@rf4spotter.ru` и `abuse@rf4spotter.ru`, определить срок реакции на обращения.
|
||||||
|
- [ ] Проверить публичные abuse-сценарии: burst заявок, крупные файлы, повторные отправки и рост очереди модерации.
|
||||||
- [ ] Зафиксировать короткий сценарий приёмки пилота и измеримые критерии: успешная отправка/модерация, понятность оценки, свежесть данных и допустимое время ответа.
|
- [ ] Зафиксировать короткий сценарий приёмки пилота и измеримые критерии: успешная отправка/модерация, понятность оценки, свежесть данных и допустимое время ответа.
|
||||||
- [ ] Согласовать первые категории рекордов, водоёмы и виды рыб.
|
- [ ] Согласовать первые категории рекордов, водоёмы и виды рыб.
|
||||||
- [ ] Наполнить базу небольшим разрешённым набором реальных данных.
|
- [ ] Наполнить базу небольшим разрешённым набором реальных данных.
|
||||||
@@ -119,8 +122,8 @@
|
|||||||
|
|
||||||
Технический production-контур, health/readiness, backup/restore и безопасные логи готовы. Следующие пункты выполняются строго по одному:
|
Технический production-контур, health/readiness, backup/restore и безопасные логи готовы. Следующие пункты выполняются строго по одному:
|
||||||
|
|
||||||
1. добавить smoke-проверку административного staging без публикации;
|
1. добавить публичные страницы правил и privacy notice, согласие формы и контакты `privacy`/`abuse`;
|
||||||
2. подготовить сценарий и измеримые критерии закрытой альфы;
|
2. подготовить сценарий и измеримые критерии открытой альфы, включая публичную нагрузку и злоупотребления;
|
||||||
3. мониторинг, DNS/TLS и проверка production-профиля на целевом сервере.
|
3. мониторинг, DNS/TLS и проверка production-профиля на целевом сервере.
|
||||||
|
|
||||||
После каждого пункта необходимо:
|
После каждого пункта необходимо:
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
# Политика использования данных RF4 Spotter
|
# Политика использования данных RF4 Spotter
|
||||||
|
|
||||||
Версия для закрытой альфы от 7 сентября 2026 года. Это проектная политика, а не замена условиям владельцев источников или требованиям применимого законодательства.
|
Версия для открытой альфы от 7 сентября 2026 года. Это проектная политика, а не замена условиям владельцев источников или требованиям применимого законодательства.
|
||||||
|
|
||||||
## Область действия
|
## Область действия
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ RF4 Spotter обрабатывает официальные публичные
|
|||||||
|
|
||||||
Технические сроки определены в `docs/data-retention.md`: попытки отправки — 1 день, непроверенные заявки — 30 дней, персональные поля одобренных заявок — 180 дней, непубликуемый staging — 90 дней, журнал модерации и provenance опубликованных записей — до 365 дней. Очистка выполняется только после успешной резервной копии.
|
Технические сроки определены в `docs/data-retention.md`: попытки отправки — 1 день, непроверенные заявки — 30 дней, персональные поля одобренных заявок — 180 дней, непубликуемый staging — 90 дней, журнал модерации и provenance опубликованных записей — до 365 дней. Очистка выполняется только после успешной резервной копии.
|
||||||
|
|
||||||
Автор добровольной заявки может запросить удаление, указав идентификатор заявки и достаточные сведения для её поиска, по адресу `privacy@rf4spotter.ru`. При удалении очищаются ник, комментарий, исходная ссылка и скриншот; обезличенный факт модерационного действия сохраняется для аудита. До настройки действующего почтового ящика форма не должна открываться внешним альфа-пользователям.
|
Автор добровольной заявки может запросить удаление, указав идентификатор заявки и достаточные сведения для её поиска, по адресу `privacy@rf4spotter.ru`; сообщения о злоупотреблениях принимаются на `abuse@rf4spotter.ru`. При удалении очищаются ник, комментарий, исходная ссылка и скриншот; обезличенный факт модерационного действия сохраняется для аудита. До настройки обоих ящиков форма не должна быть доступна публично.
|
||||||
|
|
||||||
Если запись изменена или удалена первичным источником, оператор при подтверждении снимает её с публикации и очищает производные персональные поля в ближайший цикл обслуживания. Резервные копии исчезают по собственному графику хранения и не используются для обычного чтения.
|
Если запись изменена или удалена первичным источником, оператор при подтверждении снимает её с публикации и очищает производные персональные поля в ближайший цикл обслуживания. Резервные копии исчезают по собственному графику хранения и не используются для обычного чтения.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Политика хранения данных закрытой альфы
|
# Политика хранения данных открытой альфы
|
||||||
|
|
||||||
Политика минимизирует персональные и диагностические данные, не разрушая обезличенную статистику клёва. Сроки считаются от `reported_at`, `created_at` или `last_seen_at` соответствующей записи.
|
Политика минимизирует персональные и диагностические данные, не разрушая обезличенную статистику клёва. Сроки считаются от `reported_at`, `created_at` или `last_seen_at` соответствующей записи.
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Мониторинг закрытой альфы
|
# Мониторинг открытой альфы
|
||||||
|
|
||||||
`deploy/monitor.sh` — host-side проверка production-контура. Она не изменяет данные и не печатает секреты. Успех возвращает exit code `0` и одну строку `OK`; любая проблема возвращает `1`/`2` и строку `CRITICAL`.
|
`deploy/monitor.sh` — host-side проверка production-контура. Она не изменяет данные и не печатает секреты. Успех возвращает exit code `0` и одну строку `OK`; любая проблема возвращает `1`/`2` и строку `CRITICAL`.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Production security review
|
# Production security review
|
||||||
|
|
||||||
Проверка выполнена 7 сентября 2026 года для закрытой альфы. Она охватывает код и Compose-конфигурацию; firewall, SSH, DNS и фактические права файлов проверяются отдельно на целевом сервере.
|
Проверка выполнена 7 сентября 2026 года и актуализирована для открытой альфы. Она охватывает код и Compose-конфигурацию; firewall, SSH, DNS и фактические права файлов проверяются отдельно на целевом сервере.
|
||||||
|
|
||||||
## Закрытые пункты
|
## Закрытые пункты
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
| Логи | query string, IP, Authorization и payload не журналируются; известные формы секретов редактируются |
|
| Логи | query string, IP, Authorization и payload не журналируются; известные формы секретов редактируются |
|
||||||
| Персональные данные | действует документированная retention-очистка, причём backup выполняется раньше удаления |
|
| Персональные данные | действует документированная retention-очистка, причём backup выполняется раньше удаления |
|
||||||
|
|
||||||
## Остаточные ограничения закрытой альфы
|
## Остаточные риски открытой альфы
|
||||||
|
|
||||||
- Basic Auth и bearer token общие для всех модераторов: персональная атрибуция и отзыв одной учётной записи отсутствуют.
|
- Basic Auth и bearer token общие для всех модераторов: персональная атрибуция и отзыв одной учётной записи отсутствуют.
|
||||||
- Нет MFA и отдельного identity provider; admin credentials следует передавать только ограниченному числу операторов и ротировать при любом подозрении.
|
- Нет MFA и отдельного identity provider; admin credentials следует передавать только ограниченному числу операторов и ротировать при любом подозрении.
|
||||||
|
|||||||
Reference in New Issue
Block a user