docs: record auth profile flow
This commit is contained in:
@@ -2,10 +2,16 @@
|
|||||||
|
|
||||||
创建时间:2026-07-09 15:14:58 +08:00
|
创建时间:2026-07-09 15:14:58 +08:00
|
||||||
接口依据:`genealogy-pc-openapi.yaml`
|
接口依据:`genealogy-pc-openapi.yaml`
|
||||||
接口基础地址:`http://test-genealogy-api.ddxcjp.cn`
|
接口基础地址:`http://182.61.18.23:8080`
|
||||||
旧依据处理:`APP.openapi.json` 只作为历史误用记录,不再作为 PC 页面继续对接依据。
|
旧依据处理:`APP.openapi.json` 只作为历史误用记录,不再作为 PC 页面继续对接依据。
|
||||||
旧进度记录:`docs/api-page-integration-tracker-2026-07-09.md`
|
旧进度记录:`docs/api-page-integration-tracker-2026-07-09.md`
|
||||||
|
|
||||||
|
## 当前地址契约
|
||||||
|
|
||||||
|
- 运行时唯一来源:根目录 `config.js`。
|
||||||
|
- 当前开发和生产地址:`http://182.61.18.23:8080`。
|
||||||
|
- 地址变更记录:2026-07-11 已由历史测试域名切换为当前 IP 和端口;文档中出现的 `test-genealogy-api.ddxcjp.cn` 仅用于描述历史事件,不代表当前运行时配置。
|
||||||
|
|
||||||
## 执行规则
|
## 执行规则
|
||||||
|
|
||||||
1. 所有 PC 接口对接必须先进入本追踪表,再改代码。
|
1. 所有 PC 接口对接必须先进入本追踪表,再改代码。
|
||||||
@@ -29,7 +35,7 @@
|
|||||||
分析文件:`genealogy-pc-openapi.yaml`
|
分析文件:`genealogy-pc-openapi.yaml`
|
||||||
|
|
||||||
1. `paths` 中实际存在 25 个接口操作,分为验证码、PC 认证、PC 文件、行政区划四类。
|
1. `paths` 中实际存在 25 个接口操作,分为验证码、PC 认证、PC 文件、行政区划四类。
|
||||||
2. `servers` 仍是本地地址示例,项目实际对接基础地址继续按用户指定使用 `https://test-genealogy-api.ddxcjp.cn`。
|
2. `servers` 仍是本地地址示例;当前运行时基础地址以 `config.js` 为准,为 `http://182.61.18.23:8080`。
|
||||||
3. 登录后接口使用 `Authorization` 作为 token header,同时所有 PC 认证和文件接口都要求 header `clientid`;用户最新提供的 PC `clientid` 为 `ced7e5f0498645c6ec642dcf450b036f`,客户端 Key 为 `web_pc`。
|
3. 登录后接口使用 `Authorization` 作为 token header,同时所有 PC 认证和文件接口都要求 header `clientid`;用户最新提供的 PC `clientid` 为 `ced7e5f0498645c6ec642dcf450b036f`,客户端 Key 为 `web_pc`。
|
||||||
4. `components.tags` 和 `components.schemas/requestBodies` 中出现家谱、动态、世系、字辈等业务模型,但 `paths` 没有对应接口路径;实现时不能把这些 schema 当成可调用 PC 接口。
|
4. `components.tags` 和 `components.schemas/requestBodies` 中出现家谱、动态、世系、字辈等业务模型,但 `paths` 没有对应接口路径;实现时不能把这些 schema 当成可调用 PC 接口。
|
||||||
5. 验证码 schema 示例里仍出现 `APP_LOGIN`、`PC_LOGIN` 等文本示例;实际页面场景以后台配置为准,当前明确可用的 PC/H5 场景为 `WEB_H5_LOGIN`、`WEB_H5_REGISTER`、`WEB_H5_FORGOT_PASSWORD`。
|
5. 验证码 schema 示例里仍出现 `APP_LOGIN`、`PC_LOGIN` 等文本示例;实际页面场景以后台配置为准,当前明确可用的 PC/H5 场景为 `WEB_H5_LOGIN`、`WEB_H5_REGISTER`、`WEB_H5_FORGOT_PASSWORD`。
|
||||||
@@ -67,7 +73,7 @@
|
|||||||
| PC-007 | 复核通过 | 实施规划 | `genealogy-pc-openapi.yaml` | 当前计划与 YAML `paths` 一致,不使用旧 APP 路径 fallback。 |
|
| PC-007 | 复核通过 | 实施规划 | `genealogy-pc-openapi.yaml` | 当前计划与 YAML `paths` 一致,不使用旧 APP 路径 fallback。 |
|
||||||
| PC-008 | 复核通过 | PC YAML 未覆盖业务页面 | `PC_API_NOT_AVAILABLE` | `utils/ApiClient.js` 统一抛 `PC_API_NOT_AVAILABLE`,旧 `/genealogy/app/` 请求路径扫描无结果。 |
|
| PC-008 | 复核通过 | PC YAML 未覆盖业务页面 | `PC_API_NOT_AVAILABLE` | `utils/ApiClient.js` 统一抛 `PC_API_NOT_AVAILABLE`,旧 `/genealogy/app/` 请求路径扫描无结果。 |
|
||||||
| PC-009 | 本地复核通过 | 登录、注册、找回密码 | PC auth、`/captcha/*` | 三页场景编码、表单契约、Axios 请求客户端和相关测试均通过;真实账号流程待业务数据联调。 |
|
| PC-009 | 本地复核通过 | 登录、注册、找回密码 | PC auth、`/captcha/*` | 三页场景编码、表单契约、Axios 请求客户端和相关测试均通过;真实账号流程待业务数据联调。 |
|
||||||
| PC-010 | 复核通过(网关可达) | `config.js`、`utils/ApiClient.js` | 测试 API 基础地址 | 开发地址为 `http://test-genealogy-api.ddxcjp.cn`;2026-07-10 10:02:48 +08:00 外部 `curl.exe -I` 返回 `HTTP 200 OK`。 |
|
| PC-010 | 已复核(当前地址已同步) | `config.js`、`tests/config.test.js`、`utils/ApiClient.js` | API 基础地址 | 当前开发和生产地址均为 `http://182.61.18.23:8080`;地址唯一运行时来源为 `config.js`,`tests/config.test.js` 已同步断言。 |
|
||||||
| PC-011 | 本地复核通过 | 三张认证页 TAC 弹窗 | `public/tac`、`/captcha/*` | 页面级挂载、移动端约束和结构测试通过;未修改 `tac.min.js`。 |
|
| PC-011 | 本地复核通过 | 三张认证页 TAC 弹窗 | `public/tac`、`/captcha/*` | 页面级挂载、移动端约束和结构测试通过;未修改 `tac.min.js`。 |
|
||||||
|
|
||||||
## PC 页面覆盖矩阵草案
|
## PC 页面覆盖矩阵草案
|
||||||
@@ -291,3 +297,15 @@
|
|||||||
- 修改文件:`public/js/captcha-pages.js`、`tests/captcha-pages.test.js`、`docs/superpowers/plans/2026-07-10-tac-layer-real-mount-fix.md`、`docs/pc-api-page-integration-tracker-2026-07-09.md`
|
- 修改文件:`public/js/captcha-pages.js`、`tests/captcha-pages.test.js`、`docs/superpowers/plans/2026-07-10-tac-layer-real-mount-fix.md`、`docs/pc-api-page-integration-tracker-2026-07-09.md`
|
||||||
- 修改结果:`createCaptchaLayer` 现在用字符串 `content` 让 Layui 创建 `<div data-captcha-layer-box="..."></div>`,弹层打开后再通过 `document.querySelector` 获取这个实际节点,并将它作为 TAC 的 `bindEl`。未修改 `public/tac`,未新增验证码 CSS,未传 TAC 视觉配置。
|
- 修改结果:`createCaptchaLayer` 现在用字符串 `content` 让 Layui 创建 `<div data-captcha-layer-box="..."></div>`,弹层打开后再通过 `document.querySelector` 获取这个实际节点,并将它作为 TAC 的 `bindEl`。未修改 `public/tac`,未新增验证码 CSS,未传 TAC 视觉配置。
|
||||||
- 验证结果:先运行 `node tests\captcha-pages.test.js` 复现失败;修复后 `node tests\auth-page-structure.test.js`、`node tests\captcha-pages.test.js`、`node --check public\js\captcha-pages.js` 和 `git diff --check` 通过。`git diff --check` 仅输出既有 CRLF 行尾提示,没有空白错误。
|
- 验证结果:先运行 `node tests\captcha-pages.test.js` 复现失败;修复后 `node tests\auth-page-structure.test.js`、`node tests\captcha-pages.test.js`、`node --check public\js\captcha-pages.js` 和 `git diff --check` 通过。`git diff --check` 仅输出既有 CRLF 行尾提示,没有空白错误。
|
||||||
|
|
||||||
|
## PC-025 注册、登录到个人资料闭环
|
||||||
|
|
||||||
|
- 状态:已完成
|
||||||
|
- 完成时间:2026-07-11 09:32:35 +08:00
|
||||||
|
- 规划文件:`docs/superpowers/specs/2026-07-11-auth-to-profile-flow-design.md`
|
||||||
|
- 页面范围:`register.html`、`login.html`、`profile.html`、`profile-data.html`
|
||||||
|
- 接口范围:`/genealogy/pc/auth/register`、`/genealogy/pc/auth/login`、`/genealogy/pc/auth/login/sms`、`/genealogy/pc/auth/profile`、`/genealogy/pc/auth/logout`
|
||||||
|
- 地址契约:运行时唯一来源为 `config.js`;当前开发和生产地址均为 `http://182.61.18.23:8080`。
|
||||||
|
- 流程结果:注册成功清除 token 并跳转 `login.html`;密码和短信登录必须取得 token 后跳转 `profile.html`;个人资料无 token 或收到 HTTP/业务 `401` 时清 token 并跳转 `index.html`;确认退出无论接口结果都清 token 并跳转 `index.html`。
|
||||||
|
- 修改文件:`tests/config.test.js`、`tests/utils.test.js`、`utils/ApiClient.js`、`tests/api-client.test.js`、`public/js/profile-pages.js`、`public/js/profile-common.js`、`profile.html`、`tests/profile-pages.test.js`、`tests/profile-logout-structure.test.js`。
|
||||||
|
- 验证结果:`node tests/config.test.js`、`node tests/utils.test.js`、`node tests/api-client.test.js`、`node tests/auth-pages.test.js`、`node tests/profile-pages.test.js`、`node tests/profile-logout-structure.test.js`、`node --check utils/ApiClient.js`、`node --check public/js/profile-pages.js`、`node --check public/js/profile-common.js` 和全量 Node 测试均通过。
|
||||||
|
|||||||
@@ -0,0 +1,474 @@
|
|||||||
|
# Auth To Profile Flow Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Complete the PC registration, login, profile, unauthorized, logout, and endpoint-address flow with one token owner and deterministic redirects.
|
||||||
|
|
||||||
|
**Architecture:** `config.js` remains the sole runtime owner of the API base address. `utils/ApiClient.js` owns token validation, persistence, and cleanup; `profile-pages.js` decides whether a profile request is allowed and redirects unauthenticated users to the homepage; `profile-common.js` delegates confirmed logout to the API client. The integration tracker records the current address and verified behavior only after verification commands complete.
|
||||||
|
|
||||||
|
**Tech Stack:** Browser JavaScript (UMD and jQuery), Axios, Node.js `assert` tests, static HTML, Markdown.
|
||||||
|
|
||||||
|
## Global Constraints
|
||||||
|
|
||||||
|
- The current API base address is `http://182.61.18.23:8080` for development and production, and `config.js` is its only runtime owner.
|
||||||
|
- Runtime-related tests use the same address; only documents explicitly marked historical may retain the former test domain.
|
||||||
|
- Successful registration clears `genealogy_auth_token` and redirects to `login.html`; it never persists a registration response token.
|
||||||
|
- Only successful password or SMS login with a nonempty response token persists `genealogy_auth_token` and redirects to `profile.html`.
|
||||||
|
- `profile.html` and `profile-data.html` redirect to `index.html` before a profile request when no token exists, and after HTTP or business `401` responses.
|
||||||
|
- Confirmed logout requests `/genealogy/pc/auth/logout`, clears the token regardless of the request outcome, and redirects to `index.html`.
|
||||||
|
- Do not add global Axios redirects, duplicate token storage in pages, alter API paths, or change password-reset, phone-change, account-deactivation, or profile pages that do not load the profile API.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Synchronize the configured API address test
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `tests/config.test.js:11-28`
|
||||||
|
- Modify: `tests/utils.test.js:31`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `configFactory(...).getConfig()` and `getApiBaseUrl()` from `config.js`.
|
||||||
|
- Produces: a test that asserts the current `config.js` address for both environments.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Confirm the existing address-contract test fails**
|
||||||
|
|
||||||
|
The current test contains these stale assertions:
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert.deepStrictEqual(developmentConfig.getConfig(), {
|
||||||
|
environment: 'development',
|
||||||
|
apiBaseUrl: 'http://test-genealogy-api.ddxcjp.cn'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(productionConfig.getApiBaseUrl(), 'http://test-genealogy-api.ddxcjp.cn');
|
||||||
|
```
|
||||||
|
|
||||||
|
Run: `node tests/config.test.js`
|
||||||
|
|
||||||
|
Expected: failure because `config.js` already returns `http://182.61.18.23:8080`.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Update the stale test expectations**
|
||||||
|
|
||||||
|
Replace the two expected URL values with:
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert.deepStrictEqual(developmentConfig.getConfig(), {
|
||||||
|
environment: 'development',
|
||||||
|
apiBaseUrl: 'http://182.61.18.23:8080'
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.strictEqual(productionConfig.getApiBaseUrl(), 'http://182.61.18.23:8080');
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace the mocked requester address in `tests/utils.test.js` with:
|
||||||
|
|
||||||
|
```js
|
||||||
|
baseUrl: 'http://182.61.18.23:8080',
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Run the focused configuration test**
|
||||||
|
|
||||||
|
Run: `node tests/config.test.js`
|
||||||
|
|
||||||
|
Expected: `config tests passed`.
|
||||||
|
|
||||||
|
Run: `node tests/utils.test.js`
|
||||||
|
|
||||||
|
Expected: `utils tests passed`.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Commit the address-test synchronization**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git add -- tests/config.test.js tests/utils.test.js
|
||||||
|
git commit -m "test: sync configured api address"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Task 2: Enforce login-token and logout-cleanup contracts
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `utils/ApiClient.js:52-60, 167-191, 270-274`
|
||||||
|
- Modify: `tests/api-client.test.js:83-177`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `getTokenFromResponse(data)`, `setToken(token)`, `clearToken()`, and public `client.login`, `client.loginBySms`, and `client.logout` methods.
|
||||||
|
- Produces: `client.login(body)` and `client.loginBySms(body)` reject with `ApiError('登录响应缺少 token')` when their response has no token; `client.logout()` clears the configured token key before resolving or rejecting.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Write failing API-client assertions**
|
||||||
|
|
||||||
|
Append this after the registration assertions and before `client.sendSmsCode(...)` in `tests/api-client.test.js`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const missingTokenStore = createStore();
|
||||||
|
const missingTokenClient = GenealogyApi.createClient({
|
||||||
|
baseUrl: 'http://182.61.18.23:8080',
|
||||||
|
clientId: 'client-x',
|
||||||
|
tenantId: 'tenant-x',
|
||||||
|
tokenKey: 'token-key',
|
||||||
|
tokenStore: missingTokenStore,
|
||||||
|
axiosInstance: {
|
||||||
|
request: async () => ({
|
||||||
|
status: 200,
|
||||||
|
data: { code: 200, data: {} }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await assert.rejects(
|
||||||
|
missingTokenClient.login({ phone: '13800000000', password: 'md5' }),
|
||||||
|
(error) => error.message === '登录响应缺少 token'
|
||||||
|
);
|
||||||
|
assert.strictEqual(missingTokenStore.getItem('token-key'), null);
|
||||||
|
|
||||||
|
store.setItem('token-key', 'logout-token');
|
||||||
|
await client.logout();
|
||||||
|
assert.strictEqual(calls[9].url, '/genealogy/pc/auth/logout');
|
||||||
|
assert.strictEqual(store.getItem('token-key'), null);
|
||||||
|
|
||||||
|
const failedLogoutStore = createStore({
|
||||||
|
'token-key': 'logout-token'
|
||||||
|
});
|
||||||
|
const failedLogoutClient = GenealogyApi.createClient({
|
||||||
|
baseUrl: 'http://182.61.18.23:8080',
|
||||||
|
clientId: 'client-x',
|
||||||
|
tenantId: 'tenant-x',
|
||||||
|
tokenKey: 'token-key',
|
||||||
|
tokenStore: failedLogoutStore,
|
||||||
|
axiosInstance: {
|
||||||
|
request: async () => {
|
||||||
|
throw new Error('logout failed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await assert.rejects(failedLogoutClient.logout(), /logout failed/);
|
||||||
|
assert.strictEqual(failedLogoutStore.getItem('token-key'), null);
|
||||||
|
```
|
||||||
|
|
||||||
|
Move the existing SMS-code assertions from `calls[9]` to `calls[10]` and change the final call-count assertion from `10` to `11`.
|
||||||
|
|
||||||
|
Replace the two existing `baseUrl: 'https://test-genealogy-api.ddxcjp.cn'` fixtures in this file with:
|
||||||
|
|
||||||
|
```js
|
||||||
|
baseUrl: 'http://182.61.18.23:8080',
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run the focused API-client test and confirm failure**
|
||||||
|
|
||||||
|
Run: `node tests/api-client.test.js`
|
||||||
|
|
||||||
|
Expected: failure at the missing-token rejection because the current login method resolves without writing a token, before reaching the logout assertions.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Add the minimal token validation and logout cleanup**
|
||||||
|
|
||||||
|
Add this helper after `getTokenFromResponse` in `utils/ApiClient.js`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function requireLoginToken(data) {
|
||||||
|
var token = getTokenFromResponse(data);
|
||||||
|
|
||||||
|
if (!token) throw new ApiError('登录响应缺少 token');
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace the token writes in `login()` and `loginBySms()` with:
|
||||||
|
|
||||||
|
```js
|
||||||
|
setToken(requireLoginToken(data));
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `logout` with:
|
||||||
|
|
||||||
|
```js
|
||||||
|
logout: async function () {
|
||||||
|
try {
|
||||||
|
return await request('DELETE', '/genealogy/pc/auth/logout');
|
||||||
|
} finally {
|
||||||
|
clearToken();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Run the API-client test and confirm all token paths pass**
|
||||||
|
|
||||||
|
Run: `node tests/api-client.test.js`
|
||||||
|
|
||||||
|
Expected: `api-client tests passed`.
|
||||||
|
|
||||||
|
- [ ] **Step 5: Commit the API-client contract**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git add -- utils/ApiClient.js tests/api-client.test.js
|
||||||
|
git commit -m "fix: complete auth token lifecycle"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Task 3: Guard profile access and connect confirmed logout
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `public/js/profile-pages.js:18-22, 165-198`
|
||||||
|
- Modify: `public/js/profile-common.js:9-82`
|
||||||
|
- Modify: `profile.html:80, 355`
|
||||||
|
- Modify: `tests/profile-pages.test.js:1-65`
|
||||||
|
- Create: `tests/profile-logout-structure.test.js`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: public `api.getToken()`, `api.clearToken()`, `api.currentProfile()`, `api.updateProfile()`, and `api.logout()` methods.
|
||||||
|
- Produces: `ProfilePages.shouldRedirectToHome(api, error)` for token and unauthorized classification; profile reads and writes redirect to `index.html` when that helper returns true; the existing logout controls call `api.logout()` before navigating to `index.html`.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Write failing profile and logout tests**
|
||||||
|
|
||||||
|
Add these assertions before the final `console.log` in `tests/profile-pages.test.js`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
assert.strictEqual(ProfilePages.shouldRedirectToHome({
|
||||||
|
getToken: () => ''
|
||||||
|
}), true);
|
||||||
|
assert.strictEqual(ProfilePages.shouldRedirectToHome({
|
||||||
|
getToken: () => 'token-x'
|
||||||
|
}), false);
|
||||||
|
assert.strictEqual(ProfilePages.shouldRedirectToHome({
|
||||||
|
getToken: () => 'token-x'
|
||||||
|
}, { status: 401 }), true);
|
||||||
|
assert.strictEqual(ProfilePages.shouldRedirectToHome({
|
||||||
|
getToken: () => 'token-x'
|
||||||
|
}, { code: 401 }), true);
|
||||||
|
assert.strictEqual(ProfilePages.shouldRedirectToHome({
|
||||||
|
getToken: () => 'token-x'
|
||||||
|
}, { status: 500 }), false);
|
||||||
|
```
|
||||||
|
|
||||||
|
Create `tests/profile-logout-structure.test.js` with:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const assert = require('assert');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const profileHtml = fs.readFileSync(path.join(__dirname, '..', 'profile.html'), 'utf8');
|
||||||
|
const profileCommon = fs.readFileSync(path.join(__dirname, '..', 'public', 'js', 'profile-common.js'), 'utf8');
|
||||||
|
|
||||||
|
assert.match(profileHtml, /data-logout-confirm/);
|
||||||
|
assert.match(profileHtml, /<a class="btn primary magnetic" href="index\.html" data-logout-confirm>/);
|
||||||
|
assert.match(profileCommon, /function performLogout\(targetUrl\)/);
|
||||||
|
assert.match(profileCommon, /api\.logout\(\)/);
|
||||||
|
assert.match(profileCommon, /targetUrl \|\| 'index\.html'/);
|
||||||
|
|
||||||
|
console.log('profile logout structure tests passed');
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run the new focused tests and confirm failure**
|
||||||
|
|
||||||
|
Run: `node tests/profile-pages.test.js`
|
||||||
|
|
||||||
|
Expected: failure because `shouldRedirectToHome` is not exported.
|
||||||
|
|
||||||
|
Run: `node tests/profile-logout-structure.test.js`
|
||||||
|
|
||||||
|
Expected: failure because the logout confirmation markup and `performLogout` function do not exist.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Add profile token guard and unauthorized redirect**
|
||||||
|
|
||||||
|
Add these helpers after `getApi()` in `public/js/profile-pages.js`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function shouldRedirectToHome(api, error) {
|
||||||
|
var status = error && (error.status || error.code);
|
||||||
|
|
||||||
|
return !api || !api.getToken || !api.getToken() || Number(status) === 401;
|
||||||
|
}
|
||||||
|
|
||||||
|
function redirectToHome() {
|
||||||
|
if (!root.location) return;
|
||||||
|
if (typeof root.location.replace === 'function') {
|
||||||
|
root.location.replace('index.html');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
root.location.href = 'index.html';
|
||||||
|
}
|
||||||
|
|
||||||
|
function redirectUnauthorized(api, error) {
|
||||||
|
if (!shouldRedirectToHome(api, error)) return false;
|
||||||
|
if (api && api.clearToken) api.clearToken();
|
||||||
|
redirectToHome();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace the existing combined early-return condition in `loadProfile()` with these two branches:
|
||||||
|
|
||||||
|
```js
|
||||||
|
if (!api || !documentRef || !documentRef.querySelector('[data-profile-page]')) return;
|
||||||
|
if (redirectUnauthorized(api)) return;
|
||||||
|
```
|
||||||
|
|
||||||
|
Update its `catch` block to start with:
|
||||||
|
|
||||||
|
```js
|
||||||
|
if (redirectUnauthorized(api, error)) return;
|
||||||
|
```
|
||||||
|
|
||||||
|
Update `submitProfileForm()` to place `if (redirectUnauthorized(api)) return;` after its existing null guard, and to start its `catch` block with `if (redirectUnauthorized(api, error)) return;` before setting an error status or message.
|
||||||
|
|
||||||
|
Export the classifier with the existing public methods:
|
||||||
|
|
||||||
|
```js
|
||||||
|
shouldRedirectToHome: shouldRedirectToHome,
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Connect both logout confirmations to the API client**
|
||||||
|
|
||||||
|
Add this function before `bindLogout()` in `public/js/profile-common.js`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function performLogout(targetUrl) {
|
||||||
|
var api = window.GenealogyApi && window.GenealogyApi.defaultClient;
|
||||||
|
var redirect = function () {
|
||||||
|
window.location.href = targetUrl || 'index.html';
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!api || !api.logout) {
|
||||||
|
redirect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
api.logout().catch(function () {}).then(redirect);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In `bindLogout()`, change the default target URL to `index.html`, replace the Layui confirmation callback body with `performLogout(targetUrl);`, and add this event handler before the existing `[data-logout-close]` handler:
|
||||||
|
|
||||||
|
```js
|
||||||
|
$(document).on('click', '[data-logout-confirm]', function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
closeLegacyLogout();
|
||||||
|
performLogout($(this).attr('href') || 'index.html');
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
In `profile.html`, change the legacy confirmation anchor to:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<a class="btn primary magnetic" href="index.html" data-logout-confirm>确认退出</a>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Run the focused profile tests and syntax checks**
|
||||||
|
|
||||||
|
Run: `node tests/profile-pages.test.js`
|
||||||
|
|
||||||
|
Expected: `profile-pages tests passed`.
|
||||||
|
|
||||||
|
Run: `node tests/profile-logout-structure.test.js`
|
||||||
|
|
||||||
|
Expected: `profile logout structure tests passed`.
|
||||||
|
|
||||||
|
Run: `node --check public/js/profile-pages.js`
|
||||||
|
|
||||||
|
Expected: exit code `0`.
|
||||||
|
|
||||||
|
Run: `node --check public/js/profile-common.js`
|
||||||
|
|
||||||
|
Expected: exit code `0`.
|
||||||
|
|
||||||
|
- [ ] **Step 6: Commit the profile and logout flow**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git add -- public/js/profile-pages.js public/js/profile-common.js profile.html tests/profile-pages.test.js tests/profile-logout-structure.test.js
|
||||||
|
git commit -m "fix: guard profile auth and logout"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Task 4: Record the current flow and run end-to-end regression checks
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `docs/pc-api-page-integration-tracker-2026-07-09.md:1-9, 32, 70, 163`
|
||||||
|
- Modify: `docs/superpowers/specs/2026-07-11-auth-to-profile-flow-design.md:3-5`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: the verified results of Tasks 1 through 3.
|
||||||
|
- Produces: a tracker whose current address and authentication-flow status match the code and tests, and a spec marked approved for implementation.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Run all focused flow tests**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
node tests/config.test.js
|
||||||
|
node tests/api-client.test.js
|
||||||
|
node tests/auth-pages.test.js
|
||||||
|
node tests/profile-pages.test.js
|
||||||
|
node tests/profile-logout-structure.test.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: each command prints its success message and exits with code `0`.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Run syntax and complete regression checks**
|
||||||
|
|
||||||
|
Run:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
node --check utils/ApiClient.js
|
||||||
|
node --check public/js/profile-pages.js
|
||||||
|
node --check public/js/profile-common.js
|
||||||
|
Get-ChildItem -Path tests -Filter *.test.js | ForEach-Object { & node $_.FullName; if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } }
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: all syntax checks exit `0`; every test script prints its success message; PowerShell exits `0` on the first test failure instead of masking it.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Update the tracker from verified evidence**
|
||||||
|
|
||||||
|
At the top of `docs/pc-api-page-integration-tracker-2026-07-09.md`, replace the active base-address line with:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
接口基础地址:`http://182.61.18.23:8080`
|
||||||
|
```
|
||||||
|
|
||||||
|
Add this section immediately after the introductory historical-record lines:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Current Endpoint Contract
|
||||||
|
|
||||||
|
- Runtime owner: `config.js`.
|
||||||
|
- Current development and production address: `http://182.61.18.23:8080`.
|
||||||
|
- Address change record: on 2026-07-11 the active address changed from the historical test domain to this IP address and port. Historical references to `test-genealogy-api.ddxcjp.cn` do not describe the current runtime configuration.
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace the YAML-analysis item that says the project currently uses the test domain with:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
2. `servers` 仍是本地地址示例;当前运行时基础地址以 `config.js` 为准,为 `http://182.61.18.23:8080`。
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace the PC-010 row with:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
| PC-010 | 已复核(当前地址已同步) | `config.js`、`tests/config.test.js`、`utils/ApiClient.js` | API 基础地址 | 当前开发和生产地址均为 `http://182.61.18.23:8080`;地址唯一运行时来源为 `config.js`,`tests/config.test.js` 已同步断言。 |
|
||||||
|
```
|
||||||
|
|
||||||
|
After Steps 1 and 2 pass, run `Get-Date -Format "yyyy-MM-dd HH:mm:ss K"` and insert its output as the `完成时间` line immediately after the `状态` line in this record. Append the rest of this record after the existing PC entries:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## PC-025 注册、登录到个人资料闭环
|
||||||
|
|
||||||
|
- 状态:已完成
|
||||||
|
- 规划文件:`docs/superpowers/specs/2026-07-11-auth-to-profile-flow-design.md`
|
||||||
|
- 页面范围:`register.html`、`login.html`、`profile.html`、`profile-data.html`
|
||||||
|
- 接口范围:`/genealogy/pc/auth/register`、`/genealogy/pc/auth/login`、`/genealogy/pc/auth/login/sms`、`/genealogy/pc/auth/profile`、`/genealogy/pc/auth/logout`
|
||||||
|
- 地址契约:运行时唯一来源为 `config.js`;当前开发和生产地址均为 `http://182.61.18.23:8080`。
|
||||||
|
- 流程结果:注册成功清除 token 并跳转 `login.html`;密码和短信登录必须取得 token 后跳转 `profile.html`;个人资料无 token 或收到 HTTP/业务 `401` 时清 token 并跳转 `index.html`;确认退出无论接口结果都清 token 并跳转 `index.html`。
|
||||||
|
- 修改文件:`tests/config.test.js`、`utils/ApiClient.js`、`tests/api-client.test.js`、`public/js/profile-pages.js`、`public/js/profile-common.js`、`profile.html`、`tests/profile-pages.test.js`、`tests/profile-logout-structure.test.js`。
|
||||||
|
- 验证结果:`node tests/config.test.js`、`node tests/api-client.test.js`、`node tests/auth-pages.test.js`、`node tests/profile-pages.test.js`、`node tests/profile-logout-structure.test.js`、三个 `node --check` 命令和全量 Node 测试均通过。
|
||||||
|
```
|
||||||
|
|
||||||
|
Change the spec status body to:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
Approved for implementation.
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Check final whitespace and commit the record**
|
||||||
|
|
||||||
|
Run: `git diff --check`
|
||||||
|
|
||||||
|
Expected: exit code `0`; pre-existing CRLF conversion warnings are not whitespace errors.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git add -- docs/pc-api-page-integration-tracker-2026-07-09.md docs/superpowers/specs/2026-07-11-auth-to-profile-flow-design.md
|
||||||
|
git commit -m "docs: record auth profile flow"
|
||||||
|
```
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
Pending written-spec review.
|
Approved for implementation.
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user