""" Modelli Label e MessageLabel – tagging messaggi con supporto tassonomia gerarchica. Struttura ad albero (Feature N2 – Tassonomia di Classificazione Multi-livello): parent_id = NULL → Livello 0: Ambito (Area Aziendale) parent_id = ID ambito → Livello 1: Processo parent_id = ID processo → Livello 2: Classificazione (foglia) Le label senza parent_id sono label "piatte" classiche (comportamento pre-esistente). """ import uuid from sqlalchemy import CHAR, ForeignKey, Index, String, Text from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column from app.database import Base class Label(Base): __tablename__ = "labels" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) tenant_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("tenants.id", ondelete="CASCADE"), nullable=False ) # Tassonomia: se parent_id è None è un nodo radice (Ambito) o label piatta parent_id: Mapped[uuid.UUID | None] = mapped_column( UUID(as_uuid=True), ForeignKey("labels.id", ondelete="CASCADE"), nullable=True, ) name: Mapped[str] = mapped_column(String(100), nullable=False) color: Mapped[str | None] = mapped_column(CHAR(7), nullable=True) # hex #RRGGBB description: Mapped[str | None] = mapped_column(Text, nullable=True) # Nota: i vincoli di unicità sono gestiti da indici parziali nel DB: # uq_label_name_root – UNIQUE (tenant_id, name) WHERE parent_id IS NULL # uq_label_name_parent – UNIQUE (tenant_id, name, parent_id) WHERE parent_id IS NOT NULL __table_args__ = ( Index("idx_labels_parent", "parent_id"), ) def __repr__(self) -> str: return f"