125 lines
5.0 KiB
Python
125 lines
5.0 KiB
Python
"""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")
|