chore(prep): shared groundwork for the parallel task batch
多 agent 并行批次的协调提交(消除全部共享文件冲突面): - 迁移 0004:id_session + ob_event 两表(T3/T4 用,任务不再写迁移) - ORM:UserSession / ObEvent;错误码:九个新码(40xxx/60006,含 meta) - 配置:四档 tiers / refresh TTL / 任务奖励注册表 / 埋点上限 / COS 直传全套 - 骨架:packages/analytics + packages/storage + events/uploads 空路由(已注册) - deps:AnalyticsServiceDep / StorageServiceDep;DailyBudgetGuard 接收 tiers - uv add cos-python-sdk-v5;import-linter/CI/Makefile 纳入两个新包
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
"""Sessions and client events for the Sprint-0 parallel batch.
|
||||
|
||||
Two tables that the parallel task batch (T3/T4) needs, landed together in one
|
||||
revision so no task ever writes a migration:
|
||||
|
||||
1. ``id_session`` — server-revocable refresh sessions (架构文档 §6.2, FR-ACC-05).
|
||||
2. ``ob_event`` — client telemetry (架构文档 §6.2, FR-SYS-06).
|
||||
|
||||
Partitioning (架构文档 says "按月分区") is deliberately deferred for both —
|
||||
same call as ``ob_ai_call``: plain tables until volume justifies it.
|
||||
|
||||
Reversible: 是。降级直接 drop 两表。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
revision: str = "0004"
|
||||
down_revision: str | None = "0003"
|
||||
branch_labels: str | Sequence[str] | None = None
|
||||
depends_on: str | Sequence[str] | None = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.create_table(
|
||||
"id_session",
|
||||
sa.Column("session_id", sa.BigInteger(), nullable=False),
|
||||
sa.Column("user_id", sa.BigInteger(), nullable=False),
|
||||
sa.Column("refresh_token_hash", sa.String(length=64), nullable=False),
|
||||
sa.Column("expire_at", sa.DateTime(timezone=True), nullable=False),
|
||||
sa.Column("revoked", sa.Boolean(), nullable=False, server_default=sa.text("false")),
|
||||
sa.Column("revoked_at", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
|
||||
sa.PrimaryKeyConstraint("session_id"),
|
||||
sa.UniqueConstraint("refresh_token_hash", name="uq_id_session_token_hash"),
|
||||
)
|
||||
op.create_index("ix_id_session_user", "id_session", ["user_id"])
|
||||
|
||||
op.create_table(
|
||||
"ob_event",
|
||||
sa.Column("event_id", sa.BigInteger(), nullable=False),
|
||||
sa.Column("user_id", sa.BigInteger(), nullable=False),
|
||||
sa.Column("event_name", sa.String(length=64), nullable=False),
|
||||
sa.Column("props", postgresql.JSONB(), nullable=False),
|
||||
sa.Column("client_ts", sa.DateTime(timezone=True), nullable=True),
|
||||
sa.Column("server_ts", sa.DateTime(timezone=True), nullable=False, server_default=sa.func.now()),
|
||||
sa.PrimaryKeyConstraint("event_id"),
|
||||
)
|
||||
op.create_index("ix_ob_event_name_ts", "ob_event", ["event_name", "server_ts"])
|
||||
op.create_index("ix_ob_event_user_ts", "ob_event", ["user_id", "server_ts"])
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.drop_index("ix_ob_event_user_ts", table_name="ob_event")
|
||||
op.drop_index("ix_ob_event_name_ts", table_name="ob_event")
|
||||
op.drop_table("ob_event")
|
||||
op.drop_index("ix_id_session_user", table_name="id_session")
|
||||
op.drop_table("id_session")
|
||||
Reference in New Issue
Block a user