Files
Avtex/scripts/create_xflow_brief.cjs
T

122 lines
5.7 KiB
JavaScript

const { Pool } = require('pg')
// Connection string from .env
const DB_URL = 'postgresql://xflow:xflow_pass@localhost:5433/xflow'
const pool = new Pool({ connectionString: DB_URL })
const CANVAS_ID = 'xflow-project-brief'
const OWNER_ID = 'GqbpMyUW0NaxjIy5nvCiXCiQu9t2'
const nodes = [
{
id: 'main',
type: 'text',
x: 0, y: 0,
width: 450, height: 220,
label: '🤖 XFlow — Project Brief',
text: `# 🤖 XFlow\n\n**Visual CRM/ERP system based on Obsidian Canvas.**\n\n- **Owner:** Alex Ives (almalexyz@gmail.com)\n- **Firebase UID:** \`GqbpMyUW0NaxjIy5nvCiXCiQu9t2\`\n- **Repo:** [git.a-crm.controlsystem.kz](http://git.a-crm.controlsystem.kz/AVTEX/XFlow)\n- **Prod:** [a-crm.controlsystem.kz](https://a-crm.controlsystem.kz)\n- **Local:** [localhost:3000](http://localhost:3000)`
},
{
id: 'tech-stack',
type: 'text',
x: 600, y: -250,
width: 400, height: 350,
label: '🏗️ Tech Stack',
text: `# 🏗️ Стек технологий\n\n- **Frontend:** Nuxt 3 (SSR + API routes)\n- **Canvas Engine:** Vue Flow\n- **Styling:** TailwindCSS\n- **ORM:** Prisma 7 + @prisma/adapter-pg\n- **Database:** PostgreSQL 16 (Docker)\n- **Auth:** Firebase Auth + JWT\n- **PWA:** @vite-pwa/nuxt\n- **CI/CD:** Gitea Actions`
},
{
id: 'infrastructure',
type: 'text',
x: 600, y: 250,
width: 400, height: 350,
label: '🖥️ Infrastructure',
text: `# 🖥️ Инфраструктура\n\n- **VM (Debian):** 10.0.0.120\n- **Docker Network:** \`infra\`\n- **Services:**\n - \`postgres:5432\` (Shared DB)\n - \`gitea:3001\` (Git server)\n - \`xflow:3002\` (Production app)\n - \`npb-app:3000\` (Other project)\n- **Reverse Proxy:** Nginx (FastPanel)\n\n[🔗 Перейти к карте инфраструктуры](canvas/infrastructure)`
},
{
id: 'database',
type: 'text',
x: 1100, y: 0,
width: 400, height: 300,
label: '🗄️ Database Schema',
text: `# 🗄️ Prisma Schema\n\n- **User:** Firebase ID, Email, Role (admin/user)\n- **Canvas:** ID, Name, Owner, Public, Nodes (Json), Edges (Json)\n\n⚠️ **Важно:** Узлы хранятся как JSON-массив. При обновлении нужно перезаписывать весь массив.`
},
{
id: 'auth-flow',
type: 'text',
x: -600, y: -250,
width: 400, height: 300,
label: '🔐 Auth Flow',
text: `# 🔐 Аутентификация\n\n1. Client logins via Firebase Google Auth.\n2. Token sent to \`/api/auth/google\`.\n3. Server upserts user (ID = Firebase UID).\n4. Returns JWT in \`xflow_token\` cookie.\n5. \`requireAuth\` middleware protects routes.\n\n⚠️ User.id MUST match Firebase UID.`
},
{
id: 'features',
type: 'text',
x: -600, y: 250,
width: 400, height: 420,
label: '✅ Features',
text: `# ✅ Реализовано\n\n- **Canvas:** Interactive Vue Flow editor\n- **Nodes:** text, task, ai, webhook, file, git\n- **Kanban:** Board (/tasks) with DnD\n- **AI:** Execution with context from neighbors\n- **Webhooks:** GET/POST execution\n- **Git:** Sync maps with Gitea\n- **Auth:** RBAC (user/admin) & Firebase\n- **PWA:** Service Worker & Manifest`
},
{
id: 'todo',
type: 'text',
x: 0, y: 450,
width: 400, height: 320,
label: '🔴 To-Do',
text: `# 🔴 Что нужно доделать\n\n- **AI Key:** Get a working Groq key (llama-3.3-70b).\n- **Dashboard:** Main page with stats.\n- **Webhooks:** Telegram notifications.\n- **Users:** Invitation system.\n- **Stability:** Fix PWA service worker caching issue.`
},
{
id: 'dev-tips',
type: 'text',
x: 0, y: -450,
width: 450, height: 320,
label: '💡 Dev Tips',
text: `# 💡 Советы по разработке\n\n- **Local run:** \`npm run dev\`\n- **DB Tunnel:** \`ssh -J alex@178.238.78.98 -L 5433:localhost:5432 root@10.0.0.120\`\n- **Check DB:** \`node scripts/list_users.cjs\`\n- **Test AI:** \`node scripts/test_qwen.cjs\`\n- **Note:** Don't use \`git push && ...\` in PowerShell.`
},
{
id: 'issues',
type: 'text',
x: -1100, y: 0,
width: 400, height: 280,
label: '🐛 Known Issues',
text: `# 🐛 Известные проблемы\n\n- **PWA:** Clear site data if non-precached-url error occurs.\n- **Gitea:** 403 error on push if token expired.\n- **Logs:** Remove debug logs from \`execute.post.ts\` before prod.`
}
]
const edges = [
{ id: 'e1', source: 'main', target: 'tech-stack' },
{ id: 'e2', source: 'main', target: 'infrastructure' },
{ id: 'e3', source: 'main', target: 'features' },
{ id: 'e4', source: 'main', target: 'auth-flow' },
{ id: 'e5', source: 'main', target: 'todo' },
{ id: 'e6', source: 'main', target: 'dev-tips' },
{ id: 'e7', source: 'tech-stack', target: 'database' },
{ id: 'e8', source: 'infrastructure', target: 'database' },
{ id: 'e9', source: 'features', target: 'issues' }
]
async function run() {
try {
const check = await pool.query('SELECT id FROM "Canvas" WHERE id = $1', [CANVAS_ID])
if (check.rows.length > 0) {
await pool.query(
'UPDATE "Canvas" SET nodes = $1, edges = $2, name = $3, "updatedAt" = NOW() WHERE id = $4',
[JSON.stringify(nodes), JSON.stringify(edges), '🤖 XFlow — Project Brief', CANVAS_ID]
)
console.log('✅ XFlow Brief canvas updated!')
} else {
await pool.query(
'INSERT INTO "Canvas" (id, name, "ownerId", "isPublic", nodes, edges, "createdAt", "updatedAt") VALUES ($1, $2, $3, true, $4, $5, NOW(), NOW())',
[CANVAS_ID, '🤖 XFlow — Project Brief', OWNER_ID, JSON.stringify(nodes), JSON.stringify(edges)]
)
console.log('✅ XFlow Brief canvas created!')
}
} catch (e) {
console.error('❌ Error:', e.message)
} finally {
await pool.end()
}
}
run()