best / backend /app /models /application.py
anky2002's picture
fix: Add missing ForeignKey constraints to application models
9d353ab verified
Raw
History Blame Contribute Delete
6.79 kB
"""
Application tracking models - Kanban board for job applications.
"""
import uuid
from datetime import datetime
from enum import Enum
from sqlalchemy import DateTime, ForeignKey, Integer, String, Text, func
from sqlalchemy.dialects.postgresql import JSONB, UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.core.database import Base
class ApplicationStatus(str, Enum):
WISHLIST = "wishlist"
APPLYING = "applying"
APPLIED = "applied"
SCREENING = "screening"
INTERVIEWING = "interviewing"
OFFER = "offer"
ACCEPTED = "accepted"
REJECTED = "rejected"
WITHDRAWN = "withdrawn"
GHOSTED = "ghosted"
class InterviewType(str, Enum):
PHONE_SCREEN = "phone_screen"
TECHNICAL = "technical"
BEHAVIORAL = "behavioral"
SYSTEM_DESIGN = "system_design"
ONSITE = "onsite"
HIRING_MANAGER = "hiring_manager"
TAKE_HOME = "take_home"
FINAL = "final"
OTHER = "other"
class Application(Base):
__tablename__ = "applications"
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
user_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
job_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("jobs.id", ondelete="SET NULL"), nullable=True, index=True)
custom_job_title: Mapped[str | None] = mapped_column(String(512), nullable=True)
custom_company_name: Mapped[str | None] = mapped_column(String(256), nullable=True)
custom_job_url: Mapped[str | None] = mapped_column(String(2048), nullable=True)
status: Mapped[str] = mapped_column(String(30), default=ApplicationStatus.WISHLIST, nullable=False, index=True)
priority: Mapped[int] = mapped_column(Integer, default=0)
applied_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
response_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
resume_version_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), nullable=True)
cover_letter: Mapped[str | None] = mapped_column(Text, nullable=True)
referral_contact: Mapped[str | None] = mapped_column(String(256), nullable=True)
referral_notes: Mapped[str | None] = mapped_column(Text, nullable=True)
offered_salary: Mapped[int | None] = mapped_column(Integer, nullable=True)
offered_equity: Mapped[str | None] = mapped_column(String(100), nullable=True)
notes: Mapped[str | None] = mapped_column(Text, nullable=True)
tags: Mapped[list | None] = mapped_column(JSONB, nullable=True)
extra_data: Mapped[dict | None] = mapped_column("metadata", JSONB, nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
user: Mapped["User"] = relationship(back_populates="applications")
job: Mapped["Job"] = relationship(back_populates="applications")
events: Mapped[list["ApplicationEvent"]] = relationship(back_populates="application", cascade="all, delete-orphan")
interviews: Mapped[list["Interview"]] = relationship(back_populates="application", cascade="all, delete-orphan")
contacts: Mapped[list["Contact"]] = relationship(back_populates="application")
class ApplicationEvent(Base):
"""Timeline events for an application."""
__tablename__ = "application_events"
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
application_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("applications.id", ondelete="CASCADE"), nullable=False, index=True)
event_type: Mapped[str] = mapped_column(String(50), nullable=False)
description: Mapped[str | None] = mapped_column(Text, nullable=True)
old_value: Mapped[str | None] = mapped_column(String(100), nullable=True)
new_value: Mapped[str | None] = mapped_column(String(100), nullable=True)
extra_data: Mapped[dict | None] = mapped_column("metadata", JSONB, nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
application: Mapped["Application"] = relationship(back_populates="events")
class Interview(Base):
__tablename__ = "interviews"
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
application_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("applications.id", ondelete="CASCADE"), nullable=False, index=True)
interview_type: Mapped[str] = mapped_column(String(30), nullable=False)
scheduled_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
duration_minutes: Mapped[int | None] = mapped_column(Integer, nullable=True)
location: Mapped[str | None] = mapped_column(String(512), nullable=True)
interviewer_names: Mapped[list | None] = mapped_column(JSONB, nullable=True)
notes: Mapped[str | None] = mapped_column(Text, nullable=True)
prep_notes: Mapped[str | None] = mapped_column(Text, nullable=True)
outcome: Mapped[str | None] = mapped_column(String(30), nullable=True)
feedback: Mapped[str | None] = mapped_column(Text, nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
application: Mapped["Application"] = relationship(back_populates="interviews")
class Contact(Base):
"""Contacts associated with applications (recruiters, hiring managers)."""
__tablename__ = "contacts"
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
application_id: Mapped[uuid.UUID | None] = mapped_column(UUID(as_uuid=True), ForeignKey("applications.id", ondelete="SET NULL"), nullable=True, index=True)
user_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
name: Mapped[str] = mapped_column(String(256), nullable=False)
role: Mapped[str | None] = mapped_column(String(100), nullable=True)
company: Mapped[str | None] = mapped_column(String(256), nullable=True)
email: Mapped[str | None] = mapped_column(String(320), nullable=True)
phone: Mapped[str | None] = mapped_column(String(30), nullable=True)
linkedin_url: Mapped[str | None] = mapped_column(String(512), nullable=True)
notes: Mapped[str | None] = mapped_column(Text, nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
application: Mapped["Application"] = relationship(back_populates="contacts")