feat(akte): FILE-009 Freitext-Notizen an beliebiger Ressource
CI / backend-tests (push) Successful in 2m39s
CI / frontend-build (push) Successful in 20s

Polymorphes akte_notiz-Modell (gleiches entitaet_typ/entitaet_id-Muster wie
Dokument/Historie/Mangel), CRUD-Endpunkte, NotizenPanel im Akte-Grid. Löschen
nur durch Autor oder Administrator.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
This commit is contained in:
2026-09-10 00:49:47 +02:00
co-authored by Claude Sonnet 5
parent 9c6426190e
commit 1e8d66f636
13 changed files with 366 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
import uuid
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from app.api.deps import require_roles
from app.db.session import get_db
from app.models.auth import Benutzer, RolleTyp
from app.models.notiz import AkteNotiz
from app.schemas.dokument import EntitaetTyp
from app.schemas.notiz import AkteNotizCreate, AkteNotizRead
from app.services.notiz import erstelle_notiz, liste_fuer_entitaet, loesche_notiz
router = APIRouter()
_mitarbeiter_plus = require_roles(
RolleTyp.mitarbeiter,
RolleTyp.materialverantwortlicher,
RolleTyp.leitungsverantwortlicher,
RolleTyp.administration,
)
@router.get("/notizen", response_model=list[AkteNotizRead])
async def liste_notizen(
entitaet_typ: EntitaetTyp,
entitaet_id: str,
db: AsyncSession = Depends(get_db),
_=Depends(_mitarbeiter_plus),
) -> list[AkteNotiz]:
return await liste_fuer_entitaet(db, entitaet_typ=entitaet_typ, entitaet_id=entitaet_id)
@router.post("/notizen", response_model=AkteNotizRead, status_code=status.HTTP_201_CREATED)
async def notiz_anlegen(
payload: AkteNotizCreate,
db: AsyncSession = Depends(get_db),
current_user: Benutzer = Depends(_mitarbeiter_plus),
) -> AkteNotiz:
return await erstelle_notiz(
db,
entitaet_typ=payload.entitaet_typ,
entitaet_id=payload.entitaet_id,
text=payload.text,
autor_id=current_user.id,
)
@router.delete("/notizen/{notiz_id}", status_code=status.HTTP_204_NO_CONTENT)
async def notiz_loeschen(
notiz_id: uuid.UUID,
db: AsyncSession = Depends(get_db),
current_user: Benutzer = Depends(_mitarbeiter_plus),
) -> None:
notiz = await db.get(AkteNotiz, notiz_id)
if notiz is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Notiz nicht gefunden")
ist_administrator = RolleTyp.administration.value in current_user.rollen_namen
if notiz.autor_id != current_user.id and not ist_administrator:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, detail="Nur eigene Notizen oder als Administrator löschbar"
)
await loesche_notiz(db, notiz=notiz)