chore: init company-deploy-skills with dokploy-gitea-deploy

This commit is contained in:
deploy-bot
2026-07-31 09:47:16 +08:00
commit 7b56a16fbc
7 changed files with 1125 additions and 0 deletions

41
README.md Normal file
View File

@@ -0,0 +1,41 @@
# company-deploy-skills
企业部署相关 **Agent Skills**(与 [company-deploy-mcp](https://company-deploy-mcp.loncode.site/) 配合使用)。
## 一键安装
```bash
# 推荐skills CLI支持多 Agent
npx skills add http://git.loncode.site/Buxi/company-deploy-skills --skill dokploy-gitea-deploy -g -y
# 内网兜底git clone 到常见技能目录)
curl -fsSL https://company-deploy-mcp.loncode.site/install-skill.sh | bash
```
安装后仍需在连接中心登录飞书,配置 MCP`buxi_` Key
## 包含的 Skills
| Skill | 说明 |
|-------|------|
| `dokploy-gitea-deploy` | 企业部署MCP 优先Gitea + Dokploy交付 HTTPS |
## 目录约定
```text
company-deploy-skills/
README.md
dokploy-gitea-deploy/
SKILL.md
references/
# 后续新 skill 平铺同级目录即可
```
## 与 MCP 的关系
| 组件 | 职责 |
|------|------|
| **本仓库 Skill** | 教 Agent 流程与话术 |
| **company-deploy-mcp** | 飞书身份、配额、域名、真正调 Dokploy |
连接中心https://company-deploy-mcp.loncode.site/

View File

@@ -0,0 +1,277 @@
---
name: dokploy-gitea-deploy
description: >
企业项目部署:默认走 company-deploy-mcp飞书身份 + buxi_ Key → 推 Gitea → MCP 建库/多卷/PG·MySQL/域名/HTTPS → 轮询)。
旧路径为直连 Dokploy API.env.deploy仅运维/无 MCP 时使用。触发词部署、上线、Dokploy、Gitea、
redeploy、MCP 部署、buxi_、company-deploy-mcp。Use when /dokploy-gitea-deploy。
metadata:
short-description: "企业部署:优先 MCP兼容 Dokploy 直连"
---
# 企业部署编排Gitea + Dokploy + company-deploy-mcp
业务同学不碰平台细节。Agent 负责:可构建工程 → 推代码 → 调控制面 → 交付 **HTTPS 链接**
**默认路径company-deploy-mcp必须优先。**
直连 Dokploy API 为 **legacy / 运维例外**
参考:
- `references/mcp-deploy.md`**MCP 默认状态机**(工具参数、域名/卷/库)
- `references/domain.md` — 域名与 HTTPSLets Encrypt无需通配符证书
- `references/sequence.md` — 时序
- `references/env-deploy.example` — 仅 legacy 直连用
- `references/stack-profiles.md` — Dockerfile 约定
线上连接中心:`https://company-deploy-mcp.loncode.site/`
MCP endpoint`https://company-deploy-mcp.loncode.site/mcp`
---
## 路径选择
| 条件 | 路径 |
|------|------|
| Agent 已配置 MCP `company-deploy``buxi_` Key | **MCP 默认** |
| 用户已飞书登录拿过 Key | **MCP 默认** |
| 用户明确「不要 MCP / 运维直连 / 改 Dokploy 底层」 | legacy |
| 无 MCP 且无 `.env.deploy` | **先引导连 MCP**,不要伪造部署 |
**禁止**在可用 MCP 时仍让业务填写 `DOKPLOY_API_KEY` / Gitea Token。
---
## 架构(默认)
```text
用户:「部署 / 上线」
→ AgentDockerfile + 本地验证
→ Agentensure_repositoryMCP
→ Agentgit push企业凭据用户无感
→ Agentcreate_deployment_plan + apply_deployment_plan
MCP 内部:挂卷 → PG/MySQL可选→ domainbuxi+5位.根域 + LE HTTPS→ deploy
→ Agentget_deployment_status / list_projects 轮询
→ 交付https://buxi*****.loncode.site + 脱敏说明
```
- **飞书**:身份;**buxi_ Key**:调用 MCP
- **Gitea**:源码;**Dokploy**:构建运行(由 MCP 调用,不直暴露给业务)
- **归属 / 配额 / 审计**:控制面 SQLite`owner_open_id`、运行中数量)
---
## 前置条件
### MCP 路径(默认)
1. 用户已在连接中心飞书登录Agent 已配置:
```json
{
"mcpServers": {
"company-deploy": {
"url": "https://company-deploy-mcp.loncode.site/mcp",
"headers": {
"Authorization": "Bearer buxi_..."
}
}
}
}
```
2. 项目有可构建 **Dockerfile**(进程监听 `spec.port`,状态写 `/data` 等挂载点)
3. Agent 本机可 `git push`(企业 Git 凭据,**不**向用户索要)
4. 企业侧已配:`*.DOMAIN_ROOT` DNS → Dokploy80/443 可达Lets Encrypt
无 Key引导打开连接中心登录**不要**继续直连 Dokploy。
### Legacy 路径(运维)
见文末;需 `.env.deploy` + `DEPLOY_AUTHORIZED=true`
---
## MCP 标准状态机(必须按序)
细节与 JSON 示例见 `references/mcp-deploy.md`
### 0. 身份
- 调用 `whoami`(可选):确认 `role` / `openId`
- 调用 `get_my_quota`:看运行中数量是否达上限
### 1. 工程
- 识别栈;保证 Dockerfile`.gitignore` 排除密钥
- 有状态:默认 `/data`;多目录用 `persistence[]`
- 需要库:`databases: [{ engine: "postgres"|"mysql", ... }]`
### 2. 仓库
```text
ensure_repository({ repo: "owner/name" 或 "name" })
→ git remote / commit / push
→ 记录 commitSha
```
### 3. 计划与发布
```text
create_deployment_plan({
repo, commitSha, branch,
# environment = 控制面「部署标签」,默认 default。禁止擅自 invent production/staging
# 除非用户明确说「再部署一套并行环境」。与 status/redeploy 必须同一标签;不确定 list_projects
environment: "default",
spec: {
buildType: "dockerfile",
dockerfilePath: "Dockerfile",
buildPath: "/",
port: <容器端口>,
healthcheckPath: "/",
persistence: [ /* 可选多卷;缺省自动加 /data */ ],
databases: [ /* 可选 postgres|mysql */ ],
exposeWeb: true
}
})
→ apply_deployment_plan({ planId })
→ 使用返回的 url / domain / databases密码已脱敏
```
**环境概念(易混):**
| 名称 | 是什么 | 谁决定 |
|------|--------|--------|
| Dokploy Environment | 应用建在平台哪个分组(如 preview | 控制面 `DOKPLOY_ENVIRONMENT_ID`(全站统一) |
| MCP `environment` | 部署标签,`repo+标签` 对应一套应用/域名 | Agent 参数,默认 `default`,全公司应统一 |
已有项目若当初用了非 default 标签,重部署/查状态必须继续传该标签,不要擅自改(否则会当成新项目)。
### 部署标签硬规则Agent
1. **默认且优先**:省略 `environment` 或显式 `"default"`
2. **禁止**仅因用户说「上线 / 生产 / 正式」就改成 `production`——那只是业务话术,不是部署标签。
3. **仅当**用户明确要求「第二套环境 / staging / 并行预发」时,才用非 default 标签。
4. 重部署前 `list_projects`,沿用已有 `environment` 字段。
### 4. 轮询与交付
```text
get_deployment_status / list_projects
Webcurl -skI "$url" 或健康路径(证书可能短暂签发中)
```
对用户:
-**HTTPS 链接**`apply``url`
- 不提 Gitea/Dokploy/Token
- 配额满、无权:原文转述 MCP 错误
### 5. 域名与 HTTPS控制面完成Agent 勿重复 domain.create
- 默认 host`buxi` + 5 位随机 `[a-z0-9]` + `.` + `DOMAIN_ROOT`
例:`buxi3k9xa.loncode.site`
- 首次分配后 **固定**(存在控制面 mapping
- HTTPSDokploy Traefik + **Lets Encrypt 按子域签证书****不需要**通配符证书)
- DNS建议 `*.loncode.site` → 服务器(通配 **解析**,不是通配证书)
- 证书失败:查 80/443、DNS可暂 HTTP 仅当控制面 `DOMAIN_HTTPS=false`
Agent **不要**在 MCP 路径下再调 Dokploy `domain.create`(避免双绑/冲突)。
### 6. 卷与数据库
| 能力 | 行为 |
|------|------|
| 默认卷 | Docker named volume → `/data`(避免 bind 目录不存在导致 Swarm 0/1 |
| bind 模式 | 可选;控制面 mkdir 宿主机路径,失败回退 volume |
| 多卷 | `spec.persistence[]`;缺 `/data` 仍自动补 |
| Postgres / MySQL | `spec.databases[]` → Dokploy 建库 + 注入 `DATABASE_URL` 等 |
| 重部署 | 同 repo+env 不占新配额名额;域名与库记录复用 |
应用必须把状态写在挂载路径(如 SQLite → `/data/app.db`)。
---
## 意图路由
| 用户说法 | 动作 |
|----------|------|
| 部署 / 上线 / 第一次发布 | MCP 全链路;交付 `url` |
| 重试 / 再构建 | 新 SHA → 新 plan → apply已有 mapping |
| 查状态 / 我的项目 | `list_projects` / `get_deployment_status` |
| 配额 | `get_my_quota` |
| 只要链接 | `list_projects``url`;无则查 status |
| 运维直连 Dokploy | 仅明确要求时走 legacy |
---
## 对用户话术
**成功:**
- 已发布当前版本
- 访问:`https://buxi….loncode.site/`(以 MCP 返回为准)
- 需要库时:说明已注入数据库连接(**不打印密码**
**失败:**
- 配额满 / 未登录 Key / 构建失败 / 证书签发中
- 给可执行下一步,不暴露平台密钥
---
## 安全红线
1. 永不 commit / 回显:`buxi_` Key、`MCP_AUTH_TOKEN`、Dokploy/Gitea Token、数据库密码全文
2. `apply` 返回的 `connectionUrl` 已脱敏则保持;未脱敏则遮罩
3. 普通用户不可查他人项目(控制面会 403
4. 生产破坏性操作仍受控制面策略约束
---
## Agent 检查清单MCP
- [ ] MCP 可用;`whoami` 正常
- [ ] Dockerfile + 数据写挂载点
- [ ] `ensure_repository` + push + `commitSha`
- [ ] plan 含正确 `port`;需要时 `persistence` / `databases`
- [ ] `apply` 拿到 `url`
- [ ] 轮询至终态;探活
- [ ] 未向用户索要 Dokploy/Gitea 地址或 Token
---
## Legacy直连 Dokploy运维例外
**仅当**用户明确要求或 MCP 不可用且有 `.env.deploy`
1. `set -a && source .env.deploy && set +a``DEPLOY_AUTHORIZED=true`
2. 按旧流程Dockerfile → push → `application.*` / `mounts` / `domain.create` / deploy
3. 域名规则见 `references/domain.md` **Legacy** 段(与 MCP 的 `buxi+5` 规则不同,勿混用)
4. 模板:`references/env-deploy.example`
5. 仍禁止把密钥贴进聊天
**默认对话不要走这条。** 有 MCP 时禁止向业务索要 `DOKPLOY_API_KEY`
---
## 与其它 skill 边界
| 场景 | 用 |
|------|-----|
| 企业 Dockerfile 部署(默认) | **本 skill → MCP** |
| 妙搭云端发布 | `lark-apps` |
| 无 MCP 的运维救火 | 本 skill → legacy |
---
## 故障速查MCP
| 现象 | 处理 |
|------|------|
| 401 / 要 Feishu Key | 引导连接中心登录,配置 `buxi_` |
| 运行中项目达上限 | `get_my_quota`;停/删旧应用后再部署 |
| Forbidden 看他人项目 | 非管理员;加 `ADMIN_OPEN_IDS` 或只查自己的 |
| 有部署无 HTTPS | 等 LE查 DNS/80控制面证书配置 |
| 重部署丢数据 | 确认写 `/data`;控制面默认挂载是否开启 |
| Swarm 0/1 + bind path does not exist | 控制面已默认 volume + mkdir旧应用可 `mkdir -p` 宿主机路径或删 bind 改 volume 后 redeploy |
| 要 PG/MySQL | plan 里带 `databases`,勿手建后不注入 env |

View File

@@ -0,0 +1,142 @@
# 域名与 HTTPS
## 默认路径company-deploy-mcp优先
业务部署 **不要** 手写 Dokploy `domain.create`
控制面在 `apply_deployment_plan` 内自动绑定域名并启用 HTTPS。
### 主机名规则
| 项 | 值 |
|----|-----|
| 格式 | `{prefix}{random}.{DOMAIN_ROOT}` |
| 默认 prefix | `buxi` |
| 默认 random | 5 位 `[a-z0-9]` |
| 默认根域 | `loncode.site`(以控制面 `DOMAIN_ROOT` 为准) |
| 示例 | `buxi3k9xa.loncode.site` |
- **首次** `apply``exposeWeb !== false` 时分配
- 分配后写入项目 mapping**同 repo+environment 永久复用**
- 可用 `spec.domainHost` 指定固定 host需 DNS 已解析到 Dokploy一般业务勿用
- `exposeWeb: false`不绑公网域Worker / 长连接机器人)
### HTTPS / 证书
| 项 | 说明 |
|----|------|
| 默认 | `DOMAIN_HTTPS=true``certificateType=letsencrypt` |
| 实现 | Dokploy Traefik 按**具体子域**申请 Lets Encrypt |
| **不需要** | 通配符证书(`*.loncode.site` 的 cert |
| **需要** | DNS 把子域指到 Dokploy**80/443** 公网可达HTTP-01 |
推荐 DNS一次配好所有项目共用
```text
*.loncode.site → A/AAAA → Dokploy 服务器 IP
```
这是通配 **解析**,不是通配证书。每个 `buxi*****.loncode.site` 各自签 LE。
### 交付链接
| 来源 | 字段 |
|------|------|
| `apply_deployment_plan` | `url``domain.host``domain.url` |
| `list_projects` | 每项 `url` / `domainHost` |
| `get_deployment_status` | 结合应用状态与 mapping |
格式:`https://<host>/`(控制面 `DOMAIN_HTTPS=false` 时才是 `http://`)。
Agent 探活:
```bash
curl -skI "https://buxiXXXXX.loncode.site/"
# 或健康路径
curl -skI "https://buxiXXXXX.loncode.site/healthz"
```
首次可能短暂 404 / TLS 握手失败:等 13 分钟 LE仍失败查 DNS 与 80/443。
### Agent 红线MCP 路径)
1. **不要**再调 Dokploy `domain.create`(双绑/冲突)
2. **不要**要求业务用户填 `DOKPLOY_DOMAIN`
3. **不要**把错误的宿主机端口(如别人的 `:8080`)当成产品链接
4. 证书失败:查基础设施,不要改业务代码「硬编码域名」进 Git
细节与 plan 参数见 `mcp-deploy.md`
---
## Legacy 路径:直连 Dokploy运维例外
仅当用户明确要求不走 MCP且存在项目 `.env.deploy` 时使用。
### 配置写在哪?
| 位置 | 用途 |
|------|------|
| **项目根 `.env.deploy`** | Agent 读取;必须 gitignore |
| `env-deploy.example` | 模板 |
| Dokploy 面板 Domains | 人工补绑 |
| 域名注册商 DNS | 用户/运维配置 |
### 方式 A写死完整域名
```bash
DOKPLOY_EXPOSE_WEB=true
DOKPLOY_DOMAIN=crm.loncode.site
DOKPLOY_DOMAIN_HTTPS=true
DOKPLOY_DNS_READY=true
DOKPLOY_PORT=3000
```
### 方式 B根域 + slug
```bash
DOKPLOY_EXPOSE_WEB=true
DOKPLOY_DOMAIN_ROOT=loncode.site
DOKPLOY_DOMAIN_PREFIX=
# DOKPLOY_DOMAIN 留空 → {PREFIX}{slug}.{ROOT}
```
与控制面 `buxi+5` 规则**不同**legacy 多为 app 名 slug
企业统一对外仍推荐 **MCP 的 buxi+5**,避免与连接中心体验分裂。
### 方式 C非 Web
```bash
DOKPLOY_EXPOSE_WEB=false
```
### Legacy API 示例
```bash
curl -sS -X POST \
-H "x-api-key: $DOKPLOY_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"host\": \"${DOKPLOY_DOMAIN}\",
\"applicationId\": \"${DOKPLOY_APPLICATION_ID}\",
\"https\": true,
\"certificateType\": \"letsencrypt\",
\"port\": ${DOKPLOY_PORT},
\"path\": \"/\",
\"domainType\": \"application\"
}" \
"${DOKPLOY_URL}/api/domain.create"
```
`host` **不要**带协议。证书同样依赖 DNS + 80/443。
---
## 故障速查
| 现象 | 处理 |
|------|------|
| 有 host 无 HTTPS | 等 LE查 80 是否被占用/防火墙 |
| DNS NXDOMAIN | 配 `*.DOMAIN_ROOT` 或单条 A 记录 |
| 证书反复失败 | 确认公网能访问该 host 的 80 |
| 打开了错误站点 | 是否绑到了别的 applicationId |
| MCP 与 legacy 双绑 | 停掉一侧;优先只走 MCP |

View File

@@ -0,0 +1,77 @@
# ═══ LEGACY ONLY ═══
# 默认部署请走 company-deploy-mcp飞书 + buxi_ Key不要业务项目填本文件。
# 仅运维 / 明确直连 Dokploy 时使用。
#
# 复制到目标项目根目录:
# cp ~/.grok/skills/dokploy-gitea-deploy/references/env-deploy.example .env.deploy
# 填好后set -a && source .env.deploy && set +a
# 必须 gitignore.env.deploy
# ── 授权 ──
DEPLOY_AUTHORIZED=false
ALLOW_SYNC_APP_ENV_TO_DOKPLOY=true
DO_GIT_PUSH=true
DO_DOKPLOY_DEPLOY=true
DO_HEALTHCHECK=true
FIX_DOCKERFILE=true
PROJECT_DIR=.
APP_ENV_FILE=.env
# ── Gitea ──
GITEA_URL=https://git.example.com
GITEA_USER=
GITEA_ORG=
GITEA_REPO=
GITEA_REPO_VISIBILITY=private
GITEA_REPO_EXISTS=false
GITEA_TOKEN=
GIT_PUSH_METHOD=https
GIT_BRANCH=main
GITEA_CLONE_URL=
# ── Dokploy ──
DOKPLOY_URL=https://dokploy.example.com
DOKPLOY_API_KEY=
DOKPLOY_PROJECT_NAME=
DOKPLOY_APP_NAME=
DOKPLOY_APPLICATION_ID=
DOKPLOY_BUILD_TYPE=dockerfile
DOKPLOY_DOCKERFILE_PATH=Dockerfile
DOKPLOY_PORT=8080
DOKPLOY_REPLICAS=1
DOKPLOY_VOLUME_MOUNT=
DOKPLOY_HEALTHCHECK_PATH=/healthz
DOKPLOY_GIT_AUTH_METHOD=gitea_provider
DOKPLOY_GITEA_LINKED=false
# 首次部署后勿默认 true除非依赖变了或缓存损坏
DOKPLOY_CLEAN_CACHE=false
# ── 域名 / 可访问链接Web 页面必看)──
# 是否对外提供网页链接true=部署成功后必须绑 Domain 并交付 https URL
# false=Worker/飞书长连接等,域名可选
DOKPLOY_EXPOSE_WEB=true
# 方式 A完整主机名优先。不要写 https://
# DOKPLOY_DOMAIN=crm.loncode.site
# 方式 B根域自动生成子域DOKPLOY_DOMAIN 留空时生效)
# 最终 host = {DOKPLOY_DOMAIN_PREFIX}{slug}.{DOKPLOY_DOMAIN_ROOT}
# slug 默认取 DOKPLOY_APP_NAME 或 GITEA_REPO小写非法字符变 -
# 建议 DNS 配:*.loncode.site → Dokploy 服务器 IP
DOKPLOY_DOMAIN=
DOKPLOY_DOMAIN_ROOT=
DOKPLOY_DOMAIN_PREFIX=
# HTTPS / 证书(公网建议 true + letsencrypt
DOKPLOY_DOMAIN_HTTPS=true
DOKPLOY_CERTIFICATE_TYPE=letsencrypt
# DNS 是否已指向 Dokploytrue 时 Agent 会强调证书应能签发并做探活)
DOKPLOY_DNS_READY=false
# ── 包源(构建)──
# Python / uv
PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/
# Node可选写入构建环境或 .npmrc
# NPM_CONFIG_REGISTRY=https://registry.npmmirror.com

View File

@@ -0,0 +1,301 @@
# company-deploy-mcp 默认部署路径
**连接中心(飞书登录 + 拿 Key**
`https://company-deploy-mcp.loncode.site/`
**MCP endpoint**
`https://company-deploy-mcp.loncode.site/mcp`
Agent 配置示例(用户从连接中心复制,**不要**写进业务仓库):
```json
{
"mcpServers": {
"company-deploy": {
"url": "https://company-deploy-mcp.loncode.site/mcp",
"headers": {
"Authorization": "Bearer buxi_..."
}
}
}
}
```
- Key 前缀:`buxi_`(旧 `cdp_` 若仍存在可兼容,新发一律 `buxi_`
- 身份:飞书 `open_id` 绑定到 Key管理员另见 `ADMIN_OPEN_IDS` / 平台 `MCP_AUTH_TOKEN`
- **禁止**在 MCP 可用时向业务用户索要 Dokploy / Gitea Token
---
## 工具一览
| 工具 | 读写 | 作用 |
|------|------|------|
| `whoami` | 读 | 当前身份、`role`user/admin`openId` |
| `get_my_quota` | 读 | 运行中项目数 / 上限 / 剩余 |
| `list_projects` | 读 | 用户仅自己的admin 全部 + Dokploy 运行态 |
| `inspect_project` | 读 | 某 repo+env 映射与策略(含存储策略说明) |
| `ensure_repository` | 写 | Gitea 建库(缺省组织私有库) |
| `create_deployment_plan` | 写 | 针对**已 push** 的 commit SHA 建计划 |
| `apply_deployment_plan` | 写 | 挂卷 → PG/MySQL → 域名/HTTPS → deploy |
| `get_deployment_status` | 读 | 应用与部署摘要(脱敏) |
| `get_sanitized_logs` | 读 | 脱敏诊断摘要 |
`repo` 格式:
- `Owner/name` 完整路径
- 或仅 `name` → 控制面补默认 `GITEA_ORG`
---
## 标准调用顺序(必须)
```text
0. whoami / get_my_quota # 可选但推荐;配额满先处理
1. 本地Dockerfile + 数据写 /data + .gitignore
2. ensure_repository({ repo })
3. git remote add/set-url + commit + push # Agent 本机企业凭据
4. create_deployment_plan({ repo, commitSha, branch, environment, spec })
5. apply_deployment_plan({ planId })
6. get_deployment_status / list_projects 轮询
7. curl 探活 apply 返回的 url证书可能短暂签发中
```
**Push 必须在 Agent 侧做**MCP 在服务器上读不到用户工作区未提交文件。
---
## create_deployment_plan 参数
| 字段 | 类型 | 默认 | 说明 |
|------|------|------|------|
| `repo` | string | 必填 | 见上 |
| `commitSha` | string | 必填 | 764 位 hex**已在 Gitea 上** |
| `branch` | string | `main` | 分支名 |
| `environment` | string | 控制面 `DEFAULT_DEPLOY_ENVIRONMENT`(常为 `default` | **部署标签**(非 Dokploy preview/production与 repo 组成唯一映射。查状态/重部署必须与首次 apply 相同 |
| `spec` | object | 必填 | 见下 |
### `spec` 字段
| 字段 | 类型 | 默认 | 说明 |
|------|------|------|------|
| `buildType` | `"dockerfile"` | 必填 | MVP 仅 Dockerfile |
| `dockerfilePath` | string | `Dockerfile` | 路径须以 `Dockerfile` 结尾 |
| `buildPath` | string | `/` | 构建上下文 |
| `port` | number | 必填 | **容器内**监听端口Traefik 转到这里) |
| `healthcheckPath` | string | `/` | 以 `/` 开头 |
| `persistence` | array | `[]` | 多卷;**缺 `/data` 时控制面自动补** |
| `databases` | array | `[]` | 托管 PG/MySQL可选 |
| `exposeWeb` | boolean | `true` | `false` 则不绑公网域名Worker 等) |
| `domainHost` | string | 省略 | 可选固定 host省略则 `buxi`+5 随机 |
### `persistence[]` 项
```json
{
"name": "data",
"mountPath": "/data",
"hostPath": "/optional/host/path"
}
```
- `name`:逻辑名(命名 volume / 主机子目录用)
- `mountPath`:容器内绝对路径
- `hostPath`可选bind 模式下省略则控制面生成
`{HOST_DATA_ROOT}/{appSlug}/{name}`
**应用约定:** 有状态数据必须写在挂载路径(如 SQLite → `/data/app.db`)。
重部署同 `repo`+`environment` **不重新占配额**,卷与域名复用。
### `databases[]` 项
```json
{
"engine": "postgres",
"name": "main",
"databaseName": "app",
"databaseUser": "app",
"envVar": "DATABASE_URL"
}
```
| 字段 | 说明 |
|------|------|
| `engine` | `postgres``mysql` |
| `name` | 逻辑名(多库区分);默认 `main` |
| `databaseName` / `databaseUser` | 可选覆盖 |
| `envVar` | 注入应用的环境变量名,默认 `DATABASE_URL` |
`apply`Dokploy 建库服务 → deploy 库 → 把连接串写入应用 env → 再构建应用。
**勿**在聊天中打印完整 `connectionUrl`(返回侧会尽量脱敏)。
---
## 最小示例:纯 Web自动域名 + 默认 /data
```json
{
"repo": "my-web-app",
"commitSha": "a1b2c3d4e5f6...",
"branch": "main",
"environment": "default",
"spec": {
"buildType": "dockerfile",
"dockerfilePath": "Dockerfile",
"buildPath": "/",
"port": 3000,
"healthcheckPath": "/",
"exposeWeb": true
}
}
```
`apply` 成功后典型字段:
```json
{
"planId": "...",
"applicationId": "...",
"isNewProject": true,
"url": "https://buxi3k9xa.loncode.site",
"domain": {
"host": "buxi3k9xa.loncode.site",
"url": "https://buxi3k9xa.loncode.site",
"https": true
},
"mounts": [{ "name": "data", "mountPath": "/data" }],
"databases": [],
"dataPathHint": {
"container": "/data",
"note": "Write application state under mounted paths..."
}
}
```
对用户只说:**已发布,访问 `https://buxi….loncode.site/`**(以实际返回为准)。
---
## 示例:多卷 + Postgres
**部署标签必须用默认 `default`(或省略),除非用户明确要求并行第二套环境。**
禁止因「上线/生产」等话术擅自改成 `production`(与 Dokploy 的 production 环境无关,且会导致查不到项目)。
```json
{
"repo": "Buxi/order-api",
"commitSha": "deadbeefcafebabe...",
"branch": "main",
"environment": "default",
"spec": {
"buildType": "dockerfile",
"dockerfilePath": "Dockerfile",
"buildPath": "/",
"port": 8080,
"healthcheckPath": "/healthz",
"exposeWeb": true,
"persistence": [
{ "name": "data", "mountPath": "/data" },
{ "name": "uploads", "mountPath": "/var/uploads" }
],
"databases": [
{
"engine": "postgres",
"name": "main",
"envVar": "DATABASE_URL"
}
]
}
}
```
应用启动时读 `process.env.DATABASE_URL`(或所选 `envVar`)。
若还要 MySQL 第二实例,再 push 一条 `{ "engine": "mysql", "name": "legacy", "envVar": "MYSQL_URL" }`
---
## 示例Worker不暴露 Web
```json
{
"repo": "job-worker",
"commitSha": "...",
"branch": "main",
"environment": "default",
"spec": {
"buildType": "dockerfile",
"dockerfilePath": "Dockerfile",
"buildPath": "/",
"port": 8080,
"healthcheckPath": "/healthz",
"exposeWeb": false
}
}
```
`url` / `domain` 可能为 null`get_deployment_status` 看 Dokploy 运行态即可。
---
## apply 内部顺序Agent 勿重复)
控制面在 `apply_deployment_plan` 内按序完成:
1. **配额**:仅**新建** mapping 时检查运行中数量
2. **ensure Application**(已有则复用)
3. **ensureMounts**:默认 `/data`Docker volume无需预建宿主机目录+ `persistence[]`
4. **ensureDatabases**postgres/mysql + 注入 env
5. **ensureDomain**`buxi`+5 随机 + Lets Encrypt`domain.md`
6. **deploy** 应用镜像
Agent **不要**再直连 Dokploy 做 `domain.create` / `mounts.create` / 手建 DB会双绑冲突
---
## 配额与归属
| 概念 | 行为 |
|------|------|
| 归属 | 首次成功 `apply``owner_open_id` |
| 配额 | 该用户 **Dokploy 运行中** 应用数 ≤ `MAX_RUNNING_PROJECTS_PER_USER`(常见 5 |
| 重部署 | 同 repo+env **不占新名额** |
| 可见性 | 普通用户只能 list/status 自己的admin 看全部 |
配额满错误:引导用户停掉旧应用或找管理员,**不要**绕过 MCP 硬推。
---
## 轮询建议
```text
apply 返回后:
每 1530sget_deployment_status(repo, environment)
或 list_projects 看 applicationStatus / running / url
终态:构建成功且容器 running/done
Webcurl -skI "$url" 或健康路径
证书:首次 LE 可能需 13 分钟DNS/80 未通会失败
```
`create` 的 plan **只能 apply 一次**;失败或新版本 → 新 SHA 再 `create_deployment_plan`
---
## 对用户话术(摘要)
| 场景 | 说法 |
|------|------|
| 成功 | 已发布当前版本;访问:`https://…` |
| 有数据库 | 已配置托管数据库连接(不打印密码) |
| 配额满 | 运行中项目已达上限,请先停用不用的服务 |
| 未登录 | 打开连接中心飞书登录,把配置贴到 Agent |
| 构建中 | 正在构建,稍后自动检查 |
| 证书中 | 链接已分配HTTPS 证书签发中,稍后再开 |
---
## 安全
1. 永不 commit / 回显:`buxi_`、平台 Token、DB 密码全文
2. 日志只用 `get_sanitized_logs`
3. `.env` / 密钥进 `.gitignore`
4. 生产破坏操作受控制面策略约束;不要教用户绕过

View File

@@ -0,0 +1,104 @@
# 时序
## 默认MCP 全链路(业务部署)
```text
用户 Agent company-deploy-mcp Gitea Dokploy
│ │ │ │ │
│ 部署/上线 │ │ │ │
│─────────────────►│ │ │ │
│ │ whoami / get_my_quota │ │ │
│ │────────────────────────►│ │ │
│ │ Dockerfile + 本地校验 │ │ │
│ │ ensure_repository │ │ │
│ │────────────────────────►│──建库(可选)─────►│ │
│ │◄────────────────────────│◄─────────────────│ │
│ │ git push企业凭据 │ │ │
│ │───────────────────────────────────────────►│ │
│ │ create_deployment_plan │ │ │
│ │────────────────────────►│ │ │
│ │ apply_deployment_plan │ │ │
│ │────────────────────────►│ │ │
│ │ │ ensure app │ │
│ │ │ mounts (/data+) │ │
│ │ │ postgres/mysql? │ │
│ │ │ domain buxi+5+LE │ │
│ │ │ deploy ──────────┼──────────────►│
│ │ │ │ clone/build │
│ │ get_deployment_status │ │ run │
│ │────────────────────────►│──status──────────┼──────────────►│
│ │ 探活 https://buxi…. │ │ │
│ 交付 HTTPS 链接 │ │ │ │
│◄─────────────────│ │ │ │
```
要点:
- **建库 / 挂卷 / PG·MySQL / 域名 / deploy** 全在 MCP `apply`
- **push** 只在 Agent 本机
- 业务用户不接触 Gitea / Dokploy / Token
参数与示例:`mcp-deploy.md`。域名与证书:`domain.md`
---
## 日常二次发布MCP
```text
用户 → Agent → git push → create_deployment_plan(新 SHA)
→ apply_deployment_plan
→ 复用 mapping域名、卷、库、配额名额
→ 轮询 + 探活
```
- 同一 `repo` + `environment`**不新建** Dokploy 应用名额
- 域名 host **不变**
- 数据卷 **不变**(应用须写在挂载路径)
- plan 一次性;每次发布新建 plan
---
## Legacy直连 Dokploy运维例外
```text
用户 Agent Gitea Dokploy
│ │ │ │
│ 明确要求直连 │ │ │
│───────────────────►│ source .env.deploy │ │
│ │ Dockerfile │ │
│ │ 建仓+git push │ │
│ │────────────────────►│ │
│ │ application.* │ │
│ │ mounts / domain │ │
│ │ application.deploy │ │
│ │──────────────────────────────────────────►│
│ │ 轮询 + 探活 │ │
│◄───────────────────│ │ │
```
仅当 MCP 不可用且有 `.env.deploy` + `DEPLOY_AUTHORIZED=true`
默认对话 **不要** 走这条。
---
## 责任边界
| 角色 | MCP 路径 | Legacy 路径 |
|------|----------|-------------|
| 用户 | 飞书登录拿 `buxi_`;说「部署」 | 提供/保管 `.env.deploy`(运维) |
| Agent | 工程 + push + 调 MCP 工具 + 交付 URL | 工程 + push + 直调 Dokploy API |
| company-deploy-mcp | 身份/配额/审计/Gitea 建库/Dokploy 编排 | — |
| Gitea | 源码 | 源码 |
| Dokploy | 构建运行/卷/库/Traefik+LE | 同左Agent 直调) |
---
## 异步语义
| 动作 | 含义 |
|------|------|
| `apply_deployment_plan` 返回 200 | 已受理编排与 deploy 请求 |
| `deploymentRequested: true` | 不等于用户已可稳定访问 |
| 上线完成 | Dokploy 部署终态成功 +WebHTTPS 探活通过 |
构建失败:`get_deployment_status` / `get_sanitized_logs`,修代码或 Dockerfile 后新 SHA 再 plan+apply。

View File

@@ -0,0 +1,183 @@
# 技术栈构建约定Agent 改 Dockerfile 时遵循)
## 通用
1. 基础镜像Docker Hub`python:*` / `node:*` / `nginx:*`),避免默认 `ghcr.io`
2. 多阶段或「依赖层 → 代码层」拆分。
3. BuildKit`--mount=type=cache` 缓存包管理器目录。
4. 生产 `CMD`/`ENTRYPOINT` 明确;进程监听 **`spec.port`**(与 plan 一致)。
5. 健康检查:实现 `/healthz` 或约定路径,写入 `spec.healthcheckPath`
6. Dokploy **不要每次 cleanCache**
7. **有状态数据写挂载路径**(见下),不要只写容器可写层。
---
## 持久化与 `/data`MCP 默认)
控制面默认为每个应用挂载 **容器内 `/data`**(可配置,见 `inspect_project``policy.storage`)。
| 约定 | 说明 |
|------|------|
| SQLite / 本地文件 | 路径放在 `/data/...`,例如 `/data/app.db` |
| 上传目录 | 额外 `persistence``{ "name": "uploads", "mountPath": "/var/uploads" }` |
| 日志 | ephemeral 可写容器内;需保留则挂卷 |
| 多卷 | `spec.persistence[]`;若未包含 `/data`,控制面仍自动补默认卷 |
示例环境变量(应用代码侧):
```text
DATA_DIR=/data
DATABASE_PATH=/data/app.db
```
**禁止**假设宿主机路径;只认容器内 `mountPath`
---
## 托管数据库Postgres / MySQL
plan 中声明 `spec.databases[]` 后,控制面注入连接串环境变量(默认名 `DATABASE_URL`)。
应用应:
1. 启动时读取 `process.env.DATABASE_URL`(或自定义 `envVar`
2. **不要**在镜像里写死密码
3. 迁移在启动脚本或独立 job 中执行(注意并发与锁)
示例Node
```js
const url = process.env.DATABASE_URL;
if (!url) throw new Error("DATABASE_URL is required");
```
示例Python
```python
import os
url = os.environ.get("DATABASE_URL")
if not url:
raise RuntimeError("DATABASE_URL is required")
```
Docker 内网 host 由 Dokploy 管理;应用只消费完整 URL。
---
## Pythonuv 优先)
检测:`pyproject.toml` + `uv.lock`,或 `requirements.txt`
推荐结构:
```dockerfile
FROM python:3.12-slim-bookworm
WORKDIR /app
ENV UV_LINK_MODE=copy \
UV_CONCURRENT_DOWNLOADS=16 \
UV_HTTP_TIMEOUT=120 \
PYTHONUNBUFFERED=1
ARG PIP_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/
ENV UV_DEFAULT_INDEX=${PIP_INDEX_URL} \
UV_INDEX_URL=${PIP_INDEX_URL} \
PIP_INDEX_URL=${PIP_INDEX_URL}
RUN --mount=type=cache,target=/root/.cache/pip \
pip install --no-cache-dir "uv>=0.6.0"
COPY pyproject.toml uv.lock README.md ./
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-dev --no-install-project
COPY src ./src
# …其它源码…
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-dev
# 监听 0.0.0.0,端口与 plan.spec.port 一致
ENV DATA_DIR=/data
EXPOSE 8000
CMD ["uv", "run", "your-entrypoint"]
```
说明:
- 慢点通常是 **PyPI 下包**,不是 `pip install uv` 本身。
- 主机 `~/.pip/pip.conf` **不会**自动进容器;必须 Dockerfile/build-arg。
- 飞书长连接类:`replicas=1` + 状态进 `/data``exposeWeb: false` 若无需公网页。
---
## Nodepnpm / npm
检测:`package.json`,优先 `pnpm-lock.yaml``package-lock.json``yarn.lock`
推荐结构standalone / 需 `node` 运行):
```dockerfile
FROM node:22-bookworm-slim AS deps
WORKDIR /app
RUN corepack enable
COPY package.json pnpm-lock.yaml ./
# 可选COPY .npmrc ./
RUN --mount=type=cache,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile
FROM node:22-bookworm-slim AS build
WORKDIR /app
RUN corepack enable
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN pnpm run build
FROM node:22-bookworm-slim AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV DATA_DIR=/data
COPY --from=build /app/dist ./dist
COPY --from=build /app/package.json ./
COPY --from=deps /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/index.js"]
```
静态前端Vite 等)可用 `nginx:stable-alpine``dist``spec.port` 多为 `80`
Registry 加速示例 `.npmrc`(可提交或构建时注入):
```ini
registry=https://registry.npmmirror.com
```
---
## Docker Compose
- 当前 MCP MVP **仅** `buildType: dockerfile` 单应用。
- 多服务 Composelegacy / 运维在 Dokploy 选 Compose 类型,或拆成多个 MCP 应用 + 托管 DB。
- 生产注意DB 密码走 `databases[]` 注入;卷走 `persistence[]`
---
## 构建耗时预期(经验)
| 场景 | 预期 |
|------|------|
| 首次全量(弱网 + 下包) | 1040 分钟可能 |
| 依赖层已缓存,只改代码 | 数分钟内 |
| 仅拉预构建业务镜像 | 通常更短 |
若日志出现 `Prepared N packages in 30m`:换源 + 分层缓存 + 禁止 cleanCache长期用私有镜像仓库。
---
## 与 plan.spec 对齐检查
部署前 Agent 自检:
- [ ] 容器监听 `0.0.0.0:$PORT`,且 `spec.port` 一致
- [ ] 有状态路径落在 `/data` 或其它 `persistence.mountPath`
- [ ] 需要 PG/MySQL 时 plan 带 `databases`,代码读对应 env
- [ ] Web 服务 `exposeWeb: true`默认Worker 显式 `false`
- [ ] `.gitignore` 排除 `.env`、密钥、本地 db