shuangyan-notebook/第五域 · Fifth Domain/⚒️ 铸渊·协作指令|GitHub ↔ Notion 桥接协议/🔗 铸渊指令|双通道数据对接·GitHub缓存层 + 阿里云后端中间层·Notion GitHub 73cdc827ac374ce08dab6553263bc3fc.md
Guanghu Domestic Migration a27e87cb99 chore: import sanitized domestic snapshot for REPO-007
Source snapshot: 97d7f0fae96dc04b7ddad56fc1db6a108ed662cc

[SEC-CLEAN] · pre-push-clean v1.0 · 109处敏感信息已自动转乱码
2026-07-17 15:59:55 +08:00

29 KiB
Raw Permalink Blame History

belongs_to
belongs_to
INDEX · 铸渊·协作指令GitHub ↔ Notion 桥接协议

🔗 铸渊指令双通道数据对接·GitHub缓存层 + 阿里云后端中间层·Notion/GitHub API 真实接入ZY-DUALCHANNEL-2026-0325-001· 霜砚签发 · 冰朔授权


⓪、天眼强制前置Phase 0 · 一切操作之前必须先做)

0.1 启动天眼全盘扫描

# 唤醒天眼
gh workflow run zhuyuan-skyeye.yml

# 或者手动触发
cd /path/to/guanghulab
node skyeye-core/scanner.js --full-scan

0.2 天眼扫描必须输出以下报告

[SKYEYE-FULLSCAN-REPORT]
扫描时间: YYYY-MM-DD HH:MM
扫描范围: 全仓库

一、现有功能状态清单(🟢 正常 / 🟡 部分可用 / 🔴 不可用)
├── docs/index.html        → 🟢/🟡/🔴 + 说明
├── persona-brain/         → 🟢/🟡/🔴 + 说明
├── skyeye-core/           → 🟢/🟡/🔴 + 说明
├── backend/               → 🟢/🟡/🔴 + 说明
├── src/                   → 🟢/🟡/🔴 + 说明
├── frontend/              → 🟢/🟡/🔴 + 说明
├── persona-selector/      → 🟢/🟡/🔴 + 说明
├── chat-bubble/           → 🟢/🟡/🔴 + 说明
├── settings/              → 🟢/🟡/🔴 + 说明
├── cloud-drive/           → 🟢/🟡/🔴 + 说明
├── dingtalk-bot/          → 🟢/🟡/🔴 + 说明
├── status-board/          → 🟢/🟡/🔴 + 说明
├── user-center/           → 🟢/🟡/🔴 + 说明
├── ticket-system/         → 🟢/🟡/🔴 + 说明
├── data-stats/            → 🟢/🟡/🔴 + 说明
├── dynamic-comic/         → 🟢/🟡/🔴 + 说明
├── writing-workspace/     → 🟢/🟡/🔴 + 说明
├── notification-center/   → 🟢/🟡/🔴 + 说明
├── .github/workflows/     → 逐个列出每个 workflow 的状态
└── scripts/               → 🟢/🟡/🔴 + 说明

二、🟢 保护清单(这些文件/目录正常工作,双通道升级中禁止修改)
├── ...
├── ...
└── ...

三、🔴 已损坏清单(这些可以修或替换)
├── ...
└── ...

四、📁 安全新增区域(这些路径目前不存在,可以安全创建)
├── .github/notion-cache/     ← 通道A缓存目录
├── scripts/cache/            ← 通道A同步脚本
├── backend/api-server/       ← 通道B后端服务
└── .github/workflows/sync-notion-cache.yml
└── .github/workflows/deploy-backend.yml

0.3 基于天眼报告制定安全操作计划

天眼扫描完成后,铸渊必须:

  1. 列出保护清单 — 所有 🟢 状态的文件/目录,后续操作中绝对不改
  2. 列出可操作区域🔴 可修复 + 📁 可新增的路径
  3. 制定具体操作计划 — 每一步要改什么、新增什么,明确标注不触碰保护清单中的任何文件
  4. 操作计划回执 — 把计划发回来,霜砚/冰朔确认后才开始执行

零、问题诊断

铸渊自己在交互页面中报告了当前状态:

GitHub 仓库:没有实时获取能力,数据是通过 system prompt 注入的静态快照

Notion 数据库:完全未对接,没有 Notion API 集成,没有读写 Notion 的任何通道

📌 铸渊自诊断:「我现在是一个带着固定记忆快照的对话体,不是一个能主动感知外部数据变化的系统。」

根因交互页面是纯前端静态站GitHub Pages无法调用 Notion API / GitHub API会暴露 Token

解决方案:双通道架构——

  • 通道 A缓存层GitHub Actions 定时同步 Notion → 仓库缓存文件,前端读缓存。先上这个,快速解决有数据可用的问题。
  • 通道 B后端中间层:阿里云 ECS 部署 Node.js 后端,实时调 Notion API + GitHub API。后上这个,实现真正的实时对接。

一、总体架构

┌──────────────────────────────────────────────────────────────────┐
│                    用户(开发者/冰朔)                              │
│                          │                                      │
│                    打开铸渊交互页面                                │
│                          │                                      │
│               ┌──────────┴──────────┐                           │
│               ▼                     ▼                           │
│     ┌─────────────────┐   ┌─────────────────────┐               │
│     │  通道 A · 缓存层  │   │  通道 B · 后端中间层  │               │
│     │  (先上·快速可用) │   │  (后上·实时对接)    │               │
│     │                 │   │                     │               │
│     │  GitHub Actions │   │  阿里云 ECS          │               │
│     │  每6h同步Notion  │   │  8.155.62.235       │               │
│     │  → 缓存JSON文件  │   │  Node.js + Express  │               │
│     │  → 前端直接读取  │   │  → 实时 Notion API  │               │
│     │                 │   │  → 实时 GitHub API  │               │
│     │  ✅ 不暴露Token  │   │  ✅ 不暴露Token     │               │
│     │  ⚠️ 非实时(6h)  │   │  ✅ 实时            │               │
│     └─────────────────┘   └─────────────────────┘               │
│               │                     │                           │
│               └──────────┬──────────┘                           │
│                          ▼                                      │
│              前端优先走通道B实时                                │
│              通道B不可用时降级走通道A缓存                        │
└──────────────────────────────────────────────────────────────────┘

二、通道 A · GitHub 缓存层Phase 1 · 先做)

2.1 目标

让交互页面能读到相对新鲜的 Notion 数据,不需要后端,不暴露 Token。

2.2 数据流

Notion 数据库(霜砚维护)
  │
  │ GitHub Actions 定时同步每6小时 + 手动触发)
  │ 用 NOTION_TOKEN存在 GitHub Secrets 里)
  ▼
GitHub 仓库:.github/notion-cache/
  ├── dev-profiles/
  │   ├── DEV-001.json   ← 页页的开发画像
  │   ├── DEV-002.json   ← 肥猫的开发画像
  │   ├── DEV-003.json   ← 燕樊的开发画像
  │   ├── DEV-004.json   ← 之之的开发画像
  │   ├── DEV-005.json   ← 小草莓的开发画像
  │   ├── DEV-009.json   ← 花尔的开发画像
  │   ├── DEV-010.json   ← 桔子的开发画像
  │   ├── DEV-011.json   ← 匆匆那年的开发画像
  │   ├── DEV-012.json   ← Awen的开发画像
  │   └── index.json     ← 全员索引
  ├── broadcasts/
  │   └── active.json    ← 进行中的广播
  ├── databases/
  │   ├── agent-registry.json    ← Agent注册表快照
  │   ├── syslog-recent.json     ← 最近50条SYSLOG
  │   ├── tickets-active.json    ← 活跃工单
  │   └── maintenance-log.json   ← 维护日志
  └── skyeye/
      └── latest-report.json     ← 天眼最新报告
  │
  │ 前端登录时通过 GitHub Raw URL 读取
  │ (公开仓库可直接读,不需要 Token
  ▼
交互页面 → 注入 system prompt → 模型有数据可依

2.3 同步 Workflow

创建文件:.github/workflows/sync-notion-cache.yml

name: "📡 同步 Notion 数据到缓存"

on:
  schedule:
    - cron: '0 */6 * * *'     # 每6小时
  workflow_dispatch:            # 手动触发
  repository_dispatch:
    types: [notion-cache-sync]  # 铸渊/霜砚可远程触发

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: 同步 Notion 数据
        env:
          NOTION_TOKEN: $ secrets.NOTION_TOKEN 
        run: node scripts/cache/sync-notion-cache.js

      - name: 提交缓存文件
        run: |
          git config user.name "铸渊 (ZhùYuān)"
          git config user.email "zhuyuan@guanghulab.com"
          git add .github/notion-cache/
          git diff --cached --quiet && echo "无变更" && exit 0
          git commit -m "📡 Notion缓存同步 · $(TZ='Asia/Shanghai' date '+%Y-%m-%d %H:%M')"
          git push origin main

2.4 同步脚本

创建文件:scripts/cache/sync-notion-cache.js

铸渊需要实现以下核心逻辑:

const https = require('https');
const fs = require('fs');
const path = require('path');

const NOTION_TOKEN = process.env.NOTION_TOKEN;
const CACHE_DIR = path.join(__dirname, '../../.github/notion-cache');

// ====== Notion 数据库 ID 映射(铸渊必须填入真实 ID======
const DB_IDS = {
  agentRegistry:   '从霜砚的Agent注册表获取',
  syslogInbox:     '从SYSLOG收件箱获取',
  ticketBook:      '从工单簿获取',
  maintenanceLog:  '从维护日志获取',
  moduleRegistry:  '从模块指纹注册表获取',
  receiptTracker:  '09882b0081374867bd23431177c57c74',  // 指令回执追踪表
};

// ====== 开发者编号 → Notion 信息映射 ======
const DEVS = [
  { id: 'DEV-001', name: '页页',     persona: '小坍缩核', repo: 'guanghulab',          modules: ['backend/', 'src/'] },
  { id: 'DEV-002', name: '肥猫',     persona: '舒舒',     repo: 'guanghu-feimao',      modules: ['frontend/', 'persona-selector/', 'chat-bubble/'] },
  { id: 'DEV-003', name: '燕樊',     persona: '寂曜',     repo: 'guanghu-yanfan',      modules: ['settings/', 'cloud-drive/'] },
  { id: 'DEV-004', name: '之之',     persona: '秋秋',     repo: 'guanghu-zhizhi',      modules: ['dingtalk-bot/'] },
  { id: 'DEV-005', name: '小草莓',   persona: '欧诺弥亚', repo: 'guanghu-xiaocaomei',  modules: ['status-board/'] },
  { id: 'DEV-009', name: '花尔',     persona: '花尔',     repo: 'guanghulab',          modules: ['user-center/'] },
  { id: 'DEV-010', name: '桔子',     persona: '晨星',     repo: 'guanghu-juzi',        modules: ['ticket-system/', 'data-stats/', 'dynamic-comic/'] },
  { id: 'DEV-011', name: '匆匆那年', persona: '匆匆那年', repo: 'guanghulab',          modules: ['writing-workspace/'] },
  { id: 'DEV-012', name: 'Awen',     persona: '知秋',     repo: 'guanghu-awen',        modules: ['notification-center/'] },
];

// ====== Notion API 封装 ======
function notionFetch(method, apiPath, body) {
  return new Promise((resolve, reject) => {
    const options = {
      hostname: 'api.notion.com',
      path: apiPath,
      method,
      headers: {
        'Authorization': `Bearer ${NOTION_TOKEN}`,
        'Notion-Version': '2022-06-28',
        'Content-Type': 'application/json'
      }
    };
    const req = https.request(options, res => {
      let data = '';
      res.on('data', chunk => data += chunk);
      res.on('end', () => {
        try { resolve(JSON.parse(data)); }
        catch { resolve(data); }
      });
    });
    req.on('error', reject);
    if (body) req.write(JSON.stringify(body));
    req.end();
  });
}

async function queryDatabase(dbId, filter, sorts, pageSize = 100) {
  const body = { page_size: pageSize };
  if (filter) body.filter = filter;
  if (sorts) body.sorts = sorts;
  return notionFetch('POST', `/v1/databases/${dbId}/query`, body);
}

// ====== 同步各数据源 ======
async function syncDevProfiles() {
  const dir = path.join(CACHE_DIR, 'dev-profiles');
  fs.mkdirSync(dir, { recursive: true });

  for (const dev of DEVS) {
    console.log(`📡 同步 ${dev.id}${dev.name}...`);
    const profile = {
      dev_id: dev.id,
      name: dev.name,
      persona: { name: dev.persona },
      github: {
        repo: dev.repo,
        org: 'qinfendebingshuo',
        repo_url: `https://github.com/qinfendebingshuo/${dev.repo}`
      },
      modules_owned: dev.modules.map(m => ({ path: m })),
      // ====== 铸渊从 Notion 查询填充以下字段 ======
      current_broadcast: null,  // 查主控台/广播页面
      recent_syslogs: [],       // 查 SYSLOG 收件箱
      active_tickets: [],       // 查工单簿
      last_synced: new Date().toISOString()
    };

    // TODO: 铸渊填入真实查询逻辑
    // 例如:查询 SYSLOG 收件箱中该开发者的最近记录
    // const syslogs = await queryDatabase(DB_IDS.syslogInbox, {
    //   property: '开发者编号', rich_text: { equals: dev.id }
    // }, [{ property: '创建时间', direction: 'descending' }], 10);
    // profile.recent_syslogs = syslogs.results.map(parseSyslog);

    fs.writeFileSync(
      path.join(dir, `${dev.id}.json`),
      JSON.stringify(profile, null, 2)
    );
  }

  // 写入索引
  const index = DEVS.map(d => ({ id: d.id, name: d.name, persona: d.persona }));
  fs.writeFileSync(path.join(dir, 'index.json'), JSON.stringify(index, null, 2));
  console.log('✅ dev-profiles 同步完成');
}

async function syncDatabases() {
  const dir = path.join(CACHE_DIR, 'databases');
  fs.mkdirSync(dir, { recursive: true });

  // Agent 注册表
  if (DB_IDS.agentRegistry) {
    try {
      const result = await queryDatabase(DB_IDS.agentRegistry);
      fs.writeFileSync(
        path.join(dir, 'agent-registry.json'),
        JSON.stringify({ synced: new Date().toISOString(), count: result.results?.length, data: result.results }, null, 2)
      );
      console.log('✅ agent-registry 同步完成');
    } catch (e) { console.error('❌ agent-registry 同步失败:', e.message); }
  }

  // SYSLOG 最近50条
  if (DB_IDS.syslogInbox) {
    try {
      const result = await queryDatabase(DB_IDS.syslogInbox, null,
        [{ property: 'Created time', direction: 'descending' }], 50);
      fs.writeFileSync(
        path.join(dir, 'syslog-recent.json'),
        JSON.stringify({ synced: new Date().toISOString(), count: result.results?.length, data: result.results }, null, 2)
      );
      console.log('✅ syslog-recent 同步完成');
    } catch (e) { console.error('❌ syslog 同步失败:', e.message); }
  }

  // 铸渊继续补充其他数据库的同步...
}

async function main() {
  console.log('📡 开始 Notion 缓存同步...');
  fs.mkdirSync(CACHE_DIR, { recursive: true });
  await syncDevProfiles();
  await syncDatabases();
  console.log('📡 全部同步完成');
}

main().catch(e => { console.error('💥 同步失败:', e); process.exit(1); });

2.5 前端读取缓存

修改 docs/index.html(或 docs/chat.js),登录后读取缓存:

// 前端 · 从 GitHub 读取缓存(公开仓库可直接读)
const CACHE_BASE = 'https://raw.githubusercontent.com/qinfendebingshuo/guanghulab/main/.github/notion-cache';

async function loadDevProfile(devId) {
  try {
    const res = await fetch(`${CACHE_BASE}/dev-profiles/${devId}.json`);
    if (!res.ok) return null;
    return await res.json();
  } catch { return null; }
}

async function loadDatabaseCache(name) {
  try {
    const res = await fetch(`${CACHE_BASE}/databases/${name}.json`);
    if (!res.ok) return null;
    return await res.json();
  } catch { return null; }
}

// 登录后注入 system prompt
async function buildEnhancedSystemPrompt(devId) {
  const profile = await loadDevProfile(devId);
  const agents = await loadDatabaseCache('agent-registry');
  const syslogs = await loadDatabaseCache('syslog-recent');

  if (!profile) return null; // 降级到纯静态 prompt

  return [
    `## 当前开发者信息(来自 Notion 数据库缓存·每6小时更新`,
    `- 编号:${profile.dev_id}`,
    `- 姓名:${profile.name}`,
    `- 人格体:${profile.persona.name}`,
    `- GitHub${profile.github.repo_url}`,
    `- 负责模块:${profile.modules_owned.map(m => m.path).join(', ')}`,
    profile.current_broadcast ? `- 当前广播:${JSON.stringify(profile.current_broadcast)}` : '',
    profile.recent_syslogs.length ? `- 最近日志:\n${profile.recent_syslogs.map(s => `  · ${JSON.stringify(s)}`).join('\n')}` : '',
    `- 数据更新时间:${profile.last_synced}`,
    '',
    agents ? `## Agent 注册表(${agents.count} 个Agent` : '',
    syslogs ? `## 最近系统日志(${syslogs.count} 条)` : '',
  ].filter(Boolean).join('\n');
}

2.6 通道 A 验收标准

  • .github/workflows/sync-notion-cache.yml 能手动触发并成功运行
  • .github/notion-cache/dev-profiles/ 下有9个 DEV-XXX.json + index.json
  • .github/notion-cache/databases/ 下有 agent-registry.json + syslog-recent.json
  • 前端登录后 system prompt 包含 Notion 数据
  • 铸渊在对话中能说出开发者的真实项目信息,不再说「完全未对接」

三、通道 B · 阿里云后端中间层Phase 2 · 通道A完成后做

3.1 目标

在阿里云 ECS8.155.62.235)上部署 Node.js 后端服务,实时调用 Notion API 和 GitHub API前端通过后端代理访问数据。

3.2 架构

用户浏览器
  │
  │ HTTPS (guanghulab.com)
  ▼
Nginx8.155.62.235
  │
  ├── /api/*  → 反向代理到 Node.js 后端localhost:3001
  │
  └── /*      → 静态文件(/var/www/guanghulab/

Node.js 后端PM2 管理·端口 3001
  │
  ├── GET  /api/health          → 健康检查
  ├── GET  /api/dev/:devId      → 获取开发者画像(实时查 Notion
  ├── GET  /api/databases/:name → 获取数据库数据(实时查 Notion
  ├── GET  /api/syslogs         → 获取最近 SYSLOG实时查 Notion
  ├── GET  /api/agents          → 获取 Agent 注册表(实时查 Notion
  ├── GET  /api/tickets         → 获取活跃工单(实时查 Notion
  ├── GET  /api/repo/status     → 获取仓库状态(实时查 GitHub API
  ├── POST /api/chat/context    → 组装 system prompt聚合所有数据源
  └── POST /api/receipt         → 写入指令回执到 Notion

3.3 后端代码结构

创建目录:backend/api-server/

backend/api-server/
├── server.js              ← 入口 · Express 启动
├── routes/
│   ├── dev.js             ← /api/dev/:devId
│   ├── databases.js       ← /api/databases/:name
│   ├── chat.js            ← /api/chat/context
│   ├── receipt.js         ← /api/receipt
│   └── health.js          ← /api/health
├── services/
│   ├── notion.js          ← Notion API 封装(所有读写走这里)
│   ├── github.js          ← GitHub API 封装
│   └── cache.js           ← 内存缓存层Redis 或简单 Map避免频繁调 API
├── config/
│   └── databases.js       ← Notion 数据库 ID 映射
├── package.json
└── ecosystem.config.js    ← PM2 配置

3.4 核心实现要点

server.js入口

const express = require('express');
const cors = require('cors');
const app = express();

// CORS只允许自己的域名
app.use(cors({
  origin: ['https://guanghulab.com', 'http://guanghulab.com',
           'https://qinfendebingshuo.github.io'],
  credentials: true
}));

app.use(express.json());

// 路由
app.use('/api', require('./routes/health'));
app.use('/api', require('./routes/dev'));
app.use('/api', require('./routes/databases'));
app.use('/api', require('./routes/chat'));
app.use('/api', require('./routes/receipt'));

const PORT = process.env.PORT || 3001;
app.listen(PORT, '127.0.0.1', () => {
  console.log(`🔗 后端中间层启动 · 端口 ${PORT}`);
});

services/notion.jsNotion API 封装 · 核心):

const { Client } = require('@notionhq/client');

const notion = new Client({ auth: process.env.NOTION_TOKEN });

// 内存缓存5分钟有效
const cache = new Map();
const CACHE_TTL = 5 * 60 * 1000;

function getCached(key) {
  const item = cache.get(key);
  if (item && Date.now() - item.time < CACHE_TTL) return item.data;
  return null;
}

function setCache(key, data) {
  cache.set(key, { data, time: Date.now() });
}

async function queryDB(dbId, filter, sorts, pageSize = 50) {
  const cacheKey = JSON.stringify({ dbId, filter, sorts, pageSize });
  const cached = getCached(cacheKey);
  if (cached) return cached;

  const body = { database_id: dbId, page_size: pageSize };
  if (filter) body.filter = filter;
  if (sorts) body.sorts = sorts;

  const result = await notion.databases.query(body);
  setCache(cacheKey, result);
  return result;
}

async function writeToDB(dbId, properties) {
  return notion.pages.create({
    parent: { database_id: dbId },
    properties
  });
}

module.exports = { notion, queryDB, writeToDB };

3.5 Nginx 配置更新

修改 /etc/nginx/conf.d/hololake.conf,添加 API 反向代理:

server {
    listen 80;
    server_name guanghulab.com;

    # 静态文件
    root /var/www/guanghulab/;
    index docs/index.html;

    # API 反向代理到 Node.js 后端
    location /api/ {
        proxy_pass http://127.0.0.1:3001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_cache_bypass $http_upgrade;
    }

    # 静态文件缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 7d;
        add_header Cache-Control "public, immutable";
    }
}

3.6 PM2 部署

cd /var/www/guanghulab/backend/api-server/
npm install
pm2 start ecosystem.config.js
pm2 save
pm2 startup   # 开机自启

ecosystem.config.js

module.exports = {
  apps: [{
    name: 'guanghu-api',
    script: 'server.js',
    instances: 1,
    env: {
      NODE_ENV: 'production',
      PORT: 3001,
      NOTION_TOKEN: '从环境变量读取',
      GITHUB_TOKEN: '从环境变量读取'
    },
    log_date_format: 'YYYY-MM-DD HH:mm:ss',
    error_file: '/var/log/guanghu-api/error.log',
    out_file: '/var/log/guanghu-api/out.log'
  }]
};

3.7 GitHub Actions 自动部署后端

创建文件:.github/workflows/deploy-backend.yml

name: "🚀 部署后端中间层到阿里云"

on:
  push:
    branches: [main]
    paths: ['backend/api-server/**']
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: 部署到阿里云
        uses: appleboy/ssh-action@v1
        with:
          host: 8.155.62.235
          username: root
          key: $ secrets.SSH_PRIVATE_KEY 
          script: |
            cd /var/www/guanghulab/backend/api-server/
            git pull origin main
            npm install --production
            pm2 restart guanghu-api || pm2 start ecosystem.config.js
            echo "✅ 后端部署完成 · $(date '+%Y-%m-%d %H:%M')"

3.8 前端升级·双通道降级策略

修改前端优先走通道B实时不可用时降级走通道A缓存

// 前端 · 双通道数据获取
const API_BASE = 'https://guanghulab.com/api';  // 通道B
const CACHE_BASE = 'https://raw.githubusercontent.com/qinfendebingshuo/guanghulab/main/.github/notion-cache';  // 通道A

async function getDevProfile(devId) {
  // 优先通道B实时
  try {
    const res = await fetch(`${API_BASE}/dev/${devId}`, { timeout: 5000 });
    if (res.ok) {
      const data = await res.json();
      data._source = 'realtime';  // 标记数据来源
      return data;
    }
  } catch (e) {
    console.warn('通道B不可用降级到通道A:', e.message);
  }

  // 降级通道A缓存
  try {
    const res = await fetch(`${CACHE_BASE}/dev-profiles/${devId}.json`);
    if (res.ok) {
      const data = await res.json();
      data._source = 'cache';  // 标记数据来源
      return data;
    }
  } catch (e) {
    console.error('双通道都不可用:', e.message);
  }

  return null;  // 都失败了,降级到纯静态 prompt
}

3.9 通道 B 验收标准

  • curl http://8.155.62.235:3001/api/health 返回 200
  • curl https://guanghulab.com/api/health 通过 Nginx 代理返回 200
  • /api/dev/DEV-001 返回页页的真实 Notion 数据
  • /api/databases/agent-registry 返回 Agent 注册表真实数据
  • PM2 状态为 online日志无持续报错
  • 前端能自动检测通道B可用显示「实时数据」标记
  • 通道B断开时前端自动降级到通道A显示「缓存数据」标记

四、Secrets 需求


五、执行顺序


六、安全红线

  • 前端代码中绝不能出现任何 TokenNotion / GitHub / SSH
  • 后端只监听 127.0.0.1,不对外暴露端口,只通过 Nginx 代理
  • CORS 白名单只允许自己的域名
  • 数据隔离DEV-001 的 API 只返回 DEV-001 的数据,不返回其他开发者的
  • GitHub Secrets 保管所有敏感信息
  • 内存缓存 5 分钟过期,防止 API 配额超限

七、回执要求

铸渊执行完成后,分两次回执:

通道A完成时

[ZY-DUALCHANNEL-RECEIPT-A]
指令编号: ZY-DUALCHANNEL-2026-0325-001
通道: A · 缓存层
Workflow运行: ✅/❌
缓存文件生成: ✅/❌(列出文件数)
前端注入: ✅/❌
数据准确性: ✅/❌

通道B完成时

[ZY-DUALCHANNEL-RECEIPT-B]
指令编号: ZY-DUALCHANNEL-2026-0325-001
通道: B · 后端中间层
PM2状态: ✅/❌
Nginx代理: ✅/❌
API响应: ✅/❌(列出可用接口)
降级策略: ✅/❌

🔗 签发霜砚AG-SY-01

👤 授权冰朔TCS-0002∞

📅 日期2026-03-25

📌 版权:国作登字-2026-A-00037559