docs: каноничный plan.md, остальные планы → [DEPRECATED]
This commit is contained in:
@@ -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, лимитов, ролей и аудита. План должен защищать именно эти части, а не раздувать стек.
|
||||
@@ -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
@@ -1,118 +1,107 @@
|
||||
# ~~План разработки — IP WhiteList Microservice~~ [LEGACY]
|
||||
# IP WhiteList — План разработки
|
||||
|
||||
> ⚠️ **УСТАРЕЛО.** Этот план содержит ошибки (async ORM, неполные требования, отсутствие тестов).
|
||||
> Актуальный план: `plan-v2.md`
|
||||
|
||||
> **Автор:** GitHub Copilot (DeepSeek V4 Flash)
|
||||
> **Дата:** 2026-05-29
|
||||
> **Дата:** 2026-05-30
|
||||
> **Основание:** [WhiteIPlist.txt](../WhiteIPlist.txt) (ТЗ) + фактический код в [ipwhitelist-app](../../ipwhitelist-app)
|
||||
> **Статус:** каноничный — единственный актуальный план
|
||||
|
||||
---
|
||||
|
||||
## Стек
|
||||
## 1. Текущее состояние
|
||||
|
||||
| Слой | Технология |
|
||||
|---|---|
|
||||
| Бэкенд | Python 3.11+ / FastAPI |
|
||||
| БД | PostgreSQL |
|
||||
| ORM | SQLAlchemy (async) + Alembic (миграции) |
|
||||
| Фронтенд | Jinja2 + HTMX + минимальный CSS |
|
||||
| Авторизация | Keycloak OIDC (на старте — заглушка/мок) |
|
||||
| Валидация | Pydantic + встроенный `ipaddress` |
|
||||
### Готово ✅
|
||||
|
||||
| Слой | Файлы | Что есть |
|
||||
|---|---|---|
|
||||
| БД | `sql/schema.sql` | `companies`, `whitelist_entries` (soft delete), `audit_log` + индексы |
|
||||
| Валидатор | `src/validators.js` | Все 14 запрещённых диапазонов Приложения А, /22–/32, нормализация host-битов, проверка пересечений |
|
||||
| CRUD | `src/queries.js` | `createEntry`, `updateEntry`, `deleteEntry` (soft), `listEntries`, `getExportCIDRs`, `getAudit`, `getLimit` |
|
||||
| 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)
|
||||
- [ ] Конфигурация (`.env`, `config.py`)
|
||||
- [ ] `docker-compose.yml` с PostgreSQL
|
||||
|
||||
### Этап 2 — Модели БД и миграции
|
||||
- [ ] Модель `Company` (id, clientId, name, individual_limit)
|
||||
- [ ] Модель `WhitelistEntry` (id, company_id, value, comment, created_by, created_at, updated_at, deleted_at, deleted_by)
|
||||
- [ ] Модель `AuditLog` (id, user_email, company_id, action, old_value, new_value, timestamp)
|
||||
- [ ] 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 или ручная инструкция
|
||||
| # | Требование | Готовность |
|
||||
|---|---|---|
|
||||
| 1 | Редактирование записи из UI | ❌ queries есть, роута нет |
|
||||
| 2 | Админ-панель (все компании, лимиты, аудит, фильтры) | ❌ |
|
||||
| 3 | OIDC Keycloak вместо base64-заглушки | ❌ |
|
||||
| 4 | Суммаризация CIDR в `/export` | ❌ отдаёт сырой список |
|
||||
| 5 | Клиентская валидация (JS в форме) | ❌ |
|
||||
| 6 | Переключатель компаний (multi-company) | ❌ |
|
||||
| 7 | Просмотр soft-deleted записей админом | ❌ |
|
||||
| 8 | Изменение `custom_limit` для компании | ❌ |
|
||||
|
||||
---
|
||||
|
||||
## Файловая структура (план)
|
||||
## 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/
|
||||
├── app/
|
||||
│ ├── __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
|
||||
npm install cidr-tools openid-client
|
||||
npm install --save-dev jest supertest
|
||||
```
|
||||
|
||||
Всё остальное — в рамках Express + EJS + pg.
|
||||
|
||||
---
|
||||
|
||||
## 6. Риски
|
||||
|
||||
- **Admin-роль:** неясно как «отдельный чек-бокс» из ТЗ попадает в токен — требует уточнения с командой Keycloak
|
||||
- **Multi-company claims:** ТЗ говорит о нескольких компаниях, но в claims только `clientID` — нужен реальный формат
|
||||
- **IP-ограничение `/export`:** делать в приложении или на уровне ingress — решить при деплое
|
||||
|
||||
Reference in New Issue
Block a user