"""Initial schema - all 14 tables Revision ID: 001_initial Revises: Create Date: 2026-04-01 """ from alembic import op import sqlalchemy as sa revision = "001_initial" down_revision = None branch_labels = None depends_on = None def upgrade() -> None: # --- roles --- op.create_table( "roles", sa.Column("id", sa.Integer, primary_key=True, autoincrement=True), sa.Column("name", sa.String(50), unique=True, nullable=False), sa.Column("display_name", sa.String(100), nullable=False), sa.Column("description", sa.Text), sa.Column("permissions", sa.Text), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), ) # --- users --- op.create_table( "users", sa.Column("id", sa.Integer, primary_key=True, autoincrement=True), sa.Column("username", sa.String(50), unique=True, nullable=False), sa.Column("email", sa.String(100), unique=True), sa.Column("hashed_password", sa.String(200), nullable=False), sa.Column("full_name", sa.String(100)), sa.Column("phone", sa.String(20)), sa.Column("role", sa.String(50), sa.ForeignKey("roles.name"), default="visitor"), sa.Column("is_active", sa.Boolean, default=True), sa.Column("last_login", sa.DateTime(timezone=True)), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()), ) op.create_index("ix_users_username", "users", ["username"]) # --- audit_logs --- op.create_table( "audit_logs", sa.Column("id", sa.Integer, primary_key=True, autoincrement=True), sa.Column("user_id", sa.Integer, sa.ForeignKey("users.id")), sa.Column("action", sa.String(50), nullable=False), sa.Column("resource", sa.String(100)), sa.Column("detail", sa.Text), sa.Column("ip_address", sa.String(50)), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), ) # --- device_types --- op.create_table( "device_types", sa.Column("id", sa.Integer, primary_key=True, autoincrement=True), sa.Column("code", sa.String(50), unique=True, nullable=False), sa.Column("name", sa.String(100), nullable=False), sa.Column("icon", sa.String(100)), sa.Column("data_fields", sa.JSON), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), ) # --- device_groups --- op.create_table( "device_groups", sa.Column("id", sa.Integer, primary_key=True, autoincrement=True), sa.Column("name", sa.String(100), nullable=False), sa.Column("parent_id", sa.Integer, sa.ForeignKey("device_groups.id")), sa.Column("location", sa.String(200)), sa.Column("description", sa.Text), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), ) # --- devices --- op.create_table( "devices", sa.Column("id", sa.Integer, primary_key=True, autoincrement=True), sa.Column("name", sa.String(100), nullable=False), sa.Column("code", sa.String(100), unique=True, nullable=False), sa.Column("device_type", sa.String(50), sa.ForeignKey("device_types.code"), nullable=False), sa.Column("group_id", sa.Integer, sa.ForeignKey("device_groups.id")), sa.Column("model", sa.String(100)), sa.Column("manufacturer", sa.String(100)), sa.Column("serial_number", sa.String(100)), sa.Column("rated_power", sa.Float), sa.Column("install_date", sa.DateTime(timezone=True)), sa.Column("location", sa.String(200)), sa.Column("protocol", sa.String(50)), sa.Column("connection_params", sa.JSON), sa.Column("collect_interval", sa.Integer, default=15), sa.Column("status", sa.String(20), default="offline"), sa.Column("is_active", sa.Boolean, default=True), sa.Column("metadata", sa.JSON), sa.Column("last_data_time", sa.DateTime(timezone=True)), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()), ) # --- energy_data --- op.create_table( "energy_data", sa.Column("id", sa.Integer, primary_key=True, autoincrement=True), sa.Column("device_id", sa.Integer, sa.ForeignKey("devices.id"), nullable=False), sa.Column("timestamp", sa.DateTime(timezone=True), nullable=False), sa.Column("data_type", sa.String(50), nullable=False), sa.Column("value", sa.Float, nullable=False), sa.Column("unit", sa.String(20)), sa.Column("quality", sa.Integer, default=0), sa.Column("raw_data", sa.JSON), ) op.create_index("ix_energy_data_device_id", "energy_data", ["device_id"]) op.create_index("ix_energy_data_timestamp", "energy_data", ["timestamp"]) # --- energy_daily_summary --- op.create_table( "energy_daily_summary", sa.Column("id", sa.Integer, primary_key=True, autoincrement=True), sa.Column("device_id", sa.Integer, sa.ForeignKey("devices.id"), nullable=False), sa.Column("date", sa.DateTime(timezone=True), nullable=False), sa.Column("energy_type", sa.String(50), nullable=False), sa.Column("total_consumption", sa.Float, default=0), sa.Column("total_generation", sa.Float, default=0), sa.Column("peak_power", sa.Float), sa.Column("min_power", sa.Float), sa.Column("avg_power", sa.Float), sa.Column("operating_hours", sa.Float), sa.Column("avg_cop", sa.Float), sa.Column("avg_temperature", sa.Float), sa.Column("cost", sa.Float), sa.Column("carbon_emission", sa.Float), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), ) op.create_index("ix_energy_daily_summary_device_id", "energy_daily_summary", ["device_id"]) op.create_index("ix_energy_daily_summary_date", "energy_daily_summary", ["date"]) # --- alarm_rules --- op.create_table( "alarm_rules", sa.Column("id", sa.Integer, primary_key=True, autoincrement=True), sa.Column("name", sa.String(200), nullable=False), sa.Column("device_id", sa.Integer, sa.ForeignKey("devices.id")), sa.Column("device_type", sa.String(50)), sa.Column("data_type", sa.String(50), nullable=False), sa.Column("condition", sa.String(20), nullable=False), sa.Column("threshold", sa.Float), sa.Column("threshold_high", sa.Float), sa.Column("threshold_low", sa.Float), sa.Column("duration", sa.Integer, default=0), sa.Column("severity", sa.String(20), default="warning"), sa.Column("notify_channels", sa.JSON), sa.Column("notify_targets", sa.JSON), sa.Column("auto_action", sa.JSON), sa.Column("silence_start", sa.String(10)), sa.Column("silence_end", sa.String(10)), sa.Column("is_active", sa.Boolean, default=True), sa.Column("created_by", sa.Integer, sa.ForeignKey("users.id")), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now()), ) # --- alarm_events --- op.create_table( "alarm_events", sa.Column("id", sa.Integer, primary_key=True, autoincrement=True), sa.Column("rule_id", sa.Integer, sa.ForeignKey("alarm_rules.id")), sa.Column("device_id", sa.Integer, sa.ForeignKey("devices.id"), nullable=False), sa.Column("severity", sa.String(20), nullable=False), sa.Column("title", sa.String(200), nullable=False), sa.Column("description", sa.Text), sa.Column("value", sa.Float), sa.Column("threshold", sa.Float), sa.Column("status", sa.String(20), default="active"), sa.Column("acknowledged_by", sa.Integer, sa.ForeignKey("users.id")), sa.Column("acknowledged_at", sa.DateTime(timezone=True)), sa.Column("resolved_at", sa.DateTime(timezone=True)), sa.Column("resolve_note", sa.Text), sa.Column("triggered_at", sa.DateTime(timezone=True), server_default=sa.func.now()), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), ) # --- emission_factors --- op.create_table( "emission_factors", sa.Column("id", sa.Integer, primary_key=True, autoincrement=True), sa.Column("name", sa.String(100), nullable=False), sa.Column("energy_type", sa.String(50), nullable=False), sa.Column("factor", sa.Float, nullable=False), sa.Column("unit", sa.String(20), nullable=False), sa.Column("region", sa.String(50), default="north_china"), sa.Column("scope", sa.Integer, nullable=False), sa.Column("source", sa.String(200)), sa.Column("year", sa.Integer), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), ) # --- carbon_emissions --- op.create_table( "carbon_emissions", sa.Column("id", sa.Integer, primary_key=True, autoincrement=True), sa.Column("date", sa.DateTime(timezone=True), nullable=False), sa.Column("scope", sa.Integer, nullable=False), sa.Column("category", sa.String(50), nullable=False), sa.Column("emission", sa.Float, nullable=False), sa.Column("reduction", sa.Float, default=0), sa.Column("energy_consumption", sa.Float), sa.Column("energy_unit", sa.String(20)), sa.Column("emission_factor_id", sa.Integer), sa.Column("note", sa.Text), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), ) op.create_index("ix_carbon_emissions_date", "carbon_emissions", ["date"]) # --- report_templates --- op.create_table( "report_templates", sa.Column("id", sa.Integer, primary_key=True, autoincrement=True), sa.Column("name", sa.String(100), nullable=False), sa.Column("report_type", sa.String(50), nullable=False), sa.Column("description", sa.Text), sa.Column("fields", sa.JSON, nullable=False), sa.Column("filters", sa.JSON), sa.Column("aggregation", sa.String(20), default="sum"), sa.Column("time_granularity", sa.String(20), default="hour"), sa.Column("format_config", sa.JSON), sa.Column("is_system", sa.Boolean, default=False), sa.Column("created_by", sa.Integer, sa.ForeignKey("users.id")), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), ) # --- report_tasks --- op.create_table( "report_tasks", sa.Column("id", sa.Integer, primary_key=True, autoincrement=True), sa.Column("template_id", sa.Integer, sa.ForeignKey("report_templates.id"), nullable=False), sa.Column("name", sa.String(200)), sa.Column("schedule", sa.String(50)), sa.Column("next_run", sa.DateTime(timezone=True)), sa.Column("last_run", sa.DateTime(timezone=True)), sa.Column("recipients", sa.JSON), sa.Column("export_format", sa.String(20), default="xlsx"), sa.Column("file_path", sa.String(500)), sa.Column("status", sa.String(20), default="pending"), sa.Column("is_active", sa.Boolean, default=True), sa.Column("created_by", sa.Integer, sa.ForeignKey("users.id")), sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now()), ) def downgrade() -> None: op.drop_table("report_tasks") op.drop_table("report_templates") op.drop_table("carbon_emissions") op.drop_table("emission_factors") op.drop_table("alarm_events") op.drop_table("alarm_rules") op.drop_table("energy_daily_summary") op.drop_table("energy_data") op.drop_table("devices") op.drop_table("device_groups") op.drop_table("device_types") op.drop_table("audit_logs") op.drop_table("users") op.drop_table("roles")