# SproutGate 前端文档

## 技术栈

- **运行时**：React 18
- **构建工具**：Vite 5（`@vitejs/plugin-react`）
- **Markdown 渲染**：`marked`（用于资料等富文本展示）
- **样式**：全局 `src/styles.css`

无专门路由库：根据 `window.location.pathname` 在 `App.jsx` 中分支渲染各视图。

**OAuth 与授权页**：若 URL 带有 `redirect_uri` / `return_url` 且当前路径不是 **`/authorize`**、也不是管理/用户列表/公开用户页，`useLayoutEffect` 会将浏览器 **`replace`** 到 **`{BASE_URL}authorize`** 并保留查询串，用于独立授权确认（`OAuthConsentScreen` + `UserPortal` 的 `oauthStandalone`）。顶栏在授权流程下提供「拒绝 / 取消」（`buildAuthDenyCallbackUrl`）。

## 目录结构（要点）

| 路径 | 说明 |
|------|------|
| `src/main.jsx` | 入口；生产环境可选注册 `public/sw.js` |
| `src/App.jsx` | 壳层：开屏、随机背景、按路径切换三大视图、管理员入口弹窗、图片预览 |
| `src/config.js` | `API_BASE`、OAuth 查询解析（`getAuthFlowFromSearch`，含 `scope` → `scopes`）、`buildAuthCallbackUrl` / `buildAuthDenyCallbackUrl`、`formatOAuthRedirectLabel`、`persistAuthClientFromFlow` / `authClientFetchHeaders`、地理与日期展示工具等 |
| `src/styles.css` | 全站样式（含 `.oauth-consent*`、`.oauth-authorize-*` 授权页） |
| `src/components/` | `UserPortal`、`OAuthConsentScreen`、`PublicUserPage`、`PublicUserListPage`、`AdminPanel`、`SplashScreen`、`RandomSiteBackground`、`AvatarImg` 等 |
| `src/components/userPortal/` | 用户门户局部：`UserPortalAuthSection`、`UserPortalProfileSection` 等 |
| `public/` | 静态资源（如 `logo192.png`） |

## 环境与 API 地址

后端 API 基址由 **`src/config.js`** 中的 `API_BASE` 决定：

1. 若 **`VITE_API_BASE`**（`.env` / `.env.local`）有值，则使用该地址（尾部 `/` 会自动去掉）。
2. 否则：**开发模式**（`vite` / `import.meta.env.DEV`）默认 `http://localhost:8080`；**生产构建**默认 `https://auth.api.shumengya.top`。

本地联调后端示例（在 `sproutgate-frontend` 目录）：

```bash
# .env.local
VITE_API_BASE=http://localhost:8080
```

部署到其它域名时，务必设置 `VITE_API_BASE` 为实际网关或后端地址，再执行 `npm run build`。

其它与 `config.js` 相关的常量（一般不必改）：

| 常量 | 用途 |
|------|------|
| `LOGO_192_SRC` | 顶栏 logo，带 `import.meta.env.BASE_URL` 以支持子路径部署 |
| `RAND_BG_API_ORIGIN` | 全站随机背景 API（`https://randbg.api.smyhub.com`） |
| `CLIENT_GEO_LOOKUP_URL` | 浏览器侧 IP/地理，与后端「最后访问」元数据配合 |

## 前端「路由」与页面

表格中为**部署在站点根路径**（`vite.config` 默认 `base: '/'`）时的 `pathname`。子路径部署时，实际 pathname 会带前缀，需与 Vite **`base`** 一致（顶栏链接已通过 `new URL(..., origin + BASE_URL)` 生成）。

| 路径模式 | 组件 | 说明 |
|----------|------|------|
| `/` | `UserPortal` | 登录、注册、OAuth 查询参数（`redirect_uri`、`client_id` 等）、个人资料、签到等；无 `oauthStandalone` |
| `/authorize` | `UserPortal`（`oauthStandalone`） | 第三方授权专用壳：无/无效回跳时错误提示；登录后展示 `OAuthConsentScreen`，不并排展示完整资料区 |
| `/users` | `PublicUserListPage` | 调用 `GET /api/public/users` 的公开用户目录 |
| `/user` 或 `/user/:account` | `PublicUserPage` | 公开资料与主页赞等（`account` 来自路径，支持 URL 编码） |
| `/admin` 或子路径以 `/admin` 开头 | `AdminPanel` | 管理后台（需有效管理员 Token，见下） |

管理员入口：**连点顶栏 logo 5 次** 打开弹窗，输入与后端一致的 **`X-Admin-Token`**；校验通过后 Token 写入 `localStorage`（`sproutgate_admin_token`）并跳转到带 `BASE_URL` 前缀的 `admin` 路径。

## 与后端的约定

- 所有业务请求使用 **`API_BASE`** 拼接路径，例如 `${API_BASE}/api/auth/login`。
- 认证接口在适用场景下可附带 **`authClientFetchHeaders()`** 返回的 **`X-Auth-Client`** / **`X-Auth-Client-Name`**（来自统一登录 URL 的 `client_id` / `client_name`，经 `sessionStorage` 持久化本会话）。
- 访问上报、地理展示等可按需传 **`X-Visit-Ip`**、**`X-Visit-Location`**（和 CORS 允许的头一致，详见后端文档）。
- 公开用户列表、主页、点赞分别对应后端 **`GET /api/public/users`**、**`GET /api/public/users/:account`**、**`POST /api/public/users/:account/like`**（点赞需 Bearer）。
- 管理端请求使用 **`X-Admin-Token`**（或后端支持的 Query `token`），与后端持久化的管理员配置一致（见 **`sproutgate-backend/后端文档.md`**）。

具体 REST 路径与说明以 **`sproutgate-backend/后端文档.md`**、根目录 **`萌芽账户认证中心-第三方应用API接入文档.md`** 及 **`AGENTS.md`** 为准。

## npm 脚本

| 命令 | 说明 |
|------|------|
| `npm install` | 安装依赖 |
| `npm run dev` | 启动 Vite 开发服务器（`--host`，默认端口以终端输出为准，常为 `5173`） |
| `npm run build` | 生产构建，输出到 `dist/` |
| `npm run preview` | 本地预览构建结果（`--host`） |

根目录若使用 `sproutgate.bat` / `sproutgate.sh` 的 `dev`，通常会同时拉起后端与前端，详见仓库 `AGENTS.md`。

## 构建与部署注意

- **`VITE_API_BASE`** 在构建时注入，修改后需重新 **`npm run build`**。
- 若站点部署在子路径，需配置 Vite **`base`**（如 `vite.config`），顶栏 logo 已通过 `BASE_URL` 避免裂图。
- 生产环境若开启 Service Worker，需保证 `public/sw.js` 与缓存策略符合实际 CDN/域名。

## 安全提示

- 勿把真实管理员 Token、用户口令写入前端仓库；管理员 Token 仅用于请求头，存 `localStorage` 有 XSS 风险，生产环境应强化 CSP 与依赖审计。
- `.env.local` 通常列入 `.gitignore`，避免将内网 API 地址误提交。
