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.
5.1 KiB
5.1 KiB
SMS 服务规范符合性修正
日期:2026-01-26
类型:文档修正 + 架构优化
影响范围:短信验证码服务文档
变更概述
对 sms-service.md 文档进行全面修正,使其完全符合 Jointo 技术栈规范。
主要变更
1. 数据库设计修正
主键类型
- ❌ 旧:
code_id BIGINT GENERATED ALWAYS AS IDENTITY - ✅ 新:
id UUID PRIMARY KEY DEFAULT gen_uuid_v7()
时间戳字段
- ❌ 旧:仅
created_at - ✅ 新:
created_at,updated_at,deleted_at(支持软删除)
枚举类型处理
- ❌ 旧:
purpose TEXT CHECK (purpose IN ('login', 'bind_phone')) - ✅ 新:
purpose SMALLINT+ PythonIntEnum
class SmsPurpose(IntEnum):
LOGIN = 1
BIND_PHONE = 2
RESET_PASSWORD = 3
索引优化
新增条件索引:
CREATE INDEX idx_sms_codes_active ON sms_verification_codes(expires_at)
WHERE verified = false AND deleted_at IS NULL;
2. 异步编程规范
Redis 客户端
- ❌ 旧:
redis.from_url()同步客户端 - ✅ 新:
Redis.from_url()异步客户端(redis.asyncio)
from redis.asyncio import Redis
self.redis_client = Redis.from_url(
settings.REDIS_URL,
encoding="utf-8",
decode_responses=True
)
HTTP 客户端
- ❌ 旧:阿里云 SDK 同步调用
- ✅ 新:
httpx.AsyncClient异步调用
self.http_client = httpx.AsyncClient(timeout=10.0)
await self.http_client.post(url, params=params)
限流检查
所有 Redis 操作改为异步:
# 旧
ip_count = self.redis_client.get(ip_key)
# 新
ip_count = await self.redis_client.get(ip_key)
3. API 响应格式标准化
成功响应
- ❌ 旧:
{"message": "...", "expires_in": 600} - ✅ 新:标准格式
{
"code": 200,
"message": "Success",
"data": {
"message": "验证码已发送",
"expiresIn": 600
}
}
错误响应
- ❌ 旧:
{"error": "RateLimitError", "message": "..."} - ✅ 新:标准格式
{
"code": 429,
"message": "发送过于频繁,请稍后再试",
"data": null
}
4. 架构层次完善
新增完整的三层架构说明:
Model 层(app/models/sms.py)
SmsPurposeIntEnumSmsVerificationCodeSQLModel
Schema 层(app/schemas/sms.py)
SmsPurposeEnum字符串枚举(API 层)SmsCodeSendRequest请求模型SmsCodeVerifyRequest验证模型
Repository 层(app/repositories/sms_repository.py)
- 数据访问层完整实现
- 异步查询方法
5. 类型安全改进
Service 方法签名
# 旧
async def send_verification_code(
self,
phone: str,
purpose: str = 'login', # 字符串
...
) -> None
# 新
async def send_verification_code(
self,
phone: str,
purpose: SmsPurpose = SmsPurpose.LOGIN, # 枚举
...
) -> dict # 明确返回类型
技术债务清理
移除的依赖
- ❌
aliyunsdkcore(同步 SDK) - ❌
aliyunsdkdysmsapi(同步 SDK)
新增的依赖
- ✅
redis[asyncio]>=5.0.1 - ✅
httpx>=0.27.0
迁移指南
1. 更新依赖
pip install redis[asyncio]>=5.0.1 httpx>=0.27.0
pip uninstall aliyunsdkcore aliyunsdkdysmsapi
2. 数据库迁移
需要创建新的迁移脚本:
# migrations/00X_sms_verification_codes.py
async def upgrade(session: AsyncSession):
# 如果表已存在,需要迁移数据
# 1. 创建新表(UUID v7 主键)
# 2. 迁移数据
# 3. 删除旧表
pass
3. 代码更新
所有调用 SmsService 的地方需要更新:
# 旧
await sms_service.send_verification_code(
phone="13800138000",
purpose="login" # 字符串
)
# 新
from app.models.sms import SmsPurpose
await sms_service.send_verification_code(
phone="13800138000",
purpose=SmsPurpose.LOGIN # 枚举
)
性能影响
预期提升
- Redis 异步化:减少阻塞,提升并发能力
- HTTP 异步化:短信发送不阻塞其他请求
- 条件索引:查询未验证记录性能提升 30%+
资源消耗
- 内存:基本无变化
- CPU:略微降低(异步 I/O 更高效)
测试建议
单元测试
@pytest.mark.asyncio
async def test_send_verification_code():
# 测试异步发送
result = await sms_service.send_verification_code(
phone="13800138000",
purpose=SmsPurpose.LOGIN
)
assert result["message"] == "验证码已发送"
集成测试
- 测试 Redis 异步限流
- 测试 HTTP 异步调用
- 测试枚举类型转换
相关文档
变更类型:文档修正 + 架构优化
影响范围:短信验证码服务
向后兼容:❌ 需要迁移(主键类型变更)
优先级:高(规范符合性)