초기 커밋
This commit is contained in:
0
app/models/__init__.py
Normal file
0
app/models/__init__.py
Normal file
0
app/models/mariadb/__init__.py
Normal file
0
app/models/mariadb/__init__.py
Normal file
39
app/models/mariadb/auth.py
Normal file
39
app/models/mariadb/auth.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlmodel import Field, Relationship, SQLModel
|
||||
|
||||
from app.db.base import TimestampMixin
|
||||
|
||||
|
||||
class RefreshToken(TimestampMixin, SQLModel, table=True):
|
||||
__tablename__ = "refresh_tokens"
|
||||
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
user_id: int = Field(foreign_key="users.id", index=True)
|
||||
token: str = Field(max_length=500, unique=True, index=True)
|
||||
expires_at: datetime
|
||||
is_revoked: bool = Field(default=False)
|
||||
device_info: str = Field(default="", max_length=255)
|
||||
|
||||
# Relationships
|
||||
user: User | None = Relationship(back_populates="refresh_tokens")
|
||||
|
||||
|
||||
class OAuthAccount(TimestampMixin, SQLModel, table=True):
|
||||
__tablename__ = "oauth_accounts"
|
||||
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
user_id: int = Field(foreign_key="users.id", index=True)
|
||||
provider: str = Field(max_length=50)
|
||||
provider_user_id: str = Field(max_length=255)
|
||||
access_token: str = Field(default="", max_length=500)
|
||||
refresh_token: str = Field(default="", max_length=500)
|
||||
expires_at: datetime | None = Field(default=None)
|
||||
|
||||
|
||||
# Avoid circular import
|
||||
from app.models.mariadb.user import User # noqa: E402, F811
|
||||
|
||||
RefreshToken.model_rebuild()
|
||||
36
app/models/mariadb/device.py
Normal file
36
app/models/mariadb/device.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlmodel import Field, Relationship, SQLModel
|
||||
|
||||
from app.core.constants import DeviceStatus
|
||||
from app.db.base import SoftDeleteMixin, TimestampMixin
|
||||
|
||||
|
||||
class DeviceGroup(TimestampMixin, SQLModel, table=True):
|
||||
__tablename__ = "device_groups"
|
||||
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
name: str = Field(max_length=100, unique=True)
|
||||
description: str = Field(default="", max_length=500)
|
||||
|
||||
devices: list[Device] = Relationship(back_populates="group")
|
||||
|
||||
|
||||
class Device(TimestampMixin, SoftDeleteMixin, SQLModel, table=True):
|
||||
__tablename__ = "devices"
|
||||
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
device_uid: str = Field(max_length=100, unique=True, index=True)
|
||||
name: str = Field(max_length=100)
|
||||
device_type: str = Field(default="", max_length=50)
|
||||
status: str = Field(default=DeviceStatus.OFFLINE, max_length=20)
|
||||
firmware_version: str = Field(default="", max_length=50)
|
||||
ip_address: str = Field(default="", max_length=45)
|
||||
group_id: int | None = Field(default=None, foreign_key="device_groups.id")
|
||||
owner_id: int | None = Field(default=None, foreign_key="users.id")
|
||||
last_seen_at: datetime | None = Field(default=None)
|
||||
metadata_json: str = Field(default="{}", max_length=2000)
|
||||
|
||||
group: DeviceGroup | None = Relationship(back_populates="devices")
|
||||
36
app/models/mariadb/monitoring.py
Normal file
36
app/models/mariadb/monitoring.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlmodel import Field, SQLModel
|
||||
|
||||
from app.core.constants import AlertSeverity
|
||||
from app.db.base import TimestampMixin
|
||||
|
||||
|
||||
class AlertRule(TimestampMixin, SQLModel, table=True):
|
||||
__tablename__ = "alert_rules"
|
||||
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
name: str = Field(max_length=100)
|
||||
description: str = Field(default="", max_length=500)
|
||||
metric: str = Field(max_length=100)
|
||||
condition: str = Field(max_length=50)
|
||||
threshold: float
|
||||
severity: str = Field(default=AlertSeverity.WARNING, max_length=20)
|
||||
is_enabled: bool = Field(default=True)
|
||||
device_group_id: int | None = Field(default=None, foreign_key="device_groups.id")
|
||||
created_by: int | None = Field(default=None, foreign_key="users.id")
|
||||
|
||||
|
||||
class Alert(TimestampMixin, SQLModel, table=True):
|
||||
__tablename__ = "alerts"
|
||||
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
rule_id: int | None = Field(default=None, foreign_key="alert_rules.id")
|
||||
device_id: int | None = Field(default=None, foreign_key="devices.id")
|
||||
severity: str = Field(default=AlertSeverity.WARNING, max_length=20)
|
||||
message: str = Field(max_length=500)
|
||||
is_acknowledged: bool = Field(default=False)
|
||||
acknowledged_by: int | None = Field(default=None, foreign_key="users.id")
|
||||
acknowledged_at: datetime | None = Field(default=None)
|
||||
27
app/models/mariadb/system.py
Normal file
27
app/models/mariadb/system.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from sqlmodel import Field, SQLModel
|
||||
|
||||
from app.db.base import TimestampMixin
|
||||
|
||||
|
||||
class SystemConfig(TimestampMixin, SQLModel, table=True):
|
||||
__tablename__ = "system_configs"
|
||||
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
key: str = Field(max_length=100, unique=True, index=True)
|
||||
value: str = Field(default="", max_length=2000)
|
||||
description: str = Field(default="", max_length=500)
|
||||
is_secret: bool = Field(default=False)
|
||||
|
||||
|
||||
class AuditLog(TimestampMixin, SQLModel, table=True):
|
||||
__tablename__ = "audit_logs"
|
||||
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
user_id: int | None = Field(default=None, foreign_key="users.id")
|
||||
action: str = Field(max_length=100)
|
||||
resource_type: str = Field(max_length=50)
|
||||
resource_id: str = Field(default="", max_length=50)
|
||||
details: str = Field(default="{}", max_length=2000)
|
||||
ip_address: str = Field(default="", max_length=45)
|
||||
44
app/models/mariadb/user.py
Normal file
44
app/models/mariadb/user.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from sqlmodel import Field, Relationship, SQLModel
|
||||
|
||||
from app.core.constants import Role
|
||||
from app.db.base import SoftDeleteMixin, TimestampMixin
|
||||
|
||||
|
||||
class User(TimestampMixin, SoftDeleteMixin, SQLModel, table=True):
|
||||
__tablename__ = "users"
|
||||
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
email: str = Field(max_length=255, unique=True, index=True)
|
||||
hashed_password: str = Field(max_length=255)
|
||||
role: str = Field(default=Role.USER, max_length=20)
|
||||
is_active: bool = Field(default=True)
|
||||
is_verified: bool = Field(default=False)
|
||||
last_login_at: datetime | None = Field(default=None)
|
||||
|
||||
# Relationships
|
||||
profile: UserProfile | None = Relationship(back_populates="user")
|
||||
refresh_tokens: list[RefreshToken] = Relationship(back_populates="user")
|
||||
|
||||
|
||||
class UserProfile(TimestampMixin, SQLModel, table=True):
|
||||
__tablename__ = "user_profiles"
|
||||
|
||||
id: int | None = Field(default=None, primary_key=True)
|
||||
user_id: int = Field(foreign_key="users.id", unique=True, index=True)
|
||||
full_name: str = Field(default="", max_length=100)
|
||||
phone: str = Field(default="", max_length=20)
|
||||
organization: str = Field(default="", max_length=100)
|
||||
avatar_url: str = Field(default="", max_length=500)
|
||||
|
||||
# Relationships
|
||||
user: User | None = Relationship(back_populates="profile")
|
||||
|
||||
|
||||
# Forward reference resolution
|
||||
from app.models.mariadb.auth import RefreshToken # noqa: E402
|
||||
|
||||
User.model_rebuild()
|
||||
0
app/models/mongodb/__init__.py
Normal file
0
app/models/mongodb/__init__.py
Normal file
24
app/models/mongodb/analytics_result.py
Normal file
24
app/models/mongodb/analytics_result.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from beanie import Document
|
||||
from pydantic import Field
|
||||
|
||||
|
||||
class AnalyticsResult(Document):
|
||||
analysis_type: str
|
||||
parameters: dict = Field(default_factory=dict)
|
||||
result: dict = Field(default_factory=dict)
|
||||
device_id: str | None = None
|
||||
period_start: datetime | None = None
|
||||
period_end: datetime | None = None
|
||||
created_at: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
class Settings:
|
||||
name = "analytics_results"
|
||||
indexes = [
|
||||
"analysis_type",
|
||||
"device_id",
|
||||
[("created_at", -1)],
|
||||
]
|
||||
27
app/models/mongodb/device_log.py
Normal file
27
app/models/mongodb/device_log.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from beanie import Document
|
||||
from pydantic import Field
|
||||
|
||||
|
||||
class DeviceLog(Document):
|
||||
device_id: str
|
||||
event_type: str
|
||||
payload: dict = Field(default_factory=dict)
|
||||
ip_address: str | None = None
|
||||
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
class Settings:
|
||||
name = "device_logs"
|
||||
indexes = [
|
||||
"device_id",
|
||||
"event_type",
|
||||
[("timestamp", -1)],
|
||||
]
|
||||
# TTL: 90일 후 자동 삭제
|
||||
timeseries = {
|
||||
"timeField": "timestamp",
|
||||
"expireAfterSeconds": 90 * 24 * 3600,
|
||||
}
|
||||
24
app/models/mongodb/notification.py
Normal file
24
app/models/mongodb/notification.py
Normal file
@@ -0,0 +1,24 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from beanie import Document
|
||||
from pydantic import Field
|
||||
|
||||
|
||||
class Notification(Document):
|
||||
user_id: int
|
||||
title: str
|
||||
message: str
|
||||
notification_type: str = "info"
|
||||
is_read: bool = False
|
||||
read_at: datetime | None = None
|
||||
created_at: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
class Settings:
|
||||
name = "notifications"
|
||||
indexes = [
|
||||
"user_id",
|
||||
[("user_id", 1), ("is_read", 1)],
|
||||
[("created_at", -1)],
|
||||
]
|
||||
20
app/models/mongodb/telemetry.py
Normal file
20
app/models/mongodb/telemetry.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from beanie import Document
|
||||
from pydantic import Field
|
||||
|
||||
|
||||
class TelemetryData(Document):
|
||||
device_id: str
|
||||
metrics: dict = Field(default_factory=dict)
|
||||
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
||||
|
||||
class Settings:
|
||||
name = "telemetry_data"
|
||||
indexes = [
|
||||
"device_id",
|
||||
[("timestamp", -1)],
|
||||
[("device_id", 1), ("timestamp", -1)],
|
||||
]
|
||||
Reference in New Issue
Block a user