"""ContactFolder model — hierarchical folders for organizing contacts. Supports nested folders via parent_id, per-user ownership, and sort_order for manual ordering via drag & drop. """ from __future__ import annotations import uuid from datetime import datetime from sqlalchemy import DateTime, ForeignKey, Index, Integer, String, func from sqlalchemy.dialects.postgresql import UUID as PGUUID from sqlalchemy.orm import Mapped, mapped_column, relationship from app.core.db import Base, TenantMixin class ContactFolder(Base, TenantMixin): """Hierarchical folder for organizing contacts. Folders are tenant-scoped and user-owned. A folder with parent_id=NULL is a root folder. sort_order controls display order within the same parent. """ __tablename__ = "contact_folders" __table_args__ = ( Index("ix_contact_folders_tenant_parent", "tenant_id", "parent_id"), Index("ix_contact_folders_user", "user_id"), ) id: Mapped[uuid.UUID] = mapped_column( PGUUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) name: Mapped[str] = mapped_column(String(255), nullable=False) parent_id: Mapped[uuid.UUID | None] = mapped_column( PGUUID(as_uuid=True), ForeignKey("contact_folders.id", ondelete="CASCADE"), nullable=True, ) user_id: Mapped[uuid.UUID] = mapped_column( PGUUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False ) sort_order: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0") # ── Relationships ── parent: Mapped[ContactFolder | None] = relationship( "ContactFolder", remote_side="ContactFolder.id", back_populates="children", ) children: Mapped[list[ContactFolder]] = relationship( "ContactFolder", back_populates="parent", cascade="all, delete-orphan", order_by="ContactFolder.sort_order", )