class User(Base, TimestampMixin): __tablename__ = "users" id = Column(Integer, primary_key=True) email = Column(String(320), unique=True, nullable=False, index=True) password_hash = Column(String(255), nullable=False) full_name = Column(String(200), default="") is_admin = Column(Boolean, default=False, nullable=False) is_active = Column(Boolean, default=True, nullable=False) last_login_at = Column(DateTime(timezone=True)) gmail_accounts = relationship("GmailAccount", back_populates="user", cascade="all, delete-orphan") audit_logs = relationship("AuditLog", back_populates="user") class OAuthClientConfig(Base, TimestampMixin): """An imported Google OAuth client configuration (from client_secret JSON). Secrets stored encrypted. Multiple configs may exist (e.g. per project).""" __tablename__ = "oauth_client_configs" id = Column(Integer, primary_key=True) name = Column(String(200), nullable=False) client_id = Column(String(300), nullable=False) client_secret_enc = Column(String(600), nullable=False) # encrypted redirect_uri = Column(String(500), default="") === class Recipient(Base, TimestampMixin): __tablename__ = "recipients" id = Column(Integer, primary_key=True) list_id = Column(Integer, ForeignKey("recipient_lists.id", ondelete="CASCADE"), nullable=False, index=True) email = Column(String(320), nullable=False, index=True) first_name = Column(String(150), default="") last_name = Column(String(150), default="") company_name = Column(String(250), default="") company_phone = Column(String(60), default="") customer_email = Column(String(320), default="") custom_fields = Column(JSON, default=dict) # validation / status status = Column(String(30), default="valid") # valid|invalid|duplicate|suppressed|bounced validation_error = Column(Text, default="") is_valid = Column(Boolean, default=True, nullable=False) # unsubscribe token (unique secret per recipient) unsub_token = Column(String(64), unique=True, nullable=False) list = relationship("RecipientList", back_populates="recipients") __table_args__ = (Index("ix_recipient_list_email", "list_id", "email"),) === class CompanyPhoneNumber(Base, TimestampMixin): __tablename__ = "company_phone_numbers" id = Column(Integer, primary_key=True) user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True) label = Column(String(150), default="") phone = Column(String(60), nullable=False) is_active = Column(Boolean, default=True, nullable=False) use_count = Column(Integer, default=0) class SendJob(Base, TimestampMixin): __tablename__ = "send_jobs" id = Column(Integer, primary_key=True) campaign_id = Column(Integer, ForeignKey("campaigns.id", ondelete="CASCADE"), nullable=False, index=True) campaign_recipient_id = Column(Integer, ForeignKey("campaign_recipients.id", ondelete="CASCADE"), nullable=False, index=True)