Initial Switch to V2. Completely Overhauled Backend, Frontend and General Structure.

This commit is contained in:
2026-04-17 14:37:36 +03:00
parent eb773c5531
commit 0a8a42d69b
447 changed files with 70696 additions and 492 deletions

31
backend/devices/orm.py Normal file
View File

@@ -0,0 +1,31 @@
from datetime import datetime, timezone
from sqlalchemy import BigInteger, Column, DateTime, Index, String, Text, UniqueConstraint
from sqlalchemy.dialects.postgresql import JSONB
from database.postgres import Base
def _now():
return datetime.now(timezone.utc)
class DeviceAlert(Base):
"""Current alert state per device+subsystem (upserted, not appended)."""
__tablename__ = "device_alerts"
__table_args__ = (
UniqueConstraint("device_serial", "subsystem"),
Index("idx_device_alerts_serial", "device_serial"),
)
id = Column(BigInteger, primary_key=True, autoincrement=True)
device_serial = Column(String(128), nullable=False)
subsystem = Column(String(128), nullable=False)
state = Column(String(64), nullable=False)
message = Column(Text)
updated_at = Column(DateTime(timezone=True), nullable=False, default=_now, onupdate=_now)
# NOTE: device_logs, commands, and heartbeats are NOT declared as ORM models here.
# device_logs is a partitioned table — SQLAlchemy ORM does not support declarative
# partitioned tables cleanly. All three tables are created via raw SQL in the
# Alembic migration and accessed via raw queries in database/core.py (SQLite now)
# and will be accessed via raw async SQL after Phase 5 cutover.

View File

@@ -451,11 +451,17 @@ async def remove_user_from_device(
data = device_doc.to_dict() or {}
user_list = data.get("user_list", []) or []
# Remove any entry that resolves to this user_id
new_list = [
entry for entry in user_list
if not (isinstance(entry, str) and entry.split("/")[-1] == user_id)
]
from google.cloud.firestore_v1 import DocumentReference as DocRef
def resolves_to(entry, uid: str) -> bool:
if isinstance(entry, DocRef):
return entry.id == uid
if isinstance(entry, str):
return entry.split("/")[-1] == uid
return False
# Remove any entry that resolves to this user_id (handles both DocRef and string paths)
new_list = [entry for entry in user_list if not resolves_to(entry, user_id)]
device_ref.update({"user_list": new_list})
return {"status": "removed", "user_id": user_id}