From dc83d7bef233d27b8deb186dd3824292a822d8fa Mon Sep 17 00:00:00 2001 From: Nora Date: Mon, 22 Jun 2026 14:13:30 -0600 Subject: [PATCH] feat(db): add User and Session models --- backend/src/cyclone/db.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/backend/src/cyclone/db.py b/backend/src/cyclone/db.py index accef0d..782afc2 100644 --- a/backend/src/cyclone/db.py +++ b/backend/src/cyclone/db.py @@ -30,6 +30,7 @@ from sqlalchemy import ( Numeric, String, Text, + func, text, ) from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, sessionmaker @@ -836,3 +837,27 @@ class ClearhouseORM(Base): filename_block_json: Mapped[dict] = mapped_column(JSONText, nullable=False) sftp_block_json: Mapped[dict] = mapped_column(JSONText, nullable=False) updated_at: Mapped[str] = mapped_column(String(32), nullable=False) + + +class User(Base): + """Auth user (admin / user / viewer).""" + + __tablename__ = "users" + + id: Mapped[int] = mapped_column(Integer, primary_key=True) + username: Mapped[str] = mapped_column(String(64), unique=True, index=True) + password_hash: Mapped[str] = mapped_column(String(255), nullable=False) + role: Mapped[str] = mapped_column(String(16), nullable=False) + created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) + disabled_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True) + + +class Session(Base): + """Server-side auth session (HttpOnly cookie holds the id).""" + + __tablename__ = "sessions" + + id: Mapped[str] = mapped_column(String(64), primary_key=True) + user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), index=True) + expires_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), index=True) + created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())