-- -- PostgreSQL database dump -- \restrict WBcQVZEt4bd5DvAlsuuzbb0gxp17HNTWxZmQL7NVkQKdYMDtlT8MvQQsk7EOOiq -- Dumped from database version 17.9 -- Dumped by pg_dump version 17.9 SET statement_timeout = 0; SET lock_timeout = 0; SET idle_in_transaction_session_timeout = 0; SET transaction_timeout = 0; SET client_encoding = 'UTF8'; SET standard_conforming_strings = on; SELECT pg_catalog.set_config('search_path', '', false); SET check_function_bodies = false; SET xmloption = content; SET client_min_messages = warning; SET row_security = off; SET default_tablespace = ''; SET default_table_access_method = heap; -- -- Name: Activity; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public."Activity" ( id text NOT NULL, "userId" text NOT NULL, action text NOT NULL, "targetId" text NOT NULL, "targetType" text NOT NULL, "timestamp" timestamp(3) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, metadata text ); -- -- Name: Canvas; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public."Canvas" ( id text NOT NULL, name text NOT NULL, "ownerId" text NOT NULL, "groupId" text, "isPublic" boolean DEFAULT false NOT NULL, nodes jsonb DEFAULT '[]'::jsonb NOT NULL, edges jsonb DEFAULT '[]'::jsonb NOT NULL, "createdAt" timestamp(3) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, "updatedAt" timestamp(3) without time zone NOT NULL ); -- -- Name: Follow; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public."Follow" ( id text NOT NULL, "followerId" text NOT NULL, "followingId" text NOT NULL, since timestamp(3) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL ); -- -- Name: Group; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public."Group" ( id text NOT NULL, name text NOT NULL, description text DEFAULT ''::text NOT NULL, "isPublic" boolean DEFAULT true NOT NULL, "ownerId" text NOT NULL, "createdAt" timestamp(3) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, "updatedAt" timestamp(3) without time zone NOT NULL ); -- -- Name: GroupMember; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public."GroupMember" ( id text NOT NULL, "userId" text NOT NULL, "groupId" text NOT NULL, role text DEFAULT 'member'::text NOT NULL, "joinedAt" timestamp(3) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL ); -- -- Name: Profile; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public."Profile" ( id text NOT NULL, "userId" text NOT NULL, "displayName" text NOT NULL, bio text DEFAULT ''::text NOT NULL, avatar text DEFAULT ''::text NOT NULL, "canvasCount" integer DEFAULT 0 NOT NULL, "followerCount" integer DEFAULT 0 NOT NULL, "followingCount" integer DEFAULT 0 NOT NULL, "joinedAt" timestamp(3) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL ); -- -- Name: User; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public."User" ( id text NOT NULL, email text NOT NULL, username text NOT NULL, password text NOT NULL, role text DEFAULT 'user'::text NOT NULL, "createdAt" timestamp(3) without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, "updatedAt" timestamp(3) without time zone NOT NULL ); -- -- Name: _prisma_migrations; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public._prisma_migrations ( id character varying(36) NOT NULL, checksum character varying(64) NOT NULL, finished_at timestamp with time zone, migration_name character varying(255) NOT NULL, logs text, rolled_back_at timestamp with time zone, started_at timestamp with time zone DEFAULT now() NOT NULL, applied_steps_count integer DEFAULT 0 NOT NULL ); -- -- Data for Name: Activity; Type: TABLE DATA; Schema: public; Owner: - -- COPY public."Activity" (id, "userId", action, "targetId", "targetType", "timestamp", metadata) FROM stdin; \. -- -- Data for Name: Canvas; Type: TABLE DATA; Schema: public; Owner: - -- COPY public."Canvas" (id, name, "ownerId", "groupId", "isPublic", nodes, edges, "createdAt", "updatedAt") FROM stdin; test-crm Для проверки задач GqbpMyUW0NaxjIy5nvCiXCiQu9t2 \N t [{"x": 100, "y": 100, "id": "task-1", "text": "# Создать API пользователей\\nРазработать эндпоинт для списка пользователей", "type": "task", "alarm": "2026-05-01T21:14", "label": "# Создать API пользо", "state": "in_progress", "style": {"border": "#334155", "background": "#1e293b"}, "width": 300, "height": 200, "priority": "medium", "script_id": "авяыаячс", "updatedAt": "2026-04-29T10:41:32.122Z", "assigned_to": "almalexyz"}, {"x": 450, "y": 100, "id": "task-2", "text": "# Канбан-доска\\nСделать вывод всех задач", "type": "task", "alarm": "", "label": "# Канбан-доска\\nСдела", "state": "blocked", "style": {"border": "#334155", "background": "#1e293b"}, "width": 300, "height": 200, "priority": "medium", "script_id": "", "updatedAt": "2026-04-29T10:41:31.160Z", "assigned_to": ""}, {"x": 91, "y": 438, "id": "task-3", "text": "# Проверка прав\\nНастроить доступ к картам", "type": "task", "alarm": "2026-04-25T21:14", "label": "# Проверка прав\\nНаст", "state": "review", "style": {"border": "#334155", "background": "#1e293b"}, "width": 300, "height": 200, "priority": "medium", "script_id": "тимтапр", "updatedAt": "2026-04-29T10:41:29.977Z", "assigned_to": "system"}, {"x": 450, "y": 350, "id": "task-4", "text": "# Тестирование\\nПроверить как работают бейджики", "type": "task", "alarm": "", "label": "# Тестирование\\nПрове", "state": "review", "style": {"border": "#334155", "background": "#1e293b"}, "width": 300, "height": 200, "priority": "medium", "script_id": "", "updatedAt": "2026-04-29T12:11:10.028Z", "assigned_to": ""}, {"x": 874, "y": 233, "id": "node-test-1777394609896", "text": "# My new task\\nTest", "type": "task", "alarm": "", "label": "# My new task\\nTest", "state": "completed", "style": {"border": "#334155", "background": "#1e293b"}, "width": 300, "height": 200, "priority": "high", "script_id": "", "updatedAt": "2026-04-29T12:11:14.229Z", "assigned_to": "almalexyz"}] [] 2026-04-28 20:20:03.107 2026-04-29 12:11:14.231 xflow-project 🗺️ Глобальная Архитектура XFlow GqbpMyUW0NaxjIy5nvCiXCiQu9t2 \N t [{"x": -6, "y": -136, "id": "arch-1", "text": "# 🏗️ Глобальная Архитектура\\n\\n- **Nuxt 3** - Full-stack фреймворк (SSR + API)\\n- **Prisma ORM** - Типизированный доступ к данным\\n- **PostgreSQL** - Надежное хранилище\\n- **Firebase Auth** - Вход через Google\\n- **Vue Flow** - Ядро интерактивного холста\\n- **TailwindCSS** - Современная стилизация", "type": "text", "label": "# 🏗️ Глобальная Арх", "state": "pending", "style": {"border": "#334155", "background": "#1e293b"}, "width": 400, "height": 350}, {"x": -975, "y": 192, "id": "prisma-schema", "text": "# 🗄️ База Данных & Prisma\\n\\n```prisma\\nmodel User {\\n id String @id\\n email String @unique\\n username String @unique\\n role String @default(\\"user\\")\\n canvases Canvas[]\\n groups GroupMember[]\\n}\\n\\nmodel Canvas {\\n id String @id\\n name String\\n nodes Json // Obsidian format\\n edges Json\\n owner User @relation(...)\\n}\\n\\nmodel Group {\\n id String @id\\n members GroupMember[]\\n}\\n```\\n\\n**Особенности:**\\n- Использование `Json` полей для гибкости холста\\n- Каскадное удаление данных\\n- Связи многие-ко-многим для групп", "type": "text", "label": "# 🗄️ База Данных & ", "state": "pending", "style": {"border": "#334155", "background": "#1e293b"}, "width": 450, "height": 500}, {"x": -706, "y": 899, "id": "auth-system", "text": "# 🔐 Безопасность и Auth\\n\\n1. **Firebase**: Клиентская аутентификация Google.\\n2. **Google Token**: Отправляется на `/api/auth/google`.\\n3. **Prisma Upsert**: Пользователь создается или обновляется в БД.\\n4. **JWT**: Сервер генерирует токен (с ID и ролью).\\n5. **Middleware**: Проверка JWT через `requireAuth` в серверных роутах.\\n6. **RBAC**: Роли `admin` и `user` контролируют доступ.", "type": "text", "label": "# 🔐 Безопасность и ", "state": "pending", "style": {"border": "#334155", "background": "#1e293b"}, "width": 450, "height": 350}, {"x": 773, "y": 349, "id": "git-sync", "text": "# 🔄 Git Синхронизация (Gitea)\\n\\n- **useGitSync**: Composable для управления статусом.\\n- **Real-Sync API**: Обрабатывает `init` и `sync`.\\n- **Gitea Integration**:\\n - Автоматическое создание репозиториев.\\n - Коммиты при каждом сохранении карты.\\n - Хранение `.canvas` файлов в Git для версионности.\\n - Токены доступа через `.env` переменные.", "type": "text", "label": "# 🔄 Git Синхронизац", "state": "pending", "style": {"border": "#334155", "background": "#1e293b"}, "width": 450, "height": 400}, {"x": 533, "y": 829, "id": "state-reactivity", "text": "# 🧪 Реактивность и Состояние\\n\\n- **elements**: Массив всех узлов и ребер Vue Flow.\\n- **selectedNode**: Реактивный объект для панели свойств.\\n- **useUnsavedChanges**: Отслеживание изменений (Dirty state).\\n- **commitNodeChange**: Синхронизация данных из панели свойств обратно в массив элементов перед сохранением.", "type": "text", "label": "# 🧪 Реактивность и ", "state": "pending", "style": {"border": "#334155", "background": "#1e293b"}, "width": 450, "height": 350}, {"x": 2, "y": 649, "id": "feat-1", "text": "# ✨ Ключевые Фичи\\n\\n- **Кросс-ссылки**: Навигация между картами.\\n- **Канбан**: Сводная таблица задач по пользователям.\\n- **Типы Узлов**:\\n - `Text` (Markdown)\\n - `Task` (State machine)\\n - `AI Prompt` (LLM ready)\\n - `Webhook` (External trigger)\\n - `Git Sync` (Version control)\\n- **Импорт/Экспорт**: Полная совместимость с Obsidian.", "type": "text", "label": "# ✨ Ключевые Фичи\\n\\n-", "state": "pending", "style": {"border": "#334155", "background": "#1e293b"}, "width": 400, "height": 450}, {"x": -267, "y": 1204, "id": "session-apr-28", "text": "# 🔥 Сессия 28 Апреля (Итоги)\\n\\n- ✅ Починена потеря метаданных в Prisma.\\n- ✅ Реализована навигация (двойной клик по ссылкам).\\n- ✅ Внедрена система ролей и прав.\\n- ✅ Добавлен выпадающий список для связей карт.\\n- ✅ Синхронизированы Firebase и БД ID.", "type": "text", "label": "# 🔥 Сессия 28 Апрел", "state": "pending", "style": {"border": "#334155", "background": "#1e293b"}, "width": 400, "height": 250}, {"x": 1009, "y": 75, "id": "node-1777399734802-hmxuy9", "file": "xflow-project", "type": "file", "label": "File Node", "style": {"border": "#334155", "background": "#1e293b"}, "width": 300, "height": 200}] [{"id": "e1", "toNode": "prisma-schema", "toSide": "left", "fromNode": "arch-1", "fromSide": "right"}, {"id": "e2", "toNode": "auth-system", "toSide": "left", "fromNode": "arch-1", "fromSide": "right"}, {"id": "e3", "toNode": "git-sync", "toSide": "left", "fromNode": "arch-1", "fromSide": "right"}, {"id": "e4", "toNode": "state-reactivity", "toSide": "left", "fromNode": "arch-1", "fromSide": "right"}, {"id": "e5", "toNode": "feat-1", "toSide": "left", "fromNode": "arch-1", "fromSide": "right"}, {"id": "e6", "toNode": "session-apr-28", "toSide": "left", "fromNode": "feat-1", "fromSide": "right"}, {"id": "e7", "toNode": "auth-system", "toSide": "left", "fromNode": "prisma-schema", "fromSide": "right"}] 2026-04-28 13:51:21.138 2026-04-28 18:09:17.404 session-2026-04-23 session-2026-04-23 GqbpMyUW0NaxjIy5nvCiXCiQu9t2 \N t [{"x": -200, "y": -600, "id": "title", "text": "# Сессия 23 апреля 2026\\n## CI/CD через Gitea Actions", "type": "text", "width": 400, "height": 80}, {"x": -800, "y": -400, "id": "problem1", "text": "## ❌ Проблема 1\\n**node not in PATH**\\nRunner выполнял job на хосте без node\\n\\n**Fix:** настроить runner label\\n`ubuntu-latest:docker://node:20-alpine`", "type": "text", "width": 340, "height": 200}, {"x": -400, "y": -400, "id": "problem2", "text": "## ❌ Проблема 2\\n**getaddrinfo ENOTFOUND gitea**\\nJob контейнер не в сети infra\\n\\n**Fix:** `container.network: infra` в config.yaml runner'а", "type": "text", "width": 340, "height": 200}, {"x": 0, "y": -400, "id": "problem3", "text": "## ❌ Проблема 3\\n**actions/checkout тянет с GitHub**\\nНе знает про Gitea\\n\\n**Fix:** заменить на ручной `git clone` с токеном через env переменную", "type": "text", "width": 340, "height": 200}, {"x": 400, "y": -400, "id": "problem4", "text": "## ❌ Проблема 4\\n**bash not found**\\nnode:20-alpine не имеет bash\\n\\n**Fix:** `shell: sh` + `defaults.run.shell: sh`", "type": "text", "width": 340, "height": 200}, {"x": -800, "y": -140, "id": "problem5", "text": "## ❌ Проблема 5\\n**Token URL parse error**\\nCRLF переносы в токене ломают URL\\n\\n**Fix:**\\n```sh\\nCLEAN_TOKEN=$(printf '%s' \\"${TOKEN}\\" | tr -d '\\\\r\\\\n')\\n```", "type": "text", "width": 340, "height": 200}, {"x": -400, "y": -140, "id": "problem6", "text": "## ❌ Проблема 6\\n**rsync not found**\\nНет rsync в Alpine\\n\\n**Fix:** `apk add --no-cache openssh-client rsync`\\n\\nПотом поняли что SSH не нужен вообще — runner на том же сервере", "type": "text", "width": 340, "height": 200}, {"x": 0, "y": -140, "id": "problem7", "text": "## ❌ Проблема 7\\n**docker compose -f not found**\\ndocker-cli в Alpine не поддерживает compose\\n\\n**Fix:** `apk add docker-cli-compose`\\nИспользовать `docker-compose` (v1)", "type": "text", "width": 340, "height": 200}, {"x": 400, "y": -140, "id": "problem8", "text": "## ❌ Проблема 8\\n**Duplicate mount: /var/run/docker.sock**\\nУказали sock и в options и в volumes\\n\\n**Fix:** убрать sock из options, оставить только xflow/npb", "type": "text", "width": 340, "height": 200}, {"x": -800, "y": 120, "id": "problem9", "text": "## ❌ Проблема 9\\n**Runner label \\\\\\"ubuntu-latest\\\\\\"**\\nЭкранированные кавычки в YAML\\n\\n**Fix:** убрать кавычки вокруг лейбла в config.yaml:\\n`- ubuntu-latest:docker://node:20-alpine`", "type": "text", "width": 340, "height": 180}, {"x": -400, "y": 120, "id": "problem10", "text": "## ❌ Проблема 10\\n**No such file /opt/xflow/docker-compose.yml**\\nVolume не пробрасывался в job контейнер\\n\\n**Fix:** `container.options` в config.yaml:\\n`\\"-v /opt/xflow:/opt/xflow\\"`\\n+ `valid_volumes`", "type": "text", "width": 340, "height": 180}, {"x": 0, "y": 120, "id": "problem11", "text": "## ❌ Проблема 11\\n**env file /opt/xflow/.env not found**\\n\\n**Fix:** создать `/opt/xflow/.env` на сервере с переменными:\\nNODE_ENV, DATABASE_URL,\\nNUXT_JWT_SECRET, GITEA_URL и т.д.", "type": "text", "width": 340, "height": 180}, {"x": -200, "y": 380, "id": "solution", "text": "## ✅ Итоговый стек деплоя\\n\\n**Runner config.yaml:**\\n```yaml\\nrunner:\\n labels:\\n - ubuntu-latest:docker://node:20-alpine\\ncontainer:\\n network: infra\\n options: \\"-v /opt/xflow:/opt/xflow -v /opt/npb:/opt/npb\\"\\n valid_volumes:\\n - /opt/xflow\\n - /opt/npb\\n - /var/run/docker.sock\\n```\\n\\n**Workflow шаги:**\\n1. `git clone` через env TOKEN\\n2. `npm ci && npm run build`\\n3. `cp -r .output/ /opt/xflow/.output/`\\n4. `docker-compose up -d --force-recreate`", "type": "text", "width": 500, "height": 340}, {"x": -200, "y": 780, "id": "result", "text": "## 🎉 Результат\\n\\n- **XFlow** запущен на `http://a-crm.controlsystem.kz` (порт 3002)\\n- **NPB** деплоится на порт 3003\\n- **Gitea runner** `avtex-runner` обслуживает всю организацию AVTEX\\n- Автодеплой при каждом `git push` в master/main\\n- Секрет `GIT_TOKEN` на уровне организации\\n\\n**Следующие шаги:**\\n- `prisma migrate deploy`\\n- Переписать API с db.ts на Prisma\\n- Nginx proxy для NPB", "type": "text", "width": 500, "height": 260}, {"x": 400, "y": 380, "id": "arch", "text": "## 🏗️ Архитектура сервера\\n\\n```\\nDocker network: infra\\n├── gitea (3000/3001)\\n├── postgres (5432)\\n├── gitea-runner\\n│ ├── /var/run/docker.sock\\n│ ├── /opt/xflow (volume)\\n│ └── /opt/npb (volume)\\n├── xflow (3002→3000)\\n└── npb (3003→3000)\\n```\\n\\nJump host: `alex@178.238.78.98`\\nTarget: `root@10.0.0.120`", "type": "text", "width": 340, "height": 260}] [{"id": "e1", "toNode": "problem1", "toSide": "top", "fromNode": "title", "fromSide": "bottom"}, {"id": "e2", "toNode": "problem2", "toSide": "top", "fromNode": "title", "fromSide": "bottom"}, {"id": "e3", "toNode": "problem3", "toSide": "top", "fromNode": "title", "fromSide": "bottom"}, {"id": "e4", "toNode": "problem4", "toSide": "top", "fromNode": "title", "fromSide": "bottom"}, {"id": "e5", "toNode": "problem5", "toSide": "top", "fromNode": "problem1", "fromSide": "bottom"}, {"id": "e6", "toNode": "problem6", "toSide": "top", "fromNode": "problem3", "fromSide": "bottom"}, {"id": "e7", "toNode": "problem7", "toSide": "top", "fromNode": "problem4", "fromSide": "bottom"}, {"id": "e8", "toNode": "problem8", "toSide": "top", "fromNode": "problem2", "fromSide": "bottom"}, {"id": "e9", "toNode": "problem9", "toSide": "top", "fromNode": "problem5", "fromSide": "bottom"}, {"id": "e10", "toNode": "problem10", "toSide": "top", "fromNode": "problem6", "fromSide": "bottom"}, {"id": "e11", "toNode": "problem11", "toSide": "top", "fromNode": "problem7", "fromSide": "bottom"}, {"id": "e12", "toNode": "solution", "toSide": "top", "fromNode": "problem9", "fromSide": "bottom"}, {"id": "e13", "toNode": "solution", "toSide": "top", "fromNode": "problem10", "fromSide": "bottom"}, {"id": "e14", "toNode": "solution", "toSide": "top", "fromNode": "problem11", "fromSide": "bottom"}, {"id": "e15", "toNode": "result", "toSide": "top", "fromNode": "solution", "fromSide": "bottom"}, {"id": "e16", "toNode": "arch", "toSide": "left", "fromNode": "solution", "fromSide": "right"}] 2026-04-28 13:40:23.017 2026-04-28 13:40:23.017 master-plan 🗺️ Генеральный План Развития GqbpMyUW0NaxjIy5nvCiXCiQu9t2 \N t [{"x": -3, "y": -227, "id": "root", "text": "# План Развития XFlow\\nВизуальная CRM/ERP Система", "type": "text", "label": "# План Развития XFlo", "state": "pending", "style": {"border": "#334155", "background": "#1e293b"}, "width": 400, "height": 100}, {"x": -479, "y": 162, "id": "stage1", "text": "## Этап 1: Фундамент\\nРоли (RBAC), Управление Командой, Master Canvas", "type": "text", "label": "## Этап 1: Фундамент", "state": "pending", "style": {"border": "#334155", "background": "#1e293b"}, "width": 350, "height": 150}, {"x": -844, "y": 477, "id": "s1-1", "text": "Система Ролей (RBAC)", "type": "task", "alarm": "", "label": "Система Ролей (RBAC)", "state": "review", "style": {"border": "#334155", "background": "#1e293b"}, "width": 300, "height": 120, "priority": "high", "script_id": "", "updatedAt": "2026-04-29T12:11:11.768Z", "assigned_to": "admin"}, {"x": -490, "y": 705, "id": "s1-2", "text": "Интерфейс приглашения юзеров", "type": "task", "alarm": "", "label": "Интерфейс приглашени", "state": "in_progress", "style": {"border": "#334155", "background": "#1e293b"}, "width": 300, "height": 120, "priority": "medium", "script_id": "", "updatedAt": "2026-04-29T12:11:02.137Z", "assigned_to": "admin"}, {"x": 14, "y": 197, "id": "stage2", "text": "## Этап 2: Умные Узлы\\nТипизация, Панель свойств, Цветовая индикация", "type": "text", "label": "## Этап 2: Умные Узл", "state": "pending", "style": {"border": "#334155", "background": "#1e293b"}, "width": 350, "height": 150}, {"x": -160, "y": 458, "id": "s2-1", "text": "Герметичное сохранение метаданных", "type": "task", "alarm": "", "label": "Герметичное сохранен", "state": "review", "style": {"border": "#334155", "background": "#1e293b"}, "width": 300, "height": 120, "priority": "high", "script_id": "", "updatedAt": "2026-04-29T12:11:07.662Z", "assigned_to": "antigravity"}, {"x": 220, "y": 687, "id": "s2-2", "text": "Типизация (Webhook, AI, Git)", "type": "task", "alarm": "", "label": "Типизация (Webhook, ", "state": "todo", "style": {"border": "#334155", "background": "#1e293b"}, "width": 300, "height": 120, "priority": "high", "script_id": "", "updatedAt": "2026-04-29T10:41:40.534Z", "assigned_to": "antigravity"}, {"x": 939, "y": 130, "id": "stage3", "text": "## Этап 3: Аналитика\\nКанбан-борд, Дашборд, Уведомления", "type": "text", "label": "## Этап 3: Аналитика", "state": "pending", "style": {"border": "#334155", "background": "#1e293b"}, "width": 350, "height": 150}, {"x": 500, "y": 400, "id": "s3-1", "text": "Персональный Канбан-дашборд", "type": "task", "alarm": "", "label": "Персональный Канбан-", "state": "completed", "style": {"border": "#334155", "background": "#1e293b"}, "width": 300, "height": 120, "priority": "high", "script_id": "", "assigned_to": "antigravity"}, {"x": 900, "y": 450, "id": "s3-2", "text": "Drag-n-Drop в Канбане", "type": "task", "alarm": "", "label": "Drag-n-Drop в Канбан", "state": "in_progress", "style": {"border": "#334155", "background": "#1e293b"}, "width": 300, "height": 120, "priority": "medium", "script_id": "", "updatedAt": "2026-04-29T12:11:03.674Z", "assigned_to": "admin"}, {"x": 426, "y": 109, "id": "stage4", "text": "## Этап 4: Интеграции\\nGit/Gitea Deep Sync, S3 Storage, Workflows", "type": "text", "label": "## Этап 4: Интеграци", "state": "pending", "style": {"border": "#334155", "background": "#1e293b"}, "width": 400, "height": 150}, {"x": -905, "y": -54, "id": "update", "text": "### Обновление 28.04\\n✅ Сохранение метаданных\\n✅ База под Канбан\\n✅ Типизация узлов", "type": "text", "label": "### Обновление 28.04", "state": "pending", "style": {"border": "#334155", "background": "#1e293b"}, "width": 400, "height": 200}] [{"id": "e1", "toNode": "stage1", "toSide": "left", "fromNode": "root", "fromSide": "right"}, {"id": "e2", "toNode": "stage2", "toSide": "left", "fromNode": "root", "fromSide": "right"}, {"id": "e3", "toNode": "stage3", "toSide": "left", "fromNode": "root", "fromSide": "right"}, {"id": "e4", "toNode": "stage4", "toSide": "left", "fromNode": "root", "fromSide": "right"}, {"id": "e5", "toNode": "update", "toSide": "left", "fromNode": "root", "fromSide": "right"}, {"id": "e1-1", "toNode": "s1-1", "toSide": "left", "fromNode": "stage1", "fromSide": "right"}, {"id": "e1-2", "toNode": "s1-2", "toSide": "left", "fromNode": "stage1", "fromSide": "right"}, {"id": "e2-1", "toNode": "s2-1", "toSide": "left", "fromNode": "stage2", "fromSide": "right"}, {"id": "e2-2", "toNode": "s2-2", "toSide": "left", "fromNode": "stage2", "fromSide": "right"}, {"id": "e3-1", "toNode": "s3-1", "toSide": "left", "fromNode": "stage3", "fromSide": "right"}, {"id": "e3-2", "toNode": "s3-2", "toSide": "left", "fromNode": "stage3", "fromSide": "right"}] 2026-04-28 21:57:38.688 2026-04-29 12:11:11.769 \. -- -- Data for Name: Follow; Type: TABLE DATA; Schema: public; Owner: - -- COPY public."Follow" (id, "followerId", "followingId", since) FROM stdin; \. -- -- Data for Name: Group; Type: TABLE DATA; Schema: public; Owner: - -- COPY public."Group" (id, name, description, "isPublic", "ownerId", "createdAt", "updatedAt") FROM stdin; \. -- -- Data for Name: GroupMember; Type: TABLE DATA; Schema: public; Owner: - -- COPY public."GroupMember" (id, "userId", "groupId", role, "joinedAt") FROM stdin; \. -- -- Data for Name: Profile; Type: TABLE DATA; Schema: public; Owner: - -- COPY public."Profile" (id, "userId", "displayName", bio, avatar, "canvasCount", "followerCount", "followingCount", "joinedAt") FROM stdin; \. -- -- Data for Name: User; Type: TABLE DATA; Schema: public; Owner: - -- COPY public."User" (id, email, username, password, role, "createdAt", "updatedAt") FROM stdin; system system@localhost system none admin 2026-04-28 13:40:22.99 2026-04-28 13:40:22.99 GqbpMyUW0NaxjIy5nvCiXCiQu9t2 almalexyz@gmail.com almalexyz none admin 2026-04-28 20:21:01.95 2026-04-28 20:21:01.95 \. -- -- Data for Name: _prisma_migrations; Type: TABLE DATA; Schema: public; Owner: - -- COPY public._prisma_migrations (id, checksum, finished_at, migration_name, logs, rolled_back_at, started_at, applied_steps_count) FROM stdin; \. -- -- Name: Activity Activity_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."Activity" ADD CONSTRAINT "Activity_pkey" PRIMARY KEY (id); -- -- Name: Canvas Canvas_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."Canvas" ADD CONSTRAINT "Canvas_pkey" PRIMARY KEY (id); -- -- Name: Follow Follow_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."Follow" ADD CONSTRAINT "Follow_pkey" PRIMARY KEY (id); -- -- Name: GroupMember GroupMember_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."GroupMember" ADD CONSTRAINT "GroupMember_pkey" PRIMARY KEY (id); -- -- Name: Group Group_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."Group" ADD CONSTRAINT "Group_pkey" PRIMARY KEY (id); -- -- Name: Profile Profile_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."Profile" ADD CONSTRAINT "Profile_pkey" PRIMARY KEY (id); -- -- Name: User User_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."User" ADD CONSTRAINT "User_pkey" PRIMARY KEY (id); -- -- Name: _prisma_migrations _prisma_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public._prisma_migrations ADD CONSTRAINT _prisma_migrations_pkey PRIMARY KEY (id); -- -- Name: Follow_followerId_followingId_key; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX "Follow_followerId_followingId_key" ON public."Follow" USING btree ("followerId", "followingId"); -- -- Name: GroupMember_userId_groupId_key; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX "GroupMember_userId_groupId_key" ON public."GroupMember" USING btree ("userId", "groupId"); -- -- Name: Profile_userId_key; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX "Profile_userId_key" ON public."Profile" USING btree ("userId"); -- -- Name: User_email_key; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX "User_email_key" ON public."User" USING btree (email); -- -- Name: User_username_key; Type: INDEX; Schema: public; Owner: - -- CREATE UNIQUE INDEX "User_username_key" ON public."User" USING btree (username); -- -- Name: Activity Activity_userId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."Activity" ADD CONSTRAINT "Activity_userId_fkey" FOREIGN KEY ("userId") REFERENCES public."User"(id) ON UPDATE CASCADE ON DELETE CASCADE; -- -- Name: Canvas Canvas_groupId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."Canvas" ADD CONSTRAINT "Canvas_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES public."Group"(id) ON UPDATE CASCADE ON DELETE SET NULL; -- -- Name: Canvas Canvas_ownerId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."Canvas" ADD CONSTRAINT "Canvas_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES public."User"(id) ON UPDATE CASCADE ON DELETE CASCADE; -- -- Name: Follow Follow_followerId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."Follow" ADD CONSTRAINT "Follow_followerId_fkey" FOREIGN KEY ("followerId") REFERENCES public."User"(id) ON UPDATE CASCADE ON DELETE CASCADE; -- -- Name: Follow Follow_followingId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."Follow" ADD CONSTRAINT "Follow_followingId_fkey" FOREIGN KEY ("followingId") REFERENCES public."User"(id) ON UPDATE CASCADE ON DELETE CASCADE; -- -- Name: GroupMember GroupMember_groupId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."GroupMember" ADD CONSTRAINT "GroupMember_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES public."Group"(id) ON UPDATE CASCADE ON DELETE CASCADE; -- -- Name: GroupMember GroupMember_userId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."GroupMember" ADD CONSTRAINT "GroupMember_userId_fkey" FOREIGN KEY ("userId") REFERENCES public."User"(id) ON UPDATE CASCADE ON DELETE CASCADE; -- -- Name: Profile Profile_userId_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- ALTER TABLE ONLY public."Profile" ADD CONSTRAINT "Profile_userId_fkey" FOREIGN KEY ("userId") REFERENCES public."User"(id) ON UPDATE CASCADE ON DELETE CASCADE; -- -- PostgreSQL database dump complete -- \unrestrict WBcQVZEt4bd5DvAlsuuzbb0gxp17HNTWxZmQL7NVkQKdYMDtlT8MvQQsk7EOOiq