"""Initial schema: all ACE-F v1 tables. Revision ID: 0001 Revises: Create Date: 2026-03-12 Tables created: - issuer_master, symbol_master: company reference data - job_runs: pipeline execution tracking - documents, document_exhibits: SEC filing metadata - exhibit_cache: local exhibit text cache metadata - events, event_parses: parsed event data - macro_series, macro_observations: FRED macro data - short_sale_daily: FINRA short volume data - feature_snapshots: computed ML features - order_plans: future trade plans (schema only in Phase 1) - sync_checkpoints: FRED/FINRA sync state """ from __future__ import annotations from collections.abc import Sequence import sqlalchemy as sa from alembic import op from sqlalchemy.dialects.postgresql import JSONB, UUID revision: str = "0001" down_revision: str | None = None branch_labels: str | Sequence[str] | None = None depends_on: str | Sequence[str] | None = None def upgrade() -> None: op.create_table( "issuer_master", sa.Column("issuer_id", sa.Text, primary_key=True), sa.Column("cik", sa.Text, nullable=True, unique=True), sa.Column("ticker", sa.Text, nullable=True), sa.Column("issuer_name", sa.Text, nullable=False), sa.Column("exchange", sa.Text, nullable=True), sa.Column("country_code", sa.Text, nullable=True), sa.Column("is_active", sa.Boolean, nullable=False, server_default=sa.text("true")), sa.Column( "created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), sa.Column( "updated_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), ) op.create_table( "symbol_master", sa.Column("symbol_id", sa.Text, primary_key=True), sa.Column( "issuer_id", sa.Text, sa.ForeignKey("issuer_master.issuer_id"), nullable=True, ), sa.Column("ticker", sa.Text, nullable=False), sa.Column("venue", sa.Text, nullable=True), sa.Column("asset_type", sa.Text, nullable=True), sa.Column("currency", sa.Text, nullable=True), sa.Column("start_date", sa.Date, nullable=True), sa.Column("end_date", sa.Date, nullable=True), sa.Column("is_primary", sa.Boolean, nullable=False, server_default=sa.text("true")), sa.Column( "created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), sa.Column( "updated_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), ) op.create_table( "job_runs", sa.Column("job_run_id", UUID(as_uuid=True), primary_key=True), sa.Column("job_name", sa.Text, nullable=False), sa.Column("source_name", sa.Text, nullable=True), sa.Column("run_date", sa.Date, nullable=True), sa.Column("status", sa.Text, nullable=False), sa.Column( "started_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), sa.Column("finished_at_utc", sa.DateTime(timezone=True), nullable=True), sa.Column("records_seen", sa.Integer, nullable=False, server_default=sa.text("0")), sa.Column("records_written", sa.Integer, nullable=False, server_default=sa.text("0")), sa.Column("records_skipped", sa.Integer, nullable=False, server_default=sa.text("0")), sa.Column("error_count", sa.Integer, nullable=False, server_default=sa.text("0")), sa.Column("error_summary", sa.Text, nullable=True), sa.Column("metadata_json", JSONB, nullable=False, server_default=sa.text("'{}'")), ) op.create_index("ix_job_runs_job_name_run_date", "job_runs", ["job_name", "run_date"]) op.create_table( "documents", sa.Column("document_id", sa.Text, primary_key=True), sa.Column("source_name", sa.Text, nullable=False), sa.Column( "issuer_id", sa.Text, sa.ForeignKey("issuer_master.issuer_id"), nullable=True, ), sa.Column( "symbol_id", sa.Text, sa.ForeignKey("symbol_master.symbol_id"), nullable=True, ), sa.Column("accession_no", sa.Text, nullable=True), sa.Column("form_type", sa.Text, nullable=False), sa.Column("filing_date", sa.Date, nullable=False), sa.Column("accepted_at_utc", sa.DateTime(timezone=True), nullable=True), sa.Column("primary_document_name", sa.Text, nullable=True), sa.Column("parsed_status", sa.Text, nullable=False, server_default=sa.text("'pending'")), sa.Column( "created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), sa.Column( "updated_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), sa.UniqueConstraint("accession_no", "form_type", name="uq_documents_accession_form"), ) op.create_index( "ix_documents_issuer_filing_date", "documents", ["issuer_id", "filing_date"] ) op.create_index( "ix_documents_form_type_filing_date", "documents", ["form_type", "filing_date"] ) op.create_table( "document_exhibits", sa.Column("exhibit_id", sa.Text, primary_key=True), sa.Column( "document_id", sa.Text, sa.ForeignKey("documents.document_id"), nullable=False, ), sa.Column("exhibit_code", sa.Text, nullable=False), sa.Column("exhibit_name", sa.Text, nullable=True), sa.Column( "created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), ) op.create_table( "exhibit_cache", sa.Column("id", sa.BigInteger, primary_key=True, autoincrement=True), sa.Column("accession_no", sa.Text, nullable=False), sa.Column("exhibit_type", sa.Text, nullable=False), sa.Column("content_hash", sa.Text, nullable=False), sa.Column("cache_path", sa.Text, nullable=False), sa.Column( "fetched_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), sa.UniqueConstraint( "accession_no", "exhibit_type", name="uq_exhibit_cache_accession_type" ), ) op.create_table( "events", sa.Column("event_id", sa.Text, primary_key=True), sa.Column( "issuer_id", sa.Text, sa.ForeignKey("issuer_master.issuer_id"), nullable=True, ), sa.Column( "symbol_id", sa.Text, sa.ForeignKey("symbol_master.symbol_id"), nullable=True, ), sa.Column( "primary_document_id", sa.Text, sa.ForeignKey("documents.document_id"), nullable=False, ), sa.Column("event_type", sa.Text, nullable=False), sa.Column("event_direction", sa.Text, nullable=False), sa.Column("event_date", sa.Date, nullable=False), sa.Column("filed_at_utc", sa.DateTime(timezone=True), nullable=True), sa.Column("parser_version", sa.Text, nullable=False), sa.Column("parse_confidence", sa.Numeric, nullable=True), sa.Column("status", sa.Text, nullable=False, server_default=sa.text("'pending'")), sa.Column( "created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), sa.Column( "updated_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), ) op.create_index("ix_events_event_type_date", "events", ["event_type", "event_date"]) op.create_index( "ix_events_primary_document_id", "events", ["primary_document_id"] ) op.create_table( "event_parses", sa.Column("event_parse_id", sa.BigInteger, primary_key=True, autoincrement=True), sa.Column( "event_id", sa.Text, sa.ForeignKey("events.event_id"), nullable=False ), sa.Column("parser_kind", sa.Text, nullable=False), sa.Column("parser_version", sa.Text, nullable=False), sa.Column("schema_version", sa.Text, nullable=False), sa.Column("output_json", JSONB, nullable=False), sa.Column("validation_status", sa.Text, nullable=False), sa.Column("validation_errors", JSONB, nullable=True), sa.Column( "created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), ) op.create_table( "macro_series", sa.Column("series_id", sa.Text, primary_key=True), sa.Column("title", sa.Text, nullable=True), sa.Column("frequency", sa.Text, nullable=True), sa.Column("units", sa.Text, nullable=True), sa.Column("source_name", sa.Text, nullable=False), sa.Column("metadata_json", JSONB, nullable=False, server_default=sa.text("'{}'")), sa.Column( "created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), ) op.create_table( "macro_observations", sa.Column("id", sa.BigInteger, primary_key=True, autoincrement=True), sa.Column( "series_id", sa.Text, sa.ForeignKey("macro_series.series_id"), nullable=False, ), sa.Column("observation_date", sa.Date, nullable=False), sa.Column("value", sa.Numeric, nullable=True), sa.Column( "created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), sa.UniqueConstraint( "series_id", "observation_date", name="uq_macro_obs_series_date" ), ) op.create_table( "short_sale_daily", sa.Column("id", sa.BigInteger, primary_key=True, autoincrement=True), sa.Column( "symbol_id", sa.Text, sa.ForeignKey("symbol_master.symbol_id"), nullable=True, ), sa.Column("ticker_raw", sa.Text, nullable=False), sa.Column("trade_date", sa.Date, nullable=False), sa.Column("short_volume", sa.BigInteger, nullable=False), sa.Column("short_exempt_volume", sa.BigInteger, nullable=True), sa.Column("total_volume", sa.BigInteger, nullable=True), sa.Column("source_name", sa.Text, nullable=False), sa.Column( "created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), sa.UniqueConstraint( "ticker_raw", "trade_date", "source_name", name="uq_short_sale_ticker_date_source", ), ) op.create_index( "ix_short_sale_ticker_date", "short_sale_daily", ["ticker_raw", "trade_date"] ) op.create_table( "feature_snapshots", sa.Column("feature_snapshot_id", sa.BigInteger, primary_key=True, autoincrement=True), sa.Column( "event_id", sa.Text, sa.ForeignKey("events.event_id"), nullable=False ), sa.Column("snapshot_name", sa.Text, nullable=False), sa.Column("snapshot_version", sa.Text, nullable=False), sa.Column("feature_json", JSONB, nullable=False), sa.Column( "created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), ) op.create_table( "order_plans", sa.Column("order_plan_id", sa.BigInteger, primary_key=True, autoincrement=True), sa.Column( "event_id", sa.Text, sa.ForeignKey("events.event_id"), nullable=False ), sa.Column( "symbol_id", sa.Text, sa.ForeignKey("symbol_master.symbol_id"), nullable=False, ), sa.Column("side", sa.Text, nullable=False), sa.Column("planned_entry_date", sa.Date, nullable=False), sa.Column("planned_order_type", sa.Text, nullable=False), sa.Column("planned_price", sa.Numeric, nullable=True), sa.Column("stop_price", sa.Numeric, nullable=True), sa.Column("take_profit_price", sa.Numeric, nullable=True), sa.Column("quantity_plan", sa.Numeric, nullable=True), sa.Column("status", sa.Text, nullable=False, server_default=sa.text("'draft'")), sa.Column( "created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), ) op.create_table( "sync_checkpoints", sa.Column("id", sa.BigInteger, primary_key=True, autoincrement=True), sa.Column("domain", sa.Text, nullable=False), sa.Column("last_sync_at_utc", sa.DateTime(timezone=True), nullable=True), sa.Column("last_sync_params", JSONB, nullable=False, server_default=sa.text("'{}'")), sa.Column("status", sa.Text, nullable=False), sa.Column( "created_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), sa.Column( "updated_at_utc", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()"), ), sa.UniqueConstraint("domain", name="uq_sync_checkpoints_domain"), ) def downgrade() -> None: op.drop_table("sync_checkpoints") op.drop_table("order_plans") op.drop_table("feature_snapshots") op.drop_index("ix_short_sale_ticker_date", table_name="short_sale_daily") op.drop_table("short_sale_daily") op.drop_table("macro_observations") op.drop_table("macro_series") op.drop_table("event_parses") op.drop_index("ix_events_primary_document_id", table_name="events") op.drop_index("ix_events_event_type_date", table_name="events") op.drop_table("events") op.drop_table("exhibit_cache") op.drop_table("document_exhibits") op.drop_index("ix_documents_form_type_filing_date", table_name="documents") op.drop_index("ix_documents_issuer_filing_date", table_name="documents") op.drop_table("documents") op.drop_index("ix_job_runs_job_name_run_date", table_name="job_runs") op.drop_table("job_runs") op.drop_table("symbol_master") op.drop_table("issuer_master")