You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

7.1 KiB

SMS 服务文档技术栈合规性修正

日期: 2026-01-29
类型: 文档更新
影响范围: docs/requirements/backend/04-services/user/sms-service.md


变更概述

修正短信验证码服务文档,使其完全符合 jointo-tech-stack 规范,包括异步编程、依赖注入、错误处理、日志记录和测试规范。


主要变更

1. 修正导入和类型错误

问题: 缺少 timezone 导入,导致 datetime.now(timezone.utc) 无法使用

修正:

from datetime import datetime, timedelta, timezone  # 添加 timezone
from app.core.logging import logger  # 添加日志记录

2. 优化依赖注入

问题: Service 层直接创建 Redis 和 HTTP 客户端,违反依赖注入原则

修正前:

def __init__(self, session: AsyncSession):
    self.redis_client = Redis.from_url(settings.REDIS_URL)
    self.http_client = httpx.AsyncClient(timeout=10.0)

修正后:

def __init__(self, session: AsyncSession, redis_client: Redis):
    self.redis_client = redis_client  # 由依赖注入提供
    self._http_client: Optional[httpx.AsyncClient] = None  # 懒加载

@property
def http_client(self) -> httpx.AsyncClient:
    """懒加载 HTTP 客户端"""
    if self._http_client is None:
        self._http_client = httpx.AsyncClient(timeout=10.0)
    return self._http_client

3. 添加资源管理

问题: 缺少异步上下文管理器,资源清理不规范

修正:

async def __aenter__(self):
    """异步上下文管理器入口"""
    return self

async def __aexit__(self, exc_type, exc_val, exc_tb):
    """异步上下文管理器退出,清理资源"""
    if self._http_client is not None:
        await self._http_client.aclose()

4. 增强错误处理和日志

Service 层:

async def send_verification_code(...) -> dict:
    try:
        # 业务逻辑
        logger.info("验证码已发送", extra={...})
        return result
    except (RateLimitError, ValidationError):
        raise
    except Exception as e:
        logger.error(f"发送验证码失败: {str(e)}", exc_info=True)
        raise ValidationError("发送验证码失败,请稍后重试")

Repository 层:

async def create(self, code: SmsVerificationCode) -> SmsVerificationCode:
    try:
        self.session.add(code)
        await self.session.commit()
        await self.session.refresh(code)
        return code
    except SQLAlchemyError as e:
        await self.session.rollback()
        logger.error(f"创建验证码失败: {str(e)}", exc_info=True)
        raise DatabaseError("创建验证码失败")

5. 完善 Schema 层

问题: 缺少 ConfigDict 配置和字段验证

修正:

class SmsCodeSendRequest(BaseModel):
    model_config = ConfigDict(populate_by_name=True)
    
    phone: str = Field(..., min_length=11, max_length=11, description="手机号")
    country_code: str = Field(default="+86", alias="countryCode", description="国家代码")
    purpose: SmsPurposeEnum = Field(default=SmsPurposeEnum.LOGIN, description="用途")
    
    @field_validator("phone")
    @classmethod
    def validate_phone(cls, v: str) -> str:
        if not v.isdigit():
            raise ValueError("手机号必须为纯数字")
        return v

6. 补充 API 路由层

新增内容:

  • 完整的 FastAPI 路由实现
  • 依赖注入配置(get_sessionget_redis_client
  • 统一的 ApiResponse 响应格式
  • 完整的 API 文档注释
@router.post(
    "/sms/send",
    response_model=ApiResponse[SmsCodeSendResponse],
    summary="发送短信验证码"
)
async def send_sms_code(
    request: Request,
    body: SmsCodeSendRequest,
    session: AsyncSession = Depends(get_session),
    redis_client = Depends(get_redis_client)
):
    service = SmsService(session, redis_client)
    # ...
    return ApiResponse.success(data=result)

7. 添加测试规范

新增章节:

  • 单元测试示例(test_sms_service.py
  • 集成测试示例(test_sms_api.py
  • 测试运行命令

测试覆盖:

  • 生成验证码
  • 发送验证码成功
  • IP 限流
  • 手机号限流
  • 验证验证码成功
  • 验证码错误
  • 验证码过期
  • API 集成测试

8. 统一响应格式

修正前:

{
  "code": 200,
  "message": "Success",
  "data": {...}
}

修正后:

{
  "code": 200,
  "message": "Success",
  "data": {...},
  "timestamp": "2026-01-29T10:30:00Z"
}

技术栈合规性检查

已符合规范

  • 异步编程(async/awaitAsyncSessionasyncpg
  • UUID v7 主键(generate_uuid
  • 枚举类型(IntEnum + SMALLINT
  • 仓储模式(Service/Repository 分层)
  • 时间戳字段(TIMESTAMPTZ + timezone.utc
  • 索引设计(单列、组合、条件索引)
  • 无物理外键
  • Redis 异步客户端
  • HTTP 异步客户端

新增合规项

  • 依赖注入(Redis 客户端由 FastAPI 提供)
  • 资源管理(异步上下文管理器)
  • 错误处理(try-except + 异常转换)
  • 日志记录(结构化日志 + extra 字段)
  • Schema 配置(ConfigDict + populate_by_name
  • 字段验证(@field_validator
  • API 路由层(完整实现)
  • 统一响应格式(ApiResponse + timestamp
  • 测试规范(单元测试 + 集成测试)

文档结构优化

新增章节

  1. API 路由层实现 - 完整的 FastAPI 路由代码
  2. 依赖注入配置 - get_sessionget_redis_client
  3. 测试规范 - 单元测试和集成测试示例

优化章节

  1. 服务实现 - 添加文档字符串、错误处理、日志记录
  2. Schema 层 - 添加 ConfigDict 和字段验证
  3. Repository 层 - 添加异常处理和事务回滚
  4. API 接口 - 添加响应示例和 timestamp 字段

影响评估

文档变更

  • 文档版本: v2.0 → v3.0
  • 最后更新: 2026-01-26 → 2026-01-29
  • 新增内容: ~200 行代码示例和测试用例

代码影响

  • 无破坏性变更: 文档修正不影响现有代码
  • 建议同步: 实际代码应参考文档进行相应优化

后续建议

1. 代码实现同步

建议按照文档规范更新实际代码:

  • 优化依赖注入
  • 添加结构化日志
  • 完善错误处理
  • 补充单元测试

2. 性能优化

  • 考虑使用 Redis Pipeline 批量操作
  • 添加验证码发送成功率监控
  • 优化数据库查询索引

3. 安全增强

  • 添加验证码尝试次数限制
  • 实现验证码加密存储
  • 添加异常 IP 黑名单机制

相关文档


变更作者: Kiro AI
审核状态: 待审核
文档版本: v1.0