# M7 / issue-30 开发日志：联调收束、统一端口与真实发布按钮

- Issue：#52
- 里程碑：M7 展示层与内容接入：从联调壳到真实页面
- 分支：`feat/m7-issue-30-port-and-publish`
- 日期：2026-03-25

## 背景

在 M6 完成后，为了验证三端是否真的能联调跑通，我们先做了一轮本地联调修正：统一三端端口，并把后台“发布简历”从演示接口切到真实发布接口。

这些改动已经帮助我们完成了阶段性验证，但如果不把它们正式收束成一个 Issue，就会留下两个问题：

- 关键联调改动缺少可追踪记录，后续教程很难解释“为什么突然就能跑了”。
- 代码、测试、文档、环境变量如果不一起落地，后面继续开发时会继续出现端口错位和真假接口混用。

所以本次任务的目标不是“新增大功能”，而是把已经验证过的联调结果，整理成一个正式、可复盘、可继续演进的基线。

## 本次目标

- 统一本地三端默认端口为 `web:5555 / admin:5566 / server:5577`
- 让 `admin` 的“发布简历”按钮接入真实 `/resume/publish` 链路
- 同步更新当前有效的测试、环境变量示例与部署文档

## 非目标

- 不迁移旧版 Vue 简历内容到新模型
- 不实现后台完整草稿编辑器
- 不进行 UI 重设计或主题升级
- 不在本任务里扩展更多展示层模块

## TDD / 测试设计

本次属于“联调收束型 Issue”，重点不是新增复杂业务逻辑，而是保证既有链路从演示态切到真实态后仍可验证。

先补和更新以下测试预期：

- `apps/admin/lib/auth-api.spec.ts`
  - 新增真实发布请求的客户端测试，验证会调用 `/resume/publish`
  - 同时把旧的本地 API 地址断言从 `3001` 改为 `5577`
- `apps/admin/components/export-entry-panel.spec.tsx`
  - 更新导出链接中的 API 地址预期
- `apps/web/lib/published-resume-api.spec.ts`
  - 更新公开简历读取接口的默认地址预期
- `apps/web/components/published-resume-shell.spec.tsx`
  - 更新前台导出入口的地址预期

这样做的原因是：本任务的核心风险点非常集中，就是“端口常量是否一致”和“发布按钮是否真的调用真实接口”。测试应该直接围绕这两个点，而不是扩散到下一阶段页面细节。

## 实际改动

### 1. 统一本地默认端口

调整以下默认配置，使本地三端约定固定下来：

- `apps/server/src/main.ts`
- `apps/web/package.json`
- `apps/admin/package.json`
- `apps/web/lib/env.ts`
- `apps/admin/lib/env.ts`
- `.env.example`
- `apps/server/README.md`
- `apps/web/README.md`
- `docs/40-部署上线/01-Vercel-与-云服务器-最小部署说明.md`

统一后约定如下：

- `web`：`5555`
- `admin`：`5566`
- `server`：`5577`

这样处理后，后续教程、截图、文档、启动命令、环境变量示例可以保持一致，不再出现“代码一个端口、文档另一个端口、测试又是第三个端口”的问题。

### 2. 后台发布按钮接到真实发布接口

原来后台“发布简历”仍走演示接口，不利于后续 M7 继续接真实内容流。

本次在：

- `apps/admin/lib/auth-api.ts`
- `apps/admin/components/admin-dashboard-shell.tsx`

补充真实发布客户端方法 `publishResume()`，并将发布按钮改为调用 `/resume/publish`。

同时保留 AI 演示按钮继续走 demo 接口，避免本次任务范围失控。这样我们完成的是“发布真实化”，不是“一次性把所有后台动作都改成真实业务”。

### 3. 同步测试预期

围绕端口和发布链路，更新了相关测试常量与断言，确保当前联调基线可被自动验证。

## Review 记录

### 是否符合当前 Issue 与里程碑目标

符合。

本次只处理了 `issue-30` 约定的两件事：

- 统一端口
- 发布按钮改为真实发布

没有把范围扩展到旧简历迁移、真实草稿编辑、公开页视觉升级等后续 Issue。

### 是否可抽离组件、公共函数、skills 或其他复用能力

有一处轻量复用已完成：

- 在 `apps/admin/lib/auth-api.ts` 中，把真实发布接口收敛为独立的 `publishResume()` 方法，避免页面组件直接拼接请求。

当前不需要继续抽离更大的 hooks 或 service，因为后台真实编辑流还未开始，过早抽象会让教程节奏变重。

### Review 后的边界判断

这类“联调阶段先做了、后续再补正式收束”的工作，也应该进入标准流程。原因是它虽然不是大功能，但它改变了后续所有任务的开发基线，必须能被文档、日志和测试一起说明清楚。

## 自测结果

### 自动化验证

已执行以下验证：

- `pnpm --filter @my-resume/admin typecheck`
- `pnpm --filter @my-resume/admin test`
- `pnpm --filter @my-resume/web typecheck`
- `pnpm --filter @my-resume/web test`
- `pnpm --filter @my-resume/server typecheck`
- `pnpm --filter @my-resume/admin build`
- `pnpm --filter @my-resume/web build`
- `pnpm --filter @my-resume/server build`

结果：全部通过。

本次还同步更新了 `web` 与 `admin` 的相关测试断言，保证默认 API 地址统一到 `5577`。

### 手工验证（联调阶段已完成）

此前已在本地完成过一轮联调验证：

- `admin` 使用真实账号登录成功
- 点击“发布简历”后，`POST /resume/publish` 返回成功
- 请求 `GET /resume/published` 可拿到已发布内容
- `web` 已能展示示例简历内容，不再停留在空态

本次 Issue 的作用，就是把上述已验证结果正式落到代码、测试和文档中。

## 遇到的问题

### 1. 联调验证和正式开发流程之间存在时间差

问题：为了快速确认三端能不能跑通，联调修正会先发生，但如果不及时收束，就会让仓库进入“能用但说不清”的状态。

解决方式：

- 单独补 `issue-30`
- 明确这类任务属于“联调收束型 Issue”
- 用开发日志解释其存在意义

### 2. 发布动作真假接口混用

问题：后台界面上存在“看起来已经可用”，但实际上仍调用 demo 接口的情况，容易让读者误解真实业务链路已经打通。

解决方式：

- 只把“发布简历”切到真实接口
- 把 AI 相关动作继续留在 demo/mock 阶段
- 让每个能力的真实化进度和里程碑节奏保持一致

## 可沉淀为教程/博客的点

- 为什么“联调验证通过”之后，还要专门做一次正式收束
- 教程型项目里，如何处理“临时修正”和“正式基线”之间的关系
- 如何用小 Issue 收束端口、环境变量、文档、测试这类横向配置改动

## 后续待办

- 进入 `M7 / issue-31`：`admin` 真草稿读取与保存
- 继续把展示层从“联调壳”推进到“真实内容可编辑、可发布、可展示”
- 等 M7 完整收束后，再补里程碑级教程或大纲
