feat: add better authentication features and organization management
- Introduced new database migration for enhanced user and organization management. - Updated package dependencies to include new Better Auth modules for API keys, Expo, and i18n. - Implemented SMS functionality for phone verification and password resets. - Enhanced authentication plugins with username and phone number support. - Added performance configuration options for session cookie caching and API key updates. - Updated email templates to include organization invitation messages. - Improved testing coverage for new features and configurations.
This commit is contained in:
775
docs/superpowers/plans/2026-06-11-better-auth-performance.md
Normal file
775
docs/superpowers/plans/2026-06-11-better-auth-performance.md
Normal file
@@ -0,0 +1,775 @@
|
||||
# Better Auth 接口响应时间优化实现计划
|
||||
|
||||
> **给 agent 执行者:** 必选子技能:使用 `superpowers:subagent-driven-development`(推荐)或 `superpowers:executing-plans` 按任务逐项实现本计划。步骤统一使用 checkbox(`- [ ]`)语法跟踪。
|
||||
|
||||
**目标:** 为 `cfw-auth` 的 Better Auth 热路径加入低风险性能配置和安全的请求耗时观测。
|
||||
|
||||
**方案概览:** 先抽出性能配置解析函数,再把 session cookie cache 和 API key `deferUpdates` 接入 Better Auth 配置。随后在 Worker 入口增加不改写响应的结构化观测包装,补测试和运维文档,最后验证 migration、typecheck、测试全部通过。
|
||||
|
||||
**技术栈:** Cloudflare Workers、Hono、Better Auth、D1、TypeScript、Vitest、Wrangler
|
||||
|
||||
---
|
||||
|
||||
## 文件结构
|
||||
|
||||
- 新建:`src/performance.ts`
|
||||
- 负责解析性能相关 env:session cookie cache TTL、API key defer 开关。
|
||||
- 不依赖 Better Auth、Hono 或 Worker 请求对象,便于单元测试。
|
||||
|
||||
- 新建:`src/observability.ts`
|
||||
- 负责 `/api/auth/*` 请求的耗时观测。
|
||||
- 提供 `withAuthRequestLogging(request, handler)`,只包装 Response,不读取请求体,不记录敏感 header。
|
||||
|
||||
- 修改:`src/env.ts`
|
||||
- 在 `Env` 接口中加入 `BETTER_AUTH_SESSION_COOKIE_CACHE_MAX_AGE` 和 `API_KEY_DEFER_UPDATES`。
|
||||
|
||||
- 修改:`src/auth.ts`
|
||||
- 使用 `authPerformanceConfig(env)` 设置 Better Auth `session.cookieCache`。
|
||||
- 继续保留现有 `advanced.backgroundTasks.handler`。
|
||||
|
||||
- 修改:`src/plugins.ts`
|
||||
- 使用 `authPerformanceConfig(env).apiKeyDeferUpdates` 为两个 `apiKey` config 设置 `deferUpdates`。
|
||||
|
||||
- 修改:`src/index.ts`
|
||||
- 在 `/api/auth/*` handler 中使用 `withAuthRequestLogging(...)` 包裹 Better Auth handler。
|
||||
|
||||
- 修改:`wrangler.jsonc`
|
||||
- 增加非 secret 默认变量。
|
||||
- 增加 Cloudflare `observability` 配置。
|
||||
- 不强制增加 `placement.mode = "smart"`。
|
||||
|
||||
- 修改:`tests/auth-config.test.ts`
|
||||
- 覆盖性能配置解析、Better Auth session cookie cache、API key defer 开关。
|
||||
|
||||
- 修改:`tests/auth-worker.test.ts`
|
||||
- 覆盖观测日志字段、敏感字段过滤、响应不被改写。
|
||||
|
||||
- 修改:`docs/auth-operations.md`
|
||||
- 记录性能配置、观测、生产验证和后续 Smart Placement 决策门槛。
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 当前工作树已经有账号中心插件相关未提交改动。执行本计划时不要回退那些改动。
|
||||
- 性能配置不应改变 Better Auth schema;`pnpm db:check` 应保持 migration up to date。
|
||||
- Better Auth 1.6.x 的 `session.cookieCache` 支持 `enabled` 和 `maxAge`。不要启用 `refreshCache`,它更适合 stateless/DB-less 场景。
|
||||
- `@better-auth/api-key` 的 `deferUpdates` 要求主 Better Auth 配置存在 `advanced.backgroundTasks.handler`。当前 `src/auth.ts` 已通过 Worker `waitUntil` 提供该 handler。
|
||||
|
||||
### 任务 1:抽出性能配置解析
|
||||
|
||||
**文件:**
|
||||
- 新建:`src/performance.ts`
|
||||
- 修改:`src/env.ts`
|
||||
- 测试:`tests/auth-config.test.ts`
|
||||
|
||||
- [ ] **步骤 1:先写失败测试**
|
||||
|
||||
在 `tests/auth-config.test.ts` 的 import 中加入:
|
||||
|
||||
```ts
|
||||
import { authPerformanceConfig } from "../src/performance";
|
||||
```
|
||||
|
||||
在 `auth env helpers` describe 后追加:
|
||||
|
||||
```ts
|
||||
describe("auth performance config", () => {
|
||||
it("uses conservative defaults", () => {
|
||||
expect(authPerformanceConfig(env)).toEqual({
|
||||
sessionCookieCacheMaxAge: 300,
|
||||
apiKeyDeferUpdates: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("parses session cookie cache max age from env", () => {
|
||||
expect(
|
||||
authPerformanceConfig({
|
||||
...env,
|
||||
BETTER_AUTH_SESSION_COOKIE_CACHE_MAX_AGE: "60",
|
||||
}).sessionCookieCacheMaxAge,
|
||||
).toBe(60);
|
||||
});
|
||||
|
||||
it("falls back for invalid session cookie cache max age", () => {
|
||||
expect(
|
||||
authPerformanceConfig({
|
||||
...env,
|
||||
BETTER_AUTH_SESSION_COOKIE_CACHE_MAX_AGE: "0",
|
||||
}).sessionCookieCacheMaxAge,
|
||||
).toBe(300);
|
||||
expect(
|
||||
authPerformanceConfig({
|
||||
...env,
|
||||
BETTER_AUTH_SESSION_COOKIE_CACHE_MAX_AGE: "not-a-number",
|
||||
}).sessionCookieCacheMaxAge,
|
||||
).toBe(300);
|
||||
});
|
||||
|
||||
it("allows disabling api key deferred updates", () => {
|
||||
expect(authPerformanceConfig({ ...env, API_KEY_DEFER_UPDATES: "false" })).toMatchObject({
|
||||
apiKeyDeferUpdates: false,
|
||||
});
|
||||
expect(authPerformanceConfig({ ...env, API_KEY_DEFER_UPDATES: "true" })).toMatchObject({
|
||||
apiKeyDeferUpdates: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:运行测试,确认它先失败**
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
pnpm vitest run tests/auth-config.test.ts
|
||||
```
|
||||
|
||||
预期:FAIL,错误包含 `Failed to resolve import "../src/performance"` 或 `Cannot find module '../src/performance'`。
|
||||
|
||||
- [ ] **步骤 3:编写最小实现**
|
||||
|
||||
在 `src/env.ts` 的 `Env` interface 中加入:
|
||||
|
||||
```ts
|
||||
BETTER_AUTH_SESSION_COOKIE_CACHE_MAX_AGE?: string;
|
||||
API_KEY_DEFER_UPDATES?: string;
|
||||
```
|
||||
|
||||
新建 `src/performance.ts`:
|
||||
|
||||
```ts
|
||||
import { type Env } from "./env";
|
||||
|
||||
export interface AuthPerformanceConfig {
|
||||
sessionCookieCacheMaxAge: number;
|
||||
apiKeyDeferUpdates: boolean;
|
||||
}
|
||||
|
||||
const defaultSessionCookieCacheMaxAge = 300;
|
||||
|
||||
export function authPerformanceConfig(env: Env): AuthPerformanceConfig {
|
||||
return {
|
||||
sessionCookieCacheMaxAge: positiveIntegerEnv(
|
||||
env.BETTER_AUTH_SESSION_COOKIE_CACHE_MAX_AGE,
|
||||
defaultSessionCookieCacheMaxAge,
|
||||
),
|
||||
apiKeyDeferUpdates: env.API_KEY_DEFER_UPDATES !== "false",
|
||||
};
|
||||
}
|
||||
|
||||
function positiveIntegerEnv(value: string | undefined, fallback: number): number {
|
||||
if (!value) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
const parsed = Number(value);
|
||||
if (!Number.isInteger(parsed) || parsed <= 0) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **步骤 4:再次运行测试,确认通过**
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
pnpm vitest run tests/auth-config.test.ts
|
||||
```
|
||||
|
||||
预期:PASS。
|
||||
|
||||
- [ ] **步骤 5:提交**
|
||||
|
||||
```bash
|
||||
git add src/env.ts src/performance.ts tests/auth-config.test.ts
|
||||
git commit -m "feat: add auth performance config"
|
||||
```
|
||||
|
||||
### 任务 2:接入 session cookie cache
|
||||
|
||||
**文件:**
|
||||
- 修改:`src/auth.ts`
|
||||
- 测试:`tests/auth-config.test.ts`
|
||||
|
||||
- [ ] **步骤 1:先写失败测试**
|
||||
|
||||
在 `tests/auth-config.test.ts` 顶部加入:
|
||||
|
||||
```ts
|
||||
import { createAuth } from "../src/auth";
|
||||
```
|
||||
|
||||
在 `auth plugins` describe 后追加:
|
||||
|
||||
```ts
|
||||
describe("auth runtime performance options", () => {
|
||||
it("enables session cookie cache with configured max age", () => {
|
||||
const auth = createAuth({
|
||||
BETTER_AUTH_URL: "http://localhost:8788",
|
||||
TRUSTED_ORIGINS: "http://localhost:8787",
|
||||
BETTER_AUTH_SESSION_COOKIE_CACHE_MAX_AGE: "60",
|
||||
});
|
||||
|
||||
expect(auth.options.session?.cookieCache).toEqual({
|
||||
enabled: true,
|
||||
maxAge: 60,
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:运行测试,确认它先失败**
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
pnpm vitest run tests/auth-config.test.ts
|
||||
```
|
||||
|
||||
预期:FAIL,断言显示 `auth.options.session?.cookieCache` 为 `undefined`。
|
||||
|
||||
- [ ] **步骤 3:编写最小实现**
|
||||
|
||||
在 `src/auth.ts` 中加入 import:
|
||||
|
||||
```ts
|
||||
import { authPerformanceConfig } from "./performance";
|
||||
```
|
||||
|
||||
在 `createAuth` 函数开头加入:
|
||||
|
||||
```ts
|
||||
const performance = authPerformanceConfig(env);
|
||||
```
|
||||
|
||||
在 `betterAuth({ ... })` 配置中,放在 `trustedOrigins` 后面加入:
|
||||
|
||||
```ts
|
||||
session: {
|
||||
cookieCache: {
|
||||
enabled: true,
|
||||
maxAge: performance.sessionCookieCacheMaxAge,
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
完整目标形状:
|
||||
|
||||
```ts
|
||||
export function createAuth(env: Env, runtime: AuthRuntime = {}) {
|
||||
const performance = authPerformanceConfig(env);
|
||||
|
||||
return betterAuth({
|
||||
database: env.DB,
|
||||
secret: env.BETTER_AUTH_SECRET ?? "development-secret-change-before-production",
|
||||
baseURL: env.BETTER_AUTH_URL,
|
||||
trustedOrigins: trustedOrigins(env),
|
||||
session: {
|
||||
cookieCache: {
|
||||
enabled: true,
|
||||
maxAge: performance.sessionCookieCacheMaxAge,
|
||||
},
|
||||
},
|
||||
socialProviders: createSocialProviders(env),
|
||||
// keep existing options unchanged
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **步骤 4:再次运行测试,确认通过**
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
pnpm vitest run tests/auth-config.test.ts
|
||||
```
|
||||
|
||||
预期:PASS。
|
||||
|
||||
- [ ] **步骤 5:确认 migration 没有被性能配置影响**
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
pnpm db:check
|
||||
```
|
||||
|
||||
预期:PASS,并输出 committed migration is up to date。
|
||||
|
||||
- [ ] **步骤 6:提交**
|
||||
|
||||
```bash
|
||||
git add src/auth.ts tests/auth-config.test.ts
|
||||
git commit -m "feat: enable auth session cookie cache"
|
||||
```
|
||||
|
||||
### 任务 3:接入 API key 延迟更新开关
|
||||
|
||||
**文件:**
|
||||
- 修改:`src/plugins.ts`
|
||||
- 测试:`tests/auth-config.test.ts`
|
||||
|
||||
- [ ] **步骤 1:先写失败测试**
|
||||
|
||||
在 `tests/auth-config.test.ts` 的 `auth plugins` describe 中追加:
|
||||
|
||||
```ts
|
||||
it("enables api key deferred updates by default", () => {
|
||||
const plugins = createAuthPlugins({
|
||||
BETTER_AUTH_URL: "http://localhost:8788",
|
||||
TRUSTED_ORIGINS: "http://localhost:8787",
|
||||
});
|
||||
const apiKeyPlugin = plugins.find((plugin) => plugin.id === "api-key");
|
||||
|
||||
expect(apiKeyPlugin?.options).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
configId: "default",
|
||||
deferUpdates: true,
|
||||
}),
|
||||
expect.objectContaining({
|
||||
configId: "organization",
|
||||
deferUpdates: true,
|
||||
}),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("allows disabling api key deferred updates", () => {
|
||||
const plugins = createAuthPlugins({
|
||||
BETTER_AUTH_URL: "http://localhost:8788",
|
||||
TRUSTED_ORIGINS: "http://localhost:8787",
|
||||
API_KEY_DEFER_UPDATES: "false",
|
||||
});
|
||||
const apiKeyPlugin = plugins.find((plugin) => plugin.id === "api-key");
|
||||
|
||||
expect(apiKeyPlugin?.options).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
configId: "default",
|
||||
deferUpdates: false,
|
||||
}),
|
||||
expect.objectContaining({
|
||||
configId: "organization",
|
||||
deferUpdates: false,
|
||||
}),
|
||||
]),
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:运行测试,确认它先失败**
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
pnpm vitest run tests/auth-config.test.ts
|
||||
```
|
||||
|
||||
预期:FAIL,`deferUpdates` 为 `undefined`。
|
||||
|
||||
- [ ] **步骤 3:编写最小实现**
|
||||
|
||||
在 `src/plugins.ts` 中加入 import:
|
||||
|
||||
```ts
|
||||
import { authPerformanceConfig } from "./performance";
|
||||
```
|
||||
|
||||
在 `createAuthPlugins` 函数开头加入:
|
||||
|
||||
```ts
|
||||
const performance = authPerformanceConfig(env);
|
||||
```
|
||||
|
||||
在两个 `apiKey` 配置对象中都加入:
|
||||
|
||||
```ts
|
||||
deferUpdates: performance.apiKeyDeferUpdates,
|
||||
```
|
||||
|
||||
目标形状示例:
|
||||
|
||||
```ts
|
||||
{
|
||||
configId: "default",
|
||||
defaultPrefix: "cfw_",
|
||||
requireName: true,
|
||||
enableMetadata: true,
|
||||
deferUpdates: performance.apiKeyDeferUpdates,
|
||||
rateLimit: {
|
||||
enabled: true,
|
||||
timeWindow: 1_000 * 60 * 60 * 24,
|
||||
maxRequests: 1_000,
|
||||
},
|
||||
},
|
||||
```
|
||||
|
||||
- [ ] **步骤 4:再次运行测试,确认通过**
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
pnpm vitest run tests/auth-config.test.ts
|
||||
```
|
||||
|
||||
预期:PASS。
|
||||
|
||||
- [ ] **步骤 5:提交**
|
||||
|
||||
```bash
|
||||
git add src/plugins.ts tests/auth-config.test.ts
|
||||
git commit -m "feat: defer api key counter updates"
|
||||
```
|
||||
|
||||
### 任务 4:新增认证请求观测包装
|
||||
|
||||
**文件:**
|
||||
- 新建:`src/observability.ts`
|
||||
- 修改:`src/index.ts`
|
||||
- 测试:`tests/auth-worker.test.ts`
|
||||
|
||||
- [ ] **步骤 1:先写失败测试**
|
||||
|
||||
在 `tests/auth-worker.test.ts` import 中改为:
|
||||
|
||||
```ts
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
```
|
||||
|
||||
在 `const env` 后加入:
|
||||
|
||||
```ts
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
```
|
||||
|
||||
在 `cfw-auth worker` describe 中追加:
|
||||
|
||||
```ts
|
||||
it("logs auth request timing without changing the response", async () => {
|
||||
const log = vi.spyOn(console, "log").mockImplementation(() => {});
|
||||
|
||||
const response = await worker.fetch(
|
||||
new Request("http://auth.local/api/auth/reference", {
|
||||
headers: {
|
||||
"cf-ray": "test-ray",
|
||||
Authorization: "Bearer secret-token",
|
||||
Cookie: "better-auth.session_token=secret-cookie",
|
||||
},
|
||||
}),
|
||||
env,
|
||||
);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.headers.get("content-type") ?? "").toContain("text/html");
|
||||
expect(log).toHaveBeenCalledTimes(1);
|
||||
|
||||
const [rawMessage] = log.mock.calls[0] ?? [];
|
||||
expect(typeof rawMessage).toBe("string");
|
||||
const message = String(rawMessage);
|
||||
const event = JSON.parse(message) as Record<string, unknown>;
|
||||
|
||||
expect(event).toMatchObject({
|
||||
event: "auth_request",
|
||||
method: "GET",
|
||||
path: "/api/auth/reference",
|
||||
status: 200,
|
||||
cfRay: "test-ray",
|
||||
});
|
||||
expect(typeof event.durationMs).toBe("number");
|
||||
expect(message).not.toContain("secret-token");
|
||||
expect(message).not.toContain("secret-cookie");
|
||||
expect(message.toLowerCase()).not.toContain("authorization");
|
||||
expect(message.toLowerCase()).not.toContain("cookie");
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:运行测试,确认它先失败**
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
pnpm vitest run tests/auth-worker.test.ts
|
||||
```
|
||||
|
||||
预期:FAIL,`console.log` 没有被调用。
|
||||
|
||||
- [ ] **步骤 3:编写最小实现**
|
||||
|
||||
新建 `src/observability.ts`:
|
||||
|
||||
```ts
|
||||
export type AuthRequestHandler = () => Response | Promise<Response>;
|
||||
|
||||
export async function withAuthRequestLogging(
|
||||
request: Request,
|
||||
handler: AuthRequestHandler,
|
||||
): Promise<Response> {
|
||||
const startedAt = Date.now();
|
||||
let response: Response;
|
||||
|
||||
try {
|
||||
response = await handler();
|
||||
return response;
|
||||
} finally {
|
||||
const status = response?.status ?? 500;
|
||||
logAuthRequest(request, status, Date.now() - startedAt);
|
||||
}
|
||||
}
|
||||
|
||||
function logAuthRequest(request: Request, status: number, durationMs: number): void {
|
||||
try {
|
||||
const event = {
|
||||
event: "auth_request",
|
||||
method: request.method,
|
||||
path: new URL(request.url).pathname,
|
||||
status,
|
||||
durationMs,
|
||||
colo: request.cf?.colo,
|
||||
cfRay: request.headers.get("cf-ray") ?? undefined,
|
||||
};
|
||||
|
||||
console.log(JSON.stringify(event));
|
||||
} catch {
|
||||
// Observability must not affect auth responses.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
修改 `src/index.ts`,加入 import:
|
||||
|
||||
```ts
|
||||
import { withAuthRequestLogging } from "./observability";
|
||||
```
|
||||
|
||||
把现有 auth handler:
|
||||
|
||||
```ts
|
||||
app.on(["POST", "GET"], "/api/auth/*", (c) => {
|
||||
const auth = createAuth(c.env, {
|
||||
waitUntil: (promise) => {
|
||||
c.executionCtx.waitUntil(promise);
|
||||
},
|
||||
});
|
||||
return auth.handler(c.req.raw);
|
||||
});
|
||||
```
|
||||
|
||||
改成:
|
||||
|
||||
```ts
|
||||
app.on(["POST", "GET"], "/api/auth/*", (c) => {
|
||||
const auth = createAuth(c.env, {
|
||||
waitUntil: (promise) => {
|
||||
c.executionCtx.waitUntil(promise);
|
||||
},
|
||||
});
|
||||
return withAuthRequestLogging(c.req.raw, () => auth.handler(c.req.raw));
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **步骤 4:再次运行测试,确认通过**
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
pnpm vitest run tests/auth-worker.test.ts
|
||||
```
|
||||
|
||||
预期:PASS。
|
||||
|
||||
- [ ] **步骤 5:提交**
|
||||
|
||||
```bash
|
||||
git add src/index.ts src/observability.ts tests/auth-worker.test.ts
|
||||
git commit -m "feat: log auth request latency"
|
||||
```
|
||||
|
||||
### 任务 5:补充 Wrangler 和运维文档
|
||||
|
||||
**文件:**
|
||||
- 修改:`wrangler.jsonc`
|
||||
- 修改:`docs/auth-operations.md`
|
||||
|
||||
- [ ] **步骤 1:更新 Wrangler 配置**
|
||||
|
||||
在 `wrangler.jsonc` 的 `vars` 中加入:
|
||||
|
||||
```jsonc
|
||||
"BETTER_AUTH_SESSION_COOKIE_CACHE_MAX_AGE": "300",
|
||||
"API_KEY_DEFER_UPDATES": "true"
|
||||
```
|
||||
|
||||
在顶层加入:
|
||||
|
||||
```jsonc
|
||||
"observability": {
|
||||
"enabled": true,
|
||||
"head_sampling_rate": 0.1
|
||||
},
|
||||
```
|
||||
|
||||
目标结构示例:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"$schema": "node_modules/wrangler/config-schema.json",
|
||||
"name": "cfw-auth",
|
||||
"main": "src/index.ts",
|
||||
"compatibility_date": "2026-06-10",
|
||||
"compatibility_flags": [
|
||||
"nodejs_compat"
|
||||
],
|
||||
"observability": {
|
||||
"enabled": true,
|
||||
"head_sampling_rate": 0.1
|
||||
},
|
||||
"vars": {
|
||||
"BETTER_AUTH_URL": "http://localhost:8788",
|
||||
"TRUSTED_ORIGINS": "http://localhost:8787",
|
||||
"MAIL_PROVIDER": "resend",
|
||||
"MAIL_FROM": "noreply@example.com",
|
||||
"CAPTCHA_PROVIDER": "cloudflare-turnstile",
|
||||
"BETTER_AUTH_SESSION_COOKIE_CACHE_MAX_AGE": "300",
|
||||
"API_KEY_DEFER_UPDATES": "true"
|
||||
},
|
||||
"d1_databases": [
|
||||
{
|
||||
"binding": "DB",
|
||||
"database_name": "cfw-auth",
|
||||
"database_id": "90fe25a4-9d22-43a6-9ade-3a15afc3ab47"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **步骤 2:更新运维文档**
|
||||
|
||||
在 `docs/auth-operations.md` 的 `Configuration` 小节中,追加:
|
||||
|
||||
```md
|
||||
Performance-related non-secret defaults live in `wrangler.jsonc`:
|
||||
|
||||
- `BETTER_AUTH_SESSION_COOKIE_CACHE_MAX_AGE`: Better Auth session cookie cache TTL in seconds. Default is `300`. Lower it if session revocation or role changes must propagate faster.
|
||||
- `API_KEY_DEFER_UPDATES`: When `true`, API key request counters and timestamps are deferred through Better Auth background tasks and Worker `waitUntil`.
|
||||
|
||||
Auth request latency is logged as structured JSON with:
|
||||
|
||||
- `event=auth_request`
|
||||
- `method`
|
||||
- `path`
|
||||
- `status`
|
||||
- `durationMs`
|
||||
- optional `colo`
|
||||
- optional `cfRay`
|
||||
|
||||
Do not log request bodies, cookies, authorization headers, API keys, emails, phone numbers, or OTP codes.
|
||||
```
|
||||
|
||||
在 `Deployment` 小节后追加:
|
||||
|
||||
```md
|
||||
## Performance Validation
|
||||
|
||||
After deployment, compare p50, p95, and p99 for:
|
||||
|
||||
- `/api/auth/get-session`
|
||||
- `/api/auth/api-key/verify`
|
||||
- phone OTP endpoints
|
||||
- organization invitation endpoints
|
||||
|
||||
Enable Cloudflare Smart Placement only after logs show that latency is dominated by D1 or external provider round trips. Evaluate D1 read replication or secondary storage only after the first-stage cache and deferred-update changes are measured in production.
|
||||
```
|
||||
|
||||
- [ ] **步骤 3:验证配置 schema 和文档改动**
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
pnpm typecheck
|
||||
```
|
||||
|
||||
预期:PASS。
|
||||
|
||||
- [ ] **步骤 4:提交**
|
||||
|
||||
```bash
|
||||
git add wrangler.jsonc docs/auth-operations.md
|
||||
git commit -m "docs: document auth performance operations"
|
||||
```
|
||||
|
||||
### 任务 6:全量验证和最终提交检查
|
||||
|
||||
**文件:**
|
||||
- 修改:无新文件,验证全项目状态。
|
||||
|
||||
- [ ] **步骤 1:运行 migration 检查**
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
pnpm db:check
|
||||
```
|
||||
|
||||
预期:PASS,并显示 migration up to date。若失败且 diff 只来自性能配置,说明实现错误;性能配置不应影响 schema。
|
||||
|
||||
- [ ] **步骤 2:运行类型检查**
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
pnpm typecheck
|
||||
```
|
||||
|
||||
预期:PASS。
|
||||
|
||||
- [ ] **步骤 3:运行测试**
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
pnpm test
|
||||
```
|
||||
|
||||
预期:PASS。
|
||||
|
||||
- [ ] **步骤 4:查看最终 diff**
|
||||
|
||||
运行:
|
||||
|
||||
```bash
|
||||
git status --short
|
||||
git diff -- src/performance.ts src/observability.ts src/env.ts src/auth.ts src/plugins.ts src/index.ts tests/auth-config.test.ts tests/auth-worker.test.ts wrangler.jsonc docs/auth-operations.md
|
||||
```
|
||||
|
||||
预期:只看到本计划相关文件改动。不要回退或改动当前工作树里的其它账号中心文件。
|
||||
|
||||
- [ ] **步骤 5:提交最终验证记录**
|
||||
|
||||
如果前面每个任务都已提交,且这一步没有新增文件改动,则不需要创建空提交。若本任务中修正了测试或文档小问题,则提交:
|
||||
|
||||
```bash
|
||||
git add src/performance.ts src/observability.ts src/env.ts src/auth.ts src/plugins.ts src/index.ts tests/auth-config.test.ts tests/auth-worker.test.ts wrangler.jsonc docs/auth-operations.md
|
||||
git commit -m "test: verify auth performance optimization"
|
||||
```
|
||||
|
||||
## Spec 覆盖自检
|
||||
|
||||
- session cookie cache:任务 1、任务 2 覆盖。
|
||||
- API key `deferUpdates`:任务 1、任务 3 覆盖。
|
||||
- `/api/auth/*` 结构化耗时日志:任务 4 覆盖。
|
||||
- 敏感字段不记录:任务 4 覆盖。
|
||||
- 配置可关闭或调低:任务 1、任务 3、任务 5 覆盖。
|
||||
- 不改变迁移:任务 2、任务 6 覆盖。
|
||||
- 运维与生产验证说明:任务 5 覆盖。
|
||||
|
||||
## 计划自检结论
|
||||
|
||||
- 无未完成标记或空白段落。
|
||||
- 每个代码改动任务都有先失败测试、最小实现、验证命令和提交步骤。
|
||||
- 类型、函数名和配置名在所有任务中保持一致。
|
||||
- 计划只覆盖第一阶段低风险性能优化,没有混入存储层重构或 Smart Placement 强制启用。
|
||||
Reference in New Issue
Block a user