"""create miner inventory tables Revision ID: 0005_miner_inventory Revises: 0004_scan_runs_results Create Date: 2026-07-08 """ from typing import Sequence, Union import sqlalchemy as sa from alembic import op from sqlalchemy.dialects import postgresql revision: str = "0005_miner_inventory" down_revision: Union[str, None] = "0004_scan_runs_results" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: op.create_table( "miners", sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True, server_default=sa.text("gen_random_uuid()")), sa.Column("site_id", postgresql.UUID(as_uuid=True), sa.ForeignKey("sites.id", ondelete="SET NULL"), nullable=True), sa.Column("room_id", postgresql.UUID(as_uuid=True), sa.ForeignKey("rooms.id", ondelete="SET NULL"), nullable=True), sa.Column("asset_tag", sa.Text(), nullable=True), sa.Column("current_mac", sa.Text(), nullable=True), sa.Column("current_ip", postgresql.INET(), nullable=True), sa.Column("hostname", sa.Text(), nullable=True), sa.Column("miner_sn", sa.Text(), nullable=True), sa.Column("power_sn", sa.Text(), nullable=True), sa.Column("model", sa.Text(), nullable=True), sa.Column("miner_type", sa.Text(), nullable=True), sa.Column("api_version", sa.Text(), nullable=True), sa.Column("firmware_version", sa.Text(), nullable=True), sa.Column("platform", sa.Text(), nullable=True), sa.Column("chip", sa.Text(), nullable=True), sa.Column("status", sa.Text(), nullable=False, server_default=sa.text("'discovered'")), sa.Column("notes", sa.Text(), nullable=True), sa.Column("first_seen_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), sa.Column("last_seen_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), ) op.create_index("idx_miners_site_id", "miners", ["site_id"]) op.create_index("idx_miners_room_id", "miners", ["room_id"]) op.create_index("idx_miners_current_ip", "miners", ["current_ip"]) op.create_index("idx_miners_current_mac", "miners", ["current_mac"]) op.create_index("idx_miners_miner_sn", "miners", ["miner_sn"]) op.create_index("idx_miners_status", "miners", ["status"]) op.create_index("idx_miners_last_seen_at", "miners", ["last_seen_at"]) op.create_table( "miner_network_identities", sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True, server_default=sa.text("gen_random_uuid()")), sa.Column("miner_id", postgresql.UUID(as_uuid=True), sa.ForeignKey("miners.id", ondelete="CASCADE"), nullable=False), sa.Column("mac_address", sa.Text(), nullable=False), sa.Column("ip_address", postgresql.INET(), nullable=True), sa.Column("hostname", sa.Text(), nullable=True), sa.Column("source", sa.Text(), nullable=False, server_default=sa.text("'scanner'")), sa.Column("is_current", sa.Boolean(), nullable=False, server_default=sa.text("true")), sa.Column("first_seen_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), sa.Column("last_seen_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), ) op.create_index("idx_miner_network_identities_miner_id", "miner_network_identities", ["miner_id"]) op.create_index("idx_miner_network_identities_mac_address", "miner_network_identities", ["mac_address"]) op.create_index("idx_miner_network_identities_ip_address", "miner_network_identities", ["ip_address"]) op.create_index("idx_miner_network_identities_is_current", "miner_network_identities", ["is_current"]) op.create_table( "miner_hashboards", sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True, server_default=sa.text("gen_random_uuid()")), sa.Column("miner_id", postgresql.UUID(as_uuid=True), sa.ForeignKey("miners.id", ondelete="CASCADE"), nullable=False), sa.Column("slot", sa.Integer(), nullable=False), sa.Column("pcb_sn", sa.Text(), nullable=True), sa.Column("chip_data", sa.Text(), nullable=True), sa.Column("temperature_c", sa.Numeric(), nullable=True), sa.Column("chip_frequency", sa.Numeric(), nullable=True), sa.Column("mhs_av", sa.Numeric(), nullable=True), sa.Column("mhs_1m", sa.Numeric(), nullable=True), sa.Column("mhs_15m", sa.Numeric(), nullable=True), sa.Column("hs_rt", sa.Numeric(), nullable=True), sa.Column("factory_ghs", sa.Numeric(), nullable=True), sa.Column("effective_chips", sa.Integer(), nullable=True), sa.Column("upfreq_complete", sa.Integer(), nullable=True), sa.Column("raw_json", postgresql.JSONB(), nullable=True), sa.Column("first_seen_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), sa.Column("last_seen_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), sa.UniqueConstraint("miner_id", "slot", name="uq_miner_hashboards_miner_slot"), ) op.create_index("idx_miner_hashboards_miner_id", "miner_hashboards", ["miner_id"]) op.create_index("idx_miner_hashboards_pcb_sn", "miner_hashboards", ["pcb_sn"]) op.create_table( "miner_status_snapshots", sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True, server_default=sa.text("gen_random_uuid()")), sa.Column("miner_id", postgresql.UUID(as_uuid=True), sa.ForeignKey("miners.id", ondelete="CASCADE"), nullable=False), sa.Column("observed_ip", postgresql.INET(), nullable=True), sa.Column("observed_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), sa.Column("mhs_av", sa.Numeric(), nullable=True), sa.Column("mhs_1m", sa.Numeric(), nullable=True), sa.Column("mhs_15m", sa.Numeric(), nullable=True), sa.Column("hs_rt", sa.Numeric(), nullable=True), sa.Column("power_w", sa.Numeric(), nullable=True), sa.Column("power_rate_w_per_th", sa.Numeric(), nullable=True), sa.Column("env_temp_c", sa.Numeric(), nullable=True), sa.Column("chip_temp_min_c", sa.Numeric(), nullable=True), sa.Column("chip_temp_max_c", sa.Numeric(), nullable=True), sa.Column("chip_temp_avg_c", sa.Numeric(), nullable=True), sa.Column("fan_speed_in_rpm", sa.Integer(), nullable=True), sa.Column("fan_speed_out_rpm", sa.Integer(), nullable=True), sa.Column("uptime_seconds", sa.BigInteger(), nullable=True), sa.Column("hash_stable", sa.Boolean(), nullable=True), sa.Column("pool_rejected_percent", sa.Numeric(), nullable=True), sa.Column("raw_summary_json", postgresql.JSONB(), nullable=True), sa.Column("raw_version_json", postgresql.JSONB(), nullable=True), sa.Column("raw_miner_info_json", postgresql.JSONB(), nullable=True), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), ) op.create_index("idx_miner_status_snapshots_miner_id", "miner_status_snapshots", ["miner_id"]) op.create_index("idx_miner_status_snapshots_observed_at", "miner_status_snapshots", ["observed_at"]) def downgrade() -> None: op.drop_index("idx_miner_status_snapshots_observed_at", table_name="miner_status_snapshots") op.drop_index("idx_miner_status_snapshots_miner_id", table_name="miner_status_snapshots") op.drop_table("miner_status_snapshots") op.drop_index("idx_miner_hashboards_pcb_sn", table_name="miner_hashboards") op.drop_index("idx_miner_hashboards_miner_id", table_name="miner_hashboards") op.drop_table("miner_hashboards") op.drop_index("idx_miner_network_identities_is_current", table_name="miner_network_identities") op.drop_index("idx_miner_network_identities_ip_address", table_name="miner_network_identities") op.drop_index("idx_miner_network_identities_mac_address", table_name="miner_network_identities") op.drop_index("idx_miner_network_identities_miner_id", table_name="miner_network_identities") op.drop_table("miner_network_identities") op.drop_index("idx_miners_last_seen_at", table_name="miners") op.drop_index("idx_miners_status", table_name="miners") op.drop_index("idx_miners_miner_sn", table_name="miners") op.drop_index("idx_miners_current_mac", table_name="miners") op.drop_index("idx_miners_current_ip", table_name="miners") op.drop_index("idx_miners_room_id", table_name="miners") op.drop_index("idx_miners_site_id", table_name="miners") op.drop_table("miners")