- 8 DB models (services, incidents, monitors, subscribers, etc.) - Full CRUD API for services, incidents, monitors - Public status page with live data - Incident detail page with timeline - API key authentication - Uptime monitoring scheduler - 13 tests passing - TECHNICAL_DESIGN.md with full spec
151 lines
No EOL
6.6 KiB
Python
151 lines
No EOL
6.6 KiB
Python
import uuid
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import Boolean, DateTime, Integer, String, Text, ForeignKey, Float
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.database import Base
|
|
|
|
|
|
def _uuid_str() -> str:
|
|
return str(uuid.uuid4())
|
|
|
|
|
|
class Service(Base):
|
|
__tablename__ = "services"
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
|
|
name: Mapped[str] = mapped_column(String(100), nullable=False)
|
|
slug: Mapped[str] = mapped_column(String(50), unique=True, nullable=False, index=True)
|
|
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
group_name: Mapped[str | None] = mapped_column(String(50), nullable=True)
|
|
position: Mapped[int] = mapped_column(Integer, default=0)
|
|
is_visible: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
|
|
)
|
|
|
|
incidents: Mapped[list["Incident"]] = relationship(back_populates="service")
|
|
monitors: Mapped[list["Monitor"]] = relationship(back_populates="service")
|
|
|
|
|
|
class Incident(Base):
|
|
__tablename__ = "incidents"
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
|
|
service_id: Mapped[str] = mapped_column(
|
|
String(36), ForeignKey("services.id"), nullable=False, index=True
|
|
)
|
|
title: Mapped[str] = mapped_column(String(200), nullable=False)
|
|
status: Mapped[str] = mapped_column(String(20), nullable=False, index=True)
|
|
# investigating | identified | monitoring | resolved
|
|
severity: Mapped[str] = mapped_column(String(20), nullable=False)
|
|
# minor | major | outage
|
|
started_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.utcnow)
|
|
resolved_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
|
|
)
|
|
|
|
service: Mapped["Service"] = relationship(back_populates="incidents")
|
|
updates: Mapped[list["IncidentUpdate"]] = relationship(
|
|
back_populates="incident", cascade="all, delete-orphan"
|
|
)
|
|
notifications: Mapped[list["NotificationLog"]] = relationship(back_populates="incident")
|
|
|
|
|
|
class IncidentUpdate(Base):
|
|
__tablename__ = "incident_updates"
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
|
|
incident_id: Mapped[str] = mapped_column(
|
|
String(36), ForeignKey("incidents.id"), nullable=False, index=True
|
|
)
|
|
status: Mapped[str] = mapped_column(String(20), nullable=False)
|
|
body: Mapped[str] = mapped_column(Text, nullable=False)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
|
|
incident: Mapped["Incident"] = relationship(back_populates="updates")
|
|
|
|
|
|
class Monitor(Base):
|
|
__tablename__ = "monitors"
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
|
|
service_id: Mapped[str] = mapped_column(
|
|
String(36), ForeignKey("services.id"), nullable=False, index=True
|
|
)
|
|
url: Mapped[str] = mapped_column(String(500), nullable=False)
|
|
method: Mapped[str] = mapped_column(String(10), default="GET")
|
|
expected_status: Mapped[int] = mapped_column(Integer, default=200)
|
|
timeout_seconds: Mapped[int] = mapped_column(Integer, default=10)
|
|
interval_seconds: Mapped[int] = mapped_column(Integer, default=60)
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
|
|
)
|
|
|
|
service: Mapped["Service"] = relationship(back_populates="monitors")
|
|
results: Mapped[list["MonitorResult"]] = relationship(
|
|
back_populates="monitor", cascade="all, delete-orphan"
|
|
)
|
|
|
|
|
|
class MonitorResult(Base):
|
|
__tablename__ = "monitor_results"
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
|
|
monitor_id: Mapped[str] = mapped_column(
|
|
String(36), ForeignKey("monitors.id"), nullable=False, index=True
|
|
)
|
|
status: Mapped[str] = mapped_column(String(20), nullable=False) # up | down | degraded
|
|
response_time_ms: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
status_code: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
checked_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.utcnow)
|
|
|
|
monitor: Mapped["Monitor"] = relationship(back_populates="results")
|
|
|
|
|
|
class Subscriber(Base):
|
|
__tablename__ = "subscribers"
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
|
|
email: Mapped[str] = mapped_column(String(255), unique=True, nullable=False, index=True)
|
|
is_confirmed: Mapped[bool] = mapped_column(Boolean, default=False)
|
|
confirm_token: Mapped[str | None] = mapped_column(String(100), nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
|
|
notifications: Mapped[list["NotificationLog"]] = relationship(back_populates="subscriber")
|
|
|
|
|
|
class NotificationLog(Base):
|
|
__tablename__ = "notification_logs"
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
|
|
incident_id: Mapped[str] = mapped_column(
|
|
String(36), ForeignKey("incidents.id"), nullable=False, index=True
|
|
)
|
|
subscriber_id: Mapped[str] = mapped_column(
|
|
String(36), ForeignKey("subscribers.id"), nullable=False
|
|
)
|
|
channel: Mapped[str] = mapped_column(String(20), nullable=False) # email | webhook
|
|
status: Mapped[str] = mapped_column(String(20), nullable=False) # sent | failed
|
|
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
|
|
|
|
incident: Mapped["Incident"] = relationship(back_populates="notifications")
|
|
subscriber: Mapped["Subscriber"] = relationship(back_populates="notifications")
|
|
|
|
|
|
class SiteSetting(Base):
|
|
__tablename__ = "site_settings"
|
|
|
|
id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid_str)
|
|
key: Mapped[str] = mapped_column(String(50), unique=True, nullable=False, index=True)
|
|
value: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime, default=datetime.utcnow, onupdate=datetime.utcnow
|
|
) |