# Channel 创建流程与 Settings 可见性设计

## 背景

当前创建 Channel 弹窗同时承载名称、Description、Channel 可见性和成员邀请。Description 与 Channel 可见性都是可以后置调整的设置项，放在创建时会增加首次创建负担。产品目标是让用户创建 Channel 时只需要完成必要决策：命名 Channel，并按需邀请成员。

本次 Web 与服务端同步更新，不需要保留旧 API 兼容字段。API 应保持简单干净，移除创建流程不再需要的输入。

## 目标

- 创建 Channel 只需要 Channel 名称；创建弹窗仍允许在创建后立即添加受邀成员。
- 新建 Channel 固定默认为 `private`。
- 创建 API 只接收 `name`，不接收 `description` 或 `visibility`。
- Description 与 Channel 可见性在 Channel Settings 中管理。
- Settings 中可将 Channel 从 `private` 改为 `public`，也可从 `public` 改回 `private`。
- 保留邀请 agent 时的 agent visibility 选择，因为它描述的是该 agent 在 Channel 中的参与方式，不是 Channel 本身的可见性。

## 非目标

- 不做旧请求体兼容；旧客户端若继续传 `description` / `visibility` 不作为本次支持目标。
- 不改变 agent visibility 的语义或默认值。
- 不改变 Channel 成员、manager、owner、archive、delete、leave 的权限模型。
- 不引入新的迁移或双读/双写路径。

## 用户体验

### 创建 Channel

创建弹窗保留：

1. `Name`，必填。
2. `Members`，可选，用于邀请 humans / agents / apps。

创建弹窗移除：

- `Description` 输入框。
- Channel visibility 的 `Private` / `Public` 选择区。

提交时：

- Web 调用 `createChannel(workspaceId, name)`。
- 服务端创建 `description = ""`、`visibility = "private"` 的 Channel。
- 若用户在弹窗中选择了成员，创建成功后继续按现有顺序添加成员。
- 创建成功后导航到新 Channel。

### Channel Settings

Channel Settings 组织为：

1. **Profile**
   - Name：保留现有 inline rename 能力。
   - Description：保留现有 inline 编辑能力，允许为空。

2. **Visibility & discovery**
   - Private：Only invited members can see and access this channel.
   - Public：Workspace members can discover and join this channel from search.
   - 当前状态以两张 choice tile 呈现。
   - 只有 `channel.canManage` 且非 `#all` 的 Channel 可修改。
   - 保存失败时在 Settings 顶部显示现有 warning notice。

`#all` Channel 不展示可编辑 visibility 控制，避免暗示可改变内置 Channel 的可见性。

## API 与数据模型

### Create Channel

`POST /api/v1/workspaces/:workspaceId/channels`

请求体：

```json
{
  "name": "research"
}
```

服务端行为：

- `name` 仍 trim 并校验非空。
- `name` 保存为 `display_name`；返回中的 `name` / `slug` 仍是 `#channel`、thread target、agent target 使用的链接标识。
- 新建时服务端从 `display_name` 派生协议安全 slug，保持既有 `[a-z0-9-]` 语法；当名称包含中文、标点等无法无损进入 slug 的字符时，复用既有 `channelID` fallback 生成链接标识，避免不同显示名被折叠成同一个 slug。
- 已有频道 slug 不迁移、不重算；重命名频道只更新 `display_name`，不改变已有链接标识。
- `description` 固定为空字符串。
- `visibility` 固定为 `private`。
- 响应返回完整 `ChannelResponse`。

### ChannelResponse

`ChannelResponse` 增加 `visibility` 字段，用于 Settings 展示和保存后的缓存同步：

```json
{
  "id": "chn_...",
  "name": "research",
  "displayName": "Research",
  "description": "",
  "visibility": "private"
}
```

### Update Channel

`PATCH /api/v1/workspaces/:workspaceId/channels/:channelId`

请求体支持：

```json
{
  "name": "research",
  "description": "Project planning",
  "visibility": "public"
}
```

所有字段均可选；未提供的字段保持不变。

服务端行为：

- `name`：沿用当前校验与 `#all` rename 限制。
- `description`：trim 后保存，允许为空。
- `visibility`：只允许 `private` 或 `public`；为空或未提供表示不变；非法值返回 bad request。
- `#all` Channel 不允许修改 visibility。
- 成功后返回更新后的 `ChannelResponse`，包含最新 visibility。

## 前端数据流

- `createChannel` helper 改为只接收 `workspaceId` 与 `name`。
- `updateChannel` helper 输入增加可选 `visibility`。
- `Channel` 类型增加必填 `visibility: ChannelVisibility | string`，与同步更新后的服务端响应保持一致。
- `CreateChannelModal.__test.buildCreateChannelMutationVariables` 不再接收或返回 `description` / Channel `visibility`。
- `ChannelSettingsPane.saveChannelPatch` 支持 `{ name?, description?, visibility? }`，并继续更新 channels 与 channelAccess cache。
- visibility 更新成功后 invalidate discover channels cache，因为 public/private 会影响 discover/join 列表。

## 测试计划

### 后端

- `internal/api/channel`：
  - Create request 只包含 `name`，响应 visibility 为 `private`。
  - `ChannelCreateRequest` 只定义 `name`，服务端固定写入空 description 与 private visibility。
  - Update 支持 visibility 从 private 改 public。
  - Update 拒绝非法 visibility。
  - Update 拒绝修改 `#all` visibility。

- `internal/store/app` 或相关 store 测试：
  - `UpdateChannelForUser` 更新 `scope_channel_profiles.visibility`。
  - 返回的 `ChannelSummary.Visibility` 与数据库一致。

### 前端

- `CreateChannelModal.test.ts`：
  - mutation variables 只包含 name 与成员选择。
  - 成员 snapshot 行为保持不变。

- `api.test.ts`：
  - `createChannel` 只发送 `{ name }`。
  - `updateChannel` 可发送 `{ visibility: "public" }`。

- Channel Settings source guard / component-level source tests：
  - Settings 页面包含 Visibility & discovery section。
  - CreateChannelModal 不再包含 description field 和 Channel visibility section。

### 验证命令

- `go test ./internal/api/channel ./internal/store/channel ./internal/store/app`
- `cd web && npx tsx --test src/agentteam/workspace/conversation/components/CreateChannelModal.test.ts src/agentteam/api.test.ts src/agentteam/workspace/conversation/components/SurfaceNotificationPanel.test.ts`
- `cd web && npm run typecheck`

## 风险与处理

- **Discover 列表缓存陈旧**：visibility 更新后显式 invalidate discover channels query。
- **创建后成员添加失败**：沿用现有创建后顺序添加和错误处理；不把本次变化扩大到 batch add。
- **ChannelResponse 使用方未预期 visibility**：新增字段是向响应添加信息，不改变既有字段；Settings 使用该字段，其他消费方可忽略。
- **`#all` 误操作**：Settings 不展示可编辑 visibility，服务端也拒绝修改。
