randomayzer/docs/ARCHITECTURE.md

81 lines
7.5 KiB
Markdown
Raw Permalink 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.

# Архитектура VK Giveaway Randomizer
## 1. Обзор архитектуры
Система построена по принципам чистой архитектуры (Clean Architecture / Hexagonal Architecture) с разделением на независимые слои:
```mermaid
graph TD
UI[Frontend UI: Next.js App Router] --> API[Next.js API Routes / Server Actions]
API --> Core[Core Domain Layer: Randomizer & Filtering]
API --> Providers[Social Providers Layer: VK / Telegram / YouTube]
API --> DB[(Database: PostgreSQL + Prisma)]
Providers --> VK[Official VK API / VK Mock]
```
## 2. Слои приложения
### 2.1. Core Domain Layer (`src/core/`)
Ядро приложения не зависит от конкретной социальной сети или веб-фреймворка:
- **`src/core/randomizer/`**:
- `deterministic.ts`: Реализация детерминированного генератора случайных чисел (PRNG) и перетасовки Фишера-Йетса с использованием криптографических хешей (SHA-256 HMAC).
- `hasher.ts`: Генерация фиксированного отпечатка (Snapshot Hash) списка участников перед розыгрышем.
- **`src/core/filtering/`**:
- `filter-engine.ts`: Механизм фильтрации участников на основе заданных условий (лайк, репост, коммент, подписка, черный список ID, исключение админов, дедупликация).
- **`src/core/types/`**:
- Типизированные контракты сущностей (`Giveaway`, `Participant`, `DrawResult`, `AuditRecord`, `FilterRules`).
### 2.2. Social Providers Layer (`src/providers/`)
Абстракция взаимодействия с внешними платформами:
- **`SocialMediaProvider`** (Interface):
- `fetchPost(url: string)`: Получение метаданных публикации (автор, текст, превью, счетчики).
- `fetchParticipants(params: FetchParticipantsParams)`: Загрузка списка участников (лайки, комменты, репосты).
- `checkSubscription(userIds: string[], groupId: string)`: Проверка подписки на сообщество.
- **`VkProvider`**: Боевой клиент к VK API с поддержкой пакетных запросов `execute`.
- **`VkMockProvider`**: Тестовый провайдер для демонстрации, локальной разработки и оффлайн-тестирования.
- **`ProviderFactory`**: Фабрика для получения провайдера по типу платформы (`VK`, `TELEGRAM`, `YOUTUBE`).
### 2.3. Data & Persistence Layer (`prisma/` + `src/lib/`)
- **PostgreSQL** в качестве надежного реляционного хранилища.
- **Prisma ORM** для типобезопасной работы с БД.
- Хранение всех розыгрышей, снапшотов участников и записей аудита для публичной верификации.
### 2.4. Presentation Layer (`src/app/` + `src/components/`)
- Modern React + Next.js App Router.
- Интерактивный визард создания розыгрыша с живым превью поста, настройкой условий, интерактивной таблицей участников и презентацией победителей.
---
## 3. Механизм честности и доказуемости (Provably Fair)
Каждый розыгрыш формирует криптографический аудит-след на базе алгоритма `HMAC_SHA256_FY_V1`:
1. **Снапшот участников**: Список прошедших фильтрацию (eligible) участников сортируется по `platformUserId` и канонически сериализуется:
$$\text{ParticipantsSnapshotHash} = \text{SHA256}(\text{canonicalStringify}(\text{sortedEligibleParticipants}))$$
2. **Seed Pre-Commitment (Защита от Seed Grinding)**:
- В момент фиксации слепка (`SNAPSHOT_LOCKED`) сервер генерирует CSPRNG seed и публикует его SHA-256 обязательство:
$$\text{SeedCommitment} = \text{SHA256}(\text{seed})$$
- До момента проведения жеребьевки сам `seed` строго скрыт (`seed: null`), но `seedCommitment` доступен публично. Организатор может зафиксировать его публично (например, в комментарии к конкурсному посту VK) до розыгрыша.
3. **Детерминированный выбор (`HMAC_SHA256_FY_V1`)**:
- Выборка осуществляется с помощью несмещенного сэмплинга Фишера-Йетса (Fisher-Yates) поверх потока псевдослучайных байт HMAC-SHA256:
$$\text{ByteStream} = \text{HMAC-SHA256}(\text{key} = \text{seed}, \text{data} = \text{ParticipantsSnapshotHash} \parallel \text{ConditionsHash} \parallel \text{blockIndex})$$
- Позиции победителей и резерва рассчитываются детерминированно.
4. **Публичное раскрытие и аудит**:
- После перевода розыгрыша в статус `DRAWN` сервер раскрывает `seed`.
- Любой участник может проверить:
1. $\text{SHA256}(\text{seed}) == \text{SeedCommitment}$ (гарантия того, что seed не подбирался под желаемого победителя);
2. Воспроизведение результатов выборки при наличии слепка;
3. Неизменность `deterministicProofHash` и `auditEventHash`.
### 3.1. Границы публичной проверяемости и защита приватности (PII Compromise)
- **Что проверяется внешним наблюдателем:**
- Корректность раскрытия seed относительно опубликованного pre-commitment.
- Математическая повторяемость алгоритма.
- Совпадение хешей доказательства (`deterministicProofHash`).
- **Что остаётся приватным:**
- Полный список участников и их персональные данные (PII) **не отдаются анонимным пользователям** в целях соблюдения требований защиты данных третьих лиц. Публикуются только победители и хеш слепка `participantsSnapshotHash`.
- Внешний наблюдатель без исходного списка участников не может самостоятельно с нуля пересчитать `participantsSnapshotHash`.
- **Архитектурный статус доверия:**
- Доказательство формируется и проверяется на сервере Randomayzer на основе зафиксированного в БД слепка. Децентрализованный внешний якорь (блокчейн, drand, RFC 3161) на текущем этапе не используется.