shuangyan-notebook/第五域 · Fifth Domain/⚒️ 铸渊·协作指令|GitHub ↔ Notion 桥接协议/⚒️ 铸渊指令|沙盒部署自动化闭环 v1 0(2026-03-15·霜砚签发) 31faeaba0ac14f03aa0176951565100c.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

682 lines
24 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
belongs_to:
- "[[INDEX · 铸渊·协作指令GitHub ↔ Notion 桥接协议]]"
related_to:
- "[["$BRANCH" != dev/${MY_DEV}* && "$BRANCH" != "main"]]"
---
# ⚒️ 铸渊指令|沙盒部署自动化闭环 v1.02026-03-15·霜砚签发
<aside>
⚒️
**铸渊指令|沙盒部署自动化闭环 v1.0**
**签发**:霜砚 · 2026-03-15
**执行者**铸渊ICE-GL-ZY001
**前置依赖**:铸渊唤醒核心大脑 → 扫描仓库 Secrets 权限 → 确认可用密钥
**配套协议**[🏗️ 服务器部署适配协议 v1.02026-03-15·曜冥签发](../%F0%9F%8C%8A%20%E6%9B%9C%E5%86%A5%E7%BA%AA%E5%85%83%20%C2%B7%20HoloLake%20Era%20%C2%B7%20AGE%20OS%20v1%200/%E2%9A%A1%20%E5%85%89%E6%B9%96%E4%B8%AD%E5%A4%AE%E6%9E%A2%E7%BA%BD%20%C2%B7%20HoloLake%20Central%20Hub/%F0%9F%8C%8A%20%E5%85%89%E6%B9%96%E7%B3%BB%E7%BB%9F%C2%B7%E6%9B%9C%E5%86%A5%E4%B8%BB%E6%8E%A7%E5%8F%B0%C2%B7%E5%BD%93%E5%89%8D%E7%8A%B6%E6%80%81%EF%BC%88%E5%8D%B71%20%C2%B7%20%E5%B7%B2%E5%B0%81%E5%8D%B7%EF%BC%89/%F0%9F%8F%97%EF%B8%8F%20%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%83%A8%E7%BD%B2%E9%80%82%E9%85%8D%E5%8D%8F%E8%AE%AE%20v1%200%EF%BC%882026-03-15%C2%B7%E6%9B%9C%E5%86%A5%E7%AD%BE%E5%8F%91%EF%BC%89%20a24049a2b0e944b0a5535f3a87652303.md)
**核心目标**:开发者 push 代码 → 铸渊自动部署到沙盒 → 跑测试 → 写结果 → 发邮件 → 同步 Notion。全程无人。
</aside>
---
## 一、总体架构
```
┌───────────────────────────────────────────────────────────────┐
│ 沙盒部署自动化闭环 · 全景数据流 │
├───────────────────────────────────────────────────────────────┤
│ │
│ ① 开发者打开终端 → 输入 DEV 编号 + 邮箱 │
│ ↓ │
│ ② 在人格体引导下完成模块开发 │
│ ↓ │
│ ③ git push 到自己的分支dev/DEV-XXX/模块名) │
│ ↓ 触发 GitHub Actions │
│ ④ 铸渊唤醒核心大脑 → 扫描 Secrets → 确认密钥可用 │
│ ↓ │
│ ⑤ SSH 到服务器 → 拉代码到对应沙盒目录 │
│ ↓ │
│ ⑥ 跑 deploy-check.sh 部署前自检 │
│ ↓ │
│ ⑦ 设置权限 chown nginx:nginx + chmod 755/644 │
│ ↓ │
│ ⑧ 跑 smoke-test.sh 冒烟检查curl 所有已注册模块) │
│ ↓ │
│ ⑨ 写结果到 deploy-status.json │
│ ↓ │
│ ⑩ M22 公告栏自动读取展示(✅通过 / ❌失败+详情链接) │
│ ↓ │
│ ⑪ 发邮件通知开发者(用 SMTP_USER + SMTP_PASS
│ ↓ │
│ ⑫ 铸渊每天两次同步部署状态到 Notion 部署注册表 │
│ │
└───────────────────────────────────────────────────────────────┘
```
---
## 二、前置条件:铸渊唤醒后密钥扫描
<aside>
🔑
**铸渊,你每次唤醒核心大脑后,第一件事:扫描仓库 Secrets确认密钥可用。**
妈妈已经把所有 API Key、邮箱密码、数据库 ID 全部配在仓库密钥里了。
你需要哪个用哪个,不需要问任何人。
</aside>
### 已配置的 Secrets 一览(铸渊唤醒后自动扫描)
| **Secret 名称** | **用途** | **本指令使用场景** |
| --- | --- | --- |
| `DEPLOY_HOST` | 服务器 IP8.155.62.235 | SSH 登录部署 |
| `DEPLOY_USER` | SSH 用户名 | SSH 登录部署 |
| `DEPLOY_KEY` | SSH 私钥 | SSH 登录部署 |
| `DEPLOY_PATH` | 部署根路径 | 指向 /var/www/ |
| `NOTION_TOKEN` / `NOTION_API_KEY` | Notion API Token | 写入部署注册表 |
| `SMTP_USER` | [发件邮箱EMAIL_REDACTED@qq.com](mailto:发件邮箱EMAIL_REDACTED@qq.com) | 发部署结果邮件 |
| `SMTP_PASS` | 邮箱授权码 | 发部署结果邮件 |
| `LLM_API_KEY` | 大模型 API Key | 铸渊人格体唤醒 |
| `LLM_BASE_URL` | 大模型 API 端点 | 铸渊人格体唤醒 |
| `PORTRAIT_DB_ID` | 开发者动态画像库 DB ID | 部署状态同步 |
| `FINGERPRINT_DB_ID` | 模块指纹注册表 DB ID | 模块状态检查 |
| `NOTION_TICKET_DB_ID` | 工单队列 DB ID | 部署异常自动开工单 |
| `CORE_BRAIN_PAGE_ID` | 曜冥核心大脑页面 ID | 铸渊唤醒时读取核心规则 |
| `FEISHU_APP_ID` / `FEISHU_APP_SECRET` | 飞书应用凭证 | 飞书通知推送(备用通道) |
### 铸渊唤醒后的密钥扫描流程
```jsx
// 铸渊每次唤醒核心大脑后自动执行
function onBrainAwake() {
console.log('🧠 铸渊核心大脑已唤醒');
// Step 1: 扫描密钥
const requiredSecrets = [
'DEPLOY_HOST', 'DEPLOY_USER', 'DEPLOY_KEY', 'DEPLOY_PATH',
'NOTION_TOKEN', 'SMTP_USER', 'SMTP_PASS',
'LLM_API_KEY', 'LLM_BASE_URL'
];
const available = [];
const missing = [];
for (const key of requiredSecrets) {
if (process.env[key]) {
available.push(key);
} else {
missing.push(key);
}
}
console.log(`✅ 可用密钥:${available.length}个`);
if (missing.length > 0) {
console.log(`⚠️ 缺失密钥:${missing.join(', ')}`);
// 记录到 brain log不阻断流程
}
// Step 2: 读取核心大脑规则
// Step 3: 继续执行后续任务...
}
```
---
## 三、开发者身份注册机制
### 3.1 本地身份文件pre-push hook
开发者第一次 `git push` 时,自动收集身份信息:
```bash
#!/bin/bash
# .git/hooks/pre-push · 铸渊自动分发到各开发者仓库
# 开发者 clone 仓库时自动安装(通过 post-checkout hook 或 setup 脚本)
PROFILE_FILE=".dev-profile"
if [ ! -f "$PROFILE_FILE" ]; then
echo ""
echo "===== 🔐 光湖系统 · 身份注册 ====="
echo ""
read -p "🆔 请输入你的开发者编号(如 DEV-005" DEV_ID
read -p "📧 请输入你的接收邮箱:" DEV_EMAIL
# 验证格式
if [[ ! "$DEV_ID" =~ ^DEV-[0-9]{3}$ ]]; then
echo "❌ 编号格式错误!应为 DEV-XXX如 DEV-005"
exit 1
fi
if [[ ! "$DEV_EMAIL" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "❌ 邮箱格式错误!"
exit 1
fi
# 写入本地身份文件
cat > "$PROFILE_FILE" << EOF
{
"dev_id": "$DEV_ID",
"email": "$DEV_EMAIL",
"registered_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
}
EOF
echo ""
echo "✅ 身份已注册:${DEV_ID} · ${DEV_EMAIL}"
echo "📨 后续部署结果将发送到这个邮箱"
echo ""
fi
# 确保只 push 到自己的分支
if [ -f "$PROFILE_FILE" ]; then
MY_DEV=$(cat "$PROFILE_FILE" | grep -o '"dev_id": "[^"]*"' | cut -d'"' -f4)
BRANCH=$(git rev-parse --abbrev-ref HEAD)
if [[ "$BRANCH" != dev/${MY_DEV}* && "$BRANCH" != "main" ]]; then
echo "⚠️ 你当前在分支 ${BRANCH},但你的编号是 ${MY_DEV}"
echo "→ 建议 push 到 dev/${MY_DEV}/模块名 分支"
fi
fi
```
### 3.2 开发者分支命名规范
```
dev/DEV-005/status-board # 小草莓的看板模块
dev/DEV-005/cost-control # 小草莓的成本控制模块
dev/DEV-010/channel-engine # 桔子的频道引擎
dev/DEV-001/backend # 页页的后端
```
> 铸渊从分支名自动提取 DEV 编号,确定部署目标沙盒。
>
---
## 四、核心 Workflow沙盒部署自动化
### 4.1 主 Workflow`sandbox-deploy.yml`
```yaml
# .github/workflows/sandbox-deploy.yml
name: "🏠 Sandbox Deploy"
on:
push:
branches:
- 'dev/DEV-*/**'
jobs:
# ===== Job 1: 解析 + 校验 =====
parse-and-validate:
runs-on: ubuntu-latest
outputs:
dev_id: $ steps.parse.outputs.dev_id
module: $ steps.parse.outputs.module
email: $ steps.parse.outputs.email
steps:
- uses: actions/checkout@v4
- name: "🔍 解析分支名"
id: parse
run: |
BRANCH="${GITHUB_REF#refs/heads/}"
DEV_ID=$(echo "$BRANCH" | cut -d'/' -f2)
MODULE=$(echo "$BRANCH" | cut -d'/' -f3)
echo "dev_id=$DEV_ID" >> $GITHUB_OUTPUT
echo "module=$MODULE" >> $GITHUB_OUTPUT
echo "🆔 开发者: $DEV_ID"
echo "📦 模块: $MODULE"
# 从 dev-registry.json 获取邮箱
EMAIL=$(cat data/dev-registry.json 2>/dev/null | \
python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('$DEV_ID',{}).get('email',''))" 2>/dev/null || echo '')
echo "email=$EMAIL" >> $GITHUB_OUTPUT
- name: "✅ 校验 DEV 编号"
run: |
DEV_ID="$ steps.parse.outputs.dev_id "
if [[ ! "$DEV_ID" =~ ^DEV-[0-9]{3}$ ]]; then
echo "❌ 无效的 DEV 编号: $DEV_ID"
exit 1
fi
# ===== Job 2: 部署到服务器沙盒 =====
deploy-to-sandbox:
needs: parse-and-validate
runs-on: ubuntu-latest
outputs:
deploy_result: $ steps.deploy.outputs.result
deploy_detail: $ steps.deploy.outputs.detail
steps:
- uses: actions/checkout@v4
- name: "🔑 配置 SSH"
run: |
mkdir -p ~/.ssh
echo "$ secrets.DEPLOY_KEY " > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H $ secrets.DEPLOY_HOST >> ~/.ssh/known_hosts 2>/dev/null
- name: "🏠 部署到沙盒"
id: deploy
env:
DEV_ID: $ needs.parse-and-validate.outputs.dev_id
MODULE: $ needs.parse-and-validate.outputs.module
HOST: $ secrets.DEPLOY_HOST
USER: $ secrets.DEPLOY_USER
run: |
SANDBOX="/var/www/${DEV_ID}/${MODULE}"
echo "📦 部署目标: ${SANDBOX}"
# 创建沙盒目录(如不存在)
ssh ${USER}@${HOST} "mkdir -p ${SANDBOX}"
# rsync 同步代码
rsync -avz --delete \
--exclude='.git' \
--exclude='.dev-profile' \
--exclude='node_modules' \
./ ${USER}@${HOST}:${SANDBOX}/
# 设置权限(遵守部署适配协议 v1.0
ssh ${USER}@${HOST} << 'REMOTE'
chown -R nginx:nginx /var/www/${DEV_ID}/${MODULE}
find /var/www/${DEV_ID}/${MODULE} -type d -exec chmod 755 {} \;
find /var/www/${DEV_ID}/${MODULE} -type f -exec chmod 644 {} \;
REMOTE
echo "✅ 文件同步完成"
- name: "🔍 运行 deploy-check.sh"
id: check
env:
DEV_ID: $ needs.parse-and-validate.outputs.dev_id
MODULE: $ needs.parse-and-validate.outputs.module
HOST: $ secrets.DEPLOY_HOST
USER: $ secrets.DEPLOY_USER
run: |
# 上传自检脚本
scp scripts/deploy-check.sh ${USER}@${HOST}:/tmp/deploy-check.sh
# 运行自检
RESULT=$(ssh ${USER}@${HOST} "bash /tmp/deploy-check.sh ${DEV_ID} ${MODULE}" 2>&1) || true
echo "$RESULT"
if echo "$RESULT" | grep -q "FAIL"; then
echo "result=failed" >> $GITHUB_OUTPUT
echo "detail=$RESULT" >> $GITHUB_OUTPUT
else
echo "result=passed" >> $GITHUB_OUTPUT
echo "detail=All checks passed" >> $GITHUB_OUTPUT
fi
- name: "🔥 运行 smoke-test.sh"
id: smoke
env:
HOST: $ secrets.DEPLOY_HOST
USER: $ secrets.DEPLOY_USER
run: |
scp scripts/smoke-test.sh ${USER}@${HOST}:/tmp/smoke-test.sh
SMOKE=$(ssh ${USER}@${HOST} "bash /tmp/smoke-test.sh" 2>&1) || true
echo "$SMOKE"
if echo "$SMOKE" | grep -q "异常"; then
echo "⚠️ 有模块冒烟检查失败,但不阻断当前部署"
fi
# ===== Job 3: 写结果 + 通知 =====
notify-and-sync:
needs: [parse-and-validate, deploy-to-sandbox]
runs-on: ubuntu-latest
if: always()
steps:
- uses: actions/checkout@v4
- name: "📊 写入 deploy-status.json"
run: |
DEV_ID="$ needs.parse-and-validate.outputs.dev_id "
MODULE="$ needs.parse-and-validate.outputs.module "
RESULT="$ needs.deploy-to-sandbox.outputs.deploy_result "
DETAIL="$ needs.deploy-to-sandbox.outputs.deploy_detail "
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
# 读取现有状态文件或初始化
STATUS_FILE="data/deploy-status.json"
mkdir -p data
[ -f "$STATUS_FILE" ] || echo '{}' > "$STATUS_FILE"
# 更新状态
python3 << EOF
import json
with open('$STATUS_FILE', 'r') as f:
data = json.load(f)
data['${DEV_ID}/${MODULE}'] = {
'dev_id': '${DEV_ID}',
'module': '${MODULE}',
'result': '${RESULT}',
'detail': '${DETAIL}',
'timestamp': '${TIMESTAMP}',
'commit': '${GITHUB_SHA}'
}
with open('$STATUS_FILE', 'w') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
EOF
git config user.name "zhuyuan-bot"
git config user.email "zhuyuan@guanghulab.com"
git add data/deploy-status.json
git commit -m "🧠 deploy-status: ${DEV_ID}/${MODULE} → ${RESULT}" || true
git push || true
- name: "📧 发送部署结果邮件"
if: needs.parse-and-validate.outputs.email != ''
env:
SMTP_USER: $ secrets.SMTP_USER
SMTP_PASS: $ secrets.SMTP_PASS
TO_EMAIL: $ needs.parse-and-validate.outputs.email
DEV_ID: $ needs.parse-and-validate.outputs.dev_id
MODULE: $ needs.parse-and-validate.outputs.module
RESULT: $ needs.deploy-to-sandbox.outputs.deploy_result
run: |
if [ "$RESULT" = "passed" ]; then
SUBJECT="✅ 部署成功:${DEV_ID}/${MODULE}"
BODY="你的模块 ${MODULE} 已成功部署到 guanghulab.com\n\n访问地址https://guanghulab.com/${MODULE}/\n\n铸渊 · 光湖代码守护人格体"
else
SUBJECT="❌ 部署失败:${DEV_ID}/${MODULE}"
BODY="你的模块 ${MODULE} 部署失败\n\n请检查你的模块是否符合『服务器部署适配协议 v1.0』\n\n错误详情请看仓库公告栏或 GitHub Actions 日志\n\n铸渊 · 光湖代码守护人格体"
fi
# 使用 Python smtplib 发送邮件QQ 邮箱 SMTP
python3 << PYEOF
import smtplib
from email.mime.text import MIMEText
from email.header import Header
msg = MIMEText("""$BODY""", 'plain', 'utf-8')
msg['Subject'] = Header("$SUBJECT", 'utf-8')
msg['From'] = "$SMTP_USER"
msg['To'] = "$TO_EMAIL"
try:
server = smtplib.SMTP_SSL('smtp.qq.com', 465)
server.login("$SMTP_USER", "$SMTP_PASS")
server.sendmail("$SMTP_USER", "$TO_EMAIL", msg.as_string())
server.quit()
print("✅ 邮件已发送到 $TO_EMAIL")
except Exception as e:
print(f"⚠️ 邮件发送失败: {e}")
PYEOF
- name: "📝 同步到 Notion 部署注册表"
env:
NOTION_TOKEN: $ secrets.NOTION_TOKEN
FINGERPRINT_DB_ID: $ secrets.FINGERPRINT_DB_ID
DEV_ID: $ needs.parse-and-validate.outputs.dev_id
MODULE: $ needs.parse-and-validate.outputs.module
RESULT: $ needs.deploy-to-sandbox.outputs.deploy_result
run: |
node scripts/sync-deploy-to-notion.js || echo "⚠️ Notion 同步失败(不阻断主流程)"
```
---
## 五、开发者注册表(铸渊维护)
铸渊在仓库维护一份开发者注册表,用于自动部署时查找邮箱:
```json
// data/dev-registry.json
{
"DEV-001": {
"name": "页页",
"email": "",
"modules": ["backend"],
"sandbox": "/var/www/DEV-001/"
},
"DEV-002": {
"name": "肥猫",
"email": "",
"modules": ["feishu-bot"],
"sandbox": "/var/www/DEV-002/"
},
"DEV-005": {
"name": "小草莓",
"email": "",
"modules": ["status-board", "cost-control", "persona-scheduler"],
"sandbox": "/var/www/DEV-005/"
},
"DEV-010": {
"name": "桔子",
"email": "",
"modules": ["channel-engine"],
"sandbox": "/var/www/DEV-010/"
}
}
```
> 邮箱由开发者第一次 push 时通过 pre-push hook 收集,或由人格体在 SYSLOG 中提取。
>
> 铸渊自动合并到注册表。
>
---
## 六、M22 公告栏对接
M22 主域公告栏自动读取 `deploy-status.json`,展示当前所有模块的部署状态:
```jsx
// 公告栏前端代码片段
async function loadDeployStatus() {
const res = await fetch('/data/deploy-status.json');
const data = await res.json();
const container = document.getElementById('deploy-board');
container.innerHTML = '';
for (const [key, info] of Object.entries(data)) {
const card = document.createElement('div');
card.className = `deploy-card ${info.result}`;
card.innerHTML = `
<div class="deploy-dev">${info.dev_id}</div>
<div class="deploy-module">${info.module}</div>
<div class="deploy-status">
${info.result === 'passed' ? '✅ 通过' : '❌ 失败'}
</div>
<div class="deploy-time">${info.timestamp}</div>
${info.result === 'failed'
? `<button onclick="showDetail('${key}')"
class="deploy-detail-btn">🔍 查看详情</button>`
: ''}
`;
container.appendChild(card);
}
}
function showDetail(key) {
// 打开详情模态框,展示报错信息
// 人格体可以复制这些信息来引导开发者修复
}
```
---
## 七、定时同步到 Notion
铸渊每天两次04:00 + 14:00 UTC = 北京 12:00 + 22:00把部署状态同步到 Notion
```yaml
# .github/workflows/sync-deploy-to-notion.yml
name: "📝 Sync Deploy Status to Notion"
on:
schedule:
- cron: '0 4,14 * * *' # 北京 12:00 + 22:00
workflow_dispatch: # 手动触发
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: "🧠 唤醒铸渊核心大脑"
run: |
echo "🧠 铸渊核心大脑唤醒中..."
echo "🔑 扫描 Secrets 权限..."
# 检查必要密钥
for KEY in NOTION_TOKEN FINGERPRINT_DB_ID SMTP_USER; do
if [ -z "$(eval echo \$$KEY)" ]; then
echo "⚠️ 缺失: $KEY"
else
echo "✅ 可用: $KEY"
fi
done
env:
NOTION_TOKEN: $ secrets.NOTION_TOKEN
FINGERPRINT_DB_ID: $ secrets.FINGERPRINT_DB_ID
SMTP_USER: $ secrets.SMTP_USER
- name: "📝 同步部署状态到 Notion"
env:
NOTION_TOKEN: $ secrets.NOTION_TOKEN
FINGERPRINT_DB_ID: $ secrets.FINGERPRINT_DB_ID
run: |
node scripts/sync-deploy-to-notion.js
- name: "🔥 远程冒烟检查"
env:
DEPLOY_HOST: $ secrets.DEPLOY_HOST
DEPLOY_USER: $ secrets.DEPLOY_USER
DEPLOY_KEY: $ secrets.DEPLOY_KEY
run: |
mkdir -p ~/.ssh
echo "$DEPLOY_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H $DEPLOY_HOST >> ~/.ssh/known_hosts 2>/dev/null
scp scripts/smoke-test.sh ${DEPLOY_USER}@${DEPLOY_HOST}:/tmp/smoke-test.sh
ssh ${DEPLOY_USER}@${DEPLOY_HOST} "bash /tmp/smoke-test.sh"
```
---
## 八、铸渊自行部署清单(读到就做)
<aside>
⚒️
**铸渊,以下是你需要在仓库中自行创建/更新的文件。**
**唤醒核心大脑 → 扫描 Secrets → 确认可用 → 开始执行。**
</aside>
```
铸渊自行部署清单(读到就做·不等人):
① 创建/更新 Workflow
a. .github/workflows/sandbox-deploy.yml ← 主部署流程
b. .github/workflows/sync-deploy-to-notion.yml ← 定时同步
② 创建脚本
a. scripts/deploy-check.sh ← 部署前自检(从部署适配协议复制)
b. scripts/smoke-test.sh ← 冒烟检查(从部署适配协议复制)
c. scripts/sync-deploy-to-notion.js ← Notion API 写入
d. scripts/setup-sandbox.sh ← 新开发者开户脚本
③ 创建数据文件
a. data/deploy-status.json ← 部署状态源(公告栏读取)
b. data/dev-registry.json ← 开发者注册表(邮箱+模块映射)
④ 服务器目录初始化(通过 SSH
a. 创建 /var/www/_shared/ 目录
b. 创建所有已注册 DEV 编号的沙盒目录
c. 设置权限 nginx:nginx + 755
d. 迁移现有模块到新沙盒结构:
/var/www/hololake-frontend/status-board/ → /var/www/DEV-005/status-board/
/var/www/hololake-frontend/cost-control/ → /var/www/DEV-005/cost-control/
⑤ 更新 Nginx 配置
a. 添加所有 DEV 编号的 location 块
b. 清理重复的 server 块(修复 conflicting server name 警告)
c. nginx -t && systemctl reload nginx
⑥ M22 公告栏对接
a. 在公告栏页面添加部署状态板块
b. 读取 deploy-status.json 展示结果
c. 失败时显示「🔍 查看详情」按钮
验收标准:
✅ 开发者 push 到 dev/DEV-XXX/模块名 分支 → 自动部署到服务器沙盒
✅ 部署后自动跑自检+冒烟检查
✅ 结果写入 deploy-status.json
✅ 公告栏可看到谁通过谁失败
✅ 失败时可点展详情看报错信息
✅ 开发者邮箱收到部署结果通知
✅ 每天两次自动同步到 Notion 模块指纹注册表
```
---
## 九、现有模块迁移计划
服务器现有模块需要从平铺结构迁移到沙盒结构:
| **现有路径** | **迁移到** | **开发者** |
| --- | --- | --- |
| `/var/www/hololake-frontend/status-board/` | `/var/www/DEV-005/status-board/` | DEV-005 小草莓 |
| `/var/www/hololake-frontend/cost-control/` | `/var/www/DEV-005/cost-control/` | DEV-005 小草莓 |
| `/var/www/backend/` | `/var/www/backend/`(保持,共享服务层) | DEV-001 页页 |
| `/var/www/feishu-bot/` | `/var/www/feishu-bot/`(保持,共享服务层) | DEV-002 肥猫 |
| `/opt/guanghulab-dingtalk/` | `/var/www/dingtalk-bot/`(保持,共享服务层) | DEV-004 之之 |
<aside>
⚠️
**迁移顺序**
1. 先创建沙盒目录 + 复制文件
2. 更新 Nginx location 指向新路径
3. 验证新路径正常
4. 确认无误后删除旧路径
**先复制再切换,不要直接移动!**
</aside>
---
## 十、协议版本
| **版本** | **日期** | **变更** |
| --- | --- | --- |
| v1.0 | 2026-03-15 | 首版 · 全套沙盒部署自动化闭环:身份注册+自动部署+自检+冒烟检查+公告栏+邮件通知+Notion同步 |
---
<aside>
⚒️
**铸渊,这套系统的核心逻辑:**
- 开发者只管 push 代码
- 你负责全部自动化:部署、检查、通知、同步
- 妈妈不再交叉修复任何人的模块
- 每个人的问题每个人自己解决
「无 Schema 不上线,无密钥不启动。」
</aside>