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

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

注意事项

  1. 渐进式迁移: 现有代码可以逐步迁移,不强制一次性修改
  2. 测试数据清理: 如果遇到时区错误,需要清空测试数据库中的旧数据
  3. 文档更新: 服务规范文档中的 COMMENT 语法可以保持现状,仅作为示例参考
  4. 新代码强制: 所有新代码必须遵循新规范

后续工作

  • 逐步迁移现有 Model 层代码
  • 更新服务规范文档中的 COMMENT 语法(可选)
  • 添加 pre-commit hook 检查时区规范
  • 补充更多时区相关的测试用例

维护者: Backend Team
审核者: Architecture Team