docs: каноничный plan.md, остальные планы → [DEPRECATED]

This commit is contained in:
“Naeel”
2026-05-30 07:22:49 +03:00
parent f853ed9a6b
commit 09ffa4c385
7 changed files with 644 additions and 632 deletions
+552
View File
@@ -0,0 +1,552 @@
# Актуальный план реализации — IP WhiteList
> Автор: GitHub Copilot (GPT-5.4)
> Дата: 2026-05-30
> Основание: ТЗ из WhiteIPlist.txt + фактический код в ipwhitelist-app
> Статус: заменяет предыдущую версию плана
## 1. Вывод по текущему состоянию
Предыдущий план был неполным, потому что строился не от ТЗ, а от видимого MVP. После сверки с WhiteIPlist.txt картина такая:
1. Основа сервиса уже написана лучше, чем казалось: схема БД, soft delete, аудит, custom_limit, updateEntry и полный список запрещённых диапазонов уже есть в коде.
2. Основной разрыв находится не в модели данных, а между слоями: часть функций реализована в src/queries.js, но не выведена в server.js и views.
3. Главные недостающие вещи для соответствия ТЗ: нормальная OIDC-авторизация, admin-сценарии, редактирование из UI, клиентская валидация, агрегирующий экспорт.
4. Переписывать стек или БД не нужно. Нужно довести существующую реализацию до полноты требований.
## 2. Что требует ТЗ
Сервис по ТЗ обязан поддерживать:
1. Self-service страницу управления whitelist-записями.
2. Авторизацию через Keycloak OIDC.
3. Роли client и admin.
4. Возможность работы пользователя с одной или несколькими компаниями.
5. Создание, редактирование и soft delete записей.
6. Серверную и клиентскую валидацию IPv4/CIDR.
7. Глобальный лимит и индивидуальные лимиты по компаниям.
8. Журнал аудита.
9. Внешний endpoint выдачи агрегированного списка активных CIDR.
10. Admin-функции: просмотр всех компаний, фильтрация, просмотр удалённых записей, изменение лимитов.
## 3. Что уже реализовано сейчас
### 3.1 База данных
В sql/schema.sql уже есть всё базовое, что нужно для ТЗ:
1. Таблица companies с client_id и custom_limit.
2. Таблица whitelist_entries с updated_by, updated_at, deleted_by, deleted_at.
3. Таблица audit_log.
4. Индекс активных записей и индекс по audit_log(company_id).
Вывод: схему БД переписывать не нужно.
### 3.2 Серверная логика
В src/queries.js уже реализованы:
1. getOrCreateCompany
2. getLimit
3. listEntries с includeDeleted
4. createEntry
5. updateEntry
6. deleteEntry как soft delete
7. getExportCIDRs
8. getAudit
Вывод: слой работы с БД уже покрывает значительную часть ТЗ.
### 3.3 Валидация
В src/validators.js уже есть:
1. Только IPv4.
2. Маски только /22–/32.
3. Нормализация host-битов.
4. Запрет всех диапазонов из Приложения А ТЗ, включая CGNAT, Benchmarking, Multicast, Reserved и Limited broadcast.
5. Проверка пересечений.
Вывод: серверная валидация по составу требований почти полная.
### 3.4 UI и маршруты
В server.js и views/index.ejs уже есть:
1. Главная страница со списком записей.
2. Форма добавления.
3. Soft delete через POST /delete/:id.
4. Экспорт через GET /export.
5. Вывод текущего лимита и числа использованных записей.
6. UI, близкий к стилю Nubes.
Вывод: клиентский сценарий создания и удаления уже работает как MVP.
## 4. Что не соответствует ТЗ или не доведено до конца
### 4.1 Авторизация
Сейчас в server.js не OIDC, а упрощённый decode токена через base64 без проверки подписи. Это подходит только как временная заглушка, но не соответствует ТЗ.
Нужно:
1. Реальная проверка JWT через Keycloak/JWKS или openid-client.
2. Нормальный маппинг claims в user-модель.
3. Явное определение роли admin.
4. Поддержка сценария с несколькими компаниями.
Это главный блокер продакшна.
### 4.2 Редактирование записи
updateEntry уже написана, но:
1. Нет роута POST /update/:id.
2. Нет формы редактирования в index.ejs.
3. Нет пользовательского сценария изменения записи.
То есть требование ТЗ формально не закрыто, хотя код на уровне queries уже есть.
### 4.3 Admin-функции
По ТЗ администратор должен:
1. Видеть записи всех компаний.
2. Фильтровать по компании.
3. Видеть soft-deleted записи.
4. Смотреть аудит.
5. Менять лимиты компаний.
Сейчас ничего из этого не выведено в server.js и views.
### 4.4 Экспорт
GET /export уже есть, но он отдаёт просто список value_cidr без агрегации. ТЗ требует суммаризацию в минимальный набор CIDR по всем активным записям.
Это функциональный разрыв, а не косметика.
### 4.5 Клиентская валидация
ТЗ требует валидацию на клиенте и сервере. Сейчас есть только серверная.
Нужно добавить в форму как минимум:
1. Проверку формата IPv4/CIDR.
2. Проверку диапазона маски.
3. Ограничение длины комментария.
4. Сообщение о возможной нормализации.
### 4.6 Multi-company сценарий
ТЗ явно говорит, что пользователь может принадлежать нескольким компаниям. Сейчас всё построено вокруг одного clientId в req.user.
Нужно:
1. Понять реальный формат claims.
2. Ввести activeCompany в контекст пользователя.
3. Добавить переключатель активной компании в UI.
## 5. Что не надо перепридумывать
1. Не надо переписывать проект на другой язык или другой фреймворк.
2. Не надо менять схему БД ради самой схемы.
3. Не надо переписывать validators.js целиком.
4. Не надо переписывать queries.js целиком.
5. Не надо делать SPA.
Правильный путь: минимально нарастить уже существующую Node.js/Express/EJS реализацию.
## 6. Риски и спорные места
### 6.1 overlaps в validators.js
Условие в overlaps написано нестандартно и плохо читается. Прямого доказанного бага по одной только формуле сейчас нет, но это место требует отдельного теста на:
1. полное совпадение,
2. вложенность,
3. непересекающиеся диапазоны,
4. соседние диапазоны,
5. одиночный IP против подсети.
Решение: сначала добавить точечные тесты, и только потом менять формулу, если тест покажет дефект.
### 6.2 Admin-роль
ТЗ говорит: admin это clientId = WZ01112 и отдельный чек-бокс. Сейчас неясно, как этот чек-бокс попадает в токен. Без этого нельзя финально закрыть auth-модель.
### 6.3 Multi-company claims
ТЗ требует сценарий нескольких компаний, но в списке claims указан только clientID. Здесь нужна конкретика от команды Keycloak.
## 7. Новый план реализации
### Этап 1. Довести до полноты пользовательский сценарий
Цель: закрыть основной client-flow без смены архитектуры.
1. Добавить роут POST /update/:id в server.js.
2. Добавить UI редактирования в views/index.ejs.
3. Показать updated_at и updated_by, если запись менялась.
4. Добавить клиентскую валидацию формы добавления и редактирования.
5. Добавить точечные тесты на overlaps и нормализацию.
Результат этапа: client сможет не только добавлять и удалять, но и редактировать записи, как требует ТЗ.
### Этап 2. Закрыть admin-функциональность
Цель: реализовать недостающую управленческую часть ТЗ.
1. Ввести определение роли admin в auth-слое.
2. Добавить GET /admin.
3. Добавить фильтр по компании.
4. Добавить показ удалённых записей.
5. Добавить GET /admin/audit.
6. Добавить POST /admin/limit/:companyId.
7. Добавить отдельный admin view.
Результат этапа: появляется реальная административная панель, а не только клиентский экран.
### Этап 3. Привести авторизацию к ТЗ
Цель: убрать временную заглушку и сделать реальную интеграцию с Keycloak.
1. Заменить наивный decode токена на верификацию подписи.
2. Добавить конфигурацию issuer, audience, jwks/oidc.
3. Нормализовать claims в req.user.
4. Поддержать admin-claim.
5. Поддержать multi-company claims.
6. Оставить DEV_MODE только для локальной разработки.
Результат этапа: сервис можно выводить из чисто dev-сценария.
### Этап 4. Довести экспорт до требований ТЗ
Цель: сделать экспорт пригодным для систем фильтрации.
1. Добавить суммаризацию активных записей в минимальный набор CIDR.
2. Суммаризировать по всем компаниям совместно.
3. Исключать soft-deleted записи.
4. Оставить выдачу text/plain, одна строка на объект.
5. Отдельно решить, где ограничивается доступ к export endpoint: ingress, app или оба уровня.
Результат этапа: экспорт соответствует ТЗ, а не является просто дампом таблицы.
### Этап 5. Завершение и проверка полноты
1. Сверить все пункты ТЗ с реализованным поведением.
2. Обновить тестовый сценарий.
3. Проверить UX ошибок и предупреждений.
4. Проверить поведение при снижении custom_limit ниже текущего числа активных записей.
5. Проверить сценарии admin/client отдельно.
## 8. Практический приоритет
Если делать не всё сразу, а по реальной важности, порядок такой:
1. Редактирование записи из UI.
2. Клиентская валидация.
3. Admin-панель и лимиты.
4. Реальный OIDC.
5. Multi-company.
6. Суммаризация export.
Почему именно так:
1. Редактирование уже почти готово и закрывает явный пробел ТЗ.
2. Admin-функции сейчас отсутствуют полностью.
3. OIDC блокирует продакшн, но не мешает локально добить функциональность.
4. Экспорт уже работает как черновой endpoint, но должен быть доведён до суммаризации до релиза.
## 9. Итог
Правильный план для этого проекта не “переписать всё правильно”, а “довести уже написанное до требований ТЗ”.
Текущее состояние проекта:
1. Data-layer в основном готов.
2. Server-layer частично готов.
3. UI-layer закрывает только часть client-сценария.
4. Auth-layer пока временный.
5. Admin-layer почти отсутствует.
6. Export-layer не завершён по требованиям агрегации.
Главный вывод: проект ближе к рабочему состоянию, чем казалось по старым планам, но прошлый план был методологически неверен, потому что не опирался на ТЗ и не различал “не написано” и “написано, но не подключено”.
Эта часть критична. Её нужно делать одной из первых и сразу покрывать тестами.
### Поддерживаемый ввод
1. Одиночный IPv4 адрес, который трактуется как /32.
2. IPv4 подсеть в CIDR нотации.
### Запрещённый ввод
1. IPv6.
2. Доменное имя.
3. Маска шире допустимой.
4. Любые private или special ranges из приложения А.
### Правила маски
Допустимы только /22 ... /32.
### Нормализация
Если пользователь ввёл адрес с host-битами, сервис должен:
1. Нормализовать значение до адреса сети.
2. Сохранить нормализованное значение.
3. Вернуть пользователю явное сообщение, что адрес был нормализован.
### Проверки в пределах компании
1. Запрет полного дубликата активной записи.
2. Запрет любого пересечения активной записи с существующими активными записями той же компании.
3. Между разными компаниями пересечения допускаются.
### Список запрещённых диапазонов
Нужно захардкодить как конфигурацию приложения и покрыть тестами:
1. 10.0.0.0/8
2. 172.16.0.0/12
3. 192.168.0.0/16
4. 100.64.0.0/10
5. 127.0.0.0/8
6. 169.254.0.0/16
7. 192.0.0.0/24
8. 192.0.2.0/24
9. 198.51.100.0/24
10. 203.0.113.0/24
11. 198.18.0.0/15
12. 224.0.0.0/4
13. 240.0.0.0/4
14. 255.255.255.255/32
## 10. Лимиты и конкурентность
Это важное место, которого обычно недооценивают.
### Правила лимитов
1. Есть глобальный DEFAULT_LIMIT, по умолчанию 15.
2. Для компании может быть custom_limit.
3. При снижении лимита ниже текущего количества записей существующие записи не удаляются.
4. Пока число активных записей больше лимита, новые записи создавать нельзя.
### Риск гонок
Если два запроса одновременно создают записи в одной компании, возможны:
1. Пробитие лимита.
2. Пропуск пересечения.
3. Пропуск дубликата.
### Что делать
Операцию создания и обновления записи нужно делать в транзакции с сериализацией логики на уровне компании. Практически это можно решить так:
1. Брать advisory lock по company_id перед проверками и записью.
2. Либо делать SELECT ... FOR UPDATE по строке компании, если этого достаточно для вашей схемы доступа.
Для первой версии я бы выбрал advisory lock по company_id. Это проще и надёжнее для бизнес-ограничений, которые нельзя полностью выразить обычным unique index.
## 11. Экспорт агрегированного списка
### Требования
1. В экспорт попадают только активные записи.
2. Данные берутся по всем компаниям.
3. Пересечения между компаниями допустимы на уровне хранения, но в export должны агрегироваться в минимальный набор CIDR.
4. Формат ответа: text/plain.
5. Одна строка = один CIDR.
### Что нужно зафиксировать реализационно
1. Результат должен быть отсортирован для стабильности.
2. В ответе должен быть завершающий перевод строки.
3. Content-Type должен быть text/plain; charset=utf-8.
4. Желательно отдавать Content-Disposition с понятным именем файла.
### Защита endpoint
Если endpoint на старте работает без auth, то доступ надо ограничить минимум одним из способов:
1. Проверка client IP в приложении.
2. Ограничение на reverse proxy.
3. Оба сразу.
## 12. UI-потоки
### Экран клиента
Должны быть:
1. Селектор активной компании, если компаний несколько.
2. Таблица записей.
3. Индикатор использовано X из N.
4. Форма создания записи.
5. Возможность редактирования.
6. Возможность soft delete.
### Экран администратора
Должны быть:
1. Таблица по всем компаниям.
2. Фильтр по компании.
3. Фильтр показа удалённых записей.
4. Просмотр журнала аудита.
5. Управление лимитами компании.
### UX-детали, которые обязательно сделать
1. Понятные сообщения об ошибках валидации.
2. Явное сообщение о нормализации адреса.
3. Явное сообщение о превышении лимита.
4. Явное сообщение о пересечении с существующей записью.
## 13. Пошаговый план реализации
### Этап 1. Каркас проекта
1. Создать структуру каталогов.
2. Подготовить requirements.txt.
3. Подготовить .env.example.
4. Подключить FastAPI, Jinja2, static.
5. Подготовить docker-compose.yml с PostgreSQL.
Результат этапа: приложение стартует, открывается базовая страница, есть подключение к БД.
### Этап 2. Схема БД и миграции
1. Настроить Alembic.
2. Создать initial migration.
3. Поднять таблицы companies, whitelist_entries, audit_log.
4. Добавить нужные индексы.
Результат этапа: схема БД фиксирована и воспроизводима.
### Этап 3. Валидатор CIDR
1. Реализовать разбор IPv4 и CIDR.
2. Реализовать проверку маски.
3. Реализовать нормализацию.
4. Реализовать проверку запрещённых диапазонов.
5. Написать тесты на валидатор.
Результат этапа: независимый, протестированный модуль бизнес-валидации.
### Этап 4. Сервисный слой для записей
1. Реализовать list.
2. Реализовать create.
3. Реализовать update.
4. Реализовать soft delete.
5. Реализовать проверки лимитов, дубликатов и пересечений.
6. Добавить транзакционную защиту от гонок.
Результат этапа: бизнес-операции работают без UI.
### Этап 5. Аудит
1. Добавить запись CREATE.
2. Добавить запись UPDATE со старым и новым состоянием.
3. Добавить запись DELETE.
4. Добавить интерфейс чтения для admin.
Результат этапа: все изменяющие действия фиксируются.
### Этап 6. Авторизация
1. Реализовать dev-заглушку.
2. Реализовать чтение и валидацию JWT из Keycloak.
3. Реализовать преобразование claims в current user.
4. Реализовать проверки client/admin.
5. Реализовать переключение компании.
Результат этапа: права и контекст пользователя работают сквозным образом.
### Этап 7. HTML-интерфейс
1. Реализовать страницу списка.
2. Реализовать формы создания и редактирования.
3. Реализовать soft delete из UI.
4. Реализовать админские экраны.
Результат этапа: сервис пригоден для ручной эксплуатации.
### Этап 8. Экспорт
1. Реализовать сбор всех активных CIDR.
2. Реализовать агрегацию.
3. Реализовать endpoint export.
4. Реализовать сетевое ограничение.
Результат этапа: внешняя система может забирать текстовый агрегированный whitelist.
### Этап 9. Финализация
1. Написать README.
2. Подготовить Dockerfile.
3. Подготовить пример systemd unit при необходимости.
4. Прогнать ручной smoke-test.
Результат этапа: сервис можно разворачивать и передавать коллегам.
## 14. Тестовая стратегия
Минимально обязательные тесты:
1. Валидный одиночный IPv4 превращается в /32.
2. Валидная подсеть принимается.
3. Host-биты нормализуются.
4. Маски шире допустимой границы отклоняются.
5. IPv6 отклоняется.
6. Все запрещённые диапазоны отклоняются.
7. Дубликат в одной компании запрещён.
8. Пересечение в одной компании запрещено.
9. Тот же CIDR в другой компании разрешён.
10. Soft delete освобождает лимит.
11. Export не включает soft-deleted записи.
12. Export агрегирует CIDR корректно.
13. Client не видит чужие компании.
14. Admin видит все компании.
15. Аудит создаётся для create, update, delete.
## 15. Что можно отложить после первой версии
Это не нужно тащить в MVP:
1. Полноценный SPA.
2. Сложная ORM.
3. WebSocket.
4. Фоновая очередь.
5. Исторические версии записей кроме audit log.
6. Автоматическое уведомление по email.
## 16. Главные риски проекта
1. Неясный формат claims из Keycloak.
2. Гонки при одновременном создании записей.
3. Ошибки в трактовке пересечений CIDR.
4. Неправильная нормализация адресов без понятного сообщения пользователю.
5. Слишком раннее усложнение фронтенда.
## 17. Что я бы делал первым
Если начинать реализацию прямо сейчас, порядок такой:
1. Каркас проекта.
2. Схема БД.
3. Валидатор и тесты.
4. Сервис create/update/delete с транзакциями.
5. Только потом UI и Keycloak.
Это самый безопасный путь: сначала фиксируется ядро бизнес-логики, потом уже внешний слой.
## 18. Итоговое решение
За основу реализации стоит брать простой Python/FastAPI сервис с PostgreSQL, синхронной серверной логикой, жёсткой серверной валидацией, транзакционной защитой от гонок и минималистичным HTML UI.
Главная мысль: сложность здесь не во фронтенде и не в фреймворке, а в корректной реализации правил CIDR, лимитов, ролей и аудита. План должен защищать именно эти части, а не раздувать стек.
-529
View File
@@ -1,529 +0,0 @@
# Полный план реализации — IP WhiteList Microservice
> Автор: GitHub Copilot (GPT-5.4)
> Дата: 2026-05-29
> Статус: рабочий план для реализации
## 1. Цель системы
Нужно реализовать внутренний веб-сервис, в котором клиенты облачного провайдера смогут самостоятельно управлять доверенными IPv4-адресами и подсетями. Эти записи должны исключаться из блокировки во время DDoS-митигции.
Сервис должен решать 3 задачи:
1. Дать клиенту self-service интерфейс для управления whitelist.
2. Дать администраторам и сетевым инженерам централизованный просмотр и контроль.
3. Отдавать агрегированный экспорт всех активных записей в текстовом формате для внешних систем фильтрации.
## 2. Что именно должно быть в первой рабочей версии
Первая версия должна включать:
1. Авторизацию через Keycloak OIDC.
2. Разделение прав client/admin.
3. Поддержку одной или нескольких компаний у пользователя.
4. Таблицу whitelist-записей.
5. Создание, редактирование и soft delete записей.
6. Проверку лимитов по компаниям.
7. Аудит всех изменяющих действий.
8. Экспорт агрегированного списка активных CIDR в text/plain.
9. Серверную валидацию IPv4 и CIDR по правилам ТЗ.
10. Клиентскую валидацию формы для UX.
## 3. Обязательные уточнения до начала интеграции с Keycloak
До кодирования OIDC-части нужно получить точные ответы на 3 вопроса:
1. Какой claim или role означает администратора.
Сейчас в ТЗ сказано: clientId = WZ01112 и отдельный чек-бокс. Нужно точно знать, во что это превращается в токене.
2. Как кодируется принадлежность к нескольким компаниям.
В ТЗ упомянут мультикомпанейный сценарий, но в claims перечислен только clientID. Нужно уточнить, это строка, массив, groups или другой формат.
3. Где именно ограничивается внешний экспортный endpoint по IP.
Нужно решить, это делает приложение, Nginx/Ingress, или оба уровня сразу.
Без этих 3 ответов можно делать каркас, БД, валидацию, CRUD и UI, но нельзя окончательно зафиксировать auth-слой.
## 4. Рекомендуемый стек
### Бэкенд
- Python 3.11+
- FastAPI
- Uvicorn
Причина: Python понятен команде, FastAPI даёт простой роутинг, типизацию, dependency injection и удобную основу для API и HTML-эндпоинтов.
### База данных
- PostgreSQL
- psycopg2-binary
- Alembic для миграций
Причина: нужны надёжные транзакции, аудит, индексы и понятный деплой. Здесь нет выгоды от тяжёлой ORM-магии, поэтому лучше простой и читаемый SQL.
### UI
- Jinja2
- обычные HTML-формы
- HTMX по желанию, только если реально упрощает частичные обновления
- минимальный JS для inline-валидации и уведомлений
Причина: задача не требует SPA. Простая серверная отрисовка снизит сложность и упростит поддержку.
### Авторизация
- Keycloak OIDC
- JWT-проверка по JWKS
- отдельный dev-режим без Keycloak только для локальной разработки
### Работа с IP
- стандартный модуль ipaddress
- netaddr только если стандартной библиотеки окажется недостаточно для агрегирования
Примечание: начать можно вообще без netaddr. Для суммаризации сначала стоит проверить, хватает ли ipaddress.collapse_addresses.
## 5. Архитектурные принципы
1. Синхронный код по умолчанию.
Для этой системы async не нужен. Он только повысит стоимость поддержки.
2. Серверная валидация является источником истины.
Клиентская валидация только помогает пользователю.
3. Аудит append-only.
Записи аудита нельзя изменять и удалять.
4. Все проверки прав и лимитов выполняются на сервере внутри транзакций.
5. Soft delete обязателен для whitelist-записей.
6. Значение лимита по умолчанию должно меняться через конфиг без пересборки.
7. Dev-заглушка авторизации должна быть жёстко отключаемой в production.
## 6. Предлагаемая структура проекта
```text
IPWhiteList/
├── app/
│ ├── main.py
│ ├── config.py
│ ├── db.py
│ ├── security.py
│ ├── validators.py
│ ├── cidr_utils.py
│ ├── services/
│ │ ├── entries.py
│ │ ├── companies.py
│ │ ├── audit.py
│ │ └── export.py
│ ├── repositories/
│ │ ├── entries.py
│ │ ├── companies.py
│ │ └── audit.py
│ ├── routers/
│ │ ├── ui.py
│ │ ├── admin.py
│ │ └── export.py
│ ├── auth/
│ │ ├── oidc.py
│ │ ├── dev_stub.py
│ │ └── deps.py
│ └── templates/
│ ├── base.html
│ ├── index.html
│ ├── entry_form.html
│ ├── login_error.html
│ └── admin/
│ ├── audit.html
│ └── limits.html
├── static/
│ └── style.css
├── migrations/
│ └── versions/
├── tests/
│ ├── test_validators.py
│ ├── test_entries_service.py
│ ├── test_export.py
│ └── test_auth_mapping.py
├── docs/
│ ├── plan.md
│ ├── plan-v2.md
│ └── plan-gpt54.md
├── requirements.txt
├── .env.example
├── alembic.ini
├── docker-compose.yml
├── Dockerfile
└── README.md
```
## 7. Модель данных
### Таблица companies
Назначение: хранение компаний и переопределённых лимитов.
Поля:
1. id
2. client_id
3. name
4. custom_limit
5. created_at
6. updated_at
Правила:
1. client_id уникален.
2. custom_limit может быть null, тогда используется глобальный лимит.
### Таблица whitelist_entries
Назначение: активные и удалённые whitelist-записи.
Поля:
1. id
2. company_id
3. value_cidr
4. comment
5. created_by
6. created_at
7. updated_by
8. updated_at
9. deleted_by
10. deleted_at
Правила:
1. value_cidr хранится только в нормализованном виде.
2. deleted_at is null означает активную запись.
3. comment ограничен 255 символами.
### Таблица audit_log
Назначение: неизменяемый журнал действий.
Поля:
1. id
2. user_email
3. company_id
4. action
5. old_value
6. new_value
7. created_at
Дополнительно желательно хранить:
1. target_entry_id
2. request_id
3. actor_role
Это не противоречит ТЗ и упростит разбор инцидентов.
## 8. Правила авторизации и ролей
### Клиент
1. Видит только записи своей активной компании.
2. Может создавать, редактировать и удалять записи только в допустимом контексте компании.
3. Может переключать активную компанию, если в токене действительно есть доступ к нескольким компаниям.
### Администратор
1. Видит записи всех компаний.
2. Может менять записи всех компаний.
3. Может видеть удалённые записи.
4. Может смотреть аудит.
5. Может менять custom_limit для компании.
### Что нужно реализовать в коде
1. Унифицированную модель текущего пользователя.
2. Отдельную функцию маппинга claims в внутреннюю роль.
3. Жёсткие проверки прав на уровне service-слоя, не только роутеров.
## 9. Валидация IPv4 и CIDR
Эта часть критична. Её нужно делать одной из первых и сразу покрывать тестами.
### Поддерживаемый ввод
1. Одиночный IPv4 адрес, который трактуется как /32.
2. IPv4 подсеть в CIDR нотации.
### Запрещённый ввод
1. IPv6.
2. Доменное имя.
3. Маска шире допустимой.
4. Любые private или special ranges из приложения А.
### Правила маски
Допустимы только /22 ... /32.
### Нормализация
Если пользователь ввёл адрес с host-битами, сервис должен:
1. Нормализовать значение до адреса сети.
2. Сохранить нормализованное значение.
3. Вернуть пользователю явное сообщение, что адрес был нормализован.
### Проверки в пределах компании
1. Запрет полного дубликата активной записи.
2. Запрет любого пересечения активной записи с существующими активными записями той же компании.
3. Между разными компаниями пересечения допускаются.
### Список запрещённых диапазонов
Нужно захардкодить как конфигурацию приложения и покрыть тестами:
1. 10.0.0.0/8
2. 172.16.0.0/12
3. 192.168.0.0/16
4. 100.64.0.0/10
5. 127.0.0.0/8
6. 169.254.0.0/16
7. 192.0.0.0/24
8. 192.0.2.0/24
9. 198.51.100.0/24
10. 203.0.113.0/24
11. 198.18.0.0/15
12. 224.0.0.0/4
13. 240.0.0.0/4
14. 255.255.255.255/32
## 10. Лимиты и конкурентность
Это важное место, которого обычно недооценивают.
### Правила лимитов
1. Есть глобальный DEFAULT_LIMIT, по умолчанию 15.
2. Для компании может быть custom_limit.
3. При снижении лимита ниже текущего количества записей существующие записи не удаляются.
4. Пока число активных записей больше лимита, новые записи создавать нельзя.
### Риск гонок
Если два запроса одновременно создают записи в одной компании, возможны:
1. Пробитие лимита.
2. Пропуск пересечения.
3. Пропуск дубликата.
### Что делать
Операцию создания и обновления записи нужно делать в транзакции с сериализацией логики на уровне компании. Практически это можно решить так:
1. Брать advisory lock по company_id перед проверками и записью.
2. Либо делать SELECT ... FOR UPDATE по строке компании, если этого достаточно для вашей схемы доступа.
Для первой версии я бы выбрал advisory lock по company_id. Это проще и надёжнее для бизнес-ограничений, которые нельзя полностью выразить обычным unique index.
## 11. Экспорт агрегированного списка
### Требования
1. В экспорт попадают только активные записи.
2. Данные берутся по всем компаниям.
3. Пересечения между компаниями допустимы на уровне хранения, но в export должны агрегироваться в минимальный набор CIDR.
4. Формат ответа: text/plain.
5. Одна строка = один CIDR.
### Что нужно зафиксировать реализационно
1. Результат должен быть отсортирован для стабильности.
2. В ответе должен быть завершающий перевод строки.
3. Content-Type должен быть text/plain; charset=utf-8.
4. Желательно отдавать Content-Disposition с понятным именем файла.
### Защита endpoint
Если endpoint на старте работает без auth, то доступ надо ограничить минимум одним из способов:
1. Проверка client IP в приложении.
2. Ограничение на reverse proxy.
3. Оба сразу.
## 12. UI-потоки
### Экран клиента
Должны быть:
1. Селектор активной компании, если компаний несколько.
2. Таблица записей.
3. Индикатор использовано X из N.
4. Форма создания записи.
5. Возможность редактирования.
6. Возможность soft delete.
### Экран администратора
Должны быть:
1. Таблица по всем компаниям.
2. Фильтр по компании.
3. Фильтр показа удалённых записей.
4. Просмотр журнала аудита.
5. Управление лимитами компании.
### UX-детали, которые обязательно сделать
1. Понятные сообщения об ошибках валидации.
2. Явное сообщение о нормализации адреса.
3. Явное сообщение о превышении лимита.
4. Явное сообщение о пересечении с существующей записью.
## 13. Пошаговый план реализации
### Этап 1. Каркас проекта
1. Создать структуру каталогов.
2. Подготовить requirements.txt.
3. Подготовить .env.example.
4. Подключить FastAPI, Jinja2, static.
5. Подготовить docker-compose.yml с PostgreSQL.
Результат этапа: приложение стартует, открывается базовая страница, есть подключение к БД.
### Этап 2. Схема БД и миграции
1. Настроить Alembic.
2. Создать initial migration.
3. Поднять таблицы companies, whitelist_entries, audit_log.
4. Добавить нужные индексы.
Результат этапа: схема БД фиксирована и воспроизводима.
### Этап 3. Валидатор CIDR
1. Реализовать разбор IPv4 и CIDR.
2. Реализовать проверку маски.
3. Реализовать нормализацию.
4. Реализовать проверку запрещённых диапазонов.
5. Написать тесты на валидатор.
Результат этапа: независимый, протестированный модуль бизнес-валидации.
### Этап 4. Сервисный слой для записей
1. Реализовать list.
2. Реализовать create.
3. Реализовать update.
4. Реализовать soft delete.
5. Реализовать проверки лимитов, дубликатов и пересечений.
6. Добавить транзакционную защиту от гонок.
Результат этапа: бизнес-операции работают без UI.
### Этап 5. Аудит
1. Добавить запись CREATE.
2. Добавить запись UPDATE со старым и новым состоянием.
3. Добавить запись DELETE.
4. Добавить интерфейс чтения для admin.
Результат этапа: все изменяющие действия фиксируются.
### Этап 6. Авторизация
1. Реализовать dev-заглушку.
2. Реализовать чтение и валидацию JWT из Keycloak.
3. Реализовать преобразование claims в current user.
4. Реализовать проверки client/admin.
5. Реализовать переключение компании.
Результат этапа: права и контекст пользователя работают сквозным образом.
### Этап 7. HTML-интерфейс
1. Реализовать страницу списка.
2. Реализовать формы создания и редактирования.
3. Реализовать soft delete из UI.
4. Реализовать админские экраны.
Результат этапа: сервис пригоден для ручной эксплуатации.
### Этап 8. Экспорт
1. Реализовать сбор всех активных CIDR.
2. Реализовать агрегацию.
3. Реализовать endpoint export.
4. Реализовать сетевое ограничение.
Результат этапа: внешняя система может забирать текстовый агрегированный whitelist.
### Этап 9. Финализация
1. Написать README.
2. Подготовить Dockerfile.
3. Подготовить пример systemd unit при необходимости.
4. Прогнать ручной smoke-test.
Результат этапа: сервис можно разворачивать и передавать коллегам.
## 14. Тестовая стратегия
Минимально обязательные тесты:
1. Валидный одиночный IPv4 превращается в /32.
2. Валидная подсеть принимается.
3. Host-биты нормализуются.
4. Маски шире допустимой границы отклоняются.
5. IPv6 отклоняется.
6. Все запрещённые диапазоны отклоняются.
7. Дубликат в одной компании запрещён.
8. Пересечение в одной компании запрещено.
9. Тот же CIDR в другой компании разрешён.
10. Soft delete освобождает лимит.
11. Export не включает soft-deleted записи.
12. Export агрегирует CIDR корректно.
13. Client не видит чужие компании.
14. Admin видит все компании.
15. Аудит создаётся для create, update, delete.
## 15. Что можно отложить после первой версии
Это не нужно тащить в MVP:
1. Полноценный SPA.
2. Сложная ORM.
3. WebSocket.
4. Фоновая очередь.
5. Исторические версии записей кроме audit log.
6. Автоматическое уведомление по email.
## 16. Главные риски проекта
1. Неясный формат claims из Keycloak.
2. Гонки при одновременном создании записей.
3. Ошибки в трактовке пересечений CIDR.
4. Неправильная нормализация адресов без понятного сообщения пользователю.
5. Слишком раннее усложнение фронтенда.
## 17. Что я бы делал первым
Если начинать реализацию прямо сейчас, порядок такой:
1. Каркас проекта.
2. Схема БД.
3. Валидатор и тесты.
4. Сервис create/update/delete с транзакциями.
5. Только потом UI и Keycloak.
Это самый безопасный путь: сначала фиксируется ядро бизнес-логики, потом уже внешний слой.
## 18. Итоговое решение
За основу реализации стоит брать простой Python/FastAPI сервис с PostgreSQL, синхронной серверной логикой, жёсткой серверной валидацией, транзакционной защитой от гонок и минималистичным HTML UI.
Главная мысль: сложность здесь не во фронтенде и не в фреймворке, а в корректной реализации правил CIDR, лимитов, ролей и аудита. План должен защищать именно эти части, а не раздувать стек.
+92 -103
View File
@@ -1,118 +1,107 @@
# ~~План разработки — IP WhiteList Microservice~~ [LEGACY] # IP WhiteList — План разработки
> ⚠️ **УСТАРЕЛО.** Этот план содержит ошибки (async ORM, неполные требования, отсутствие тестов). > **Дата:** 2026-05-30
> Актуальный план: `plan-v2.md` > **Основание:** [WhiteIPlist.txt](../WhiteIPlist.txt) (ТЗ) + фактический код в [ipwhitelist-app](../../ipwhitelist-app)
> **Статус:** каноничный — единственный актуальный план
> **Автор:** GitHub Copilot (DeepSeek V4 Flash)
> **Дата:** 2026-05-29
--- ---
## Стек ## 1. Текущее состояние
| Слой | Технология | ### Готово ✅
|---|---|
| Бэкенд | Python 3.11+ / FastAPI | | Слой | Файлы | Что есть |
| БД | PostgreSQL | |---|---|---|
| ORM | SQLAlchemy (async) + Alembic (миграции) | | БД | `sql/schema.sql` | `companies`, `whitelist_entries` (soft delete), `audit_log` + индексы |
| Фронтенд | Jinja2 + HTMX + минимальный CSS | | Валидатор | `src/validators.js` | Все 14 запрещённых диапазонов Приложения А, /22–/32, нормализация host-битов, проверка пересечений |
| Авторизация | Keycloak OIDC (на старте — заглушка/мок) | | CRUD | `src/queries.js` | `createEntry`, `updateEntry`, `deleteEntry` (soft), `listEntries`, `getExportCIDRs`, `getAudit`, `getLimit` |
| Валидация | Pydantic + встроенный `ipaddress` | | UI | `views/index.ejs` | Список, форма добавления, кнопка удаления, стиль Nubes |
| Роуты | `server.js` | `GET /`, `POST /add`, `POST /delete/:id`, `GET /export`, `GET /healthz` |
### Написано в queries.js, но не подключено к роутам
- `updateEntry` — нет `POST /update/:id`, нет UI редактирования
- `getAudit` — нет страницы аудита
- `listEntries(companyId, includeDeleted=true)` — флаг есть, не используется
--- ---
## Этапы ## 2. Что требует ТЗ, но отсутствует
### Этап 1 — Каркас проекта | # | Требование | Готовность |
- [ ] Структура проекта: `app/`, `templates/`, `static/`, `migrations/` |---|---|---|
- [ ] `requirements.txt` (FastAPI, SQLAlchemy, asyncpg, Alembic, Jinja2, python-keycloak) | 1 | Редактирование записи из UI | ❌ queries есть, роута нет |
- [ ] Конфигурация (`.env`, `config.py`) | 2 | Админ-панель (все компании, лимиты, аудит, фильтры) | ❌ |
- [ ] `docker-compose.yml` с PostgreSQL | 3 | OIDC Keycloak вместо base64-заглушки | ❌ |
| 4 | Суммаризация CIDR в `/export` | ❌ отдаёт сырой список |
### Этап 2 — Модели БД и миграции | 5 | Клиентская валидация (JS в форме) | ❌ |
- [ ] Модель `Company` (id, clientId, name, individual_limit) | 6 | Переключатель компаний (multi-company) | ❌ |
- [ ] Модель `WhitelistEntry` (id, company_id, value, comment, created_by, created_at, updated_at, deleted_at, deleted_by) | 7 | Просмотр soft-deleted записей админом | ❌ |
- [ ] Модель `AuditLog` (id, user_email, company_id, action, old_value, new_value, timestamp) | 8 | Изменение `custom_limit` для компании | ❌ |
- [ ] Alembic initial migration
### Этап 3 — Валидация IPv4
- [ ] Валидатор: одиночный IPv4 / CIDR
- [ ] Проверка маски: /32 – /22 (шире /21 — отказ)
- [ ] Нормализация host-битов в 0
- [ ] Запрет серых/приватных диапазонов (Приложение А из ТЗ)
- [ ] Проверка дубликатов и пересечений в пределах компании
### Этап 4 — CRUD + Бизнес-логика
- [ ] Создание записи (с проверкой лимита)
- [ ] Просмотр таблицы записей (для клиента — свои компании, для админа — все)
- [ ] Редактирование (с повторной валидацией)
- [ ] Soft delete (deleted_at, deleted_by)
- [ ] Лимиты: глобальный default 15, индивидуальный per-company
### Этап 5 — Аудит
- [ ] Запись всех изменяющих операций в `AuditLog`
- [ ] Просмотр журнала (только админ)
### Этап 6 — Внешний endpoint
- [ ] `GET /api/v1/whitelist/aggregated` — txt-файл
- [ ] Суммаризация (агрегация) CIDR всех компаний
- [ ] Только активные (не soft-deleted) записи
### Этап 7 — Авторизация (заглушка → Keycloak)
- [ ] Заглушка: header `X-Client-ID`, `X-User-Email`, `X-Role`
- [ ] Роли: client / admin
- [ ] Переключатель компаний (для пользователей в нескольких компаниях)
- [ ] Позже: полноценный OIDC через Keycloak
### Этап 8 — UI (Jinja2 + HTMX)
- [ ] Страница входа / редирект на Keycloak
- [ ] Таблица записей с фильтрами
- [ ] Форма создания/редактирования (с клиентской валидацией)
- [ ] Индикатор лимита: «использовано X из N»
- [ ] Админка: фильтр по компаниям, просмотр удалённых, журнал аудита
### Этап 9 — Деплой
- [ ] Systemd unit / Dockerfile
- [ ] Nginx reverse proxy (если нужно)
- [ ] CI/CD или ручная инструкция
--- ---
## Файловая структура (план) ## 3. Порядок реализации
### Этап 1 — Пользовательский сценарий (client-flow)
- [x] Валидатор IPv4/CIDR — полный
- [x] Создание / удаление / экспорт
- [ ] **Добавить `POST /update/:id`** в `server.js`
- [ ] **Добавить inline-форму редактирования** в `views/index.ejs`
- [ ] **Клиентская валидация** (JS: формат, маска, длина комментария)
### Этап 2 — Административная панель
- [ ] Определение admin-роли (`clientId === 'WZ01112'` + чекбокс)
- [ ] `GET /admin` — страница со всеми компаниями
- [ ] `POST /admin/limit/:companyId` — изменение custom_limit
- [ ] `GET /admin/audit` — журнал аудита
- [ ] Фильтр по компании + показ удалённых записей
### Этап 3 — Авторизация Keycloak OIDC
- [ ] `npm install openid-client`
- [ ] Замена base64-decode на проверку подписи JWT
- [ ] Маппинг claims → `req.user` (clientId, email, role)
- [ ] Оставить `DEV_MODE` только для локальной разработки
### Этап 4 — Экспорт и Multi-company
- [ ] `npm install cidr-tools` — суммаризация в `GET /export`
- [ ] Переключатель активной компании (если несколько `clientId` в claims)
### Этап 5 — Завершение
- [ ] Автотесты (`jest` + `supertest`)
- [ ] Пагинация (если лимит > 50)
- [ ] Сверка всех пунктов ТЗ
---
## 4. Что НЕ делать
- ❌ Не переписывать на Python/FastAPI
- ❌ Не менять схему БД
- ❌ Не переписывать `validators.js` (он полный)
- ❌ Не переписывать `queries.js`
- ❌ Не делать SPA
---
## 5. Зависимости для установки
``` ```
IPWhiteList/ npm install cidr-tools openid-client
├── app/ npm install --save-dev jest supertest
│ ├── __init__.py
│ ├── main.py # FastAPI app
│ ├── config.py # Настройки из .env
│ ├── models.py # SQLAlchemy модели
│ ├── schemas.py # Pydantic схемы
│ ├── validators.py # IPv4/CIDR валидация
│ ├── crud.py # CRUD-операции
│ ├── auth.py # Авторизация (заглушка → Keycloak)
│ ├── routers/
│ │ ├── __init__.py
│ │ ├── entries.py # CRUD whitelist
│ │ ├── admin.py # Админка
│ │ └── external.py # Внешний endpoint
│ └── utils.py # Суммаризация CIDR, лимиты
├── templates/
│ ├── base.html
│ ├── index.html # Таблица записей
│ ├── entry_form.html # Форма создания/редактирования
│ └── admin/
│ ├── audit.html # Журнал аудита
│ └── limits.html # Управление лимитами
├── static/
│ └── style.css
├── migrations/
│ └── alembic/
├── docs/
│ ├── plan.md # Этот файл
│ └── WhiteIPlist.docx # Исходное ТЗ
├── .env.example
├── docker-compose.yml
├── requirements.txt
└── README.md
``` ```
Всё остальное — в рамках Express + EJS + pg.
---
## 6. Риски
- **Admin-роль:** неясно как «отдельный чек-бокс» из ТЗ попадает в токен — требует уточнения с командой Keycloak
- **Multi-company claims:** ТЗ говорит о нескольких компаниях, но в claims только `clientID` — нужен реальный формат
- **IP-ограничение `/export`:** делать в приложении или на уровне ingress — решить при деплое