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.
6.3 KiB
6.3 KiB
Skill 更新:时区规范和 PostgreSQL COMMENT 语法规范
日期: 2026-01-28
类型: 规范更新
影响范围: jointo-tech-stack skill (backend.md, database.md)
变更概述
将时间与时区规范集成到 jointo-tech-stack skill 中,并修正 PostgreSQL COMMENT 语法规范。
变更详情
1. backend.md - 新增时区规范章节
位置: 在"日志规范"之后
新增内容:
核心原则
- 始终使用 Aware Datetime
- 统一使用 UTC
- 数据库使用 TIMESTAMP WITHOUT TIME ZONE
Model 层规范
- 正确示例:使用
lambda: datetime.now(timezone.utc) - 错误示例对比:废弃的
datetime.utcnow、缺少 lambda 包装、缺少 timezone 导入
Service 层规范
- 时间操作标准模式
- 时间计算使用 aware datetime
数据库层规范
- 使用
COMMENT ON COLUMN语法(修正) - TIMESTAMP WITHOUT TIME ZONE 标准
Alembic 迁移规范
- 时间戳字段迁移模板
- COMMENT 语法正确用法
API Schema 规范
- ISO 8601 格式处理
- Pydantic 自动序列化
常见错误和解决方案
- 错误 1: naive 和 aware datetime 混用
- 错误 2: datetime.utcnow() 已废弃
- 错误 3: PostgreSQL 行内 COMMENT 语法错误(新增)
- 错误 4: 缺少 lambda 包装
检查清单
- 7 项开发时自查项目
2. database.md - 修正 COMMENT 语法和 UUID 生成规范
修正内容:
UUID v7 生成规范(重要修正)✅
- ❌ 删除:
gen_uuid_v7()数据库函数示例代码 - ✅ 强调:UUID 必须在应用层生成
- ✅ 新增:禁止使用数据库函数的说明
- ✅ 新增:应用层生成的原因(性能、扩展性、一致性、可测试性)
修正前:
-- 创建 UUID v7 生成函数
CREATE OR REPLACE FUNCTION gen_uuid_v7() RETURNS UUID AS $$
...
$$ LANGUAGE plpgsql VOLATILE;
修正后:
# ✅ 正确:应用层生成
from app.utils.id_generator import generate_uuid
user_id: UUID = Field(
sa_column=Column(
PG_UUID(as_uuid=True),
primary_key=True,
default=generate_uuid # 应用层生成
)
)
# ❌ 错误:禁止使用数据库函数
CREATE TABLE users (
user_id UUID PRIMARY KEY DEFAULT gen_uuid_v7() -- 禁止
);
表结构示例
- ✅ 修正:Model 层时间戳使用
datetime.now(timezone.utc) - ✅ 新增:SQL 表结构示例使用
COMMENT ON语法 - ❌ 标注:行内 COMMENT 语法为错误示例
修正前:
created_at: datetime = Field(default_factory=datetime.utcnow)
修正后:
created_at: datetime = Field(
default_factory=lambda: datetime.now(timezone.utc),
description="创建时间(UTC)"
)
SQL 语法修正:
-- ✅ 正确
CREATE TABLE folders (...);
COMMENT ON TABLE folders IS '文件夹表';
COMMENT ON COLUMN folders.id IS '文件夹唯一标识';
-- ❌ 错误
CREATE TABLE wrong_folders (
id UUID PRIMARY KEY COMMENT '文件夹唯一标识' -- 语法错误
);
影响范围
开发流程
- 开发时自动遵循时区规范
- 避免 naive datetime 导致的运行时错误
- 统一 PostgreSQL COMMENT 语法
现有代码
- 需要逐步迁移使用
datetime.utcnow()的代码 - 需要修正使用行内 COMMENT 的文档(非强制)
迁移指南
1. 修正 Model 层时间戳
# 搜索所有使用 datetime.utcnow 的文件
grep -r "datetime.utcnow" server/app/models/
# 替换为 datetime.now(timezone.utc)
修正模板:
# 修正前
from datetime import datetime
created_at: datetime = Field(default_factory=datetime.utcnow)
# 修正后
from datetime import datetime, timezone
created_at: datetime = Field(
default_factory=lambda: datetime.now(timezone.utc),
description="创建时间(UTC)"
)
2. 修正 Service 层时间操作
# 修正前
now = datetime.now() # naive
user.last_login_at = datetime.utcnow()
# 修正后
now = datetime.now(timezone.utc) # aware
user.last_login_at = datetime.now(timezone.utc)
3. 修正迁移脚本 COMMENT 语法
# 修正前(错误)
op.create_table(
'users',
sa.Column('id', postgresql.UUID(as_uuid=True), primary_key=True, comment='用户ID')
)
# 修正后(正确)
op.create_table(
'users',
sa.Column('id', postgresql.UUID(as_uuid=True), primary_key=True)
)
# 添加注释
op.execute("COMMENT ON COLUMN users.id IS '用户唯一标识'")
验证方法
1. 检查 Model 层
# 检查是否还有使用 datetime.utcnow
grep -r "datetime.utcnow" server/app/models/
# 检查是否导入了 timezone
grep -r "from datetime import.*timezone" server/app/models/
2. 运行测试
# 在 Docker 容器内运行测试
docker exec jointo-server-app pytest tests/ -v
# 检查是否有时区相关错误
# TypeError: can't subtract offset-naive and offset-aware datetimes
3. 检查数据库注释
-- 在 PostgreSQL 中查看表注释
SELECT
c.table_name,
c.column_name,
pgd.description
FROM pg_catalog.pg_statio_all_tables AS st
INNER JOIN pg_catalog.pg_description pgd ON (pgd.objoid = st.relid)
INNER JOIN information_schema.columns c ON (
pgd.objsubid = c.ordinal_position AND
c.table_schema = st.schemaname AND
c.table_name = st.relname
)
WHERE c.table_schema = 'public'
ORDER BY c.table_name, c.ordinal_position;
相关文档
- 完整时区规范:
docs/architecture/datetime-timezone-standards.md - Backend Skill:
.claude/skills/jointo-tech-stack/references/backend.md - Database Skill:
.claude/skills/jointo-tech-stack/references/database.md - Alembic 迁移指南:
docs/server/guides/alembic-migration-guide.md
注意事项
- 渐进式迁移: 现有代码可以逐步迁移,不强制一次性修改
- 测试数据清理: 如果遇到时区错误,需要清空测试数据库中的旧数据
- 文档更新: 服务规范文档中的 COMMENT 语法可以保持现状,仅作为示例参考
- 新代码强制: 所有新代码必须遵循新规范
后续工作
- 逐步迁移现有 Model 层代码
- 更新服务规范文档中的 COMMENT 语法(可选)
- 添加 pre-commit hook 检查时区规范
- 补充更多时区相关的测试用例
维护者: Backend Team
审核者: Architecture Team