geo/backend/alembic/versions/a79329c23b20_initial_comple...

1100 lines
73 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""initial complete schema
Revision ID: a79329c23b20
Revises:
Create Date: 2026-06-01 22:01:36.025373
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = 'a79329c23b20'
down_revision: Union[str, Sequence[str], None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
"""Upgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('agent_registry',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('name', sa.String(length=50), nullable=False),
sa.Column('display_name', sa.String(length=100), nullable=True),
sa.Column('agent_type', sa.String(length=50), nullable=False),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('version', sa.String(length=20), nullable=True),
sa.Column('endpoint', sa.String(length=500), nullable=True),
sa.Column('status', sa.String(length=20), server_default='offline', nullable=False),
sa.Column('capabilities', sa.JSON(), nullable=True),
sa.Column('last_heartbeat', sa.DateTime(timezone=True), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('name')
)
op.create_index('idx_agent_registry_agent_type', 'agent_registry', ['agent_type'], unique=False)
op.create_index('idx_agent_registry_name', 'agent_registry', ['name'], unique=False)
op.create_index('idx_agent_registry_status', 'agent_registry', ['status'], unique=False)
op.create_table('api_keys',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('user_id', sa.UUID(), nullable=False),
sa.Column('engine_type', sa.String(length=20), nullable=False),
sa.Column('encrypted_key', sa.String(length=500), nullable=False),
sa.Column('key_hint', sa.String(length=50), nullable=False),
sa.Column('key_source', sa.String(length=10), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('priority', sa.Integer(), nullable=False),
sa.Column('last_verified_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_api_keys_engine_status', 'api_keys', ['engine_type', 'status'], unique=False)
op.create_index('idx_api_keys_user_engine', 'api_keys', ['user_id', 'engine_type'], unique=False)
op.create_index(op.f('ix_api_keys_user_id'), 'api_keys', ['user_id'], unique=False)
op.create_table('brands',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('user_id', sa.UUID(), nullable=False),
sa.Column('name', sa.String(length=50), nullable=False),
sa.Column('aliases', sa.JSON(), nullable=False),
sa.Column('website', sa.String(length=500), nullable=True),
sa.Column('industry', sa.String(length=50), nullable=True),
sa.Column('platforms', sa.JSON(), nullable=False),
sa.Column('frequency', sa.String(length=20), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('last_queried_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('next_query_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_table('optimization_insights',
sa.Column('id', sa.String(length=36), nullable=False),
sa.Column('organization_id', sa.String(length=36), nullable=False),
sa.Column('content_id', sa.String(length=36), nullable=True),
sa.Column('insight_type', sa.String(length=30), nullable=False),
sa.Column('title', sa.String(length=200), nullable=False),
sa.Column('description', sa.Text(), nullable=False),
sa.Column('recommendation', sa.Text(), nullable=False),
sa.Column('severity', sa.String(length=20), nullable=False),
sa.Column('applied', sa.Boolean(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_optimization_insights_organization_id'), 'optimization_insights', ['organization_id'], unique=False)
op.create_table('organizations',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('name', sa.String(length=100), nullable=False),
sa.Column('slug', sa.String(length=50), nullable=False),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('logo_url', sa.String(length=500), nullable=True),
sa.Column('plan', sa.String(length=20), server_default='free', nullable=False),
sa.Column('max_members', sa.Integer(), server_default='5', nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('slug')
)
op.create_index('idx_organizations_slug', 'organizations', ['slug'], unique=False)
op.create_table('platform_rule_versions',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('rule_id', sa.String(length=100), nullable=False),
sa.Column('platform', sa.String(length=50), nullable=False),
sa.Column('version', sa.Integer(), nullable=False),
sa.Column('rule_data', sa.JSON(), nullable=False),
sa.Column('change_summary', sa.String(length=500), nullable=True),
sa.Column('created_by', sa.String(length=100), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_rule_versions_platform', 'platform_rule_versions', ['platform'], unique=False)
op.create_index('idx_rule_versions_rule_id', 'platform_rule_versions', ['rule_id'], unique=False)
op.create_index(op.f('ix_platform_rule_versions_rule_id'), 'platform_rule_versions', ['rule_id'], unique=False)
op.create_table('platform_rules',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('platform', sa.String(length=50), nullable=False),
sa.Column('rule_category', sa.String(length=50), nullable=False),
sa.Column('rule_name', sa.String(length=200), nullable=False),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('check_criteria', sa.JSON(), nullable=True),
sa.Column('severity', sa.String(length=20), nullable=False),
sa.Column('is_active', sa.Boolean(), server_default='true', nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_platform_rules_is_active', 'platform_rules', ['is_active'], unique=False)
op.create_index('idx_platform_rules_platform', 'platform_rules', ['platform'], unique=False)
op.create_index('idx_platform_rules_platform_category', 'platform_rules', ['platform', 'rule_category'], unique=False)
op.create_index('idx_platform_rules_rule_category', 'platform_rules', ['rule_category'], unique=False)
op.create_table('publish_records',
sa.Column('id', sa.String(length=36), nullable=False),
sa.Column('organization_id', sa.String(length=36), nullable=False),
sa.Column('content_title', sa.String(length=200), nullable=False),
sa.Column('content_id', sa.String(length=36), nullable=True),
sa.Column('platform', sa.String(length=50), nullable=False),
sa.Column('published_url', sa.String(length=500), nullable=True),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('published_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_publish_records_organization_id'), 'publish_records', ['organization_id'], unique=False)
op.create_table('alert_settings',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('brand_id', sa.UUID(), nullable=False),
sa.Column('user_id', sa.UUID(), nullable=False),
sa.Column('alert_type', sa.String(length=50), nullable=False, comment='告警类型: score_drop / score_rise / negative_sentiment / competitor_overtake / new_platform_mention'),
sa.Column('enabled', sa.Boolean(), nullable=False),
sa.Column('threshold', sa.Float(), nullable=True, comment='阈值如评分下降超过5分触发'),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['brand_id'], ['brands.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_alert_settings_brand_id', 'alert_settings', ['brand_id'], unique=False)
op.create_index('idx_alert_settings_brand_type', 'alert_settings', ['brand_id', 'alert_type'], unique=True)
op.create_index('idx_alert_settings_user_id', 'alert_settings', ['user_id'], unique=False)
op.create_index(op.f('ix_alert_settings_user_id'), 'alert_settings', ['user_id'], unique=False)
op.create_table('alerts',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('brand_id', sa.UUID(), nullable=False),
sa.Column('user_id', sa.UUID(), nullable=False),
sa.Column('alert_type', sa.String(length=50), nullable=False, comment='告警类型: score_drop / score_rise / negative_sentiment / competitor_overtake / new_platform_mention'),
sa.Column('severity', sa.String(length=20), nullable=False, comment='严重程度: critical / warning / info'),
sa.Column('title', sa.String(length=200), nullable=False),
sa.Column('message', sa.Text(), nullable=False),
sa.Column('data', sa.JSON(), nullable=True, comment='告警相关数据JSON'),
sa.Column('is_read', sa.Boolean(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['brand_id'], ['brands.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_alerts_alert_type', 'alerts', ['alert_type'], unique=False)
op.create_index('idx_alerts_brand_id', 'alerts', ['brand_id'], unique=False)
op.create_index('idx_alerts_created_at', 'alerts', ['created_at'], unique=False)
op.create_index('idx_alerts_is_read', 'alerts', ['is_read'], unique=False)
op.create_index('idx_alerts_user_id', 'alerts', ['user_id'], unique=False)
op.create_index('idx_alerts_user_read', 'alerts', ['user_id', 'is_read'], unique=False)
op.create_index(op.f('ix_alerts_user_id'), 'alerts', ['user_id'], unique=False)
op.create_table('competitor_insights',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('brand_id', sa.UUID(), nullable=False),
sa.Column('competitor_name', sa.String(length=100), nullable=False),
sa.Column('analysis_type', sa.String(length=50), nullable=False),
sa.Column('insight_data', sa.JSON(), nullable=True),
sa.Column('citation_count_brand', sa.Integer(), nullable=False),
sa.Column('citation_count_competitor', sa.Integer(), nullable=False),
sa.Column('sentiment_brand', sa.Float(), nullable=True),
sa.Column('sentiment_competitor', sa.Float(), nullable=True),
sa.Column('platform_breakdown', sa.JSON(), nullable=True),
sa.Column('gap_analysis', sa.JSON(), nullable=True),
sa.Column('opportunity_areas', sa.JSON(), nullable=True),
sa.Column('recommendations', sa.JSON(), nullable=True),
sa.Column('confidence', sa.String(length=20), nullable=False),
sa.Column('period_days', sa.Integer(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['brand_id'], ['brands.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_competitor_insights_analysis_type', 'competitor_insights', ['analysis_type'], unique=False)
op.create_index('idx_competitor_insights_brand_id', 'competitor_insights', ['brand_id'], unique=False)
op.create_table('competitors',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('brand_id', sa.UUID(), nullable=False),
sa.Column('name', sa.String(length=50), nullable=False),
sa.Column('aliases', sa.JSON(), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['brand_id'], ['brands.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_table('content_metrics',
sa.Column('id', sa.String(length=36), nullable=False),
sa.Column('publish_record_id', sa.String(length=36), nullable=False),
sa.Column('recorded_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('views', sa.Integer(), nullable=False),
sa.Column('likes', sa.Integer(), nullable=False),
sa.Column('comments', sa.Integer(), nullable=False),
sa.Column('shares', sa.Integer(), nullable=False),
sa.Column('bookmarks', sa.Integer(), nullable=False),
sa.Column('ai_citation_count', sa.Integer(), nullable=False),
sa.Column('search_impressions', sa.Integer(), nullable=False),
sa.Column('search_clicks', sa.Integer(), nullable=False),
sa.Column('avg_read_duration', sa.Float(), nullable=False),
sa.Column('read_completion_rate', sa.Float(), nullable=False),
sa.ForeignKeyConstraint(['publish_record_id'], ['publish_records.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('detection_tasks',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('brand_id', sa.UUID(), nullable=False),
sa.Column('user_id', sa.UUID(), nullable=False),
sa.Column('name', sa.String(length=200), nullable=False),
sa.Column('frequency', sa.String(length=20), nullable=False),
sa.Column('engines', sa.JSON(), nullable=False),
sa.Column('queries', sa.JSON(), nullable=False),
sa.Column('competitor_names', sa.JSON(), nullable=True),
sa.Column('is_active', sa.Boolean(), nullable=False),
sa.Column('last_run_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('next_run_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['brand_id'], ['brands.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_detection_tasks_brand_id', 'detection_tasks', ['brand_id'], unique=False)
op.create_index('idx_detection_tasks_is_active', 'detection_tasks', ['is_active'], unique=False)
op.create_index('idx_detection_tasks_user_id', 'detection_tasks', ['user_id'], unique=False)
op.create_index(op.f('ix_detection_tasks_user_id'), 'detection_tasks', ['user_id'], unique=False)
op.create_table('diagnosis_records',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('brand_id', sa.UUID(), nullable=False),
sa.Column('user_id', sa.UUID(), nullable=False),
sa.Column('diagnosis_type', sa.String(length=20), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('overall_score', sa.Float(), nullable=True),
sa.Column('result_json', sa.JSON(), nullable=True),
sa.Column('error_message', sa.Text(), nullable=True),
sa.Column('collection_metadata', sa.JSON(), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('completed_at', sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(['brand_id'], ['brands.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_diagnosis_records_brand_id', 'diagnosis_records', ['brand_id'], unique=False)
op.create_index('idx_diagnosis_records_created_at', 'diagnosis_records', ['created_at'], unique=False)
op.create_index('idx_diagnosis_records_status', 'diagnosis_records', ['status'], unique=False)
op.create_index('idx_diagnosis_records_user_id', 'diagnosis_records', ['user_id'], unique=False)
op.create_table('monitoring_records',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('brand_id', sa.UUID(), nullable=False),
sa.Column('content_id', sa.String(length=36), nullable=True),
sa.Column('query_keywords', sa.String(length=500), nullable=True),
sa.Column('platform', sa.String(length=50), nullable=True),
sa.Column('baseline_citation_count', sa.Integer(), server_default='0', nullable=False),
sa.Column('baseline_sentiment', sa.Float(), nullable=True),
sa.Column('baseline_rank', sa.Integer(), nullable=True),
sa.Column('current_citation_count', sa.Integer(), server_default='0', nullable=False),
sa.Column('current_sentiment', sa.Float(), nullable=True),
sa.Column('current_rank', sa.Integer(), nullable=True),
sa.Column('change_type', sa.String(length=20), nullable=True),
sa.Column('change_details', sa.JSON(), nullable=True),
sa.Column('check_interval_hours', sa.Integer(), server_default='24', nullable=False),
sa.Column('last_checked_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('next_check_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('status', sa.String(length=20), server_default='active', nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['brand_id'], ['brands.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_monitoring_records_brand_id', 'monitoring_records', ['brand_id'], unique=False)
op.create_index('idx_monitoring_records_next_check_at', 'monitoring_records', ['next_check_at'], unique=False)
op.create_index('idx_monitoring_records_status', 'monitoring_records', ['status'], unique=False)
op.create_table('schema_suggestions',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('brand_id', sa.UUID(), nullable=False),
sa.Column('schema_type', sa.String(length=50), nullable=False),
sa.Column('target_url', sa.String(length=500), nullable=True),
sa.Column('json_ld_template', sa.JSON(), nullable=False),
sa.Column('json_ld_filled', sa.JSON(), nullable=True),
sa.Column('priority', sa.String(length=20), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('diagnosis_dimensions', sa.JSON(), nullable=True),
sa.Column('implementation_difficulty', sa.String(length=20), nullable=False),
sa.Column('estimated_impact', sa.Text(), nullable=True),
sa.Column('validation_errors', sa.JSON(), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['brand_id'], ['brands.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_schema_suggestions_brand_id', 'schema_suggestions', ['brand_id'], unique=False)
op.create_index('idx_schema_suggestions_brand_status', 'schema_suggestions', ['brand_id', 'status'], unique=False)
op.create_index('idx_schema_suggestions_schema_type', 'schema_suggestions', ['schema_type'], unique=False)
op.create_index('idx_schema_suggestions_status', 'schema_suggestions', ['status'], unique=False)
op.create_table('suggestions',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('brand_id', sa.UUID(), nullable=False),
sa.Column('type', sa.String(length=50), nullable=False, comment='建议类型: content_optimization/platform_targeting/competitor_gap/query_expansion/citation_improvement'),
sa.Column('priority', sa.String(length=20), nullable=False, comment='优先级: high/medium/low'),
sa.Column('title', sa.String(length=200), nullable=False),
sa.Column('description', sa.Text(), nullable=False),
sa.Column('action', sa.Text(), nullable=True, comment='具体操作步骤'),
sa.Column('expected_impact', sa.String(length=200), nullable=True, comment='预期效果'),
sa.Column('difficulty', sa.String(length=20), nullable=False, comment='难度: easy/medium/hard'),
sa.Column('status', sa.String(length=20), nullable=False, comment='状态: pending/in_progress/completed/dismissed'),
sa.Column('generated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('batch_id', sa.UUID(), nullable=False),
sa.Column('source', sa.String(length=20), nullable=False, comment='生成来源: rule/llm'),
sa.ForeignKeyConstraint(['brand_id'], ['brands.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_suggestions_batch_id', 'suggestions', ['batch_id'], unique=False)
op.create_index('idx_suggestions_brand_id', 'suggestions', ['brand_id'], unique=False)
op.create_index('idx_suggestions_brand_status', 'suggestions', ['brand_id', 'status'], unique=False)
op.create_index('idx_suggestions_status', 'suggestions', ['status'], unique=False)
op.create_index('idx_suggestions_type', 'suggestions', ['type'], unique=False)
op.create_table('trend_insights',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('brand_id', sa.UUID(), nullable=False),
sa.Column('trend_type', sa.String(length=20), nullable=False),
sa.Column('keyword', sa.String(length=200), nullable=True),
sa.Column('platform', sa.String(length=50), nullable=True),
sa.Column('period_start', sa.DateTime(timezone=True), nullable=False),
sa.Column('period_end', sa.DateTime(timezone=True), nullable=False),
sa.Column('data_points', sa.JSON(), nullable=True),
sa.Column('change_rate', sa.Float(), nullable=True),
sa.Column('absolute_change', sa.Integer(), nullable=True),
sa.Column('sentiment_trend', sa.JSON(), nullable=True),
sa.Column('cause_analysis', sa.Text(), nullable=True),
sa.Column('recommendations', sa.JSON(), nullable=True),
sa.Column('confidence', sa.Float(), nullable=False),
sa.Column('severity', sa.String(length=20), server_default='info', nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['brand_id'], ['brands.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_trend_insights_brand_id', 'trend_insights', ['brand_id'], unique=False)
op.create_index('idx_trend_insights_created_at', 'trend_insights', ['created_at'], unique=False)
op.create_index('idx_trend_insights_period_start', 'trend_insights', ['period_start'], unique=False)
op.create_index('idx_trend_insights_trend_type', 'trend_insights', ['trend_type'], unique=False)
op.create_table('usage_records',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('user_id', sa.UUID(), nullable=False),
sa.Column('brand_id', sa.UUID(), nullable=True),
sa.Column('engine_type', sa.String(length=20), nullable=False),
sa.Column('query', sa.String(length=500), nullable=False),
sa.Column('input_tokens', sa.Integer(), nullable=False),
sa.Column('output_tokens', sa.Integer(), nullable=False),
sa.Column('cost', sa.Float(), nullable=False),
sa.Column('extra_data', sa.JSON(), nullable=False),
sa.Column('timestamp', sa.DateTime(timezone=True), nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['brand_id'], ['brands.id'], ondelete='SET NULL'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_usage_records_engine_timestamp', 'usage_records', ['engine_type', 'timestamp'], unique=False)
op.create_index('idx_usage_records_user_engine', 'usage_records', ['user_id', 'engine_type'], unique=False)
op.create_index('idx_usage_records_user_timestamp', 'usage_records', ['user_id', 'timestamp'], unique=False)
op.create_index(op.f('ix_usage_records_timestamp'), 'usage_records', ['timestamp'], unique=False)
op.create_index(op.f('ix_usage_records_user_id'), 'usage_records', ['user_id'], unique=False)
op.create_table('users',
sa.Column('id', sa.Text(), nullable=False),
sa.Column('email', sa.Text(), nullable=False),
sa.Column('phone', sa.Text(), nullable=True),
sa.Column('username', sa.Text(), nullable=True),
sa.Column('password', sa.Text(), nullable=False),
sa.Column('firstName', sa.Text(), nullable=True),
sa.Column('lastName', sa.Text(), nullable=True),
sa.Column('avatar', sa.Text(), nullable=True),
sa.Column('isActive', sa.Boolean(), nullable=False),
sa.Column('emailVerified', sa.Boolean(), nullable=False),
sa.Column('phoneVerified', sa.Boolean(), nullable=False),
sa.Column('lastLoginAt', sa.DateTime(timezone=True), nullable=True),
sa.Column('createdAt', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updatedAt', sa.DateTime(timezone=True), nullable=False),
sa.Column('mfaSecret', sa.Text(), nullable=True),
sa.Column('mfaEnabled', sa.Boolean(), nullable=False),
sa.Column('loginAttempts', sa.Integer(), nullable=False),
sa.Column('lockedUntil', sa.DateTime(timezone=True), nullable=True),
sa.Column('organization_id', sa.UUID(), nullable=True),
sa.Column('role', sa.String(length=20), server_default='owner', nullable=False),
sa.Column('plan', sa.String(length=20), server_default='free', nullable=False),
sa.Column('max_queries', sa.Integer(), server_default='5', nullable=False),
sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], ondelete='SET NULL'),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('email')
)
op.create_table('agent_configs',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('agent_id', sa.UUID(), nullable=False),
sa.Column('config_key', sa.String(length=100), nullable=False),
sa.Column('config_value', sa.JSON(), nullable=False),
sa.Column('description', sa.String(length=500), nullable=True),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_by', sa.String(length=36), nullable=True),
sa.ForeignKeyConstraint(['agent_id'], ['agent_registry.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['updated_by'], ['users.id'], ondelete='SET NULL'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_agent_configs_agent_id', 'agent_configs', ['agent_id'], unique=False)
op.create_index('idx_agent_configs_agent_key', 'agent_configs', ['agent_id', 'config_key'], unique=True)
op.create_table('brand_knowledge',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('organization_id', sa.UUID(), nullable=False),
sa.Column('category', sa.String(length=50), nullable=False),
sa.Column('title', sa.String(length=200), nullable=False),
sa.Column('content', sa.Text(), nullable=False),
sa.Column('metadata', sa.JSON(), nullable=True),
sa.Column('is_active', sa.Boolean(), server_default='true', nullable=False),
sa.Column('created_by', sa.String(length=36), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['created_by'], ['users.id'], ondelete='SET NULL'),
sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_brand_knowledge_category', 'brand_knowledge', ['category'], unique=False)
op.create_index('idx_brand_knowledge_is_active', 'brand_knowledge', ['is_active'], unique=False)
op.create_index('idx_brand_knowledge_organization_id', 'brand_knowledge', ['organization_id'], unique=False)
op.create_table('content_baselines',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('monitoring_record_id', sa.UUID(), nullable=False),
sa.Column('brand_name', sa.String(length=100), nullable=False),
sa.Column('keyword', sa.String(length=200), nullable=False),
sa.Column('platform', sa.String(length=50), nullable=False),
sa.Column('citation_count', sa.Integer(), nullable=False),
sa.Column('sentiment_score', sa.Float(), nullable=True),
sa.Column('rank_position', sa.Integer(), nullable=True),
sa.Column('snapshot_data', sa.JSON(), nullable=True),
sa.Column('recorded_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['monitoring_record_id'], ['monitoring_records.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_content_baselines_monitoring_record_id', 'content_baselines', ['monitoring_record_id'], unique=False)
op.create_table('geo_plans',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('organization_id', sa.UUID(), nullable=False),
sa.Column('brand_id', sa.UUID(), nullable=False),
sa.Column('title', sa.String(length=500), nullable=False),
sa.Column('status', sa.String(length=20), server_default='draft', nullable=False),
sa.Column('diagnosis_score', sa.Integer(), nullable=False),
sa.Column('target_score', sa.Integer(), nullable=False),
sa.Column('estimated_weeks', sa.Integer(), nullable=False),
sa.Column('plan_data', sa.JSON(), nullable=True),
sa.Column('source', sa.String(length=20), nullable=False),
sa.Column('created_by', sa.String(length=36), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['brand_id'], ['brands.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['created_by'], ['users.id'], ondelete='SET NULL'),
sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_geo_plans_brand_id', 'geo_plans', ['brand_id'], unique=False)
op.create_index('idx_geo_plans_organization_id', 'geo_plans', ['organization_id'], unique=False)
op.create_index('idx_geo_plans_status', 'geo_plans', ['status'], unique=False)
op.create_table('knowledge_bases',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('organization_id', sa.UUID(), nullable=False),
sa.Column('name', sa.String(length=200), nullable=False),
sa.Column('type', sa.String(length=20), nullable=False),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('document_count', sa.Integer(), server_default='0', nullable=False),
sa.Column('status', sa.String(length=20), server_default='active', nullable=False),
sa.Column('created_by', sa.String(length=36), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['created_by'], ['users.id'], ondelete='SET NULL'),
sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_knowledge_bases_organization_id', 'knowledge_bases', ['organization_id'], unique=False)
op.create_index('idx_knowledge_bases_status', 'knowledge_bases', ['status'], unique=False)
op.create_index('idx_knowledge_bases_type', 'knowledge_bases', ['type'], unique=False)
op.create_table('knowledge_search_logs',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('organization_id', sa.UUID(), nullable=False),
sa.Column('user_id', sa.String(length=36), nullable=True),
sa.Column('query', sa.Text(), nullable=False),
sa.Column('knowledge_base_ids', sa.JSON(), nullable=True),
sa.Column('results_count', sa.Integer(), server_default='0', nullable=False),
sa.Column('latency_ms', sa.Integer(), server_default='0', nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='SET NULL'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_knowledge_search_logs_created_at', 'knowledge_search_logs', ['created_at'], unique=False)
op.create_index('idx_knowledge_search_logs_organization_id', 'knowledge_search_logs', ['organization_id'], unique=False)
op.create_index('idx_knowledge_search_logs_user_id', 'knowledge_search_logs', ['user_id'], unique=False)
op.create_table('lifecycle_projects',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('organization_id', sa.UUID(), nullable=False),
sa.Column('brand_name', sa.String(length=100), nullable=False),
sa.Column('brand_aliases', sa.JSON(), server_default='[]', nullable=False),
sa.Column('current_stage', sa.Integer(), server_default='1', nullable=False),
sa.Column('status', sa.String(length=20), server_default='active', nullable=False),
sa.Column('created_by', sa.String(length=36), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['created_by'], ['users.id'], ondelete='SET NULL'),
sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_lifecycle_projects_brand_name', 'lifecycle_projects', ['brand_name'], unique=False)
op.create_index('idx_lifecycle_projects_organization_id', 'lifecycle_projects', ['organization_id'], unique=False)
op.create_index('idx_lifecycle_projects_status', 'lifecycle_projects', ['status'], unique=False)
op.create_table('org_members',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('organization_id', sa.UUID(), nullable=False),
sa.Column('user_id', sa.String(length=36), nullable=False),
sa.Column('role', sa.String(length=20), server_default='viewer', nullable=False),
sa.Column('joined_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('invited_by', sa.UUID(), nullable=True),
sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_org_members_org_user', 'org_members', ['organization_id', 'user_id'], unique=True)
op.create_index('idx_org_members_organization_id', 'org_members', ['organization_id'], unique=False)
op.create_index('idx_org_members_user_id', 'org_members', ['user_id'], unique=False)
op.create_table('payment_orders',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('user_id', sa.String(length=36), nullable=False),
sa.Column('plan', sa.String(length=20), nullable=False),
sa.Column('amount', sa.Float(), nullable=False),
sa.Column('currency', sa.String(length=10), nullable=False),
sa.Column('payment_provider', sa.String(length=20), nullable=False),
sa.Column('payment_id', sa.String(length=255), nullable=True),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('pay_url', sa.String(length=1024), nullable=True),
sa.Column('callback_data', sa.JSON(), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('paid_at', sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_table('queries',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('user_id', sa.String(length=36), nullable=False),
sa.Column('keyword', sa.String(length=200), nullable=False),
sa.Column('target_brand', sa.String(length=100), nullable=False),
sa.Column('brand_aliases', sa.JSON(), nullable=False),
sa.Column('platforms', sa.JSON(), nullable=False),
sa.Column('frequency', sa.String(length=20), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('last_queried_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('next_query_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_queries_next_query_at', 'queries', ['next_query_at'], unique=False)
op.create_index('idx_queries_status', 'queries', ['status'], unique=False)
op.create_index('idx_queries_user_id', 'queries', ['user_id'], unique=False)
op.create_table('subscriptions',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('user_id', sa.String(length=36), nullable=False),
sa.Column('plan', sa.String(length=20), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('start_date', sa.Date(), nullable=False),
sa.Column('end_date', sa.Date(), nullable=False),
sa.Column('amount', sa.Numeric(precision=10, scale=2), nullable=True),
sa.Column('payment_method', sa.String(length=50), nullable=True),
sa.Column('payment_id', sa.String(length=255), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_table('agent_tasks',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('agent_id', sa.UUID(), nullable=False),
sa.Column('task_type', sa.String(length=50), nullable=False),
sa.Column('status', sa.String(length=20), server_default='pending', nullable=False),
sa.Column('priority', sa.Integer(), server_default='0', nullable=False),
sa.Column('input_data', sa.JSON(), nullable=True),
sa.Column('output_data', sa.JSON(), nullable=True),
sa.Column('error_message', sa.Text(), nullable=True),
sa.Column('created_by', sa.String(length=36), nullable=True),
sa.Column('organization_id', sa.UUID(), nullable=False),
sa.Column('project_id', sa.UUID(), nullable=True),
sa.Column('scheduled_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('started_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('completed_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['agent_id'], ['agent_registry.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['created_by'], ['users.id'], ondelete='SET NULL'),
sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['project_id'], ['lifecycle_projects.id'], ondelete='SET NULL'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_agent_tasks_agent_id', 'agent_tasks', ['agent_id'], unique=False)
op.create_index('idx_agent_tasks_created_by', 'agent_tasks', ['created_by'], unique=False)
op.create_index('idx_agent_tasks_organization_id', 'agent_tasks', ['organization_id'], unique=False)
op.create_index('idx_agent_tasks_project_id', 'agent_tasks', ['project_id'], unique=False)
op.create_index('idx_agent_tasks_status', 'agent_tasks', ['status'], unique=False)
op.create_index('idx_agent_tasks_task_type', 'agent_tasks', ['task_type'], unique=False)
op.create_table('citation_records',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('query_id', sa.UUID(), nullable=False),
sa.Column('platform', sa.String(length=50), nullable=False),
sa.Column('cited', sa.Boolean(), nullable=False),
sa.Column('citation_position', sa.Integer(), nullable=True),
sa.Column('citation_text', sa.Text(), nullable=True),
sa.Column('competitor_brands', sa.JSON(), nullable=False),
sa.Column('raw_response', sa.Text(), nullable=True),
sa.Column('confidence', sa.Float(), nullable=True),
sa.Column('match_type', sa.String(length=20), nullable=True),
sa.Column('sentiment', sa.String(length=20), nullable=True, comment='情感倾向: positive / neutral / negative'),
sa.Column('sentiment_confidence', sa.Float(), nullable=True, comment='情感分析置信度 0.0-1.0'),
sa.Column('sentiment_key_phrases', sa.JSON(), nullable=True, comment='关键情感短语列表'),
sa.Column('data_source', sa.String(length=20), nullable=True, comment='数据来源类型: ai_platform / search_engine / unknown'),
sa.Column('source_urls', sa.JSON(), nullable=True, comment='提取的引用URL列表'),
sa.Column('source_titles', sa.JSON(), nullable=True, comment='提取的引用来源标题列表'),
sa.Column('citation_contexts', sa.JSON(), nullable=True, comment='引用出现的上下文片段列表'),
sa.Column('ai_response_text', sa.Text(), nullable=True, comment='AI回答原始文本去掉data_source标记后的纯文本'),
sa.Column('queried_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['query_id'], ['queries.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_citation_records_platform', 'citation_records', ['platform'], unique=False)
op.create_index('idx_citation_records_queried_at', 'citation_records', ['queried_at'], unique=False)
op.create_index('idx_citation_records_query_id', 'citation_records', ['query_id'], unique=False)
op.create_table('contents',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('organization_id', sa.UUID(), nullable=False),
sa.Column('project_id', sa.UUID(), nullable=True),
sa.Column('title', sa.String(length=500), nullable=False),
sa.Column('content_type', sa.String(length=50), nullable=False),
sa.Column('body', sa.Text(), nullable=True),
sa.Column('status', sa.String(length=20), server_default='draft', nullable=False),
sa.Column('target_platforms', sa.JSON(), nullable=True),
sa.Column('keywords', sa.JSON(), nullable=True),
sa.Column('metadata', sa.JSON(), nullable=True),
sa.Column('created_by', sa.String(length=36), nullable=True),
sa.Column('current_version', sa.Integer(), server_default='1', nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['created_by'], ['users.id'], ondelete='SET NULL'),
sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['project_id'], ['lifecycle_projects.id'], ondelete='SET NULL'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_contents_content_type', 'contents', ['content_type'], unique=False)
op.create_index('idx_contents_created_by', 'contents', ['created_by'], unique=False)
op.create_index('idx_contents_organization_id', 'contents', ['organization_id'], unique=False)
op.create_index('idx_contents_project_id', 'contents', ['project_id'], unique=False)
op.create_index('idx_contents_status', 'contents', ['status'], unique=False)
op.create_table('geo_plan_actions',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('plan_id', sa.UUID(), nullable=False),
sa.Column('action_type', sa.String(length=50), nullable=False),
sa.Column('title', sa.String(length=500), nullable=False),
sa.Column('description', sa.Text(), nullable=False),
sa.Column('reason', sa.Text(), nullable=False),
sa.Column('priority', sa.String(length=10), nullable=False),
sa.Column('status', sa.String(length=20), server_default='pending', nullable=False),
sa.Column('target_keyword', sa.String(length=200), nullable=True),
sa.Column('target_platform', sa.String(length=50), nullable=True),
sa.Column('content_style', sa.String(length=50), nullable=True),
sa.Column('estimated_impact', sa.String(length=500), nullable=True),
sa.Column('difficulty', sa.String(length=10), nullable=False),
sa.Column('execution_params', sa.JSON(), nullable=True),
sa.Column('sort_order', sa.Integer(), server_default='0', nullable=False),
sa.Column('completed_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['plan_id'], ['geo_plans.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_geo_plan_actions_plan_id', 'geo_plan_actions', ['plan_id'], unique=False)
op.create_index('idx_geo_plan_actions_priority', 'geo_plan_actions', ['priority'], unique=False)
op.create_index('idx_geo_plan_actions_status', 'geo_plan_actions', ['status'], unique=False)
op.create_table('keywords',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('organization_id', sa.UUID(), nullable=False),
sa.Column('project_id', sa.UUID(), nullable=True),
sa.Column('keyword', sa.String(length=200), nullable=False),
sa.Column('category', sa.String(length=50), nullable=False),
sa.Column('priority', sa.Integer(), server_default='0', nullable=False),
sa.Column('search_volume', sa.Integer(), nullable=True),
sa.Column('competition_level', sa.String(length=20), nullable=True),
sa.Column('status', sa.String(length=20), server_default='active', nullable=False),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['project_id'], ['lifecycle_projects.id'], ondelete='SET NULL'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_keywords_category', 'keywords', ['category'], unique=False)
op.create_index('idx_keywords_keyword', 'keywords', ['keyword'], unique=False)
op.create_index('idx_keywords_organization_id', 'keywords', ['organization_id'], unique=False)
op.create_index('idx_keywords_project_id', 'keywords', ['project_id'], unique=False)
op.create_index('idx_keywords_status', 'keywords', ['status'], unique=False)
op.create_table('knowledge_documents',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('knowledge_base_id', sa.UUID(), nullable=False),
sa.Column('title', sa.String(length=500), nullable=False),
sa.Column('source_type', sa.String(length=20), nullable=False),
sa.Column('source_url', sa.String(length=2000), nullable=True),
sa.Column('content', sa.Text(), nullable=False),
sa.Column('content_hash', sa.String(length=64), nullable=False),
sa.Column('chunk_count', sa.Integer(), server_default='0', nullable=False),
sa.Column('status', sa.String(length=20), server_default='processing', nullable=False),
sa.Column('error_message', sa.Text(), nullable=True),
sa.Column('metadata', sa.JSON(), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['knowledge_base_id'], ['knowledge_bases.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_knowledge_documents_content_hash', 'knowledge_documents', ['content_hash'], unique=False)
op.create_index('idx_knowledge_documents_knowledge_base_id', 'knowledge_documents', ['knowledge_base_id'], unique=False)
op.create_index('idx_knowledge_documents_status', 'knowledge_documents', ['status'], unique=False)
op.create_table('project_stages',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('project_id', sa.UUID(), nullable=False),
sa.Column('stage_number', sa.Integer(), nullable=False),
sa.Column('status', sa.String(length=20), server_default='pending', nullable=False),
sa.Column('started_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('completed_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('notes', sa.Text(), nullable=True),
sa.Column('metrics', sa.JSON(), nullable=True),
sa.ForeignKeyConstraint(['project_id'], ['lifecycle_projects.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_project_stages_project_id', 'project_stages', ['project_id'], unique=False)
op.create_index('idx_project_stages_project_stage', 'project_stages', ['project_id', 'stage_number'], unique=True)
op.create_index('idx_project_stages_status', 'project_stages', ['status'], unique=False)
op.create_table('query_tasks',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('query_id', sa.UUID(), nullable=False),
sa.Column('platform', sa.String(length=50), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('error_message', sa.Text(), nullable=True),
sa.Column('scheduled_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('started_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('completed_at', sa.DateTime(timezone=True), nullable=True),
sa.ForeignKeyConstraint(['query_id'], ['queries.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_query_tasks_status', 'query_tasks', ['status'], unique=False)
op.create_table('agent_task_logs',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('task_id', sa.UUID(), nullable=False),
sa.Column('agent_id', sa.UUID(), nullable=False),
sa.Column('log_level', sa.String(length=10), nullable=False),
sa.Column('message', sa.Text(), nullable=False),
sa.Column('metadata', sa.JSON(), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['agent_id'], ['agent_registry.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['task_id'], ['agent_tasks.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_agent_task_logs_agent_id', 'agent_task_logs', ['agent_id'], unique=False)
op.create_index('idx_agent_task_logs_created_at', 'agent_task_logs', ['created_at'], unique=False)
op.create_index('idx_agent_task_logs_task_id', 'agent_task_logs', ['task_id'], unique=False)
op.create_table('attribution_records',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('user_id', sa.Text(), nullable=False),
sa.Column('brand_id', sa.UUID(), nullable=False),
sa.Column('content_id', sa.UUID(), nullable=True),
sa.Column('baseline_score', sa.Float(), nullable=False),
sa.Column('current_score', sa.Float(), nullable=True),
sa.Column('score_delta', sa.Float(), nullable=True),
sa.Column('attribution_window_days', sa.Integer(), server_default='28', nullable=False),
sa.Column('published_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('window_end_at', sa.DateTime(timezone=True), nullable=True),
sa.Column('status', sa.String(length=20), server_default='tracking', nullable=False),
sa.Column('attributed_dimensions', sa.JSON(), nullable=True),
sa.Column('roi_percentage', sa.Float(), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['brand_id'], ['brands.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['content_id'], ['contents.id'], ondelete='SET NULL'),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_attribution_records_brand_id', 'attribution_records', ['brand_id'], unique=False)
op.create_index('idx_attribution_records_content_id', 'attribution_records', ['content_id'], unique=False)
op.create_index('idx_attribution_records_status', 'attribution_records', ['status'], unique=False)
op.create_index('idx_attribution_records_user_id', 'attribution_records', ['user_id'], unique=False)
op.create_table('content_reviews',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('content_id', sa.UUID(), nullable=False),
sa.Column('reviewer_id', sa.String(length=36), nullable=False),
sa.Column('status', sa.String(length=20), nullable=False),
sa.Column('comments', sa.Text(), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['content_id'], ['contents.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['reviewer_id'], ['users.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_content_reviews_content_id', 'content_reviews', ['content_id'], unique=False)
op.create_index('idx_content_reviews_reviewer_id', 'content_reviews', ['reviewer_id'], unique=False)
op.create_table('content_versions',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('content_id', sa.UUID(), nullable=False),
sa.Column('version_number', sa.Integer(), nullable=False),
sa.Column('title', sa.String(length=500), nullable=True),
sa.Column('body', sa.Text(), nullable=True),
sa.Column('change_summary', sa.String(length=500), nullable=True),
sa.Column('created_by', sa.String(length=36), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['content_id'], ['contents.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['created_by'], ['users.id'], ondelete='SET NULL'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_content_versions_content_id', 'content_versions', ['content_id'], unique=False)
op.create_index('idx_content_versions_content_version', 'content_versions', ['content_id', 'version_number'], unique=True)
op.create_table('distribution_schedules',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('organization_id', sa.UUID(), nullable=False),
sa.Column('content_title', sa.String(length=500), nullable=False),
sa.Column('content_id', sa.UUID(), nullable=True),
sa.Column('platforms', sa.JSON(), nullable=True),
sa.Column('tips', sa.JSON(), nullable=True),
sa.Column('status', sa.String(length=20), server_default='pending', nullable=False),
sa.Column('created_by', sa.String(length=36), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['content_id'], ['contents.id'], ondelete='SET NULL'),
sa.ForeignKeyConstraint(['created_by'], ['users.id'], ondelete='SET NULL'),
sa.ForeignKeyConstraint(['organization_id'], ['organizations.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_distribution_schedules_created_by', 'distribution_schedules', ['created_by'], unique=False)
op.create_index('idx_distribution_schedules_organization_id', 'distribution_schedules', ['organization_id'], unique=False)
op.create_index('idx_distribution_schedules_status', 'distribution_schedules', ['status'], unique=False)
op.create_table('knowledge_chunks',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('document_id', sa.UUID(), nullable=False),
sa.Column('content', sa.Text(), nullable=False),
sa.Column('embedding', sa.Text(), nullable=True),
sa.Column('chunk_index', sa.Integer(), nullable=False),
sa.Column('token_count', sa.Integer(), server_default='0', nullable=False),
sa.Column('metadata', sa.JSON(), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['document_id'], ['knowledge_documents.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('idx_knowledge_chunks_chunk_index', 'knowledge_chunks', ['document_id', 'chunk_index'], unique=False)
op.create_index('idx_knowledge_chunks_document_id', 'knowledge_chunks', ['document_id'], unique=False)
op.create_table('knowledge_entities',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('knowledge_base_id', sa.UUID(), nullable=False),
sa.Column('name', sa.String(length=500), nullable=False),
sa.Column('entity_type', sa.Enum('ORGANIZATION', 'PRODUCT', 'PERSON', 'LOCATION', 'TECHNOLOGY', 'BRAND', 'EVENT', 'CONCEPT', 'OTHER', name='entitytype'), nullable=False),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('properties', sa.JSON(), nullable=True),
sa.Column('source_chunk_id', sa.UUID(), nullable=True),
sa.Column('confidence', sa.String(length=20), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['knowledge_base_id'], ['knowledge_bases.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['source_chunk_id'], ['knowledge_chunks.id'], ondelete='SET NULL'),
sa.PrimaryKeyConstraint('id')
)
op.create_index('ix_entities_kb_name', 'knowledge_entities', ['knowledge_base_id', 'name'], unique=False)
op.create_index('ix_entities_kb_type', 'knowledge_entities', ['knowledge_base_id', 'entity_type'], unique=False)
op.create_index(op.f('ix_knowledge_entities_entity_type'), 'knowledge_entities', ['entity_type'], unique=False)
op.create_index(op.f('ix_knowledge_entities_name'), 'knowledge_entities', ['name'], unique=False)
op.create_table('knowledge_relations',
sa.Column('id', sa.UUID(), nullable=False),
sa.Column('source_entity_id', sa.UUID(), nullable=False),
sa.Column('target_entity_id', sa.UUID(), nullable=False),
sa.Column('relation_type', sa.Enum('COMPETES_WITH', 'PARTNERS_WITH', 'ACQUIRES', 'SUBSIDIARY_OF', 'PRODUCES', 'USES_TECHNOLOGY', 'PART_OF', 'LOCATED_IN', 'FOUNDED_IN', 'CEO_OF', 'FOUNDER_OF', 'RELATED_TO', 'MENTIONED_IN', 'ALSO_KNOWN_AS', name='relationtype'), nullable=False),
sa.Column('properties', sa.JSON(), nullable=True),
sa.Column('source_chunk_id', sa.UUID(), nullable=True),
sa.Column('confidence', sa.String(length=20), nullable=True),
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False),
sa.ForeignKeyConstraint(['source_chunk_id'], ['knowledge_chunks.id'], ondelete='SET NULL'),
sa.ForeignKeyConstraint(['source_entity_id'], ['knowledge_entities.id'], ondelete='CASCADE'),
sa.ForeignKeyConstraint(['target_entity_id'], ['knowledge_entities.id'], ondelete='CASCADE'),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_knowledge_relations_relation_type'), 'knowledge_relations', ['relation_type'], unique=False)
op.create_index('ix_relations_source', 'knowledge_relations', ['source_entity_id'], unique=False)
op.create_index('ix_relations_target', 'knowledge_relations', ['target_entity_id'], unique=False)
op.create_index('ix_relations_type', 'knowledge_relations', ['relation_type'], unique=False)
# ### end Alembic commands ###
def downgrade() -> None:
"""Downgrade schema."""
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index('ix_relations_type', table_name='knowledge_relations')
op.drop_index('ix_relations_target', table_name='knowledge_relations')
op.drop_index('ix_relations_source', table_name='knowledge_relations')
op.drop_index(op.f('ix_knowledge_relations_relation_type'), table_name='knowledge_relations')
op.drop_table('knowledge_relations')
op.drop_index(op.f('ix_knowledge_entities_name'), table_name='knowledge_entities')
op.drop_index(op.f('ix_knowledge_entities_entity_type'), table_name='knowledge_entities')
op.drop_index('ix_entities_kb_type', table_name='knowledge_entities')
op.drop_index('ix_entities_kb_name', table_name='knowledge_entities')
op.drop_table('knowledge_entities')
op.drop_index('idx_knowledge_chunks_document_id', table_name='knowledge_chunks')
op.drop_index('idx_knowledge_chunks_chunk_index', table_name='knowledge_chunks')
op.drop_table('knowledge_chunks')
op.drop_index('idx_distribution_schedules_status', table_name='distribution_schedules')
op.drop_index('idx_distribution_schedules_organization_id', table_name='distribution_schedules')
op.drop_index('idx_distribution_schedules_created_by', table_name='distribution_schedules')
op.drop_table('distribution_schedules')
op.drop_index('idx_content_versions_content_version', table_name='content_versions')
op.drop_index('idx_content_versions_content_id', table_name='content_versions')
op.drop_table('content_versions')
op.drop_index('idx_content_reviews_reviewer_id', table_name='content_reviews')
op.drop_index('idx_content_reviews_content_id', table_name='content_reviews')
op.drop_table('content_reviews')
op.drop_index('idx_attribution_records_user_id', table_name='attribution_records')
op.drop_index('idx_attribution_records_status', table_name='attribution_records')
op.drop_index('idx_attribution_records_content_id', table_name='attribution_records')
op.drop_index('idx_attribution_records_brand_id', table_name='attribution_records')
op.drop_table('attribution_records')
op.drop_index('idx_agent_task_logs_task_id', table_name='agent_task_logs')
op.drop_index('idx_agent_task_logs_created_at', table_name='agent_task_logs')
op.drop_index('idx_agent_task_logs_agent_id', table_name='agent_task_logs')
op.drop_table('agent_task_logs')
op.drop_index('idx_query_tasks_status', table_name='query_tasks')
op.drop_table('query_tasks')
op.drop_index('idx_project_stages_status', table_name='project_stages')
op.drop_index('idx_project_stages_project_stage', table_name='project_stages')
op.drop_index('idx_project_stages_project_id', table_name='project_stages')
op.drop_table('project_stages')
op.drop_index('idx_knowledge_documents_status', table_name='knowledge_documents')
op.drop_index('idx_knowledge_documents_knowledge_base_id', table_name='knowledge_documents')
op.drop_index('idx_knowledge_documents_content_hash', table_name='knowledge_documents')
op.drop_table('knowledge_documents')
op.drop_index('idx_keywords_status', table_name='keywords')
op.drop_index('idx_keywords_project_id', table_name='keywords')
op.drop_index('idx_keywords_organization_id', table_name='keywords')
op.drop_index('idx_keywords_keyword', table_name='keywords')
op.drop_index('idx_keywords_category', table_name='keywords')
op.drop_table('keywords')
op.drop_index('idx_geo_plan_actions_status', table_name='geo_plan_actions')
op.drop_index('idx_geo_plan_actions_priority', table_name='geo_plan_actions')
op.drop_index('idx_geo_plan_actions_plan_id', table_name='geo_plan_actions')
op.drop_table('geo_plan_actions')
op.drop_index('idx_contents_status', table_name='contents')
op.drop_index('idx_contents_project_id', table_name='contents')
op.drop_index('idx_contents_organization_id', table_name='contents')
op.drop_index('idx_contents_created_by', table_name='contents')
op.drop_index('idx_contents_content_type', table_name='contents')
op.drop_table('contents')
op.drop_index('idx_citation_records_query_id', table_name='citation_records')
op.drop_index('idx_citation_records_queried_at', table_name='citation_records')
op.drop_index('idx_citation_records_platform', table_name='citation_records')
op.drop_table('citation_records')
op.drop_index('idx_agent_tasks_task_type', table_name='agent_tasks')
op.drop_index('idx_agent_tasks_status', table_name='agent_tasks')
op.drop_index('idx_agent_tasks_project_id', table_name='agent_tasks')
op.drop_index('idx_agent_tasks_organization_id', table_name='agent_tasks')
op.drop_index('idx_agent_tasks_created_by', table_name='agent_tasks')
op.drop_index('idx_agent_tasks_agent_id', table_name='agent_tasks')
op.drop_table('agent_tasks')
op.drop_table('subscriptions')
op.drop_index('idx_queries_user_id', table_name='queries')
op.drop_index('idx_queries_status', table_name='queries')
op.drop_index('idx_queries_next_query_at', table_name='queries')
op.drop_table('queries')
op.drop_table('payment_orders')
op.drop_index('idx_org_members_user_id', table_name='org_members')
op.drop_index('idx_org_members_organization_id', table_name='org_members')
op.drop_index('idx_org_members_org_user', table_name='org_members')
op.drop_table('org_members')
op.drop_index('idx_lifecycle_projects_status', table_name='lifecycle_projects')
op.drop_index('idx_lifecycle_projects_organization_id', table_name='lifecycle_projects')
op.drop_index('idx_lifecycle_projects_brand_name', table_name='lifecycle_projects')
op.drop_table('lifecycle_projects')
op.drop_index('idx_knowledge_search_logs_user_id', table_name='knowledge_search_logs')
op.drop_index('idx_knowledge_search_logs_organization_id', table_name='knowledge_search_logs')
op.drop_index('idx_knowledge_search_logs_created_at', table_name='knowledge_search_logs')
op.drop_table('knowledge_search_logs')
op.drop_index('idx_knowledge_bases_type', table_name='knowledge_bases')
op.drop_index('idx_knowledge_bases_status', table_name='knowledge_bases')
op.drop_index('idx_knowledge_bases_organization_id', table_name='knowledge_bases')
op.drop_table('knowledge_bases')
op.drop_index('idx_geo_plans_status', table_name='geo_plans')
op.drop_index('idx_geo_plans_organization_id', table_name='geo_plans')
op.drop_index('idx_geo_plans_brand_id', table_name='geo_plans')
op.drop_table('geo_plans')
op.drop_index('idx_content_baselines_monitoring_record_id', table_name='content_baselines')
op.drop_table('content_baselines')
op.drop_index('idx_brand_knowledge_organization_id', table_name='brand_knowledge')
op.drop_index('idx_brand_knowledge_is_active', table_name='brand_knowledge')
op.drop_index('idx_brand_knowledge_category', table_name='brand_knowledge')
op.drop_table('brand_knowledge')
op.drop_index('idx_agent_configs_agent_key', table_name='agent_configs')
op.drop_index('idx_agent_configs_agent_id', table_name='agent_configs')
op.drop_table('agent_configs')
op.drop_table('users')
op.drop_index(op.f('ix_usage_records_user_id'), table_name='usage_records')
op.drop_index(op.f('ix_usage_records_timestamp'), table_name='usage_records')
op.drop_index('idx_usage_records_user_timestamp', table_name='usage_records')
op.drop_index('idx_usage_records_user_engine', table_name='usage_records')
op.drop_index('idx_usage_records_engine_timestamp', table_name='usage_records')
op.drop_table('usage_records')
op.drop_index('idx_trend_insights_trend_type', table_name='trend_insights')
op.drop_index('idx_trend_insights_period_start', table_name='trend_insights')
op.drop_index('idx_trend_insights_created_at', table_name='trend_insights')
op.drop_index('idx_trend_insights_brand_id', table_name='trend_insights')
op.drop_table('trend_insights')
op.drop_index('idx_suggestions_type', table_name='suggestions')
op.drop_index('idx_suggestions_status', table_name='suggestions')
op.drop_index('idx_suggestions_brand_status', table_name='suggestions')
op.drop_index('idx_suggestions_brand_id', table_name='suggestions')
op.drop_index('idx_suggestions_batch_id', table_name='suggestions')
op.drop_table('suggestions')
op.drop_index('idx_schema_suggestions_status', table_name='schema_suggestions')
op.drop_index('idx_schema_suggestions_schema_type', table_name='schema_suggestions')
op.drop_index('idx_schema_suggestions_brand_status', table_name='schema_suggestions')
op.drop_index('idx_schema_suggestions_brand_id', table_name='schema_suggestions')
op.drop_table('schema_suggestions')
op.drop_index('idx_monitoring_records_status', table_name='monitoring_records')
op.drop_index('idx_monitoring_records_next_check_at', table_name='monitoring_records')
op.drop_index('idx_monitoring_records_brand_id', table_name='monitoring_records')
op.drop_table('monitoring_records')
op.drop_index('idx_diagnosis_records_user_id', table_name='diagnosis_records')
op.drop_index('idx_diagnosis_records_status', table_name='diagnosis_records')
op.drop_index('idx_diagnosis_records_created_at', table_name='diagnosis_records')
op.drop_index('idx_diagnosis_records_brand_id', table_name='diagnosis_records')
op.drop_table('diagnosis_records')
op.drop_index(op.f('ix_detection_tasks_user_id'), table_name='detection_tasks')
op.drop_index('idx_detection_tasks_user_id', table_name='detection_tasks')
op.drop_index('idx_detection_tasks_is_active', table_name='detection_tasks')
op.drop_index('idx_detection_tasks_brand_id', table_name='detection_tasks')
op.drop_table('detection_tasks')
op.drop_table('content_metrics')
op.drop_table('competitors')
op.drop_index('idx_competitor_insights_brand_id', table_name='competitor_insights')
op.drop_index('idx_competitor_insights_analysis_type', table_name='competitor_insights')
op.drop_table('competitor_insights')
op.drop_index(op.f('ix_alerts_user_id'), table_name='alerts')
op.drop_index('idx_alerts_user_read', table_name='alerts')
op.drop_index('idx_alerts_user_id', table_name='alerts')
op.drop_index('idx_alerts_is_read', table_name='alerts')
op.drop_index('idx_alerts_created_at', table_name='alerts')
op.drop_index('idx_alerts_brand_id', table_name='alerts')
op.drop_index('idx_alerts_alert_type', table_name='alerts')
op.drop_table('alerts')
op.drop_index(op.f('ix_alert_settings_user_id'), table_name='alert_settings')
op.drop_index('idx_alert_settings_user_id', table_name='alert_settings')
op.drop_index('idx_alert_settings_brand_type', table_name='alert_settings')
op.drop_index('idx_alert_settings_brand_id', table_name='alert_settings')
op.drop_table('alert_settings')
op.drop_index(op.f('ix_publish_records_organization_id'), table_name='publish_records')
op.drop_table('publish_records')
op.drop_index('idx_platform_rules_rule_category', table_name='platform_rules')
op.drop_index('idx_platform_rules_platform_category', table_name='platform_rules')
op.drop_index('idx_platform_rules_platform', table_name='platform_rules')
op.drop_index('idx_platform_rules_is_active', table_name='platform_rules')
op.drop_table('platform_rules')
op.drop_index(op.f('ix_platform_rule_versions_rule_id'), table_name='platform_rule_versions')
op.drop_index('idx_rule_versions_rule_id', table_name='platform_rule_versions')
op.drop_index('idx_rule_versions_platform', table_name='platform_rule_versions')
op.drop_table('platform_rule_versions')
op.drop_index('idx_organizations_slug', table_name='organizations')
op.drop_table('organizations')
op.drop_index(op.f('ix_optimization_insights_organization_id'), table_name='optimization_insights')
op.drop_table('optimization_insights')
op.drop_table('brands')
op.drop_index(op.f('ix_api_keys_user_id'), table_name='api_keys')
op.drop_index('idx_api_keys_user_engine', table_name='api_keys')
op.drop_index('idx_api_keys_engine_status', table_name='api_keys')
op.drop_table('api_keys')
op.drop_index('idx_agent_registry_status', table_name='agent_registry')
op.drop_index('idx_agent_registry_name', table_name='agent_registry')
op.drop_index('idx_agent_registry_agent_type', table_name='agent_registry')
op.drop_table('agent_registry')
# ### end Alembic commands ###