# PocketBay 用户系统接入手册（给 AI 编程助手）

你正在修改用户的当前项目，使它复用 PocketBay 的登录用户。请直接检查并修改项目代码，不要要求用户阅读本手册，也不要虚构不存在的 npm/pip SDK。

## 可用能力

PocketBay 已在网关层完成登录、应用域独立会话和访问门禁。应用不需要实现注册、密码、验证码、OAuth 回调或 Token 刷新。

应用可使用两种身份入口：

1. 所有应用都可同源请求 `GET /.pocketbay/user`。
2. 动态应用后端可读取网关注入的请求头：
   - `X-PocketBay-User`：应用内稳定用户 ID，字符串类型
   - `X-PocketBay-Name`：URL 编码后的昵称
   - `X-PocketBay-Plan`：PocketBay 平台套餐 `free|plus|pro`
   - `X-PocketBay-Auth`：短寿命平台断言；当前接入不要求应用自行解析

`plan` 只代表 PocketBay 平台套餐，不代表应用自己的付费会员或应用内购权益。

## `/.pocketbay/user` 返回格式

已登录：

```json
{
  "authenticated": true,
  "user": {
    "id": "usr_...",
    "name": "用户昵称",
    "avatar_url": "https://..."
  },
  "plan": "free",
  "client_id": "pb_app_..."
}
```

未登录或项目未开启用户系统：

```json
{"authenticated": false}
```

退出当前应用登录：

```http
POST /.pocketbay/logout
```

## 第 1 步：分析项目

先阅读项目结构、框架、数据模型和现有认证代码，判断：

- 纯静态/浏览器应用：使用 `/.pocketbay/user`。
- Next.js、Node、Python 等动态应用：优先在服务端读取 `X-PocketBay-User`；浏览器需要头像昵称时可调用 `/.pocketbay/user`。
- 已有用户系统且已有用户数据：不要删除用户表或静默按邮箱合并。增加 `pocketbay_subject` 映射，并向用户说明需要账号迁移策略。
- 仅做整站登录门禁、不需要在页面识别用户：无需修改源码，只提醒用户在项目设置开启 PocketBay 用户系统。

除非替换现有认证可能导致账号或数据迁移风险，否则不要停下来让用户选择，直接采用最小安全改动。

## 第 2 步：按项目类型接入

### 静态或纯前端应用

增加统一身份加载函数：

```js
export async function getPocketBayUser() {
  const response = await fetch("/.pocketbay/user", {
    credentials: "same-origin",
    cache: "no-store"
  });
  if (!response.ok) throw new Error("PocketBay 用户信息加载失败");
  return response.json();
}
```

页面初始化时先显示加载状态，再根据 `authenticated` 渲染。业务数据只能使用返回的 `user.id` 作为用户归属，不得使用昵称、查询参数或 `localStorage` 中自造的 ID。

### Next.js App Router

服务端读取身份：

```ts
import { headers } from "next/headers";

export function getPocketBayIdentity() {
  const requestHeaders = headers();
  const userId = requestHeaders.get("x-pocketbay-user");
  if (!userId) return null;
  return {
    id: userId,
    name: decodeURIComponent(requestHeaders.get("x-pocketbay-name") || ""),
    plan: requestHeaders.get("x-pocketbay-plan") || "free",
  };
}
```

在 Route Handler、Server Component 或 Server Action 中使用该身份。不要让浏览器提交 `user_id` 后直接信任。

### Express / Node

```js
export function pocketBayUser(req) {
  const id = req.get("X-PocketBay-User");
  if (!id) return null;
  return {
    id,
    name: decodeURIComponent(req.get("X-PocketBay-Name") || ""),
    plan: req.get("X-PocketBay-Plan") || "free"
  };
}
```

### FastAPI / Python

```python
from fastapi import Header, HTTPException

def pocketbay_user(
    user_id: str | None = Header(default=None, alias="X-PocketBay-User"),
    plan: str = Header(default="free", alias="X-PocketBay-Plan"),
):
    if not user_id:
        raise HTTPException(status_code=401, detail="未登录")
    return {"id": user_id, "plan": plan}
```

## 第 3 步：用户数据隔离

如果应用保存每个用户的数据：

- 业务表增加字符串字段 `pocketbay_subject`，建议长度至少 64。
- 创建和查询数据时始终从服务端可信身份取得 subject。
- 所有读取、更新、删除语句都必须带 `pocketbay_subject = 当前用户` 条件。
- 不要把 PocketBay subject 当数字解析。
- subject 仅在当前应用内稳定；Fork 后是新的应用身份空间。

示例：

```sql
SELECT * FROM notes
WHERE pocketbay_subject = :current_user;
```

## 第 4 步：本地开发

本地开发环境没有 PocketBay 网关注入身份。可以增加仅开发环境生效的 mock 用户，但必须满足：

- 生产环境绝不接受客户端传入的用户 ID。
- mock 逻辑由明确的开发环境变量控制。
- 不把 mock 用户或绕过开关提交为生产默认值。

## 第 5 步：检查并交付

完成修改后：

1. 运行项目已有的类型检查、测试或构建。
2. 检查所有用户数据读写是否按 PocketBay subject 隔离。
3. 删除旧登录入口前，确认不会造成现有账号数据丢失。
4. 告诉用户具体修改了哪些文件。
5. 如果代码有改动，告诉用户需要重新部署。
6. 提醒用户部署后进入 PocketBay 项目 Settings，开启“PocketBay 用户系统”；仅修改代码不会自动开启网关认证。

## 禁止事项

- 不要读取或共享 `pocketbay.com` 的平台 Cookie、Refresh Token 或控制台 Access Token。
- 不要自己实现 `/.pocketbay/callback`，该路径由平台网关处理。
- 不要使用邮箱作为跨应用主键；当前接口也不会向应用提供邮箱。
- 不要信任浏览器提交的 `X-PocketBay-*`、`user_id` 或套餐值。
- 不要把 `free|plus|pro` 当作应用自己的购买权益。

平台入口：https://pocketbay.com/app-auth
机器手册：https://pocketbay.com/api/app-auth/instructions
