Files
factoryOps-v2/alembic/versions/c5d6e7f8a9b0_add_alarms.py
Johngreen 843f72e048
All checks were successful
Deploy to Production / deploy (push) Successful in 1m17s
feat: Phase 6 — alarm system (auto-generate, list, acknowledge)
- Add Alarm model with tenant/part/machine relationships and 3 indexes
- Add alembic migration c5d6e7f8a9b0_add_alarms
- Add alarms API: list (filter by ack/severity), summary, acknowledge
- Auto-generate alarms on counter update (threshold warning, critical at 100%)
- Duplicate alarm prevention for same part+alarm_type
- Add alarms frontend page with active/acknowledged tabs, summary badges
- 9 new tests (67/67 total passing)

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
2026-02-10 14:39:03 +09:00

77 lines
2.3 KiB
Python

"""add_alarms
Revision ID: c5d6e7f8a9b0
Revises: b4c5d6e7f8a9
Create Date: 2026-02-10 14:20:00.000000
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
revision: str = "c5d6e7f8a9b0"
down_revision: Union[str, None] = "b4c5d6e7f8a9"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.create_table(
"alarms",
sa.Column("id", postgresql.UUID(as_uuid=True), primary_key=True),
sa.Column(
"tenant_id",
sa.String(50),
sa.ForeignKey("tenants.id"),
nullable=False,
),
sa.Column(
"equipment_part_id",
postgresql.UUID(as_uuid=True),
sa.ForeignKey("equipment_parts.id"),
nullable=False,
),
sa.Column(
"machine_id",
postgresql.UUID(as_uuid=True),
sa.ForeignKey("machines.id"),
nullable=False,
),
sa.Column("alarm_type", sa.String(30), nullable=False),
sa.Column("severity", sa.String(20), nullable=False),
sa.Column("message", sa.String(500), nullable=False),
sa.Column("lifecycle_pct_at_trigger", sa.Float, nullable=False),
sa.Column("is_acknowledged", sa.Boolean, default=False),
sa.Column(
"acknowledged_by",
postgresql.UUID(as_uuid=True),
sa.ForeignKey("users.id"),
nullable=True,
),
sa.Column(
"acknowledged_at",
postgresql.TIMESTAMP(timezone=True),
nullable=True,
),
sa.Column(
"created_at",
postgresql.TIMESTAMP(timezone=True),
server_default=sa.func.now(),
),
)
op.create_index("ix_alarms_tenant_ack", "alarms", ["tenant_id", "is_acknowledged"])
op.create_index("ix_alarms_tenant_severity", "alarms", ["tenant_id", "severity"])
op.create_index(
"ix_alarms_tenant_part", "alarms", ["tenant_id", "equipment_part_id"]
)
def downgrade() -> None:
op.drop_index("ix_alarms_tenant_part", table_name="alarms")
op.drop_index("ix_alarms_tenant_severity", table_name="alarms")
op.drop_index("ix_alarms_tenant_ack", table_name="alarms")
op.drop_table("alarms")