"""Add analytics tables (publish_records, content_metrics, optimization_insights) Revision ID: f6g8h0i2de56 Revises: e5f7g9h1cd45 Create Date: 2026-05-23 14:00:00.000000 """ from typing import Sequence, Union import sqlalchemy as sa from alembic import op # revision identifiers, used by Alembic. revision: str = "f6g8h0i2de56" down_revision: Union[str, None] = "e5f7g9h1cd45" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: # ------------------------------------------------------------------ # # 1. publish_records # ------------------------------------------------------------------ # op.create_table( "publish_records", sa.Column("id", sa.String(36), primary_key=True, nullable=False), sa.Column("organization_id", sa.String(36), nullable=False), sa.Column("content_title", sa.String(200), nullable=False), sa.Column("content_id", sa.String(36), nullable=True), sa.Column("platform", sa.String(50), nullable=False), sa.Column("published_url", sa.String(500), nullable=True), sa.Column("status", sa.String(20), server_default="draft", nullable=False), sa.Column("published_at", sa.DateTime(), nullable=True), sa.Column( "created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False, ), ) op.create_index("idx_publish_records_organization_id", "publish_records", ["organization_id"]) op.create_index("idx_publish_records_platform", "publish_records", ["platform"]) op.create_index("idx_publish_records_status", "publish_records", ["status"]) op.create_index("idx_publish_records_created_at", "publish_records", ["created_at"]) # ------------------------------------------------------------------ # # 2. content_metrics # ------------------------------------------------------------------ # op.create_table( "content_metrics", sa.Column("id", sa.String(36), primary_key=True, nullable=False), sa.Column( "publish_record_id", sa.String(36), sa.ForeignKey("publish_records.id", ondelete="CASCADE"), nullable=False, ), sa.Column( "recorded_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False, ), # 互动指标 sa.Column("views", sa.Integer(), server_default="0", nullable=False), sa.Column("likes", sa.Integer(), server_default="0", nullable=False), sa.Column("comments", sa.Integer(), server_default="0", nullable=False), sa.Column("shares", sa.Integer(), server_default="0", nullable=False), sa.Column("bookmarks", sa.Integer(), server_default="0", nullable=False), # GEO核心指标 sa.Column("ai_citation_count", sa.Integer(), server_default="0", nullable=False), sa.Column("search_impressions", sa.Integer(), server_default="0", nullable=False), sa.Column("search_clicks", sa.Integer(), server_default="0", nullable=False), # 阅读指标 sa.Column("avg_read_duration", sa.Float(), server_default="0.0", nullable=False), sa.Column("read_completion_rate", sa.Float(), server_default="0.0", nullable=False), ) op.create_index( "idx_content_metrics_publish_record_id", "content_metrics", ["publish_record_id"] ) op.create_index("idx_content_metrics_recorded_at", "content_metrics", ["recorded_at"]) # ------------------------------------------------------------------ # # 3. optimization_insights # ------------------------------------------------------------------ # op.create_table( "optimization_insights", sa.Column("id", sa.String(36), primary_key=True, nullable=False), sa.Column("organization_id", sa.String(36), nullable=False), sa.Column("content_id", sa.String(36), nullable=True), sa.Column("insight_type", sa.String(30), nullable=False), sa.Column("title", sa.String(200), nullable=False), sa.Column("description", sa.Text(), nullable=False), sa.Column("recommendation", sa.Text(), nullable=False), sa.Column("severity", sa.String(20), server_default="info", nullable=False), sa.Column("applied", sa.Boolean(), server_default="false", nullable=False), sa.Column( "created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False, ), ) op.create_index( "idx_optimization_insights_organization_id", "optimization_insights", ["organization_id"], ) op.create_index( "idx_optimization_insights_insight_type", "optimization_insights", ["insight_type"], ) op.create_index( "idx_optimization_insights_created_at", "optimization_insights", ["created_at"], ) def downgrade() -> None: op.drop_table("optimization_insights") op.drop_table("content_metrics") op.drop_table("publish_records")