diff --git a/packages/db/prisma/migrations/20260904090000_taeter_und_mittaeter/migration.sql b/packages/db/prisma/migrations/20260904090000_taeter_und_mittaeter/migration.sql new file mode 100644 index 0000000..902c26b --- /dev/null +++ b/packages/db/prisma/migrations/20260904090000_taeter_und_mittaeter/migration.sql @@ -0,0 +1,13 @@ +-- Täter und Mittäter als Beteiligtenrollen. +-- +-- Damit wird eine Lücke sichtbar, die es schon vorher gab: ein Beteiligter darf +-- die Akte lesen, gleich in welcher Rolle. Bei „Betroffener" fiel das nicht auf, +-- bei „Täter" wäre es offensichtlich falsch — der Beschuldigte läse die +-- Ermittlung gegen sich selbst mit. +-- +-- Die Prüfung in lib/access/caseFilter.ts unterscheidet deshalb ab jetzt +-- Arbeitsrollen (LEAD, INVESTIGATOR, OBSERVER) von Angaben über den Fall +-- (WITNESS, SUBJECT, SUSPECT, ACCOMPLICE). Nur die ersten öffnen die Akte. + +ALTER TYPE "ParticipantRole" ADD VALUE IF NOT EXISTS 'SUSPECT'; +ALTER TYPE "ParticipantRole" ADD VALUE IF NOT EXISTS 'ACCOMPLICE'; diff --git a/packages/db/prisma/schema.prisma b/packages/db/prisma/schema.prisma index b8b5e02..f8e8285 100644 --- a/packages/db/prisma/schema.prisma +++ b/packages/db/prisma/schema.prisma @@ -410,12 +410,21 @@ model CaseParticipant { @@index([personnelFileId]) } +/// Rollen eines Beteiligten. +/// +/// Zwei Gruppen, und der Unterschied entscheidet ueber den Zugriff: LEAD, +/// INVESTIGATOR und OBSERVER **arbeiten** an der Akte und duerfen sie deshalb +/// lesen. WITNESS, SUBJECT, SUSPECT und ACCOMPLICE sind Angaben **ueber** den +/// Fall und verschaffen keinen Zugang — sonst laese der Beschuldigte die +/// Ermittlung gegen sich selbst mit. Siehe lib/cases/terms.ts. enum ParticipantRole { LEAD INVESTIGATOR + OBSERVER WITNESS SUBJECT - OBSERVER + SUSPECT + ACCOMPLICE } /// Schlaegt jede Freigabestufe. Deckt den Fall ab, dass gegen einen hochrangigen diff --git a/web/app/(app)/suche/page.tsx b/web/app/(app)/suche/page.tsx index 2798545..34899e2 100644 --- a/web/app/(app)/suche/page.tsx +++ b/web/app/(app)/suche/page.tsx @@ -3,7 +3,12 @@ import Link from 'next/link' import { db } from '@/lib/db' import { requireUser } from '@/lib/auth/current' import { parseFilters, toSearchParams, SEARCH_KINDS } from '@/lib/search/query' -import { searchCases, searchDocuments, searchPersonnel } from '@/lib/search/service' +import { + searchCases, + searchCounts, + searchDocuments, + searchPersonnel, +} from '@/lib/search/service' import { builtinViews } from '@/lib/search/views' import { de } from '@/lib/i18n/de' import { StampMark, classificationEdgeStyle } from '@/components/StampMark' @@ -44,12 +49,17 @@ export default async function SearchPage({ ]) const levelName = new Map(levels.map((l) => [l.level, l.name])) - const ergebnis = + const [ergebnis, zahlen] = await Promise.all([ filters.kind === 'document' - ? await searchDocuments(user.permissions, filters) + ? searchDocuments(user.permissions, filters) : filters.kind === 'personnel' - ? await searchPersonnel(user.permissions, filters) - : await searchCases(user.permissions, filters) + ? searchPersonnel(user.permissions, filters) + : searchCases(user.permissions, filters), + // Die Zahlen der anderen Arten. Ohne sie sucht man nach einem Namen, landet + // auf den Fallakten und erfährt nie, dass es dazu auch eine Personalakte + // gibt — der Reiter sieht leer aus wie jeder andere. + searchCounts(user.permissions, filters), + ]) const statusTags = filters.kind === 'personnel' ? await listStatusTags() : [] @@ -64,16 +74,26 @@ export default async function SearchPage({ -