Phase 7 abgeschlossen: Suche mit gestuftem Index, Facetten, Palette
Der bisherige Suchvektor enthielt nur, was jeder sehen darf. Das war leck-sicher und unbrauchbar zugleich: ab Stufe 1 fand die Suche nichts von dem, was einen Fall ausmacht. SearchIndex hält jetzt sechs Zeilen je Ziel, eine pro Freigabestufe. Die Zeile zur Stufe N enthält alles, was ein Leser dieser Stufe sehen darf. Eine Suche nimmt genau diese eine Zeile und kann deshalb nichts finden, was sie nicht lesen darf — auch keinen höher eingestuften Eintrag in einer sichtbaren Akte. Schwärzungen werden dabei stufenweise aufgelöst: strip_redactions_above entfernt nur, was über der Stufe liegt. Sonst fände ein Leser der Stufe 4 einen Namen nicht, den er auf der Seite im Klartext sieht, und ein Leser der Stufe 1 einen, den er dort nur als Balken sieht. Die Suchbedingung ist nicht die Zugriffsprüfung: der Volltext liefert Kandidaten, die Sichtbarkeit kommt aus visibleCaseWhere — derselben Funktion wie in der Fallliste, und Treffer, Trefferzahl und Facettenzähler entstehen gemeinsam in einer Abfrage. Eine in SQL nachgebaute Sichtbarkeitsregel wäre die Sorte Duplikat, die auseinanderläuft. Filter stehen in der Adresse. Damit ist jeder Zustand teilbar, der Zurück-Knopf tut das Richtige, und eine gespeicherte Ansicht ist ein Lesezeichen. Die mitgelieferten Ansichten stehen im Programm, weil sie von der Gegenwart abhängen. Strg+K öffnet die Kommandopalette. Im Grundgerüst steckt nur das Tastaturereignis, die Palette selbst wird beim Öffnen geholt — das kostet die anderen Seiten rund hundert Byte. Offen geblieben: "Zuletzt geöffnet" als Ansicht. Dafür müsste jeder Aufruf jeder Akte mitgeschrieben werden; das wäre eine Überwachungsfunktion, die niemand bestellt hat. In TASKS vermerkt. 165 Tests im Web-Paket, 17 in der Datenbank, 7 im Worker, 34 e2e. Grösste Route bei 119,7 kB gegen 120 erlaubte. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
34a8b96dd3
commit
71c20f4b95
@@ -648,3 +648,73 @@ geändert da; das Aufräumen war von Hand nötig.
|
||||
Die Lehre steht hier, weil sie sich wiederholen wird: **vor jedem neuen Modell, Enum oder Feld
|
||||
im Schema nachsehen, ob es das schon gibt.** Das Schema ist über achthundert Zeilen lang, und
|
||||
der Teil, den man gerade nicht bearbeitet, ist der, den man vergisst.
|
||||
|
||||
## Suche
|
||||
|
||||
### Ein Vektor je Freigabestufe
|
||||
|
||||
Der Suchvektor aus Phase 2 enthielt nur, was **jeder** sehen darf (`minClearance = 0`). Das
|
||||
war leck-sicher und unbrauchbar zugleich: ab Stufe 1 fand die Suche nichts von dem, was einen
|
||||
Fall ausmacht. Der Kommentar in der Migration sagte schon, dass Phase 7 getrennte Vektoren je
|
||||
Stufe ergänzt — hier sind sie.
|
||||
|
||||
`SearchIndex` hält je Ziel sechs Zeilen, eine für jede Stufe. Die Zeile zur Stufe N enthält
|
||||
alles, was ein Leser dieser Stufe sehen darf: Kopfdaten, Abschnitte und Einträge bis
|
||||
einschliesslich N. Eine Suche nimmt **genau eine Zeile** — die zur eigenen Stufe — und kann
|
||||
deshalb nichts finden, was sie nicht lesen darf.
|
||||
|
||||
Sechs Zeilen je Fall statt einer ist bei ein paar hundert Akten kein Thema, und die Abfrage
|
||||
wird dadurch einfacher, nicht schwerer: kein `DISTINCT`, keine Aggregation über mehrere
|
||||
Zeilen, ein einzelner Gleichheitsvergleich auf `minClearance`.
|
||||
|
||||
### Schwärzungen werden stufenweise aufgelöst
|
||||
|
||||
`strip_redactions` warf jede markierte Stelle weg. Für einen gestuften Index ist das falsch in
|
||||
beide Richtungen: ein Leser der Stufe 4 fände einen Namen nicht, den er auf der Seite im
|
||||
Klartext sieht, und ohne die Funktion fände ein Leser der Stufe 1 einen, den er dort nur als
|
||||
Balken sieht.
|
||||
|
||||
`strip_redactions_above(text, stufe)` entfernt deshalb nur, was **über** der Stufe liegt, und
|
||||
löst die übrigen Marker auf. Ein Durchgang je Stufe darüber, weil die Stufe als Ziffer im
|
||||
Marker steht und `regexp_replace` nicht auf einen Fund hin verzweigen kann.
|
||||
|
||||
### Die Suchbedingung ist nicht die Zugriffsprüfung
|
||||
|
||||
Die Suche läuft in zwei Schritten, und der Unterschied ist der Punkt:
|
||||
|
||||
1. **Was passt** — eine Abfrage auf `SearchIndex`, die höchstens 500 Kennungen nach Rang
|
||||
liefert.
|
||||
2. **Was der Suchende sehen darf und wie viele es sind** — eine Abfrage mit
|
||||
`visibleCaseWhere` und den Filtern. Treffer, Trefferzahl **und Facettenzähler** entstehen
|
||||
dort gemeinsam.
|
||||
|
||||
Der erste Schritt ist eine Suchbedingung, kein Filter im Sinne von docs/08 — die
|
||||
Zugriffsprüfung steht ausschliesslich im zweiten und stammt aus derselben Funktion wie in der
|
||||
Fallliste. Es gibt keine zweite Fassung davon, und es sollte auch nie eine geben: eine in SQL
|
||||
nachgebaute Sichtbarkeitsregel wäre genau die Sorte Duplikat, die irgendwann auseinanderläuft.
|
||||
|
||||
Die Begrenzung auf 500 kann bei sehr allgemeinen Begriffen etwas abschneiden. Die Oberfläche
|
||||
sagt das dann ausdrücklich, statt eine vollständige Liste vorzutäuschen.
|
||||
|
||||
### Filter stehen in der Adresse, Ansichten sind Lesezeichen
|
||||
|
||||
Jeder Zustand der Suchseite ist eine Adresse. Damit ist er teilbar, der Zurück-Knopf tut das
|
||||
Richtige, und eine gespeicherte Ansicht ist nichts weiter als eine gemerkte Adresse.
|
||||
|
||||
Die **mitgelieferten** Ansichten stehen im Programm und nicht in der Datenbank, weil sie von
|
||||
der Gegenwart abhängen: „Wiedervorlage diese Woche" und „unbearbeitet seit 14 Tagen" wären als
|
||||
gespeicherte Zeitpunkte schon am nächsten Tag falsch.
|
||||
|
||||
„Zuletzt geöffnet" aus docs/08 fehlt: dafür müsste jeder Aufruf jeder Akte mitgeschrieben
|
||||
werden, und das Zugriffsprotokoll führt nur Stufe 3 aufwärts. Eine eigene Spur dafür anzulegen
|
||||
wäre eine Überwachungsfunktion, die niemand bestellt hat — wenn sie gebraucht wird, sollte das
|
||||
eine bewusste Entscheidung sein und keine Nebenwirkung.
|
||||
|
||||
### Die Kommandopalette wiegt nichts
|
||||
|
||||
Strg+K steckt in jeder Seite, und die Fallakte hat kein Bündel übrig. Deshalb ist der Teil im
|
||||
Grundgerüst nur ein Tastaturereignis; die Palette selbst wird geholt, wenn jemand sie öffnet.
|
||||
Das kostet die anderen Seiten rund hundert Byte.
|
||||
|
||||
Sie sucht bewusst schmal — Aktenzeichen, Titel, Namen, kein Volltext über Inhalte. Wer sie
|
||||
öffnet, will springen, nicht recherchieren.
|
||||
|
||||
Reference in New Issue
Block a user