31 KiB
RESTful API 重构实现计划
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: 将后端 HTTP API 改造为完全符合 RESTful 规范,同步更新前端适配代码,并添加路由文档。
Architecture:
- 后端:重命名路由 URL,简化响应模型,profile 模块重命名为 users
- 前端:更新 API 调用路径,简化响应模型
- 文档:新增路由文档,更新 AGENTS.md 规则
Tech Stack: FastAPI, Pydantic, Flutter, Dart
Phase 1: 后端 Schema 重构
Task 1: 重命名和简化 Auth Schema
Files:
- Modify:
backend/src/v1/auth/schemas.py
Step 1: 更新 schema 文件
将现有 schema 重命名并简化:
from __future__ import annotations
from typing import Literal
from pydantic import BaseModel, EmailStr, Field
class VerificationCreateRequest(BaseModel):
username: str = Field(min_length=3, max_length=30)
email: EmailStr
password: str = Field(min_length=6)
redirect_to: str | None = None
class VerificationResendRequest(BaseModel):
email: EmailStr
class VerificationVerifyRequest(BaseModel):
email: EmailStr
token: str = Field(pattern=r"^\d{6}$")
class SessionCreateRequest(BaseModel):
email: EmailStr
password: str = Field(min_length=6)
class SessionRefreshRequest(BaseModel):
refresh_token: str = Field(min_length=1)
class SessionDeleteRequest(BaseModel):
refresh_token: str = Field(min_length=1)
class AuthUser(BaseModel):
id: str
email: EmailStr
class SessionResponse(BaseModel):
access_token: str
refresh_token: str
expires_in: int
token_type: str
user: AuthUser
class UserByEmailResponse(BaseModel):
id: str
email: EmailStr
created_at: str
email_confirmed_at: str | None = None
class VerificationCreateResponse(BaseModel):
email: EmailStr
class PasswordResetRequest(BaseModel):
email: EmailStr
redirect_to: str | None = None
class PasswordResetResponse(BaseModel):
message: str = "Password reset email sent"
Step 2: 验证类型检查
Run: cd backend && uv run basedpyright src/v1/auth/schemas.py
Expected: No errors
Step 3: Commit
git add backend/src/v1/auth/schemas.py
git commit -m "refactor(auth): rename and simplify auth schemas for RESTful API"
Task 2: 创建 Users Schema
Files:
- Create:
backend/src/v1/users/schemas.py
Step 1: 创建 users schema 文件
from __future__ import annotations
from pydantic import (
AnyHttpUrl,
BaseModel,
ConfigDict,
Field,
field_validator,
model_validator,
)
class UserResponse(BaseModel):
id: str
username: str
avatar_url: str | None = None
bio: str | None = None
class UserUpdateRequest(BaseModel):
model_config = ConfigDict(extra="forbid")
username: str | None = Field(default=None, min_length=3, max_length=30)
avatar_url: str | None = Field(default=None)
bio: str | None = Field(default=None, max_length=200)
@field_validator("avatar_url", mode="before")
@classmethod
def validate_avatar_url(cls, v: str | None) -> str | None:
if v is None:
return None
parsed = AnyHttpUrl(v)
if parsed.scheme not in ("http", "https"):
raise ValueError("avatar_url must use http or https scheme")
return str(parsed)
@model_validator(mode="after")
def require_one_field(self) -> "UserUpdateRequest":
if self.username is None and self.avatar_url is None and self.bio is None:
raise ValueError("At least one field must be provided")
return self
Step 2: 验证类型检查
Run: cd backend && uv run basedpyright src/v1/users/schemas.py
Expected: No errors
Step 3: Commit
git add backend/src/v1/users/schemas.py
git commit -m "feat(users): create users schemas"
Task 3: 创建 Users 模块基础文件
Files:
- Create:
backend/src/v1/users/__init__.py - Create:
backend/src/v1/users/dependencies.py - Move:
backend/src/v1/profile/repository.py→backend/src/v1/users/repository.py - Move:
backend/src/v1/profile/service.py→backend/src/v1/users/service.py
Step 1: 创建 __init__.py
from __future__ import annotations
Step 2: 创建 dependencies.py
from __future__ import annotations
from typing import Annotated
from fastapi import Depends
from core.auth.models import CurrentUser
from core.db import get_db
from v1.auth.dependencies import get_current_user
from v1.users.repository import UserRepository
from v1.users.service import UserService
async def get_user_repository(
db=Depends(get_db),
) -> UserRepository:
return UserRepository(db)
async def get_user_service(
repo: Annotated[UserRepository, Depends(get_user_repository)],
current_user: Annotated[CurrentUser, Depends(get_current_user)],
) -> UserService:
return UserService(repo, current_user)
Step 3: 移动并更新 repository.py
复制 v1/profile/repository.py 到 v1/users/repository.py,无需修改内容。
Step 4: 移动并更新 service.py
复制 v1/profile/service.py 到 v1/users/service.py,更新导入:
from v1.users.schemas import UserResponse, UserUpdateRequest
Step 5: 验证类型检查
Run: cd backend && uv run basedpyright src/v1/users/
Expected: No errors
Step 4: Commit
git add backend/src/v1/users/
git commit -m "feat(users): create users module from profile"
Phase 2: 后端路由重构
Task 4: 重构 Auth Router
Files:
- Modify:
backend/src/v1/auth/router.py
Step 1: 更新路由定义
from __future__ import annotations
from typing import Annotated
from fastapi import APIRouter, Depends, Response
from fastapi import HTTPException
from core.auth.models import CurrentUser
from v1.auth.rate_limit import enforce_rate_limit
from v1.auth.dependencies import get_auth_service
from v1.users.dependencies import get_current_user
from v1.auth.schemas import (
VerificationCreateRequest,
VerificationCreateResponse,
VerificationResendRequest,
VerificationVerifyRequest,
SessionCreateRequest,
SessionDeleteRequest,
SessionRefreshRequest,
SessionResponse,
UserByEmailResponse,
)
from v1.auth.service import AuthService
router = APIRouter(prefix="/auth", tags=["auth"])
@router.post("/verifications", response_model=VerificationCreateResponse, status_code=202)
async def create_verification(
payload: VerificationCreateRequest,
service: AuthService = Depends(get_auth_service),
) -> VerificationCreateResponse:
await enforce_rate_limit(
scope="signup_start",
identifier=payload.email,
limit=5,
window_seconds=60,
)
return await service.create_verification(payload)
@router.post("/verifications/resend", status_code=204)
async def resend_verification(
payload: VerificationResendRequest,
service: AuthService = Depends(get_auth_service),
) -> Response:
await enforce_rate_limit(
scope="signup_resend",
identifier=payload.email,
limit=5,
window_seconds=60,
)
await service.resend_verification(payload)
return Response(status_code=204)
@router.post("/verifications/verify", response_model=SessionResponse)
async def verify_verification(
payload: VerificationVerifyRequest,
service: AuthService = Depends(get_auth_service),
) -> SessionResponse:
await enforce_rate_limit(
scope="signup_verify",
identifier=payload.email,
limit=10,
window_seconds=600,
)
return await service.verify_verification(payload)
@router.post("/sessions", response_model=SessionResponse)
async def create_session(
payload: SessionCreateRequest,
service: AuthService = Depends(get_auth_service),
) -> SessionResponse:
await enforce_rate_limit(
scope="login",
identifier=payload.email,
limit=10,
window_seconds=60,
)
return await service.create_session(payload)
@router.post("/sessions/refresh", response_model=SessionResponse)
async def refresh_session(
payload: SessionRefreshRequest,
service: AuthService = Depends(get_auth_service),
) -> SessionResponse:
await enforce_rate_limit(
scope="refresh",
identifier=payload.refresh_token,
limit=10,
window_seconds=60,
)
return await service.refresh_session(payload)
@router.delete("/sessions", status_code=204)
async def delete_session(
payload: SessionDeleteRequest,
service: AuthService = Depends(get_auth_service),
) -> Response:
await enforce_rate_limit(
scope="logout",
identifier=payload.refresh_token,
limit=10,
window_seconds=60,
)
await service.delete_session(payload.refresh_token)
return Response(status_code=204)
@router.get("/users", response_model=UserByEmailResponse)
async def get_user_by_email(
email: str,
current_user: Annotated[CurrentUser, Depends(get_current_user)],
service: AuthService = Depends(get_auth_service),
) -> UserByEmailResponse:
if current_user.role != "service_role" and current_user.email != email:
raise HTTPException(status_code=403, detail="Forbidden")
return await service.get_user_by_email(email)
Step 2: 验证类型检查
Run: cd backend && uv run basedpyright src/v1/auth/router.py
Expected: No errors
Step 3: Commit
git add backend/src/v1/auth/router.py
git commit -m "refactor(auth): rename routes to RESTful style"
Task 5: 重构 Auth Service
Files:
- Modify:
backend/src/v1/auth/service.py
Step 1: 更新 service 方法名和导入
更新导入和方法名以匹配新的 schema:
from v1.auth.schemas import (
VerificationCreateRequest,
VerificationCreateResponse,
VerificationResendRequest,
VerificationVerifyRequest,
SessionCreateRequest,
SessionDeleteRequest,
SessionRefreshRequest,
SessionResponse,
UserByEmailResponse,
)
将方法重命名:
signup_start→create_verificationsignup_resend→resend_verificationsignup_verify→verify_verificationlogin→create_sessionrefresh→refresh_sessionlogout→delete_session
create_verification 返回 VerificationCreateResponse(email=payload.email)。
Step 2: 验证类型检查
Run: cd backend && uv run basedpyright src/v1/auth/service.py
Expected: No errors
Step 3: Commit
git add backend/src/v1/auth/service.py
git commit -m "refactor(auth): rename service methods for RESTful API"
Task 6: 更新 Auth Gateway
Files:
- Modify:
backend/src/v1/auth/gateway.py
Step 1: 更新导入和方法调用
更新导入使用新 schema 名称,方法调用更新为新的 service 方法名。
Step 2: 验证类型检查
Run: cd backend && uv run basedpyright src/v1/auth/gateway.py
Expected: No errors
Step 3: Commit
git add backend/src/v1/auth/gateway.py
git commit -m "refactor(auth): update gateway for new service methods"
Task 7: 创建 Users Router
Files:
- Create:
backend/src/v1/users/router.py
Step 1: 创建 users router
from __future__ import annotations
from typing import Annotated
from fastapi import APIRouter, Depends, Path
from v1.users.dependencies import get_user_service
from v1.users.schemas import UserResponse, UserUpdateRequest
from v1.users.service import UserService
router = APIRouter(prefix="/users", tags=["users"])
@router.get("/me", response_model=UserResponse)
async def get_me(
service: Annotated[UserService, Depends(get_user_service)],
) -> UserResponse:
return await service.get_me()
@router.patch("/me", response_model=UserResponse)
async def update_me(
payload: UserUpdateRequest,
service: Annotated[UserService, Depends(get_user_service)],
) -> UserResponse:
return await service.update_me(payload)
@router.get("/{username}", response_model=UserResponse)
async def get_by_username(
username: Annotated[
str, Path(min_length=3, max_length=30, pattern="^[a-zA-Z0-9_]+$")
],
service: Annotated[UserService, Depends(get_user_service)],
) -> UserResponse:
return await service.get_by_username(username)
Step 2: 验证类型检查
Run: cd backend && uv run basedpyright src/v1/users/router.py
Expected: No errors
Step 3: Commit
git add backend/src/v1/users/router.py
git commit -m "feat(users): create users router"
Task 8: 更新 Agent Chat Router
Files:
- Modify:
backend/src/v1/agent_chat/router.py
Step 1: 更新 URL 路径
将 /run 改为根路径:
@router.post("", response_model=AgentChatRunResponse)
async def run_agent_chat(
payload: AgentChatRunRequest,
service: Annotated[AgentChatService, Depends(get_agent_chat_service)],
) -> AgentChatRunResponse:
return await service.run(payload)
Step 2: 验证类型检查
Run: cd backend && uv run basedpyright src/v1/agent_chat/router.py
Expected: No errors
Step 3: Commit
git add backend/src/v1/agent_chat/router.py
git commit -m "refactor(agent-chat): change route to RESTful style"
Task 9: 更新主路由注册
Files:
- Modify:
backend/src/v1/router.py
Step 1: 更新路由注册
from __future__ import annotations
from fastapi import APIRouter
from core.http.models import HealthResponse
from v1.agent_chat.router import router as agent_chat_router
from v1.auth.router import router as auth_router
from v1.infra.router import router as infra_router
from v1.users.router import router as users_router
router = APIRouter(prefix="/api/v1")
router.include_router(auth_router)
router.include_router(infra_router)
router.include_router(users_router)
router.include_router(agent_chat_router)
@router.get("/health", response_model=HealthResponse)
async def health() -> HealthResponse:
return HealthResponse(status="ok")
Step 2: 验证类型检查
Run: cd backend && uv run basedpyright src/v1/router.py
Expected: No errors
Step 3: Commit
git add backend/src/v1/router.py
git commit -m "refactor: register users router instead of profile"
Phase 3: 后端测试更新
Task 10: 更新 Auth 路由测试
Files:
- Modify:
backend/tests/integration/test_auth_routes.py
Step 1: 更新测试用例的 URL 和断言
/signup/start→/auth/verifications/signup/resend→/auth/verifications/resend/signup/verify→/auth/verifications/verify/login→/auth/sessions/refresh→/auth/sessions/refresh/logout→/auth/sessions/users/by-email→/auth/users?email=xxx
更新断言:
signup_start响应只包含email字段signup_resend响应为 204,无 body
Step 2: 运行测试验证
Run: cd backend && uv run pytest tests/integration/test_auth_routes.py -v
Expected: All tests pass
Step 3: Commit
git add backend/tests/integration/test_auth_routes.py
git commit -m "test(auth): update integration tests for RESTful routes"
Task 11: 创建 Users 路由测试
Files:
- Move:
backend/tests/integration/test_profile_routes.py→backend/tests/integration/test_users_routes.py
Step 1: 移动并更新测试文件
- 更新 URL:
/profile/me→/users/me,/profile/{username}→/users/{username} - 更新导入和断言
Step 2: 运行测试验证
Run: cd backend && uv run pytest tests/integration/test_users_routes.py -v
Expected: All tests pass
Step 3: Commit
git add backend/tests/integration/test_users_routes.py
git rm backend/tests/integration/test_profile_routes.py
git commit -m "test(users): rename profile tests to users"
Task 12: 运行完整测试套件
Step 1: 运行所有后端测试
Run: cd backend && uv run pytest -v
Expected: All tests pass
Step 2: 运行类型检查
Run: cd backend && uv run basedpyright src/
Expected: No errors
Step 3: 运行 lint
Run: cd backend && uv run ruff check src/
Expected: No errors
Phase 4: 前端适配
Task 13: 更新 Auth API
Files:
- Modify:
apps/lib/features/auth/data/auth_api.dart
Step 1: 更新 URL 路径
import 'package:social_app/core/api/api_client.dart';
import 'models/signup_request.dart';
import 'models/login_request.dart';
import 'models/auth_response.dart';
class AuthApi {
final ApiClient _client;
static const _prefix = '/api/v1/auth';
AuthApi(this._client);
Future<VerificationCreateResponse> createVerification(SignupStartRequest request) async {
final response = await _client.post(
'$_prefix/verifications',
data: request.toJson(),
);
return VerificationCreateResponse.fromJson(response.data);
}
Future<void> resendVerification(SignupResendRequest request) async {
await _client.post(
'$_prefix/verifications/resend',
data: request.toJson(),
);
}
Future<AuthResponse> verifyVerification(SignupVerifyRequest request) async {
final response = await _client.post(
'$_prefix/verifications/verify',
data: request.toJson(),
);
return AuthResponse.fromJson(response.data);
}
Future<AuthResponse> createSession(LoginRequest request) async {
final response = await _client.post(
'$_prefix/sessions',
data: request.toJson(),
);
return AuthResponse.fromJson(response.data);
}
Future<AuthResponse> refreshSession(RefreshRequest request) async {
final response = await _client.post(
'$_prefix/sessions/refresh',
data: request.toJson(),
);
return AuthResponse.fromJson(response.data);
}
Future<void> deleteSession(LogoutRequest request) async {
await _client.delete(
'$_prefix/sessions',
data: request.toJson(),
);
}
}
Step 2: Commit
git add apps/lib/features/auth/data/auth_api.dart
git commit -m "refactor(auth): update API routes to RESTful style"
Task 14: 更新 Auth Response Models
Files:
- Modify:
apps/lib/features/auth/data/models/auth_response.dart
Step 1: 简化响应模型
class AuthUser {
final String id;
final String email;
const AuthUser({required this.id, required this.email});
factory AuthUser.fromJson(Map<String, dynamic> json) {
return AuthUser(id: json['id'] as String, email: json['email'] as String);
}
}
class AuthResponse {
final String accessToken;
final String refreshToken;
final int expiresIn;
final String tokenType;
final AuthUser user;
const AuthResponse({
required this.accessToken,
required this.refreshToken,
required this.expiresIn,
required this.tokenType,
required this.user,
});
factory AuthResponse.fromJson(Map<String, dynamic> json) {
return AuthResponse(
accessToken: json['access_token'] as String,
refreshToken: json['refresh_token'] as String,
expiresIn: json['expires_in'] as int,
tokenType: json['token_type'] as String,
user: AuthUser.fromJson(json['user'] as Map<String, dynamic>),
);
}
}
class VerificationCreateResponse {
final String email;
const VerificationCreateResponse({required this.email});
factory VerificationCreateResponse.fromJson(Map<String, dynamic> json) {
return VerificationCreateResponse(email: json['email'] as String);
}
}
删除 SignupStartResponse 和 SignupResendResponse。
Step 2: Commit
git add apps/lib/features/auth/data/models/auth_response.dart
git commit -m "refactor(auth): simplify response models"
Task 15: 更新 Auth Repository
Files:
- Modify:
apps/lib/features/auth/data/auth_repository.dart - Modify:
apps/lib/features/auth/data/auth_repository_impl.dart
Step 1: 更新方法名和返回类型
将方法名和返回类型更新为新的 API 方法。
Step 2: Commit
git add apps/lib/features/auth/data/auth_repository.dart
git add apps/lib/features/auth/data/auth_repository_impl.dart
git commit -m "refactor(auth): update repository for new API"
Task 16: 更新 Register Cubit
Files:
- Modify:
apps/lib/features/auth/presentation/cubits/register_cubit.dart
Step 1: 更新 API 调用
signupStart→createVerificationsignupResend→resendVerification(现在返回 void)- 更新返回类型
Step 2: Commit
git add apps/lib/features/auth/presentation/cubits/register_cubit.dart
git commit -m "refactor(auth): update register cubit for new API"
Task 17: 更新 Auth Cubit
Files:
- Modify:
apps/lib/features/auth/presentation/cubits/auth_cubit.dart
Step 1: 更新 API 调用
login→createSessionrefresh→refreshSessionlogout→deleteSession
Step 2: Commit
git add apps/lib/features/auth/presentation/cubits/auth_cubit.dart
git commit -m "refactor(auth): update auth cubit for new API"
Task 18: 创建 Users API 和 Repository
Files:
- Create:
apps/lib/features/users/data/users_api.dart - Create:
apps/lib/features/users/data/users_repository.dart - Create:
apps/lib/features/users/data/users_repository_impl.dart - Create:
apps/lib/features/users/data/models/user_response.dart
Step 1: 创建 users_api.dart
import 'package:social_app/core/api/api_client.dart';
import 'models/user_response.dart';
class UsersApi {
final ApiClient _client;
static const _prefix = '/api/v1/users';
UsersApi(this._client);
Future<UserResponse> getMe() async {
final response = await _client.get('$_prefix/me');
return UserResponse.fromJson(response.data);
}
Future<UserResponse> updateMe(UserUpdateRequest request) async {
final response = await _client.patch(
'$_prefix/me',
data: request.toJson(),
);
return UserResponse.fromJson(response.data);
}
Future<UserResponse> getByUsername(String username) async {
final response = await _client.get('$_prefix/$username');
return UserResponse.fromJson(response.data);
}
}
Step 2: 创建 user_response.dart
class UserResponse {
final String id;
final String username;
final String? avatarUrl;
final String? bio;
const UserResponse({
required this.id,
required this.username,
this.avatarUrl,
this.bio,
});
factory UserResponse.fromJson(Map<String, dynamic> json) {
return UserResponse(
id: json['id'] as String,
username: json['username'] as String,
avatarUrl: json['avatar_url'] as String?,
bio: json['bio'] as String?,
);
}
}
class UserUpdateRequest {
final String? username;
final String? avatarUrl;
final String? bio;
const UserUpdateRequest({this.username, this.avatarUrl, this.bio});
Map<String, dynamic> toJson() {
return {
if (username != null) 'username': username,
if (avatarUrl != null) 'avatar_url': avatarUrl,
if (bio != null) 'bio': bio,
};
}
}
Step 3: Commit
git add apps/lib/features/users/
git commit -m "feat(users): create users API and models"
Task 19: 更新使用 Profile 的页面
Files:
- Modify: 所有引用 profile API 的 cubit 和 screen
Step 1: 全局搜索 profile 引用
Run: cd apps && grep -r "profile" lib/ --include="*.dart"
Step 2: 更新为 users API
更新所有引用 profile 的代码改为使用新的 users API。
Step 3: Commit
git add apps/lib/
git commit -m "refactor: migrate profile to users API"
Task 20: 更新 ApiClient 添加 delete 和 patch 方法
Files:
- Modify:
apps/lib/core/api/api_client.dart
Step 1: 添加 delete 和 patch 方法
Future<Response<T>> delete<T>(
String path, {
dynamic data,
Options? options,
}) async {
try {
return await _dio.delete<T>(path, data: data, options: options);
} on DioException catch (e) {
throw ApiException.fromDioError(e);
}
}
Future<Response<T>> patch<T>(
String path, {
dynamic data,
Options? options,
}) async {
try {
return await _dio.patch<T>(path, data: data, options: options);
} on DioException catch (e) {
throw ApiException.fromDioError(e);
}
}
Step 2: Commit
git add apps/lib/core/api/api_client.dart
git commit -m "feat(api): add delete and patch methods"
Task 21: 更新前端测试
Files:
- Modify:
apps/test/features/auth/presentation/cubits/register_cubit_test.dart - 其他相关测试文件
Step 1: 更新测试用例
更新 mock 和断言以匹配新的 API 方法名和返回类型。
Step 2: 运行测试
Run: cd apps && flutter test
Expected: All tests pass
Step 3: Commit
git add apps/test/
git commit -m "test: update tests for RESTful API"
Phase 5: 文档
Task 22: 创建路由文档
Files:
- Create:
docs/runtime/runtime-route.md
Step 1: 创建路由文档
# Runtime API Routes
本文档记录所有 HTTP API 端点。修改路由时必须同步更新此文档。
## 格式说明
- Request/Response 使用 JSON 格式
- 错误响应使用 RFC 7807 `application/problem+json`
- 所有端点前缀: `/api/v1`
## Auth
### POST /auth/verifications
创建验证码(注册发起)。
**Request:**
```json
{
"username": "string (3-30 chars)",
"email": "string (email)",
"password": "string (min 6 chars)",
"redirect_to": "string? (optional)"
}
Response: 202 Accepted
{
"email": "user@example.com"
}
Errors:
- 422: 请求参数无效
- 429: 请求过于频繁
POST /auth/verifications/resend
重发验证码。
Request:
{
"email": "string (email)"
}
Response: 204 No Content
Errors:
- 422: 请求参数无效
- 429: 请求过于频繁
POST /auth/verifications/verify
验证码校验。
Request:
{
"email": "string (email)",
"token": "string (6 digits)"
}
Response: 200 OK
{
"access_token": "string",
"refresh_token": "string",
"expires_in": 3600,
"token_type": "bearer",
"user": {
"id": "string",
"email": "string"
}
}
Errors:
- 401: 验证码无效或已过期
- 422: 请求参数无效
- 429: 请求过于频繁
POST /auth/sessions
登录(创建会话)。
Request:
{
"email": "string (email)",
"password": "string (min 6 chars)"
}
Response: 200 OK
{
"access_token": "string",
"refresh_token": "string",
"expires_in": 3600,
"token_type": "bearer",
"user": {
"id": "string",
"email": "string"
}
}
Errors:
- 401: 邮箱或密码错误
- 422: 请求参数无效
- 429: 请求过于频繁
POST /auth/sessions/refresh
刷新 Token。
Request:
{
"refresh_token": "string"
}
Response: 200 OK
{
"access_token": "string",
"refresh_token": "string",
"expires_in": 3600,
"token_type": "bearer",
"user": {
"id": "string",
"email": "string"
}
}
Errors:
- 401: 无效的 refresh token
- 422: 请求参数无效
DELETE /auth/sessions
登出(删除会话)。
Request:
{
"refresh_token": "string"
}
Response: 204 No Content
Errors:
- 422: 请求参数无效
GET /auth/users
按邮箱查询用户(需要认证)。
Query Parameters:
email: string (required)
Response: 200 OK
{
"id": "string",
"email": "string",
"created_at": "string (ISO 8601)",
"email_confirmed_at": "string? (ISO 8601)"
}
Errors:
- 403: 无权限访问
- 404: 用户不存在
- 422: 请求参数无效
Users
GET /users/me
获取当前用户信息(需要认证)。
Response: 200 OK
{
"id": "string",
"username": "string",
"avatar_url": "string?",
"bio": "string?"
}
Errors:
- 401: 未认证
PATCH /users/me
更新当前用户信息(需要认证)。
Request:
{
"username": "string? (3-30 chars)",
"avatar_url": "string? (URL)",
"bio": "string? (max 200 chars)"
}
Response: 200 OK
{
"id": "string",
"username": "string",
"avatar_url": "string?",
"bio": "string?"
}
Errors:
- 401: 未认证
- 422: 请求参数无效
GET /users/{username}
按用户名查询用户(需要认证)。
Path Parameters:
username: string (3-30 chars, alphanumeric and underscore)
Response: 200 OK
{
"id": "string",
"username": "string",
"avatar_url": "string?",
"bio": "string?"
}
Errors:
- 401: 未认证
- 404: 用户不存在
- 422: 请求参数无效
Agent Chat
POST /agent-chats
运行 Agent 对话(需要认证)。
Request:
{
"message": "string (1-8000 chars)",
"session_id": "string? (UUID)"
}
Response: 200 OK
{
"session_id": "string (UUID)",
"output": "string",
"events": [
{
"type": "string",
"run_id": "string?",
"message_id": "string?",
"delta": "string?",
"tool_name": "string?",
"result": "string?",
"output": "string?",
"error": "string?"
}
]
}
Errors:
- 401: 未认证
- 422: 请求参数无效
Infra
GET /infra/health
检查基础设施健康状态。
Response: 200 OK
{
"status": "healthy" | "unhealthy",
"services": {
"redis": {
"status": "healthy" | "unhealthy",
"latency_ms": 0
}
}
}
GET /health
检查服务健康状态。
Response: 200 OK
{
"status": "ok"
}
Error Response Format (RFC 7807)
所有错误响应使用 application/problem+json 格式:
{
"type": "about:blank",
"title": "Unauthorized",
"status": 401,
"detail": "验证码无效或已过期",
"instance": "/api/v1/auth/verifications/verify"
}
前端应优先读取 detail 字段显示给用户。
**Step 2: Commit**
```bash
git add docs/runtime/runtime-route.md
git commit -m "docs: add runtime route documentation"
Task 23: 更新根目录 AGENTS.md
Files:
- Modify:
AGENTS.md
Step 1: 添加路由同步规则
在文件末尾添加:
## API Route Documentation
When modifying HTTP routes (adding, updating, or removing endpoints):
- Sync changes to `docs/runtime/runtime-route.md`
- Include: HTTP method, path, request/response schema, status codes, error format
- Keep documentation in sync with actual implementation
Step 2: Commit
git add AGENTS.md
git commit -m "docs: add route sync rule to AGENTS.md"
Phase 6: 验收
Task 24: 端到端验证
Step 1: 启动后端服务
Run: docker compose --env-file .env -f infra/docker/docker-compose.yml up -d
Step 2: 运行后端测试
Run: cd backend && uv run pytest -v
Expected: All tests pass
Step 3: 运行前端测试
Run: cd apps && flutter test
Expected: All tests pass
Step 4: 手动验证注册/登录流程
使用 Flutter app 或 curl 测试:
- POST /api/v1/auth/verifications - 注册
- POST /api/v1/auth/verifications/verify - 验证
- POST /api/v1/auth/sessions - 登录
- GET /api/v1/users/me - 获取用户信息
- DELETE /api/v1/auth/sessions - 登出
Summary
| Phase | Tasks | Description |
|---|---|---|
| Phase 1 | 1-3 | 后端 Schema 重构 |
| Phase 2 | 4-9 | 后端路由重构 |
| Phase 3 | 10-12 | 后端测试更新 |
| Phase 4 | 13-21 | 前端适配 |
| Phase 5 | 22-23 | 文档 |
| Phase 6 | 24 | 验收 |