Files
MABEA/backend/app/models/dokument.py
T
patrickandClaude Sonnet 5 069a1ee7ee
CI / backend-tests (push) Successful in 2m14s
CI / frontend-build (push) Successful in 36s
feat(dokumente): DOC-002 feste Dokumenttypen statt Freitext
Neues Pflichtfeld dokumenttyp (Enum: Prüfprotokoll/Wartungsbericht/
Bedienungsanleitung/Rechnung/Zulassungsdokument/Sonstiges, Migration 0026)
- macht Dokumente kategorisier- und filterbar statt nur per Freitext-
Beschreibung auffindbar zu sein. Backend: Pflichtfeld beim Upload, optionaler
Query-Filter bei GET /dokumente. Frontend: Auswahl-Dropdown beim Upload,
Typ-Badge + Filter-Dropdown in der Liste (DokumentePanel).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-08 10:32:25 +02:00

56 lines
2.5 KiB
Python

import enum
import uuid
from datetime import datetime
from sqlalchemy import ForeignKey, Integer, String
from sqlalchemy.dialects.postgresql import ENUM as PgEnum, TIMESTAMP, UUID
from sqlalchemy.orm import Mapped, mapped_column
from app.db.base import Base
class DokumentTyp(str, enum.Enum):
"""DOC-002: feste Kategorie statt Freitext - macht Dokumente filter-/
wiederfindbar (Nutzer-Vorgabe Modul 10: Prüfprotokolle/Wartungsberichte/
Bedienungsanleitungen/Rechnungen/Zulassungsdokumente)."""
pruefprotokoll = "pruefprotokoll"
wartungsbericht = "wartungsbericht"
bedienungsanleitung = "bedienungsanleitung"
rechnung = "rechnung"
zulassungsdokument = "zulassungsdokument"
sonstiges = "sonstiges"
dokument_typ_pg = PgEnum(DokumentTyp, name="dokument_typ", create_type=False)
class Dokument(Base):
"""Roadmap Phase 5 (Modul Dokumente): polymorpher Datei-Anhang an beliebige
Ressource (Objekt, Objektposition, Geräteinstanz, Mangel, Fahrzeugdetails,
Benutzer, ...) - gleiches entitaet_typ/entitaet_id-Muster wie Historie/
Mangel. Datei liegt lokal auf Platte (self-hosted, kein Cloud-Zwang),
speicherpfad ist relativ zu settings.upload_dir."""
__tablename__ = "dokument"
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
entitaet_typ: Mapped[str] = mapped_column(String, nullable=False)
entitaet_id: Mapped[str] = mapped_column(String, nullable=False)
dateiname: Mapped[str] = mapped_column(String, nullable=False)
speicherpfad: Mapped[str] = mapped_column(String, nullable=False)
mime_type: Mapped[str] = mapped_column(String, nullable=False)
groesse_bytes: Mapped[int] = mapped_column(Integer, nullable=False)
# SHA-256 des Dateiinhalts (DOC-001: Duplikat-Erkennung) - hex-codiert, 64
# Zeichen. Vergleich nur innerhalb derselben entitaet_typ/entitaet_id, nicht
# global (gleiche Datei an zwei verschiedenen Objekten ist kein Duplikat).
# Nullable wegen Altbestand vor dieser Migration (Hash nachträglich ohne
# Dateizugriff nicht sinnvoll befüllbar); jeder neue Upload setzt ihn.
dateihash: Mapped[str | None] = mapped_column(String(64))
dokumenttyp: Mapped[DokumentTyp] = mapped_column(
dokument_typ_pg, nullable=False, default=DokumentTyp.sonstiges
)
beschreibung: Mapped[str | None] = mapped_column(String)
hochgeladen_von: Mapped[int] = mapped_column(ForeignKey("benutzer.id"), nullable=False)
hochgeladen_am: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), nullable=False)