commit 0f89c4d126d77961388534cac46a33d4d805313c Author: Codex Date: Mon May 4 10:02:18 2026 +0300 АРХ - NODEDC PLATFORM: каркас платформенного репозитория diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e640d2 --- /dev/null +++ b/.gitignore @@ -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/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..037ea0f --- /dev/null +++ b/README.md @@ -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, а приложения сохраняют собственные доменные БД и роли. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..fea0c3a --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -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. diff --git a/docs/AUTH_MODEL.md b/docs/AUTH_MODEL.md new file mode 100644 index 0000000..98ad0ee --- /dev/null +++ b/docs/AUTH_MODEL.md @@ -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. diff --git a/docs/DEPLOYMENT_LOCAL.md b/docs/DEPLOYMENT_LOCAL.md new file mode 100644 index 0000000..e50bdce --- /dev/null +++ b/docs/DEPLOYMENT_LOCAL.md @@ -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 и отдельной задачи. diff --git a/docs/DISCOVERY_REPORT.md b/docs/DISCOVERY_REPORT.md new file mode 100644 index 0000000..4adcdbe --- /dev/null +++ b/docs/DISCOVERY_REPORT.md @@ -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. diff --git a/docs/MIGRATION_PLANE_USER.md b/docs/MIGRATION_PLANE_USER.md new file mode 100644 index 0000000..abf9193 --- /dev/null +++ b/docs/MIGRATION_PLANE_USER.md @@ -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 +``` + +Требования: + +- idempotent; +- проверяет конфликтующий mapping; +- ничего не меняет в задачах/workspace; +- выводит summary; +- поддерживает dry-run. diff --git a/docs/SECURITY_CHECKLIST.md b/docs/SECURITY_CHECKLIST.md new file mode 100644 index 0000000..03c4290 --- /dev/null +++ b/docs/SECURITY_CHECKLIST.md @@ -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. diff --git a/infra/.env.example b/infra/.env.example new file mode 100644 index 0000000..cec8bc5 --- /dev/null +++ b/infra/.env.example @@ -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 diff --git a/infra/README.md b/infra/README.md new file mode 100644 index 0000000..597038b --- /dev/null +++ b/infra/README.md @@ -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 и отдельного шага миграции. diff --git a/packages/auth-sdk/README.md b/packages/auth-sdk/README.md new file mode 100644 index 0000000..54bc8e0 --- /dev/null +++ b/packages/auth-sdk/README.md @@ -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 приложений. diff --git a/tasks/CODEX_PLATFORM_AUTH_TASK.md b/tasks/CODEX_PLATFORM_AUTH_TASK.md new file mode 100644 index 0000000..24954e6 --- /dev/null +++ b/tasks/CODEX_PLATFORM_AUTH_TASK.md @@ -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.