АРХ - 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

24
.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
.DS_Store
# local env and secrets
.env
.env.*
!.env.example
!.env.*.example
# dependencies and build output
node_modules/
dist/
build/
.turbo/
.next/
coverage/
# logs
*.log
logs/
# local runtime data
tmp/
data/
volumes/

37
README.md Normal file
View File

@ -0,0 +1,37 @@
# NODE.DC Platform
Платформенный слой для multi-app authentication architecture NODE.DC.
Эта папка не является монорепозиторием всех приложений. Здесь живут общая архитектура, Authentik/reverse-proxy инфраструктура, правила локального разворачивания, auth model, migration plan для Plane и будущий общий auth-sdk.
Git repo:
- `origin`: `https://git.dcserve.ru/SILVER/NODEDC_PLATFORM.git`
- local branch: `main`
Текущие приложения остаются отдельными репозиториями:
- Launcher: `/Users/dcconstructions/Downloads/mnt/data/nodedc_launcher`
- Task Manager / Plane fork: `/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER`
- Plane runtime: `/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/plane-app`
- Plane source fork: `/Users/dcconstructions/Downloads/mnt/data/dc_taskmanager/NODEDC_TASKMANAGER/plane-src`
## Нулевой этап
Нулевой этап фиксирует discovery и каркас платформы без изменения бизнес-логики Launcher и Plane.
Артефакты:
- `docs/DISCOVERY_REPORT.md`
- `docs/ARCHITECTURE.md`
- `docs/AUTH_MODEL.md`
- `docs/DEPLOYMENT_LOCAL.md`
- `docs/SECURITY_CHECKLIST.md`
- `docs/MIGRATION_PLANE_USER.md`
- `infra/README.md`
- `packages/auth-sdk/README.md`
- `tasks/CODEX_PLATFORM_AUTH_TASK.md`
## Базовое правило
Plane не переносится внутрь Launcher. Launcher не становится владельцем таблиц Plane. Authentik становится единым Identity Provider, а приложения сохраняют собственные доменные БД и роли.

109
docs/ARCHITECTURE.md Normal file
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
docs/AUTH_MODEL.md Normal file
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
docs/DEPLOYMENT_LOCAL.md Normal file
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
docs/DISCOVERY_REPORT.md Normal file
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.

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.

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.

30
infra/.env.example Normal file
View File

@ -0,0 +1,30 @@
# domains
AUTH_DOMAIN=auth.local.nodedc
LAUNCHER_DOMAIN=launcher.local.nodedc
TASK_DOMAIN=task.local.nodedc
# authentik
AUTHENTIK_SECRET_KEY=
AUTHENTIK_POSTGRES_PASSWORD=
AUTHENTIK_REDIS_HOST=redis-authentik
# launcher oidc
LAUNCHER_OIDC_ISSUER=http://auth.local.nodedc/application/o/launcher/
LAUNCHER_OIDC_CLIENT_ID=
LAUNCHER_OIDC_CLIENT_SECRET=
LAUNCHER_OIDC_REDIRECT_URI=http://launcher.local.nodedc/auth/callback
# plane oidc
PLANE_OIDC_ISSUER=http://auth.local.nodedc/application/o/task-manager/
PLANE_OIDC_CLIENT_ID=
PLANE_OIDC_CLIENT_SECRET=
PLANE_OIDC_REDIRECT_URI=http://task.local.nodedc/auth/oidc/callback
# security
SESSION_SECRET=
COOKIE_DOMAIN=.local.nodedc
COOKIE_SECURE=false
# current external local apps
LOCAL_LAUNCHER_URL=http://localhost:5173
LOCAL_TASK_MANAGER_URL=http://localhost:8090

26
infra/README.md Normal file
View File

@ -0,0 +1,26 @@
# NODE.DC Platform Infra
Эта папка предназначена для локального и staging infra слоя:
- Authentik;
- reverse proxy;
- локальные домены;
- shared env examples;
- будущие docker compose файлы.
На нулевом этапе здесь фиксируется только каркас. Рабочий `docker-compose.dev.yml` создается отдельным этапом после согласования ports/domains и стратегии подключения текущих Launcher/Plane runtime.
## Expected files
```text
infra/
.env.example
docker-compose.dev.yml
docker-compose.staging.yml
reverse-proxy/
authentik/
```
## Current decision
Текущий Plane runtime не переносится в compose платформы до backup и отдельного шага миграции.

View File

@ -0,0 +1,31 @@
# NODE.DC Auth SDK
Будущий общий пакет для приложений, которые контролируются кодом NODE.DC.
## Target responsibilities
- загрузка JWKS;
- валидация JWT;
- проверка issuer/audience/exp;
- нормализация claims;
- helper `requireAppAccess(groupName)`;
- helper `getCurrentUser()`;
- typed `AuthUser`.
## Type contract
```ts
export type AuthUser = {
sub: string;
email: string;
name?: string;
groups: string[];
entitlements?: string[];
};
```
## Scope
Первый SDK рассчитан на Launcher backend и будущие Node.js/Next.js сервисы.
Для Plane fork на Python/Django нужна отдельная реализация middleware по тем же правилам, а этот пакет остается спецификацией для TypeScript приложений.

View File

@ -0,0 +1,41 @@
# CODEX Platform Auth Task
## Goal
Построить NODE.DC platform auth architecture:
- Authentik как единый Identity Provider;
- Launcher как access/admin control plane;
- Plane fork как отдельное приложение;
- reverse proxy как внешний защитный слой;
- сохранение существующего Plane user и всех связанных данных;
- поддержка будущих приложений.
## Hard constraints
- Не класть Plane внутрь Launcher.
- Не делать единую `users` таблицу для всех приложений.
- Не ломать существующего Plane user.
- Не менять `owner`, `assignee`, `created_by`, `member` связи Plane без отдельной миграции.
- Не хранить service tokens во frontend.
- Не использовать reverse-proxy forward-auth как единственный долгосрочный auth mechanism для собственных приложений.
## Phase 0 result
Выполнены:
- discovery текущих путей Launcher и Task Manager;
- фиксация решения не переносить репозитории физически;
- platform skeleton;
- базовые документы архитектуры, auth model, local deployment, security и migration plan.
## Next phases
1. Local domains + reverse proxy.
2. Authentik bootstrap.
3. Launcher backend/BFF.
4. Launcher OIDC login and app filtering.
5. Launcher admin API and audit.
6. Plane OIDC integration.
7. Plane user migration command.
8. Security acceptance and staging path.