"""ticker_universe — server-wide set of tracked tickers, no user attribution Phase G of the multi-user migration. Adds the additive table only; old portfolio tables (positions / portfolio_snapshots / portfolios) are dropped in migration 0010 after the new path is verified end-to-end. Revision ID: 0009 Revises: 0008 Create Date: 2026-05-16 """ from typing import Sequence, Union import sqlalchemy as sa from alembic import op revision: str = "0009" down_revision: Union[str, None] = "0008" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: op.create_table( "ticker_universe", # Yahoo Finance ticker is the canonical key. T212 shortnames are # resolved to Yahoo tickers at parse time via instrument_map. sa.Column("yahoo_ticker", sa.String(32), primary_key=True), sa.Column("currency", sa.String(8)), sa.Column("first_seen_at", sa.DateTime(timezone=True), nullable=False), # Refreshed whenever the ticker appears in a /api/portfolio/parse # or /api/analyze request. Eviction cron prunes rows older than # the configured TTL. sa.Column("last_referenced_at", sa.DateTime(timezone=True), nullable=False), ) op.create_index( "ix_universe_last_ref", "ticker_universe", ["last_referenced_at"] ) def downgrade() -> None: op.drop_index("ix_universe_last_ref", table_name="ticker_universe") op.drop_table("ticker_universe")