АРХ - NODEDC PLATFORM: каркас платформенного репозитория

This commit is contained in:
Codex
2026-05-04 10:02:18 +03:00
commit 0f89c4d126
12 changed files with 755 additions and 0 deletions
+109
View File
@@ -0,0 +1,109 @@
# Architecture: NODE.DC Multi-App Platform
## Цель
Собрать единую платформенную основу для Launcher, Task Manager / Plane и будущих приложений NODE.DC.
Целевой пользовательский сценарий:
1. Пользователь открывает Launcher.
2. Если сессии нет, его отправляет в Authentik.
3. После логина Launcher получает identity и app access.
4. Launcher показывает только доступные приложения.
5. Переход в Task Manager не требует повторного логина.
6. Прямой URL Task Manager тоже защищен.
## Роли компонентов
`Authentik` является единым Identity Provider:
- логин;
- пароль;
- активность пользователя;
- группы;
- app access;
- OIDC claims;
- будущие invite/enrollment/MFA flows.
`Launcher` является control plane:
- входная точка пользователя;
- список доступных приложений;
- admin UI управления пользователями и доступами;
- backend-интеграция с Authentik API;
- audit log админских действий.
`Task Manager / Plane` остается отдельным приложением:
- собственная БД;
- собственные workspace/project/task/comment модели;
- собственные роли workspace/project;
- OIDC login через Authentik;
- mapping внешней identity на существующего Plane user.
`Reverse proxy` является внешним защитным и маршрутизирующим слоем:
- единая точка входа;
- HTTPS в staging/production;
- routing по app domain;
- forward headers для Authentik;
- deny для пользователей без app access.
## Repository layout
Рабочая схема:
```text
NODEDC/
DOC/
platform/
docs/
infra/
packages/
tasks/
/Users/dcconstructions/Downloads/mnt/data/nodedc_launcher
/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER
```
`platform/` не забирает исходники Launcher и Plane внутрь себя. Он хранит только платформенный слой и договоренности между приложениями.
## Data ownership
Не создается единая общая таблица `users` для всех приложений.
Логическая схема:
```text
authentik_db -> identity, groups, app access
launcher_db -> app registry, local profiles, audit
plane_db -> workspace, projects, tasks, comments, app roles
future_app_db -> доменная логика будущих приложений
```
Связь между identity и локальными пользователями выполняется через explicit mapping, а не через прямое чтение чужих таблиц.
## Auth flow
Для приложений, которые контролируются кодом:
- OIDC Authorization Code Flow + PKCE;
- backend/session или BFF layer;
- JWT/JWKS validation server-side;
- проверка `issuer`, `audience`, `exp`, `sub`;
- проверка app access group;
- локальный user profile или external identity link.
Для legacy/временных приложений допускается reverse proxy forward-auth, но это временный внешний слой, а не единственная долгосрочная модель.
## Plane migration rule
Существующий Plane user нельзя пересоздавать.
Нужен mapping:
```text
authentik_user.sub -> existing plane_user.id
```
Plane должен логинить существующего пользователя по link, сохраняя все старые workspace, assignee, owner, created_by, comments и attachments.
+108
View File
@@ -0,0 +1,108 @@
# Auth Model
## Identity source
Единственный источник identity: Authentik.
Launcher, Plane и будущие приложения не хранят пароли пользователей и не становятся главным источником truth по логину.
## Required claims
Минимальный normalized user object:
```ts
type AuthUser = {
sub: string;
email: string;
name?: string;
groups: string[];
entitlements?: string[];
};
```
Обязательные проверки:
- `iss` совпадает с настроенным issuer;
- `aud` совпадает с client/application audience;
- `exp` не истек;
- `sub` непустой и стабилен;
- `email` присутствует для user-facing приложений;
- `groups` или `entitlements` содержат требуемый app access.
## Groups
Минимальная группа верхнего уровня:
```text
nodedc:superadmin
```
Launcher:
```text
nodedc:launcher:access
nodedc:launcher:admin
nodedc:launcher:user-manager
```
Task Manager:
```text
nodedc:taskmanager:access
nodedc:taskmanager:admin
```
Future apps:
```text
nodedc:agents:access
nodedc:tender:access
nodedc:onec:access
nodedc:dm:access
```
## Access levels
Уровень 1: Authentik app access.
Отвечает на вопрос, можно ли открыть приложение.
Уровень 2: Launcher admin roles.
Отвечает на вопрос, можно ли управлять пользователями, группами, app registry и audit.
Уровень 3: Application roles.
Например, Plane workspace owner/admin/member/viewer. Эти роли остаются внутри Plane.
## Launcher backend requirements
Backend должен:
- хранить Authentik service token только server-side;
- выполнять admin calls к Authentik API;
- хранить audit log;
- возвращать frontend только нормализованные данные пользователя и разрешенные действия;
- не отдавать access/refresh/service tokens в browser bundle.
## Plane identity link
Минимальная таблица или эквивалентная модель в Plane:
```text
external_identity_link
provider = authentik
authentik_sub
email
plane_user_id
created_at
last_login_at
status
```
Правило миграции:
- сначала искать link по `authentik_sub`;
- если link найден, логинить связанный `plane_user_id`;
- если link не найден, но email совпадает и включен migration auto-link, создать link;
- если доступа нет, вернуть deny.
+81
View File
@@ -0,0 +1,81 @@
# Local Deployment Plan
## Domains
Для локальной разработки целевая схема:
```text
127.0.0.1 auth.local.nodedc
127.0.0.1 launcher.local.nodedc
127.0.0.1 task.local.nodedc
127.0.0.1 agents.local.nodedc
127.0.0.1 tender.local.nodedc
127.0.0.1 onec.local.nodedc
127.0.0.1 dm.local.nodedc
```
## Current local apps
Launcher сейчас запускается как Vite app из:
```text
/Users/dcconstructions/Downloads/mnt/data/nodedc_launcher
```
Task Manager сейчас доступен как Plane self-host runtime:
```text
http://localhost:8090
```
Runtime:
```text
/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/plane-app
```
Source fork:
```text
/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/plane-src
```
## Target local flow
Первый local infra milestone:
```text
auth.local.nodedc -> Authentik
launcher.local.nodedc -> Launcher web/backend
task.local.nodedc -> Plane proxy/runtime
```
Все внешние запросы идут через reverse proxy.
## Environment
Базовые переменные должны жить в:
```text
platform/infra/.env
```
Пример значений хранится в:
```text
platform/infra/.env.example
```
## Implementation order
1. Согласовать локальные domain/port bindings.
2. Добавить reverse proxy config.
3. Поднять Authentik server, worker, Postgres и Redis.
4. Прокинуть Authentik за proxy с корректными headers.
5. Подключить текущий Launcher как внешний сервис или через compose service.
6. Подключить текущий Plane runtime как внешний service target.
7. После стабилизации собрать воспроизводимый compose.
## Notes
Текущий Plane runtime не переносится на нулевом этапе. Любое изменение `plane-app/plane.env`, volumes или startup scripts делается только после backup и отдельной задачи.
+106
View File
@@ -0,0 +1,106 @@
# Discovery Report: NODE.DC Platform
Дата: 2026-05-04
## Источники
- Базовое ТЗ: `/Users/dcconstructions/Downloads/mnt/NODEDC/DOC/BASE/tz_codex_platform_authentik_launcher_plane.md`
- Краткое ТЗ: `/Users/dcconstructions/Downloads/mnt/NODEDC/DOC/BASE/nodedc_auth.md`
- Launcher repo: `/Users/dcconstructions/Downloads/mnt/data/nodedc_launcher`
- Task Manager repo: `/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER`
## Workspace
`/Users/dcconstructions/Downloads/mnt/NODEDC` используется как внешний workspace-корень для платформенной работы.
Текущая папка `NODEDC` до нулевого этапа содержала только базовые документы в `DOC/BASE`. Отдельного git-репозитория в этой папке нет.
## Launcher
Путь: `/Users/dcconstructions/Downloads/mnt/data/nodedc_launcher`
Факты discovery:
- отдельный git-репозиторий;
- Vite/React приложение;
- основной entrypoint: `src/main.tsx`;
- команды из `package.json`: `npm run dev`, `npm run build`, `npm run preview`, `npm run test`;
- backend слоя в текущем Launcher не найдено;
- значит OIDC/session handling, Authentik service token, app registry и audit log нельзя хранить только во frontend.
Минимальный вывод: для production-like auth нужен Launcher backend или BFF слой.
## Task Manager / Plane
Путь: `/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER`
Факты discovery:
- отдельный git-репозиторий;
- self-host runtime лежит в `plane-app`;
- локальный fork исходников лежит в `plane-src`;
- Plane CE self-host запущен через Docker;
- локальный URL стенда: `http://localhost:8090`;
- текущий compose/env: `plane-app/docker-compose.yaml` и `plane-app/plane.env`;
- текущий fork Plane: `plane-src`, версия `1.3.0`;
- основной runtime-контейнер API: `plane-app-api-1`;
- активные контейнеры Plane: web, proxy, api, worker, beat-worker, db, redis, minio, mq, admin, space, live.
Текущий workspace в Plane:
- slug: `nodedc`;
- name: `NODE DC`;
- owner: `dcctouch@gmail.com`;
- codex user: `codex@nodedc.local`.
Существующие проекты в workspace `nodedc` на момент discovery:
- `NODEDCLAUN` / `NODEDC LAUNCHER`
- `CODEX` / `DCTM-WT-CODEX`
- `NODEDCTASK` / `NODEDC TASKMANAGER`
- `MGR` / `Менеджмент`
- `BUH` / `Бухгалтерия`
## NDC details в карточках
Канон карточек описан в `/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/AGENTS.md`.
Структурированные блоки карточки хранятся в `Issue.detail_layout` под ключом:
```text
nodedc_structured_blocks
```
Типы блоков:
- `text`: текстовый блок с `title` и `body`;
- `checker`: чекер с `title` и пунктами `items`.
Frontend отображает эти блоки через компоненты:
- `plane-src/apps/web/core/components/issues/issue-detail-widgets/structured-content.helpers.ts`
- `plane-src/apps/web/core/components/issues/issue-detail-widgets/structured-content-blocks.tsx`
## Решение по переносам
Физически переносить Launcher и Task Manager внутрь `NODEDC` на нулевом этапе не нужно.
Причины:
- оба приложения уже являются отдельными git-репозиториями;
- Plane runtime завязан на текущие `plane-app`, `plane.env`, volumes и backup;
- перенос может сломать локальный self-host стенд;
- платформенный слой должен управлять интеграцией, а не становиться монорепозиторием всех исходников.
Допустимый вариант позже: добавить symlink или workspace manifest из `NODEDC` на внешние репозитории, если это потребуется для удобства навигации.
## Риски
- Нельзя пересоздавать существующего Plane admin/user, иначе потеряются связи workspace, задач, комментариев и assignee.
- Нельзя делать Authentik admin token доступным frontend-коду Launcher.
- Нельзя полагаться только на reverse proxy как единственный долгосрочный auth layer для приложений, которые мы контролируем кодом.
- Нельзя публиковать наружу Postgres, Redis, MinIO и внутренние API в staging/production.
## Следующий технический шаг
Создать локальный `platform/infra` слой с Authentik и reverse proxy, но сначала согласовать конкретную схему доменов, ports и secrets.
+108
View File
@@ -0,0 +1,108 @@
# Plane User Migration Plan
## Цель
Связать существующего пользователя Plane с Authentik identity без потери workspace, projects, tasks, comments, attachments и истории.
## Current baseline
Текущий рабочий Plane workspace:
```text
workspace slug: nodedc
workspace name: NODE DC
workspace owner: dcctouch@gmail.com
codex user: codex@nodedc.local
```
Перед реализацией OIDC нужно дополнительно снять точный snapshot:
- users;
- profiles;
- workspace memberships;
- project memberships;
- issue ownership;
- issue assignees;
- comments;
- attachments;
- uploaded files/storage.
## Backup before changes
Перед любыми изменениями Plane auth:
```text
plane_db dump
plane-app/plane.env
uploads / MinIO volumes
redis, если в нем есть важные очереди/сессии
rabbitmq, если есть невыполненные jobs
```
## Mapping model
Минимальная модель:
```text
external_identity_link
id
provider = authentik
authentik_sub
email
plane_user_id
created_at
last_login_at
status
```
Уникальность:
- `provider + authentik_sub`;
- `provider + plane_user_id`;
- желательно `provider + email`, если email используется для migration auto-link.
## Login flow
```text
Authentik login
-> Plane OIDC callback
-> validate state/nonce/token
-> validate issuer/audience/exp/sub
-> check nodedc:taskmanager:access
-> find external_identity_link by authentik_sub
-> login existing plane_user_id
```
Migration auto-link допускается только контролируемо:
```text
if no link and email matches existing Plane user and migration mode enabled:
create external_identity_link
else:
deny or provisioning flow
```
## Forbidden during migration
- Не пересоздавать существующего Plane user.
- Не менять `created_by`.
- Не менять `owner_id`.
- Не менять `assignee_id`.
- Не менять `member_id`.
- Не делать bulk update связей задач без отдельной проверки.
## Management command target
Целевая команда:
```bash
python manage.py link_authentik_user --email admin@example.ru --sub <authentik-sub>
```
Требования:
- idempotent;
- проверяет конфликтующий mapping;
- ничего не меняет в задачах/workspace;
- выводит summary;
- поддерживает dry-run.
+54
View File
@@ -0,0 +1,54 @@
# Security Checklist
## Network
- [ ] Наружу опубликованы только reverse proxy ports.
- [ ] Postgres не опубликован наружу в staging/production.
- [ ] Redis не опубликован наружу в staging/production.
- [ ] MinIO/storage не опубликован наружу в staging/production.
- [ ] Внутренние API не доступны напрямую извне.
- [ ] Authentik получает корректные `X-Forwarded-Proto`, `X-Forwarded-For`, `Host`.
- [ ] WebSocket headers настроены для Authentik/Plane/live.
## Authentik
- [ ] Каждое приложение имеет отдельный Authentik Application.
- [ ] Каждое приложение имеет отдельный Provider.
- [ ] Для каждого приложения задана отдельная access policy.
- [ ] Группы app access заведены отдельно от app-local ролей.
- [ ] MFA/enrollment policy вынесены в отдельный этап.
## Launcher
- [ ] Authentik service token хранится только server-side.
- [ ] Frontend не получает service token.
- [ ] Admin endpoints требуют `nodedc:superadmin` или `nodedc:launcher:admin`.
- [ ] Все admin actions пишутся в audit log.
- [ ] Удаление пользователя реализовано как deactivate/disable, не hard delete.
## Plane
- [ ] Перед изменениями сделан backup DB/env/uploads/storage.
- [ ] Существующий Plane user не пересоздается.
- [ ] `owner_id`, `created_by`, `assignee_id`, `member_id` не меняются без отдельной миграции.
- [ ] Публичный signup отключен.
- [ ] Лишние обходные auth сценарии закрыты или явно оставлены как временные.
- [ ] OIDC login проверяет state/nonce/token.
- [ ] `authentik_sub` связан с существующим `plane_user_id`.
## Tokens and secrets
- [ ] Secrets не попадают в git.
- [ ] Access/refresh tokens не логируются.
- [ ] Session cookies имеют `secure=true` в staging/production.
- [ ] В production включены HTTPS и HSTS.
## Acceptance scenarios
- [ ] Без логина Launcher отправляет в Authentik.
- [ ] Пользователь без `nodedc:taskmanager:access` не видит Task Manager в Launcher.
- [ ] Пользователь без `nodedc:taskmanager:access` получает deny на прямой `task.local.nodedc`.
- [ ] Пользователь с доступом открывает Task Manager.
- [ ] Старый Plane admin после OIDC видит старые workspace/tasks/comments.
- [ ] Деактивированный пользователь теряет доступ.
- [ ] Admin action появляется в audit log.