52 lines
2.7 KiB
Python
52 lines
2.7 KiB
Python
"""Abgeglichene Ordner: Dokumente vom Rechner einer Person, die sich regelmäßig ändern.
|
|
|
|
Der Browser gleicht einen lokalen Ordner mit Bifröst ab (nur Neues und Geändertes); gespeichert wird der
|
|
ausgelesene Text, nicht das Original. Office-Dokumente, PDF und Bilder liest ein zentraler MCP-Server
|
|
(Rolle „documents“) aus, Textdateien Bifröst selbst. Sichtbar je Ordner: nur für die Person, die abgleicht
|
|
(nur ihre eigenen Runs in ihren eigenen Chats), oder für den ganzen Workspace (mit Bestätigung).
|
|
"""
|
|
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import BigInteger, Computed, ForeignKey, Identity, Index, String, Text, UniqueConstraint
|
|
from sqlalchemy.dialects.postgresql import TSVECTOR
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from app.core.database import Base, now
|
|
|
|
PRIVATE, WORKSPACE = "private", "workspace"
|
|
# Datei: wartet auf Auslese | ausgelesen | Fehler | Format ohne Auslese
|
|
PENDING, OK, ERROR, UNSUPPORTED = "pending", "ok", "error", "unsupported"
|
|
|
|
|
|
class DocFolder(Base):
|
|
__tablename__ = "doc_folders"
|
|
|
|
id: Mapped[int] = mapped_column(primary_key=True)
|
|
workspace_id: Mapped[int] = mapped_column(ForeignKey("workspaces.id", ondelete="CASCADE"), index=True)
|
|
owner_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"), index=True)
|
|
name: Mapped[str] = mapped_column(String(100))
|
|
scope: Mapped[str] = mapped_column(String(20), default=PRIVATE) # private | workspace
|
|
exposure_confirmed: Mapped[bool] = mapped_column(default=False)
|
|
synced: Mapped[datetime | None] # letzter vollständiger Abgleich
|
|
created: Mapped[datetime] = mapped_column(default=now)
|
|
|
|
|
|
class DocFile(Base):
|
|
__tablename__ = "doc_files"
|
|
__table_args__ = (UniqueConstraint("folder_id", "path"),
|
|
Index("ix_doc_files_search", "search", postgresql_using="gin"))
|
|
|
|
id: Mapped[int] = mapped_column(BigInteger, Identity(), primary_key=True)
|
|
folder_id: Mapped[int] = mapped_column(ForeignKey("doc_folders.id", ondelete="CASCADE"), index=True)
|
|
path: Mapped[str] = mapped_column(String(500)) # relativ zum Ordner
|
|
size: Mapped[int] = mapped_column(BigInteger)
|
|
modified: Mapped[int] = mapped_column(BigInteger) # lastModified im Browser (ms); erkennt Änderungen
|
|
sha256: Mapped[str] = mapped_column(String(64))
|
|
status: Mapped[str] = mapped_column(String(20), default=PENDING)
|
|
error: Mapped[str] = mapped_column(Text, default="")
|
|
text: Mapped[str] = mapped_column(Text, default="")
|
|
# Volltextsuche über Pfad und Inhalt (deutsche Stammformen)
|
|
search = mapped_column(TSVECTOR, Computed("to_tsvector('german', coalesce(path, '') || ' ' || coalesce(text, ''))",
|
|
persisted=True))
|
|
updated: Mapped[datetime] = mapped_column(default=now)
|