"""User model with role enum and soft-delete.""" from __future__ import annotations from enum import Enum from typing import TYPE_CHECKING from sqlalchemy import Boolean, String, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column, relationship from app.models.base import Base, OrgScopedMixin, SoftDeleteMixin, TimestampMixin if TYPE_CHECKING: from app.models.org import Org class UserRole(str, Enum): """User role for RBAC.""" admin = "admin" sales_manager = "sales_manager" sales_rep = "sales_rep" class User(Base, TimestampMixin, SoftDeleteMixin, OrgScopedMixin): __tablename__ = "users" __table_args__ = (UniqueConstraint("org_id", "email", name="uq_users_org_email"),) id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) email: Mapped[str] = mapped_column(String(255), nullable=False, index=True) password_hash: Mapped[str] = mapped_column(String(255), nullable=False) name: Mapped[str] = mapped_column(String(255), nullable=False) role: Mapped[UserRole] = mapped_column( String(32), nullable=False, default=UserRole.sales_rep, server_default=UserRole.sales_rep.value, ) avatar_url: Mapped[str | None] = mapped_column(String(1024), nullable=True) email_notifications: Mapped[bool] = mapped_column( Boolean, nullable=False, default=True, server_default="1" ) # Relationship back to org (string reference avoids circular import at runtime) org: Mapped[Org] = relationship(back_populates="users", lazy="joined") def __repr__(self) -> str: return f""