mirror of
https://github.com/velocitatem/cvfs.git
synced 2026-05-31 08:43:37 +00:00
Finish MVP and dockerize
This commit is contained in:
21
apps/backend/fastapi/app/models/__init__.py
Normal file
21
apps/backend/fastapi/app/models/__init__.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from .cv import (
|
||||
AiSuggestion,
|
||||
CvDocument,
|
||||
CvPatch,
|
||||
CvVersion,
|
||||
PublicAsset,
|
||||
Specialization,
|
||||
Submission,
|
||||
SubmissionStatus,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"CvDocument",
|
||||
"CvVersion",
|
||||
"CvPatch",
|
||||
"Specialization",
|
||||
"Submission",
|
||||
"SubmissionStatus",
|
||||
"PublicAsset",
|
||||
"AiSuggestion",
|
||||
]
|
||||
152
apps/backend/fastapi/app/models/cv.py
Normal file
152
apps/backend/fastapi/app/models/cv.py
Normal file
@@ -0,0 +1,152 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import enum
|
||||
|
||||
from sqlalchemy import Boolean, DateTime, Enum, ForeignKey, String, Text
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.db.base import Base
|
||||
from app.models.mixins import IdentifierMixin, TimestampMixin
|
||||
|
||||
|
||||
class CvDocument(Base, IdentifierMixin, TimestampMixin):
|
||||
__tablename__ = "cv_documents"
|
||||
|
||||
owner_id: Mapped[str] = mapped_column(String(255), index=True)
|
||||
title: Mapped[str] = mapped_column(String(255))
|
||||
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
root_version_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("cv_versions.id"), nullable=True
|
||||
)
|
||||
|
||||
versions: Mapped[list["CvVersion"]] = relationship(
|
||||
"CvVersion", back_populates="document"
|
||||
)
|
||||
|
||||
|
||||
class CvVersion(Base, IdentifierMixin, TimestampMixin):
|
||||
__tablename__ = "cv_versions"
|
||||
|
||||
document_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("cv_documents.id", ondelete="CASCADE")
|
||||
)
|
||||
parent_version_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("cv_versions.id"), nullable=True
|
||||
)
|
||||
branch_name: Mapped[str] = mapped_column(String(120), default="root")
|
||||
version_label: Mapped[str | None] = mapped_column(String(120), nullable=True)
|
||||
artifact_docx_key: Mapped[str | None] = mapped_column(String(512), nullable=True)
|
||||
preview_html_key: Mapped[str | None] = mapped_column(String(512), nullable=True)
|
||||
structured_blocks: Mapped[list[dict] | None] = mapped_column(JSONB, default=list)
|
||||
metadata_json: Mapped[dict | None] = mapped_column(JSONB, default=dict)
|
||||
|
||||
document: Mapped[CvDocument] = relationship("CvDocument", back_populates="versions")
|
||||
parent: Mapped["CvVersion" | None] = relationship(
|
||||
"CvVersion", remote_side="CvVersion.id"
|
||||
)
|
||||
patches: Mapped[list["CvPatch"]] = relationship("CvPatch", back_populates="version")
|
||||
submissions: Mapped[list["Submission"]] = relationship(
|
||||
"Submission", back_populates="version"
|
||||
)
|
||||
|
||||
|
||||
class CvPatch(Base, IdentifierMixin, TimestampMixin):
|
||||
__tablename__ = "cv_patches"
|
||||
|
||||
version_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("cv_versions.id", ondelete="CASCADE")
|
||||
)
|
||||
target_path: Mapped[str] = mapped_column(String(255))
|
||||
operation: Mapped[str] = mapped_column(String(64))
|
||||
old_value: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
new_value: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
metadata_json: Mapped[dict | None] = mapped_column(JSONB, default=dict)
|
||||
|
||||
version: Mapped[CvVersion] = relationship("CvVersion", back_populates="patches")
|
||||
|
||||
|
||||
class Specialization(Base, IdentifierMixin, TimestampMixin):
|
||||
__tablename__ = "specializations"
|
||||
|
||||
document_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("cv_documents.id", ondelete="CASCADE")
|
||||
)
|
||||
name: Mapped[str] = mapped_column(String(120))
|
||||
description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
based_on_version_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("cv_versions.id"), nullable=True
|
||||
)
|
||||
metadata_json: Mapped[dict | None] = mapped_column(JSONB, default=dict)
|
||||
|
||||
|
||||
class SubmissionStatus(str, enum.Enum):
|
||||
draft = "draft"
|
||||
tailoring = "tailoring"
|
||||
pending_review = "pending_review"
|
||||
published = "published"
|
||||
archived = "archived"
|
||||
|
||||
|
||||
class Submission(Base, IdentifierMixin, TimestampMixin):
|
||||
__tablename__ = "submissions"
|
||||
|
||||
version_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("cv_versions.id", ondelete="CASCADE")
|
||||
)
|
||||
company_name: Mapped[str] = mapped_column(String(160))
|
||||
role_title: Mapped[str] = mapped_column(String(160))
|
||||
job_url: Mapped[str | None] = mapped_column(String(512), nullable=True)
|
||||
job_description: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
status: Mapped[SubmissionStatus] = mapped_column(
|
||||
Enum(SubmissionStatus), default=SubmissionStatus.draft
|
||||
)
|
||||
metadata_json: Mapped[dict | None] = mapped_column(JSONB, default=dict)
|
||||
|
||||
version: Mapped[CvVersion] = relationship("CvVersion", back_populates="submissions")
|
||||
suggestions: Mapped[list["AiSuggestion"]] = relationship(
|
||||
"AiSuggestion", back_populates="submission"
|
||||
)
|
||||
public_asset: Mapped["PublicAsset" | None] = relationship(
|
||||
"PublicAsset", back_populates="submission"
|
||||
)
|
||||
|
||||
|
||||
class PublicAsset(Base, IdentifierMixin, TimestampMixin):
|
||||
__tablename__ = "public_assets"
|
||||
|
||||
submission_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("submissions.id", ondelete="SET NULL"), nullable=True
|
||||
)
|
||||
version_id: Mapped[str | None] = mapped_column(
|
||||
ForeignKey("cv_versions.id"), nullable=True
|
||||
)
|
||||
slug: Mapped[str] = mapped_column(String(160), unique=True, index=True)
|
||||
artifact_key: Mapped[str] = mapped_column(String(512))
|
||||
is_public: Mapped[bool] = mapped_column(Boolean, default=True)
|
||||
expires_at: Mapped[str | None] = mapped_column(
|
||||
DateTime(timezone=True), nullable=True
|
||||
)
|
||||
|
||||
submission: Mapped[Submission | None] = relationship(
|
||||
"Submission", back_populates="public_asset"
|
||||
)
|
||||
version: Mapped[CvVersion | None] = relationship("CvVersion")
|
||||
|
||||
|
||||
class AiSuggestion(Base, IdentifierMixin, TimestampMixin):
|
||||
__tablename__ = "ai_suggestions"
|
||||
|
||||
submission_id: Mapped[str] = mapped_column(
|
||||
ForeignKey("submissions.id", ondelete="CASCADE")
|
||||
)
|
||||
target_path: Mapped[str] = mapped_column(String(255))
|
||||
operation: Mapped[str] = mapped_column(String(64))
|
||||
proposed_text: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
rationale: Mapped[str | None] = mapped_column(Text, nullable=True)
|
||||
accepted: Mapped[bool | None] = mapped_column(Boolean, nullable=True)
|
||||
metadata_json: Mapped[dict | None] = mapped_column(JSONB, default=dict)
|
||||
|
||||
submission: Mapped[Submission] = relationship(
|
||||
"Submission", back_populates="suggestions"
|
||||
)
|
||||
23
apps/backend/fastapi/app/models/mixins.py
Normal file
23
apps/backend/fastapi/app/models/mixins.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from uuid import uuid4
|
||||
|
||||
from sqlalchemy import DateTime
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
|
||||
class IdentifierMixin:
|
||||
id: Mapped[str] = mapped_column(
|
||||
UUID(as_uuid=False), primary_key=True, default=lambda: str(uuid4())
|
||||
)
|
||||
|
||||
|
||||
class TimestampMixin:
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=datetime.utcnow
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow
|
||||
)
|
||||
Reference in New Issue
Block a user