From f853ed9a6b6c3523e635d9c1045e71248b33ed3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Sat, 30 May 2026 07:18:53 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20=D0=BF=D0=BE=D0=BB=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D1=8C=D1=8E=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D0=BD=20=D0=BF=D0=BB=D0=B0=D0=BD=20Gemini=20=D0=BD=D0=B0?= =?UTF-8?q?=20=D0=BE=D1=81=D0=BD=D0=BE=D0=B2=D0=B5=20=D1=84=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=BE=D0=B3=D0=BE=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=B4=D0=BE=D0=B1=D0=B0=D0=B7=D1=8B=20=D0=B8=20=D0=A2?= =?UTF-8?q?=D0=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/plan-gemini.md | 111 ++++++++++++++++---------------------------- 1 file changed, 40 insertions(+), 71 deletions(-) diff --git a/docs/plan-gemini.md b/docs/plan-gemini.md index b1c0839..4740652 100644 --- a/docs/plan-gemini.md +++ b/docs/plan-gemini.md @@ -1,86 +1,55 @@ -# План разработки — IP WhiteList Microservice +# Актуальный план разработки — IP WhiteList Microservice > **Автор:** GitHub Copilot (Gemini 3.1 Pro Preview) -> **Дата:** 2026-05-29 +> **Дата:** 2026-05-30 +> **Основание:** ТЗ (WhiteIPlist.txt) + Реальный код (Node.js/Express) ---- +## 1. Анализ предыдущего плана и моё мнение -## 1. Анализ предыдущих планов и моё видение +Мой предыдущий план (`plan-gemini.md`) оказался **полностью оторванным от реальности**. Я предполагал писать всё с нуля на Python/FastAPI+SQLModel. На деле же ядро полностью готово и написано на **Node.js, Express, EJS и чистом SQL (pg pool)**. +Писать с нуля на питоне — это плодить техдолг и выкидывать рабочий код. Более того, серверная валидация, структура БД, CRUD и UI уже в целом соответствуют ТЗ, но сильно не хватает связующих звеньев. -Я изучил ТЗ и варианты коллег (DeepSeek, Claude, GPT-5.4). -- **DeepSeek** предложил избыточный Async/ORM подход. -- **Claude** упростил до psycopg2 и HTMX, но оставил много "белых пятен" в работе с Keycloak. -- **GPT-5.4** дал отличный продуктовый разбор рисков (гонки, лимиты, нормализация), но оставил проект заблокированным до "уточнения с командой Keycloak". +Поэтому мой главный тезис: **хватит придумывать архитектуру, нужно закрывать дыры по функциональным требованиям ТЗ в текущем Node.js проекте.** -**Мой подход (Gemini 3.1 Pro):** -Мы не будем блокировать разработку в ожидании ответов от админов Keycloak. Разночтения с форматами claims (как выглядит админ, как выглядит мульти-аккаунт) мы вынесем в **гибкую конфигурацию (.env)**. Если формат токена изменится, нам не придется править код, мы просто поменяем переменные окружения. -Также мы откажемся от сторонней библиотеки `netaddr`, так как встроенный модуль Python `ipaddress` имеет встроенную функцию `collapse_addresses()`, которая идеально решает задачу агрегации по ТЗ. +## 2. Разрыв между ТЗ (WhiteIPlist.txt) и кодом (Node.js) ---- +Что готово и работает: +- **База данных:** Полная структура (`companies`, `whitelist_entries`, `audit_log`), реализован soft delete (`deleted_at`). +- **Слой данных (`queries.js`):** Работает базовый CRUD, сохраняются логи аудита, обрабатываются ограничения (глобальные и кастомные). +- **Валидация (`validators.js`):** Реализованы проверки на IPv4, маски /22-/32, зашиты все запрещённые диапазоны (RFC1918, CGNAT, Loopback и т.д.). +- **UI:** Причесанный EJS-шаблон добавления/просмотра/удаления. -## 2. Технологический стек +Чего не хватает по ТЗ (Фокус дальнейшей разработки): +1. **Авторизация (Keycloak OIDC):** Сейчас сделан временный парсинг JWT через Base64 без валидации ключей (DEV_MODE). +2. **Multi-company и Роли (Админ/Клиент):** Не реализованы переключатель компаний и админские страницы (видимость всех записей, изменение лимитов, просмотр аудита). +3. **Редактирование записей:** Метод `updateEntry` написан в БД-слое, но UI и роут отсутствуют. Формально ТЗ не закрыто. +4. **Агрегация в Экспорте:** Маршрут `GET /export` просто выплёвывает адреса в столбик, тогда как ТЗ жёстко требует суммаризировать подсети в минимальный набор CIDR. +5. **Клиентская валидация:** ТЗ явно требует валидировать формат и маски на фронтенде перед отправкой. -* **Бэкенд:** FastAPI (Python 3.11+). Обеспечивает Pydantic-валидацию (используем встроенный `IPv4Network`). -* **СУБД:** PostgreSQL. -* **Доступ к данным:** SQLModel (надстройка над SQLAlchemy). Дает удобство ORM без избыточной сложности, синхронный режим. -* **Суммаризация (Агрегация):** Standard Library Python `ipaddress.collapse_addresses`. -* **Фронтенд:** Jinja2 + HTMX + TailwindCSS (через CDN или standalone cli для простоты). -* **Авторизация:** Dependency injection в FastAPI для OIDC/JWT. Заглушка (MockOIDC) для локальной разработки. +## 3. Детальный план по шагам (Node.js) ---- +### Этап 1: Исправление багов в текущем MVP +- [ ] **Баг с overlaps:** В `validators.js` функция `overlaps()` содержит логическую ошибку в `start`/`end` (может пропускать пересекающиеся подсети). Переписать условие. +- [ ] **UI Редактирования:** Добавить роут `POST /update/:id` в `server.js` и добавить кнопку/форму "Изменить" в `index.ejs`, подключив существующую `updateEntry(...)`. -## 3. Решение узких мест (Архитектурные решения) +### Этап 2: Строгое соответствие ТЗ (Валидация и Экспорт) +- [ ] **Суммаризация CIDR:** Так как в Node.js нет `ipaddress.collapse_addresses`, необходимо использовать библиотеку вроде `cidr-tools` (функция `merge()` отлично справится) для `GET /export`. +- [ ] **Клиентская валидация:** Добавить минимальный JavaScript в `index.ejs` для проверки валидности вводимого IP-адреса и маски до ухода POST-запроса, чтобы экономить серверные ресурсы (Требование ТЗ). -**Проблема 1: Как определять администратора и принадлежность к компаниям из токена?** -*Решение:* Выносим структуру токена в `Config`. -```env -OIDC_COMPANY_CLAIM="client_id" # Может быть списком или строкой, обработаем оба варианта -OIDC_ADMIN_CLAIM_KEY="roles" -OIDC_ADMIN_CLAIM_VALUE="whitelist-admin" -``` -Код будет динамически проверять, совпали ли значения, указанные в конфиге, с данными из токена. +### Этап 3: Подключение OIDC Keycloak +- [ ] Установка библиотеки `openid-client` (или `passport-openidconnect`). +- [ ] Настройка middleware: получение сертификатов из Keycloak, валидация подписи JWT-токена. +- [ ] Извлечение claim `clientID` (и логика переключения между компаниями, если `clientID` является массивом). Определение роли (кто админ, `WZ01112`). Обязательный отказ от dev-заглушки в PROD. -**Проблема 2: Гонки при записи и лимиты** -*Решение:* -1. Проверка лимита делается запросом `SELECT count(*) FROM entries WHERE company_id = X AND deleted_at IS NULL FOR UPDATE`. Блокировка на чтение защитит транзакцию от гонок. -2. В БД создадим уникальный индекс `CREATE UNIQUE INDEX unique_active_cidr ON entries (company_id, value_cidr) WHERE deleted_at IS NULL;` для защиты от дубликатов на уровне СУБД. +### Этап 4: Админ-панель (пользователь WZ01112) +- [ ] Роут `GET /admin` и шаблон `admin.ejs`. Таблица со всеми компаниями и их лимитами, фильтрацией. +- [ ] Функционал установки `custom_limit` для компании. +- [ ] Страница/вкладка `GET /admin/audit` для просмотра `audit_log`. +- [ ] Переключатель отображения Soft-deleted записей. -**Проблема 3: Пересечения внутри компании** -*Решение:* Перед INSERT/UPDATE выгружаем все активные подсети компании и проверяем через `new_cidr.overlaps(existing_cidr)`. Выгрузка делается в рамках заблокированной транзакции (см. пункт выше). +## 4. Зависимости +В `package.json` придется добавить лишь две новые production-зависимости, не усложняя проект: +- `cidr-tools` (для агрегации при экспорте) +- `openid-client` / `jsonwebtoken` (для безопасной работы с Keycloak) ---- - -## 4. Поэтапный план реализации - -### Этап 1. Ядро и База данных (Бизнес-логика) -- [ ] Инициализация FastAPI проекта, настройка SQLModel. -- [ ] Определение сущностей БД: `Company`, `WhitelistEntry` (CIDR хранится как `String`, но Pydantic проверяет `IPv4Network`), `AuditLog`. -- [ ] Валидаторы (запрещенные списки Приложения А, маска /32 - /22). Нормализация `strict=False` в `ipaddress`, чтобы `192.168.1.5/24` автоматически перегонялось в `192.168.1.0/24`. -- [ ] Написание Unit-тестов для валидаторов. - -### Этап 2. Слой данных (CRUD) и защита от гонок -- [ ] Сервис создания записи: проверка макс. лимита (15 по умолчанию или `company.custom_limit`), поиск пересечений, запись AuditLog. -- [ ] Сервис Soft-Delete и редактирования. -- [ ] Тесты CRUD-сервисов. - -### Этап 3. Авторизация (Keycloak) -- [ ] Настройка `auth/jwt.py` для валидации RS256 подписей. -- [ ] Парсинг токена на основе гибких правил из `.env` (роли, список компаний). -- [ ] FastAPI Security Depends (`get_current_user`). - -### Этап 4. Внешний API (Export Endpoint) -- [ ] Роут `GET /api/v1/export/whitelist.txt`. -- [ ] Выборка всех `value_cidr` где `deleted_at IS NULL`. -- [ ] Агрегация: `[str(net) for net in ipaddress.collapse_addresses(net_list)]`. -- [ ] Middleware для ограничения доступа по списку разрешенных `EXPORT_ALLOWED_IPS`. - -### Этап 5. Пользовательский Интерфейс (UI) -- [ ] Jinja2 шаблоны и использование HTMX для добавления/удаления строк таблицы без перезагрузки всей страницы. -- [ ] Отображение предупреждений (нормализация, превышение лимита). -- [ ] Селектор активной компании. -- [ ] Панель администратора (все компании, настройка `custom_limit`, просмотр аудита). - -### Этап 6. Инфраструктура -- [ ] Dockerfile. -- [ ] docker-compose окружение (App + Postgres). -- [ ] Документация (README с описанием переменных окружения). \ No newline at end of file +Всё остальное будет реализовано в рамках существующего стека.