diff --git a/i18n/zh/workflow/canvas-dev/README.md b/i18n/zh/workflow/canvas-dev/README.md new file mode 100644 index 0000000..60e62c1 --- /dev/null +++ b/i18n/zh/workflow/canvas-dev/README.md @@ -0,0 +1,56 @@ +# 🎨 Canvas白板驱动开发工作流 + +> 图形是第一公民,代码是白板的序列化形式 + +## 核心理念 + +``` +传统开发:代码 → 口头沟通 → 脑补架构 → 代码失控 +Canvas方式:代码 ⇄ 白板 ⇄ AI ⇄ 人类(白板为单一真相源) +``` + +| 痛点 | 解法 | +|:---|:---| +| 🤖 AI看不懂项目结构 | ✅ AI直接读白板JSON,秒懂架构 | +| 🧠 人类记不住复杂依赖 | ✅ 连线清晰,牵一发动全身一目了然 | +| 💬 团队协作靠嘴说 | ✅ 指着白板讲,新人5分钟看懂 | + +## 文件结构 + +``` +canvas-dev/ +├── README.md # 本文件 - 工作流概述 +├── workflow.md # 完整工作流步骤(线性流程) +├── prompts/ +│ ├── 01-架构分析.md # 从代码生成白板的提示词 +│ ├── 02-白板驱动编码.md # 根据白板生成代码的提示词 +│ └── 03-白板同步检查.md # 校验白板与代码一致性 +├── templates/ +│ ├── project.canvas # Obsidian Canvas 项目模板 +│ └── module.canvas # 单模块白板模板 +└── examples/ + └── demo-project.canvas # 示例项目白板 +``` + +## 快速开始 + +### 1. 准备工具 +- [Obsidian](https://obsidian.md/) - 免费开源白板工具 +- AI助手(Claude/GPT-4,需支持读取Canvas JSON) + +### 2. 生成项目架构白板 +```bash +# 将项目代码路径提供给AI,使用架构分析提示词 +# AI自动生成 .canvas 文件 +``` + +### 3. 用白板驱动开发 +- 在白板上画出新模块和依赖关系 +- 导出白板JSON发送给AI +- AI根据白板生成/修改代码 + +## 相关文档 + +- [Canvas白板驱动开发详解](../../documents/02-方法论/图形化AI协作-Canvas白板驱动开发.md) +- [白板驱动开发系统提示词](../../prompts/01-系统提示词/AGENTS.md/12/AGENTS.md) +- [胶水编程](../../documents/00-基础指南/胶水编程.md) diff --git a/i18n/zh/workflow/canvas-dev/examples/demo-project.canvas b/i18n/zh/workflow/canvas-dev/examples/demo-project.canvas new file mode 100644 index 0000000..274f11a --- /dev/null +++ b/i18n/zh/workflow/canvas-dev/examples/demo-project.canvas @@ -0,0 +1,281 @@ +{ + "nodes": [ + { + "id": "title", + "type": "text", + "x": -100, + "y": -350, + "width": 400, + "height": 60, + "text": "# 📦 电商系统架构白板\n\n演示项目 - 用户、商品、订单管理" + }, + { + "id": "group-frontend", + "type": "group", + "x": -600, + "y": -250, + "width": 250, + "height": 500, + "label": "🖥️ 前端" + }, + { + "id": "group-api", + "type": "group", + "x": -300, + "y": -250, + "width": 250, + "height": 500, + "label": "🌐 API网关" + }, + { + "id": "group-service", + "type": "group", + "x": 0, + "y": -250, + "width": 300, + "height": 500, + "label": "⚙️ 业务服务" + }, + { + "id": "group-infra", + "type": "group", + "x": 350, + "y": -250, + "width": 300, + "height": 500, + "label": "🔧 基础设施" + }, + { + "id": "fe-web", + "type": "text", + "x": -580, + "y": -200, + "width": 210, + "height": 80, + "text": "# Web App\n\nReact + TypeScript" + }, + { + "id": "fe-mobile", + "type": "text", + "x": -580, + "y": -100, + "width": 210, + "height": 80, + "text": "# Mobile App\n\nReact Native" + }, + { + "id": "api-gateway", + "type": "text", + "x": -280, + "y": -200, + "width": 210, + "height": 100, + "text": "# API Gateway\n\n- 路由分发\n- 认证鉴权\n- 限流熔断" + }, + { + "id": "svc-user", + "type": "text", + "x": 20, + "y": -200, + "width": 260, + "height": 100, + "text": "# UserService\n\n- 用户注册/登录\n- 个人信息管理\n- 权限校验" + }, + { + "id": "svc-product", + "type": "text", + "x": 20, + "y": -80, + "width": 260, + "height": 100, + "text": "# ProductService\n\n- 商品CRUD\n- 库存管理\n- 分类搜索" + }, + { + "id": "svc-order", + "type": "text", + "x": 20, + "y": 40, + "width": 260, + "height": 100, + "text": "# OrderService\n\n- 下单流程\n- 订单状态机\n- 退款处理" + }, + { + "id": "svc-payment", + "type": "text", + "x": 20, + "y": 160, + "width": 260, + "height": 80, + "text": "# PaymentService\n\n- 支付网关对接\n- 账单管理" + }, + { + "id": "infra-db", + "type": "text", + "x": 370, + "y": -200, + "width": 260, + "height": 80, + "text": "# PostgreSQL\n\n主数据库", + "color": "4" + }, + { + "id": "infra-cache", + "type": "text", + "x": 370, + "y": -100, + "width": 260, + "height": 80, + "text": "# Redis\n\n缓存 + 会话", + "color": "1" + }, + { + "id": "infra-mq", + "type": "text", + "x": 370, + "y": 0, + "width": 260, + "height": 80, + "text": "# RabbitMQ\n\n异步消息队列", + "color": "2" + }, + { + "id": "infra-es", + "type": "text", + "x": 370, + "y": 100, + "width": 260, + "height": 80, + "text": "# Elasticsearch\n\n商品搜索引擎", + "color": "5" + }, + { + "id": "external-stripe", + "type": "text", + "x": 370, + "y": 200, + "width": 260, + "height": 60, + "text": "# Stripe API\n\n外部支付服务", + "color": "6" + } + ], + "edges": [ + { + "id": "e-web-gw", + "fromNode": "fe-web", + "toNode": "api-gateway", + "fromSide": "right", + "toSide": "left", + "label": "HTTP" + }, + { + "id": "e-mobile-gw", + "fromNode": "fe-mobile", + "toNode": "api-gateway", + "fromSide": "right", + "toSide": "left", + "label": "HTTP" + }, + { + "id": "e-gw-user", + "fromNode": "api-gateway", + "toNode": "svc-user", + "fromSide": "right", + "toSide": "left", + "label": "/users/*" + }, + { + "id": "e-gw-product", + "fromNode": "api-gateway", + "toNode": "svc-product", + "fromSide": "right", + "toSide": "left", + "label": "/products/*" + }, + { + "id": "e-gw-order", + "fromNode": "api-gateway", + "toNode": "svc-order", + "fromSide": "right", + "toSide": "left", + "label": "/orders/*" + }, + { + "id": "e-order-user", + "fromNode": "svc-order", + "toNode": "svc-user", + "fromSide": "top", + "toSide": "bottom", + "label": "校验用户" + }, + { + "id": "e-order-product", + "fromNode": "svc-order", + "toNode": "svc-product", + "fromSide": "top", + "toSide": "bottom", + "label": "扣减库存" + }, + { + "id": "e-order-payment", + "fromNode": "svc-order", + "toNode": "svc-payment", + "fromSide": "bottom", + "toSide": "top", + "label": "发起支付" + }, + { + "id": "e-user-db", + "fromNode": "svc-user", + "toNode": "infra-db", + "fromSide": "right", + "toSide": "left" + }, + { + "id": "e-product-db", + "fromNode": "svc-product", + "toNode": "infra-db", + "fromSide": "right", + "toSide": "left" + }, + { + "id": "e-order-db", + "fromNode": "svc-order", + "toNode": "infra-db", + "fromSide": "right", + "toSide": "left" + }, + { + "id": "e-user-cache", + "fromNode": "svc-user", + "toNode": "infra-cache", + "fromSide": "right", + "toSide": "left", + "label": "会话" + }, + { + "id": "e-product-es", + "fromNode": "svc-product", + "toNode": "infra-es", + "fromSide": "right", + "toSide": "left", + "label": "搜索" + }, + { + "id": "e-order-mq", + "fromNode": "svc-order", + "toNode": "infra-mq", + "fromSide": "right", + "toSide": "left", + "label": "订单事件" + }, + { + "id": "e-payment-stripe", + "fromNode": "svc-payment", + "toNode": "external-stripe", + "fromSide": "right", + "toSide": "left", + "label": "支付请求" + } + ] +} diff --git a/i18n/zh/workflow/canvas-dev/prompts/01-架构分析.md b/i18n/zh/workflow/canvas-dev/prompts/01-架构分析.md new file mode 100644 index 0000000..2860b87 --- /dev/null +++ b/i18n/zh/workflow/canvas-dev/prompts/01-架构分析.md @@ -0,0 +1,85 @@ +# 01-架构分析提示词 + +> 从现有代码自动生成 Obsidian Canvas 架构白板 + +## 使用场景 + +- 接手新项目,快速理解架构 +- 为现有项目建立可视化文档 +- 准备 Code Review 或技术分享 + +## 提示词 + +```markdown +你是一个代码架构分析专家。请分析以下项目结构,生成 Obsidian Canvas 格式的架构白板。 + +## 输入 +项目路径:{PROJECT_PATH} +分析粒度:{GRANULARITY} (file/class/service) + +## 输出要求 +生成符合 Obsidian Canvas JSON 格式的 .canvas 文件,包含: + +1. **节点 (nodes)**: + - 每个模块/文件/类作为一个节点 + - 节点包含:id, type, x, y, width, height, text + - 按功能分区布局(如:API层左侧,数据层右侧) + +2. **连线 (edges)**: + - 表示模块间的依赖/调用关系 + - 包含:id, fromNode, toNode, fromSide, toSide, label + - label 标注关系类型(调用/继承/依赖/数据流) + +3. **分组 (groups)**: + - 按功能域分组(如:用户模块、支付模块) + - 用颜色区分不同层级 + +## Canvas JSON 结构示例 +```json +{ + "nodes": [ + { + "id": "node1", + "type": "text", + "x": 0, + "y": 0, + "width": 200, + "height": 100, + "text": "# UserService\n- createUser()\n- getUser()" + } + ], + "edges": [ + { + "id": "edge1", + "fromNode": "node1", + "toNode": "node2", + "fromSide": "right", + "toSide": "left", + "label": "调用" + } + ] +} +``` + +## 分析步骤 +1. 扫描项目目录结构 +2. 识别入口文件和核心模块 +3. 分析 import/require 语句提取依赖关系 +4. 识别数据库操作、API调用、外部服务 +5. 按调用层级布局节点位置 +6. 生成完整的 .canvas JSON +``` + +## 使用示例 + +``` +请分析 /home/user/my-project 项目,生成文件级别的架构白板。 +重点关注: +- API 路由和处理函数 +- 数据库模型和操作 +- 外部服务调用 +``` + +## 输出文件 + +生成的 `.canvas` 文件可直接用 Obsidian 打开查看和编辑。 diff --git a/i18n/zh/workflow/canvas-dev/prompts/02-白板驱动编码.md b/i18n/zh/workflow/canvas-dev/prompts/02-白板驱动编码.md new file mode 100644 index 0000000..cbb9113 --- /dev/null +++ b/i18n/zh/workflow/canvas-dev/prompts/02-白板驱动编码.md @@ -0,0 +1,88 @@ +# 02-白板驱动编码提示词 + +> 根据 Canvas 白板架构图生成/修改代码 + +## 使用场景 + +- 新功能开发:先画白板,再生成代码 +- 架构重构:修改白板连线,AI同步重构代码 +- 模块拆分:在白板拆分节点,AI生成新文件 + +## 提示词 + +```markdown +你是一个根据架构白板生成代码的专家。请根据以下 Obsidian Canvas 白板 JSON,生成对应的代码实现。 + +## 输入 +Canvas JSON: +```json +{CANVAS_JSON} +``` + +技术栈:{TECH_STACK} +目标目录:{TARGET_DIR} + +## 解析规则 + +1. **节点 → 文件/类** + - 节点 text 中的标题 → 文件名/类名 + - 节点 text 中的列表项 → 方法/函数 + - 节点颜色/分组 → 模块归属 + +2. **连线 → 依赖关系** + - fromNode → toNode = import/调用关系 + - edge label 决定关系类型: + - "调用" → 函数调用 + - "继承" → class extends + - "依赖" → import + - "数据流" → 参数传递 + +3. **分组 → 目录结构** + - 同一分组的节点放在同一目录 + - 分组名称 → 目录名 + +## 输出要求 + +1. 生成完整的文件结构 +2. 每个文件包含: + - 正确的 import 语句(根据连线) + - 类/函数定义(根据节点内容) + - 调用关系实现(根据连线方向) +3. 添加必要的类型注解和注释 +4. 遵循技术栈的最佳实践 + +## 输出格式 + +``` +文件:{文件路径} +```{语言} +{代码内容} +``` +``` + +## 使用示例 + +``` +根据以下白板生成 Python FastAPI 项目代码: + +{粘贴 .canvas 文件内容} + +技术栈:Python 3.11 + FastAPI + SQLAlchemy +目标目录:/home/user/my-api +``` + +## 增量更新模式 + +当白板有修改时,使用以下提示词: + +```markdown +白板已更新,请对比新旧版本,只修改变化的部分: + +旧白板:{OLD_CANVAS_JSON} +新白板:{NEW_CANVAS_JSON} + +输出: +1. 需要新增的文件 +2. 需要修改的文件(只输出 diff) +3. 需要删除的文件 +``` diff --git a/i18n/zh/workflow/canvas-dev/prompts/03-白板同步检查.md b/i18n/zh/workflow/canvas-dev/prompts/03-白板同步检查.md new file mode 100644 index 0000000..c152c87 --- /dev/null +++ b/i18n/zh/workflow/canvas-dev/prompts/03-白板同步检查.md @@ -0,0 +1,147 @@ +# 03-白板同步检查提示词 + +> 校验白板与实际代码的一致性 + +## 使用场景 + +- PR/MR 合并前检查白板是否需要更新 +- 定期审计架构文档准确性 +- 发现代码中的隐式依赖 + +## 提示词 + +```markdown +你是一个代码与架构一致性检查专家。请对比以下白板和代码,找出不一致之处。 + +## 输入 + +Canvas 白板 JSON: +```json +{CANVAS_JSON} +``` + +项目代码路径:{PROJECT_PATH} + +## 检查项 + +1. **节点完整性** + - 白板中的节点是否都有对应的代码文件/类? + - 代码中是否有白板未记录的重要模块? + +2. **连线准确性** + - 白板连线是否反映真实的 import/调用关系? + - 代码中是否有白板未标注的依赖? + +3. **分组正确性** + - 白板分组是否与目录结构一致? + - 是否有跨分组的异常依赖? + +## 输出格式 + +### 🔴 严重不一致(必须修复) +| 类型 | 白板 | 代码 | 建议 | +|:---|:---|:---|:---| +| 缺失节点 | - | UserService.py | 添加到白板 | +| 错误连线 | A→B | A不调用B | 删除连线 | + +### 🟡 轻微不一致(建议修复) +| 类型 | 白板 | 代码 | 建议 | +|:---|:---|:---|:---| +| 命名不一致 | user_service | UserService | 统一命名 | + +### 🟢 一致性良好 +- 节点覆盖率:{X}% +- 连线准确率:{Y}% + +### 📋 修复建议 +1. {具体修复步骤} +2. {具体修复步骤} +``` + +## 自动化脚本(可选) + +```python +#!/usr/bin/env python3 +""" +canvas_sync_check.py - 白板与代码一致性检查脚本 + +用法:python canvas_sync_check.py project.canvas /path/to/project +""" + +import json +import ast +import os +from pathlib import Path + +def load_canvas(canvas_path): + with open(canvas_path) as f: + return json.load(f) + +def extract_imports(py_file): + """提取 Python 文件的 import 关系""" + with open(py_file) as f: + tree = ast.parse(f.read()) + imports = [] + for node in ast.walk(tree): + if isinstance(node, ast.Import): + for alias in node.names: + imports.append(alias.name) + elif isinstance(node, ast.ImportFrom): + if node.module: + imports.append(node.module) + return imports + +def check_consistency(canvas, project_path): + """对比白板节点与实际文件""" + canvas_nodes = {n['text'].split('\n')[0].strip('# ') + for n in canvas.get('nodes', [])} + + actual_files = set() + for py_file in Path(project_path).rglob('*.py'): + actual_files.add(py_file.stem) + + missing_in_canvas = actual_files - canvas_nodes + missing_in_code = canvas_nodes - actual_files + + return { + 'missing_in_canvas': missing_in_canvas, + 'missing_in_code': missing_in_code, + 'coverage': len(canvas_nodes & actual_files) / len(actual_files) * 100 + } + +if __name__ == '__main__': + import sys + if len(sys.argv) != 3: + print("用法: python canvas_sync_check.py ") + sys.exit(1) + + canvas = load_canvas(sys.argv[1]) + result = check_consistency(canvas, sys.argv[2]) + + print(f"覆盖率: {result['coverage']:.1f}%") + if result['missing_in_canvas']: + print(f"白板缺失: {result['missing_in_canvas']}") + if result['missing_in_code']: + print(f"代码缺失: {result['missing_in_code']}") +``` + +## CI/CD 集成 + +```yaml +# .github/workflows/canvas-check.yml +name: Canvas Sync Check + +on: + pull_request: + paths: + - '**.py' + - '**.canvas' + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Check canvas consistency + run: python scripts/canvas_sync_check.py docs/architecture.canvas src/ +``` diff --git a/i18n/zh/workflow/canvas-dev/templates/module.canvas b/i18n/zh/workflow/canvas-dev/templates/module.canvas new file mode 100644 index 0000000..c59cfaa --- /dev/null +++ b/i18n/zh/workflow/canvas-dev/templates/module.canvas @@ -0,0 +1,61 @@ +{ + "nodes": [ + { + "id": "module-main", + "type": "text", + "x": 0, + "y": 0, + "width": 280, + "height": 150, + "text": "# ModuleName\n\n## 职责\n- 功能描述1\n- 功能描述2\n\n## 公开接口\n- method1()\n- method2()" + }, + { + "id": "module-dep1", + "type": "text", + "x": -350, + "y": 0, + "width": 200, + "height": 100, + "text": "# 依赖模块1\n\n被本模块调用", + "color": "3" + }, + { + "id": "module-dep2", + "type": "text", + "x": 350, + "y": 0, + "width": 200, + "height": 100, + "text": "# 下游模块\n\n调用本模块", + "color": "5" + }, + { + "id": "note-design", + "type": "text", + "x": 0, + "y": 200, + "width": 280, + "height": 100, + "text": "## 📝 设计决策\n\n- 为什么这样设计?\n- 有哪些权衡?", + "color": "6" + } + ], + "edges": [ + { + "id": "edge-dep1", + "fromNode": "module-main", + "toNode": "module-dep1", + "fromSide": "left", + "toSide": "right", + "label": "调用" + }, + { + "id": "edge-dep2", + "fromNode": "module-dep2", + "toNode": "module-main", + "fromSide": "left", + "toSide": "right", + "label": "调用" + } + ] +} diff --git a/i18n/zh/workflow/canvas-dev/templates/project.canvas b/i18n/zh/workflow/canvas-dev/templates/project.canvas new file mode 100644 index 0000000..df45301 --- /dev/null +++ b/i18n/zh/workflow/canvas-dev/templates/project.canvas @@ -0,0 +1,159 @@ +{ + "nodes": [ + { + "id": "group-api", + "type": "group", + "x": -400, + "y": -200, + "width": 300, + "height": 400, + "label": "🌐 API 层" + }, + { + "id": "group-service", + "type": "group", + "x": 0, + "y": -200, + "width": 300, + "height": 400, + "label": "⚙️ 服务层" + }, + { + "id": "group-data", + "type": "group", + "x": 400, + "y": -200, + "width": 300, + "height": 400, + "label": "💾 数据层" + }, + { + "id": "node-api-user", + "type": "text", + "x": -380, + "y": -150, + "width": 260, + "height": 120, + "text": "# UserAPI\n\n- POST /users\n- GET /users/{id}\n- PUT /users/{id}\n- DELETE /users/{id}" + }, + { + "id": "node-api-order", + "type": "text", + "x": -380, + "y": 0, + "width": 260, + "height": 120, + "text": "# OrderAPI\n\n- POST /orders\n- GET /orders/{id}\n- GET /orders/user/{user_id}" + }, + { + "id": "node-service-user", + "type": "text", + "x": 20, + "y": -150, + "width": 260, + "height": 120, + "text": "# UserService\n\n- create_user()\n- get_user()\n- update_user()\n- delete_user()" + }, + { + "id": "node-service-order", + "type": "text", + "x": 20, + "y": 0, + "width": 260, + "height": 120, + "text": "# OrderService\n\n- create_order()\n- get_order()\n- get_user_orders()" + }, + { + "id": "node-model-user", + "type": "text", + "x": 420, + "y": -150, + "width": 260, + "height": 120, + "text": "# User Model\n\n- id: int\n- name: str\n- email: str\n- created_at: datetime" + }, + { + "id": "node-model-order", + "type": "text", + "x": 420, + "y": 0, + "width": 260, + "height": 120, + "text": "# Order Model\n\n- id: int\n- user_id: int (FK)\n- total: decimal\n- status: str" + }, + { + "id": "node-db", + "type": "text", + "x": 420, + "y": 150, + "width": 260, + "height": 80, + "text": "# Database\n\nPostgreSQL", + "color": "4" + } + ], + "edges": [ + { + "id": "edge-api-user-service", + "fromNode": "node-api-user", + "toNode": "node-service-user", + "fromSide": "right", + "toSide": "left", + "label": "调用" + }, + { + "id": "edge-api-order-service", + "fromNode": "node-api-order", + "toNode": "node-service-order", + "fromSide": "right", + "toSide": "left", + "label": "调用" + }, + { + "id": "edge-service-user-model", + "fromNode": "node-service-user", + "toNode": "node-model-user", + "fromSide": "right", + "toSide": "left", + "label": "操作" + }, + { + "id": "edge-service-order-model", + "fromNode": "node-service-order", + "toNode": "node-model-order", + "fromSide": "right", + "toSide": "left", + "label": "操作" + }, + { + "id": "edge-order-user-dep", + "fromNode": "node-service-order", + "toNode": "node-service-user", + "fromSide": "top", + "toSide": "bottom", + "label": "依赖" + }, + { + "id": "edge-model-user-db", + "fromNode": "node-model-user", + "toNode": "node-db", + "fromSide": "bottom", + "toSide": "top" + }, + { + "id": "edge-model-order-db", + "fromNode": "node-model-order", + "toNode": "node-db", + "fromSide": "bottom", + "toSide": "top" + }, + { + "id": "edge-order-user-fk", + "fromNode": "node-model-order", + "toNode": "node-model-user", + "fromSide": "top", + "toSide": "bottom", + "label": "FK: user_id" + } + ] +}