# 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 必须在应用层生成 - ✅ 新增:禁止使用数据库函数的说明 - ✅ 新增:应用层生成的原因(性能、扩展性、一致性、可测试性) **修正前**: ```sql -- 创建 UUID v7 生成函数 CREATE OR REPLACE FUNCTION gen_uuid_v7() RETURNS UUID AS $$ ... $$ LANGUAGE plpgsql VOLATILE; ``` **修正后**: ```python # ✅ 正确:应用层生成 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 语法为错误示例 **修正前**: ```python created_at: datetime = Field(default_factory=datetime.utcnow) ``` **修正后**: ```python created_at: datetime = Field( default_factory=lambda: datetime.now(timezone.utc), description="创建时间(UTC)" ) ``` **SQL 语法修正**: ```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 层时间戳 ```bash # 搜索所有使用 datetime.utcnow 的文件 grep -r "datetime.utcnow" server/app/models/ # 替换为 datetime.now(timezone.utc) ``` **修正模板**: ```python # 修正前 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 层时间操作 ```python # 修正前 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 语法 ```python # 修正前(错误) 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 层 ```bash # 检查是否还有使用 datetime.utcnow grep -r "datetime.utcnow" server/app/models/ # 检查是否导入了 timezone grep -r "from datetime import.*timezone" server/app/models/ ``` ### 2. 运行测试 ```bash # 在 Docker 容器内运行测试 docker exec jointo-server-app pytest tests/ -v # 检查是否有时区相关错误 # TypeError: can't subtract offset-naive and offset-aware datetimes ``` ### 3. 检查数据库注释 ```sql -- 在 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` --- ## 注意事项 1. **渐进式迁移**: 现有代码可以逐步迁移,不强制一次性修改 2. **测试数据清理**: 如果遇到时区错误,需要清空测试数据库中的旧数据 3. **文档更新**: 服务规范文档中的 COMMENT 语法可以保持现状,仅作为示例参考 4. **新代码强制**: 所有新代码必须遵循新规范 --- ## 后续工作 - [ ] 逐步迁移现有 Model 层代码 - [ ] 更新服务规范文档中的 COMMENT 语法(可选) - [ ] 添加 pre-commit hook 检查时区规范 - [ ] 补充更多时区相关的测试用例 --- **维护者**: Backend Team **审核者**: Architecture Team