docs(quick-260921-m34): 288 any auf 15 gesenkt, jede verbliebene mit Urteil
Zusammenfassung mit Urteilsregister und STATE.md zum Quick-Vorgang 260921-m34. Der groesste Posten war ein einziges Missverstaendnis: 105 Stellen trugen eine Zusicherung an der Mandantenbindung, die nie noetig war - prisma.$extends() liefert laengst einen getypten Klienten. Die tenantId-Frage wurde hergeleitet statt nach Bequemlichkeit entschieden: string ohne Fragezeichen, belegt aus Pflichtspalte im Schema, Bestandstyp und dem Super-Admin-Zweig der Mandantenpruefung - der diesen Typ gar nicht liest und deshalb nicht zu totem Code werden kann. Der Waechter blieb ueber den ganzen Lauf unveraendert. Vier Befunde gemeldet statt still repariert. Zwei brauchen eine Entscheidung, beide wuerden Verhalten aendern - darunter ein sicherheitsrelevanter: die IMAP-Einstellung STARTTLS erzwingt nichts, weil die gesetzte Option in imapflow 1.4.3 nicht existiert. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
This commit is contained in:
+414
@@ -0,0 +1,414 @@
|
||||
---
|
||||
phase: quick-260921-m34
|
||||
plan: 01
|
||||
subsystem: apps/api (Typdisziplin)
|
||||
tags: [typescript, any, refactor, mandantentrennung, prisma, node-forge, imapflow]
|
||||
status: complete
|
||||
requires: []
|
||||
provides:
|
||||
- "apps/api/src/auth/types/auth-user.ts (AuthUser, AuthenticatedRequest, JwtPayload, UploadedFileLike)"
|
||||
- "apps/api/src/prisma/prisma-error.ts (prismaErrorCode, prismaErrorTarget)"
|
||||
affects:
|
||||
- "apps/api/src (48 Dateien)"
|
||||
- "apps/web/src/test/setup.ts"
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "catch (e: unknown) plus Form-Eingrenzung statt catch (e: any)"
|
||||
- "Mitgelieferte Bibliothekstypen vor eigenen Handschnittstellen"
|
||||
- "Ehrliches any mit geschriebener Begruendung statt erzwungener Zusicherung"
|
||||
key-files:
|
||||
created:
|
||||
- apps/api/src/auth/types/auth-user.ts
|
||||
- apps/api/src/prisma/prisma-error.ts
|
||||
modified:
|
||||
- apps/api/src/prisma/prisma-tenant.extension.ts
|
||||
- apps/api/src/cert-manager/cert-manager.service.ts
|
||||
- apps/api/src/inbox/imap.provider.ts
|
||||
- apps/api/src/inbox/exchange-inbox.provider.ts
|
||||
- apps/api/src/calendar/providers/exchange.provider.ts
|
||||
- apps/api/src/user/user.service.ts
|
||||
- apps/api/src/groups/groups.service.ts
|
||||
- apps/api/src/ldap/ldap.service.ts
|
||||
- apps/api/src/mail/mail.service.ts
|
||||
decisions:
|
||||
- "AuthUser.tenantId ist string, aus drei Belegen hergeleitet; der SUPER_ADMIN-Zweig in TenantGuard bleibt unangetastet"
|
||||
- "Fehlereingrenzung per Form-Pruefung statt instanceof PrismaClientKnownRequestError, weil alle Testdoppel angehaengte .code-Felder werfen"
|
||||
- "15 Befunde bleiben mit Urteil und Begruendung stehen; Null war ausdruecklich nicht das Ziel"
|
||||
metrics:
|
||||
duration: "1h 20min (16:09 bis 17:29 Uhr, 21.09.2026)"
|
||||
completed: 2026-09-21
|
||||
actuals:
|
||||
tokens: 151201
|
||||
tasks: 3
|
||||
commits: 7
|
||||
plan_head_before: 8d845e7
|
||||
---
|
||||
|
||||
# Quick-Aufgabe 260921-m34: 288 any im Backend einzeln beurteilen Summary
|
||||
|
||||
Die 288 `any`-Befunde in `apps/api` sind auf **15** gefallen, jeder der 288 hat
|
||||
ein Urteil mit Begruendung, und die Arbeit hat sieben falsche Annahmen im
|
||||
Bestandscode aufgedeckt, die alle gemeldet und keine still repariert wurden.
|
||||
|
||||
## Die Zahl, und was sie bedeutet
|
||||
|
||||
| Groesse | Ausgang | Ende |
|
||||
|---|---|---|
|
||||
| `lint/suspicious/noExplicitAny` in `apps/api/src` | **288** (48 Dateien) | **15** (7 Dateien) |
|
||||
| dasselbe in `apps/web/src` | 1 | 0 |
|
||||
| `lint/style/noNonNullAssertion` in `apps/api/src` | 56 | 56 |
|
||||
| `as unknown as` in `apps/api/src` | 33 | 33 |
|
||||
| `ts-expect-error` / `ts-ignore` | 0 / 0 | 0 / 0 |
|
||||
| Lint-Unterdrueckungsmarker | 1 | 1 |
|
||||
| Befunde der Schwere `error` | 0 | 0 |
|
||||
|
||||
Die vier Zeilen in der Mitte sind die wichtigsten der Tabelle. Sie belegen, dass
|
||||
die 273 verschwundenen Befunde tatsaechlich getypt und nicht bloss stillgelegt
|
||||
wurden: haette die Arbeit die bequeme Abkuerzung genommen, waere mindestens einer
|
||||
dieser Zaehlwerte gestiegen. Keiner ist gestiegen.
|
||||
|
||||
### Aufteilung der 288 auf die drei Urteile (D-01)
|
||||
|
||||
| Urteil | Anzahl | Was dahintersteckt |
|
||||
|---|---:|---|
|
||||
| **typisiert** | 252 | Die Zusicherung war ueberfluessig oder der richtige Typ war ableitbar — aus Prismas Erweiterungstypen, aus den beiden Signierstellen des Tokens, aus `schema.prisma`, oder aus den mitgelieferten Typen einer Fremdbibliothek. |
|
||||
| **auf `unknown` umgestellt** | 21 | 18 Fehlerfaenger, die beiden `.then((results: unknown[]) => ...)` in `prisma-tenant.extension.ts` und `intercept(): Observable<unknown>`. |
|
||||
| **bleibt** | 15 | Register unten. Jede Stelle traegt ihre Begruendung ausserdem direkt im Code. |
|
||||
| | **288** | |
|
||||
|
||||
Der Plan hat 20 bis 40 verbleibende Befunde erwartet; es sind 15 geworden. Der
|
||||
Unterschied kommt nicht daher, dass hier mehr erzwungen wurde, sondern aus drei
|
||||
Messungen, die guenstiger ausfielen als die Vorschau: `@types/node-forge`
|
||||
beschreibt PKCS7 besser als angenommen (die vier `p7: any` liessen sich mit dem
|
||||
mitgelieferten `Captured<...>`-Typ aufloesen), `imapflow` deklariert
|
||||
`node.parameters` bereits vollstaendig, und `expect.extend(matchers)` in
|
||||
`apps/web` brauchte seine Zusicherung schlicht nicht mehr. Die Zaehlwerte oben
|
||||
sind der Beleg, dass dabei nichts gegen eine Behauptung getauscht wurde.
|
||||
|
||||
## Urteilsregister: die 15 Stellen, die bleiben
|
||||
|
||||
Jede dieser Zeilen steht so auch als Kommentar an der Codestelle. Wer spaeter
|
||||
hier aufraeumen will, findet die Begruendung dort, wo er zuerst nachsieht.
|
||||
|
||||
| # | Datei:Zeile | Form | Begruendung (gemessen) |
|
||||
|---|---|---|---|
|
||||
| 1 | `cert-manager/cert-manager.service.ts:296` | `cert.publicKey as any` | `@types/node-forge` kennt nur `PublicKey = rsa.PublicKey \| ed25519.Key` (index.d.ts:232). Der EC-Zweig darunter liest `curve` und `params.curve.q.bitLength()` — Felder, die node-forge zur Laufzeit liefert, die der mitgelieferte Typ aber gar nicht kennt. Eine Umdeutung ueber zwei Stufen wuerde dieselbe Luecke verdecken und zusaetzlich geprueft aussehen. |
|
||||
| 2 | `cert-manager/cert-manager.service.ts:318` | `(e: any)` | `Certificate.extensions` ist in `@types/node-forge` als `any[]` deklariert (index.d.ts:435). Der mitgelieferte Typ sagt ueber den Inhalt einer Erweiterung nichts aus. |
|
||||
| 3 | `cert-manager/cert-manager.service.ts:319` | `(sanExt as any)` | wie 2 — `sanExt` stammt aus demselben `any[]`. |
|
||||
| 4 | `cert-manager/cert-manager.service.ts:319` | `(n: any)` | wie 2. Eine eigene Schnittstelle fuer `altNames` waere unbelegt: der Compiler koennte sie an keiner Stelle gegen etwas pruefen, sie saehe aber geprueft aus (D-02). |
|
||||
| 5 | `cert-manager/cert-manager.service.ts:589` | `null as any` | node-forge 1.4.0 nimmt hier einen fehlenden Schluessel an und erzeugt ein reines Zertifikatsbuendel; `@types/node-forge` schliesst `null` aus. Die mitgelieferten Typen beschreiben die Bibliothek an dieser Stelle nachweislich falsch. |
|
||||
| 6 | `cert-manager/cert-manager.service.ts:752` | `null as any` | wie 5, zweite Aufrufstelle. |
|
||||
| 7 | `dkv/dkv-scheduler.service.ts:144` | `job as any` | Ohne die Zusicherung meldet `tsc`, dass das lokale `job` nur die Form `{ start(): void }` hat, waehrend `addCronJob()` einen vollstaendigen `CronJob` verlangt. Ursache ist der `require()`-Umweg aus 07-04 (pnpm-Isolation, `cron` ist nur mittelbare Abhaengigkeit). Aufloesen hiesse die Beschaffung der Klasse aendern (Verhaltensaenderung, D-03) oder `cron` direkt aufnehmen (neue Abhaengigkeit, D-04). |
|
||||
| 8 | `tenders/tender-digest.scheduler.ts:94` | `job as any` | wie 7. |
|
||||
| 9 | `tenders/tender-scheduler.service.ts:143` | `job as any` | wie 7. |
|
||||
| 10 | `groups/groups.service.ts:373` | `(u: any)` | Gefolge von 12: `tx` ist selbst `any`, und `any.map()` gibt dem Parameter keine kontextuelle Typisierung. Faellt automatisch mit 12. |
|
||||
| 11 | `groups/groups.service.ts:390` | `(a: any)` | wie 10. |
|
||||
| 12 | `prisma/prisma-tenant.extension.ts:264` | `fn: (tx: any)` | In Aufgabe 1 gemessen und verworfen: `Prisma.TransactionClient` erzwingt an den vier Aufrufstellen vollstaendige Prisma-Erzeugungstypen und bricht das absichtlich unvollstaendige Testdoppel in `prisma-tenant.extension.spec.ts` (TS2322). Das waere eine Aenderung an einer Teststruktur, kein ehrliches Typisieren. |
|
||||
| 13 | `prisma/prisma-tenant.extension.ts:266` | `async (tx: any)` | wie 12, dieselbe Funktion. |
|
||||
| 14 | `inbox/imap.provider.ts:78` | `(node as any).disposition...` | **Befund B-05.** Bleibt absichtlich sichtbar: der Ausdruck liest `.parameters` von einer Zeichenkette und ist zur Laufzeit immer `undefined`. Umbiegen auf `dispositionParameters` waere eine Verhaltensaenderung. |
|
||||
| 15 | `inbox/imap.provider.ts:402` | `} as any` | **Befund B-06.** Bleibt absichtlich sichtbar: die Zusicherung verdeckt, dass `requireTLS` in imapflow 1.4.3 gar nicht existiert. Die Option zu entfernen waere eine stille Reparatur. |
|
||||
|
||||
Die Gruppen dahinter sind klein: sechs Stellen an node-forge, drei an der
|
||||
Cron-Beschaffung, vier an der Transaktionshilfe, zwei absichtlich stehen
|
||||
gelassene Befunde an imapflow.
|
||||
|
||||
## Die aufgedeckten falschen Annahmen (D-03)
|
||||
|
||||
Diese Aufgabe hat ohne bekannten Fehler begonnen. Das hier ist ihr eigentlicher
|
||||
Ertrag: sieben Stellen, an denen der Bestandscode etwas annimmt, was nicht
|
||||
stimmt. **Keine davon wurde still repariert** — das Verhalten der API ist
|
||||
unveraendert.
|
||||
|
||||
**B-01 — `tenders/tender-matching.service.ts:159` (Aufgabe 1).**
|
||||
Die Handannotation `(match: { tender: unknown })` verengte den Wert falsch,
|
||||
sobald der Prisma-Klient richtig getypt war. Sie existierte nur, um unter dem
|
||||
`any`-Klienten TS7006 zu vermeiden. Annotation geloescht, damit der hergeleitete
|
||||
Typ durchkommt; keine Zusicherung an ihrer Stelle.
|
||||
|
||||
**B-02 — `dashboard/dashboard.controller.ts:74` (Aufgabe 2b).**
|
||||
Der Handler las `req.user?.role` nach `extractContext()` und gab die Rolle an
|
||||
`getWidgets(role: Role)` weiter, das sie zwingend verlangt. Die Annahme "hier
|
||||
gibt es immer einen Aufrufer" stimmt — die Pruefung "No user context" erzwingt
|
||||
sie —, aber sie stand in einer anderen Methode, wo der Compiler sie nicht sehen
|
||||
konnte. `extractContext()` gibt die Rolle jetzt mit zurueck: keine neue Pruefung,
|
||||
kein erfundener Wert, gleiche Reihenfolge, gleiche Meldungen.
|
||||
|
||||
**B-03 — `tenders/tenders.controller.ts:142` (Aufgabe 2b).**
|
||||
`resolveRequestingTenantId()` erklaerte `string | undefined`, liest aber
|
||||
`req.tenantId`, das `TenantGuard` fuer einen SUPER_ADMIN ohne Mandanten auf
|
||||
`null` setzt. Die Erklaerung war nie vollstaendig. Auf
|
||||
`string | null | undefined` erweitert — reine Erklaerung: die Funktion
|
||||
entscheidet seit jeher ueber den Wahrheitswert und faellt bei `null` wie bei
|
||||
`undefined` zu (nur global sichtbare Ausschreibungen).
|
||||
|
||||
**B-04 — Falle im Mandantentrennungs-Erkenner (Aufgabe 3b).**
|
||||
Die naheliegende Prisma-Schreibweise `Prisma.UserGetPayload<{ select: typeof X }>`
|
||||
laesst `rls-access-inventory.spec.ts` rot werden: der Erkenner zaehlt **jede**
|
||||
`select:`-Angabe ausserhalb eines erkannten Modellaufrufs als Verstoss und
|
||||
unterscheidet Typposition nicht von Aufrufposition. Beim ersten Versuch gemessen.
|
||||
Der Erkenner ist die Mandantenkontrolle (T-M34-03) und wurde **nicht**
|
||||
aufgeweicht — stattdessen leitet der Zeilentyp ueber `Pick<User, keyof typeof
|
||||
PLATFORM_USER_SELECT>` her, was ohne das Wort `select` auskommt. Wer kuenftig
|
||||
`UserGetPayload` einsetzen will, muss zuerst den Erkenner erweitern, nicht die
|
||||
Ausnahmeliste.
|
||||
|
||||
**B-05 — `inbox/imap.provider.ts:78` (Aufgabe 3c). Sicherheitsnah, offen.**
|
||||
`(node as any).disposition?.parameters?.filename` liest `.parameters` von einer
|
||||
**Zeichenkette**: imapflow deklariert `disposition` als `string`
|
||||
(`imap-flow.d.ts:448`, also "attachment"/"inline"), die zugehoerigen Parameter
|
||||
liegen in einem eigenen Feld `dispositionParameters` (:450). Der Ausdruck ist zur
|
||||
Laufzeit **immer** `undefined`, `dispositionFilename` ist stets `''`. Folge:
|
||||
Anhaenge, die als `application/octet-stream` kommen (typisch fuer Outlook),
|
||||
werden ueber den Dateinamen aus Content-Disposition **nicht** erkannt — nur ueber
|
||||
den aus Content-Type. Betrifft den DKV-Rechnungseinzug. Nicht repariert, weil das
|
||||
Umbiegen erstmals Anhaenge einsammeln wuerde, die heute uebersprungen werden —
|
||||
eine Verhaltensaenderung, die ein Mensch entscheiden muss.
|
||||
|
||||
**B-06 — `inbox/imap.provider.ts:402` (Aufgabe 3c). Sicherheitsnah, offen.**
|
||||
`requireTLS: config.encryption === 'starttls'` wird an `new ImapFlow(...)`
|
||||
uebergeben, aber `requireTLS` kommt in imapflow 1.4.3 **nirgends** vor — weder in
|
||||
`ImapFlowOptions` (`lib/imap-flow.d.ts`) noch im Laufzeitcode
|
||||
(`lib/imap-flow.js`), beides durchsucht. Die Option wird still verworfen; ein
|
||||
STARTTLS-Zwang entsteht durch sie nicht. Genau das `} as any` hat es verdeckt.
|
||||
Die Einstellung "STARTTLS" in der Postfach-Konfiguration bewirkt damit nicht das,
|
||||
was ihr Name verspricht. Nicht repariert (D-03), Zusicherung bleibt sichtbar
|
||||
stehen, damit der Befund in der Zaehlung nicht verschwindet.
|
||||
|
||||
**B-07 — httpntlm-Antwortrumpf (Aufgabe 3c). Ohne Auswirkung, aber falsch.**
|
||||
Beide Exchange-Wege riefen `res.body?.toString('utf-8')` auf und nahmen damit
|
||||
einen Buffer an. Gemessen: httpntlm reicht an httpreq durch, und httpreq gibt den
|
||||
Rumpf als **Zeichenkette** zurueck, solange die Option `binary` nicht gesetzt ist
|
||||
(`httpreq@1.1.1/lib/httpreq.js:391`) — keiner der beiden Aufrufer setzt sie. Das
|
||||
ging bisher nur gut, weil `String.prototype.toString()` sein Argument ignoriert.
|
||||
Die Testdoppel reichen umgekehrt wirklich einen Buffer herein, beide Formen kommen
|
||||
also vor. `NtlmResponse.body` nennt jetzt beide; die Fallunterscheidung liefert
|
||||
fuer jede exakt dasselbe Ergebnis wie zuvor.
|
||||
|
||||
## Die `tenantId`-Entscheidung im gemeinsamen Aufrufer-Typ
|
||||
|
||||
`AuthUser.tenantId` ist **`string`**, nicht `string | undefined`. Die Messung
|
||||
allein haette in die falsche Richtung gedraengt (`string | undefined` erzeugte
|
||||
acht Fehler im Produktivcode, `string` keinen); entschieden wurde auf drei
|
||||
Belegen:
|
||||
|
||||
1. `apps/api/prisma/schema.prisma` deklariert `User.tenantId String` **ohne** `?`.
|
||||
Die Spalte ist Pflicht, und beide Signierstellen schreiben genau diesen
|
||||
Spaltenwert — seit dem ersten Commit des Anmeldedienstes (6190f3d) gibt es
|
||||
keine Token-Erzeugung ohne diesen Anspruch.
|
||||
2. Der Bestand beschreibt dasselbe Objekt in `SessionUser`
|
||||
(`bug-reports.service.ts`) bereits als `tenantId: string`. `SessionUser` ist
|
||||
jetzt ein `Pick<>` von `AuthUser`, damit es keine zweite, abweichende
|
||||
Beschreibung desselben Objekts gibt.
|
||||
3. `TenantGuard` haelt fuer SUPER_ADMIN einen Zweig ohne Mandanten vor und setzt
|
||||
dort `req.tenantId = null`.
|
||||
|
||||
Beleg 3 spricht **nicht** gegen `string`, und genau daran haengt die
|
||||
Sicherheitsfrage: der Zweig in `TenantGuard` ist eine Tiefenverteidigung gegen
|
||||
ein Token ohne diesen Anspruch, und er liest `AuthUser` gar nicht — der Waechter
|
||||
holt sein Anfrageobjekt ungetypt. Dieser Typ kann den Zweig also nicht zu totem
|
||||
Code machen. Dass es den Zweig gibt, steht ausserdem weiterhin im Typsystem, nur
|
||||
an der richtigen Stelle: `AuthenticatedRequest.tenantId` ist
|
||||
`string | null | undefined`.
|
||||
|
||||
Am Typ steht dazu eine ausdrueckliche Warnung fuer spaetere Leser, dass der
|
||||
SUPER_ADMIN-Zweig ein Schutzzweig ist und nicht entfernt oder wegtypisiert werden
|
||||
darf (T-M34-01). `tenant.guard.ts` wurde in diesem ganzen Lauf **nicht
|
||||
angefasst** — in Aufgabe 2 per `git diff --stat` nachgewiesen.
|
||||
|
||||
## Was die Arbeit sonst noch geaendert hat
|
||||
|
||||
**Zwei neue Dateien, beide klein und begruendet.**
|
||||
`apps/api/src/auth/types/auth-user.ts` traegt den gemeinsamen Aufrufer-Typ; jedes
|
||||
Feld hat seine Herkunft als Kommentar. `apps/api/src/prisma/prisma-error.ts`
|
||||
traegt `prismaErrorCode()` und `prismaErrorTarget()`.
|
||||
|
||||
**Warum die Fehlereingrenzung Form-Pruefungen macht und kein `instanceof`.**
|
||||
Der naheliegende Weg waere
|
||||
`err instanceof Prisma.PrismaClientKnownRequestError` gewesen. Gemessen: samtliche
|
||||
Testdoppel in `apps/api` werfen `new Error(...)` mit angehaengtem `.code`
|
||||
(groups, user, ldap, tenders, module-grants, admin-seed) und
|
||||
`dashboard.service.spec.ts:451` ein reines `{ code: 'P2002' }`. Ein
|
||||
`instanceof`-Test haette all diese Werte in den jeweils **anderen** Zweig
|
||||
geschickt — eine Verhaltensaenderung, und nach T-M34-06 genau die Art von
|
||||
Aenderung, die einen Hintergrundlauf kuenftig abbrechen laesst, der heute
|
||||
weiterlaeuft. Die Helfer bilden `err?.code` und `err?.meta?.target` deshalb eins
|
||||
zu eins ab, nur ohne `any`.
|
||||
|
||||
**Nebengewinne ohne neue Zusicherungen.** In `cert-manager.service.ts` sind 25
|
||||
Zusicherungen der Form `file.buffer as Buffer` weggefallen, weil `file` kein
|
||||
`any` mehr ist. In `dkv` und `settings` fielen `req.tenantId as string |
|
||||
undefined` weg. `as unknown as` ist trotzdem bei 33 geblieben — dieselbe Zahl wie
|
||||
zu Beginn.
|
||||
|
||||
## Abweichungen vom Plan
|
||||
|
||||
**1. [Regel 3 — blockierend] Neue Datei `prisma/prisma-error.ts` statt 18
|
||||
Eingrenzungen von Hand.** Der Plan nennt fuer Aufgabe 3 Schritt A keine neue
|
||||
Datei. 18 Fehlerfaenger einzeln mit einer vierzeiligen Form-Pruefung zu versehen
|
||||
haette dieselbe Logik achtzehnmal wiederholt und die Begruendung, warum kein
|
||||
`instanceof` verwendet wird, achtzehnmal daneben. Die Datei liegt in `prisma/`,
|
||||
weil alle Aufrufer Prisma-Fehlercodes pruefen. Keine neue Abhaengigkeit.
|
||||
Commit: `32591b6`.
|
||||
|
||||
**2. [Regel 1 — Fehler] Erste Fassung von `user.service.ts` machte die
|
||||
Mandanten-Spec rot.** `Prisma.UserGetPayload<{ select: typeof X }>` hat
|
||||
`rls-access-inventory.spec.ts` gebrochen (siehe B-04). Sofort im selben Schritt
|
||||
auf `Pick<User, ...>` umgestellt, der Erkenner blieb unangetastet, Spec wieder
|
||||
30/30. Commit: `3892c5f`.
|
||||
|
||||
**3. [Messung weicht vom Plan ab] `calendar.service.ts:206/255` sind keine
|
||||
Prisma-JSON-Eingaben.** Der Plan vermutete `Prisma.InputJsonValue`. Gemessen:
|
||||
es sind dynamisch gebaute Erzeugungs- und Aenderungseingaben fuer
|
||||
`CalendarSource`. Richtig getypt mit
|
||||
`Prisma.CalendarSourceUncheckedCreateInput` / `...UncheckedUpdateInput`.
|
||||
Commit: `3892c5f`.
|
||||
|
||||
**4. [Messung weicht vom Plan ab] node-forge war besser beschrieben als
|
||||
erwartet.** Der Plan rechnete damit, dass ein Teil der elf Stellen bleibt.
|
||||
Gemessen: die vier `p7: any` liessen sich mit dem mitgelieferten
|
||||
`Captured<PkcsEnvelopedData | PkcsSignedData>` aufloesen, `cert.siginfo` war
|
||||
ohnehin getypt. Sechs bleiben, fuenf wurden getypt. Commit: `d8fb9ae`.
|
||||
|
||||
## Pruefungen — die echten Ausgaben
|
||||
|
||||
### `noExplicitAny`, `noNonNullAssertion`, `error`-Befunde
|
||||
|
||||
```
|
||||
$ npx biome lint --reporter=json --max-diagnostics=2000 apps/api/src | python3 -c "..."
|
||||
any 15 nonnull 56 error 0
|
||||
Rueckgabewert: 0
|
||||
```
|
||||
|
||||
Schranke der Aufgabe: `any <= 45`, `nonnull <= 56`, `error == 0`. Alle drei
|
||||
eingehalten.
|
||||
|
||||
### Vollstaendige Restliste (Pruefung 2 der Aufgabe)
|
||||
|
||||
```
|
||||
apps/api/src/cert-manager/cert-manager.service.ts:296:40 | const pubKey = cert.publicKey as any;
|
||||
apps/api/src/cert-manager/cert-manager.service.ts:318:48 | const sanExt = cert.extensions?.find((e: any) => e.name === 'subjectAltName');
|
||||
apps/api/src/cert-manager/cert-manager.service.ts:319:41 | const san: string[] = ((sanExt as any)?.altNames ?? []).map((n: any) =>
|
||||
apps/api/src/cert-manager/cert-manager.service.ts:319:71 | const san: string[] = ((sanExt as any)?.altNames ?? []).map((n: any) =>
|
||||
apps/api/src/cert-manager/cert-manager.service.ts:589:19 | null as any, // cert-only PFX - null key accepted by node-forge 1.4.0
|
||||
apps/api/src/cert-manager/cert-manager.service.ts:752:19 | null as any, // cert-only PFX - null key accepted by node-forge 1.4.0
|
||||
apps/api/src/dkv/dkv-scheduler.service.ts:144:55 | this.schedulerRegistry.addCronJob(jobName, job as any);
|
||||
apps/api/src/groups/groups.service.ts:373:33 | data: users.map((u: any) => ({
|
||||
apps/api/src/groups/groups.service.ts:390:39 | data: activations.map((a: any) => ({
|
||||
apps/api/src/inbox/imap.provider.ts:78:15 | ((node as any).disposition?.parameters?.filename as string | undefined)?.toLowerCase() ?? '';
|
||||
apps/api/src/inbox/imap.provider.ts:402:10 | } as any);
|
||||
apps/api/src/prisma/prisma-tenant.extension.ts:264:12 | fn: (tx: any) => Promise<T>,
|
||||
apps/api/src/prisma/prisma-tenant.extension.ts:266:41 | return prisma.$transaction(async (tx: any) => {
|
||||
apps/api/src/tenders/tender-digest.scheduler.ts:94:63 | this.schedulerRegistry.addCronJob(this.JOB_NAME, job as any);
|
||||
apps/api/src/tenders/tender-scheduler.service.ts:143:61 | this.schedulerRegistry.addCronJob(this.JOB_NAME, job as any);
|
||||
TOTAL 15
|
||||
```
|
||||
|
||||
Jede dieser 15 Zeilen steht im Urteilsregister oben. `apps/web/src` liefert
|
||||
keine Zeile mehr.
|
||||
|
||||
### Unterdrueckungsmarker
|
||||
|
||||
```
|
||||
### 3. Unterdrueckungsmarker
|
||||
keine stillgelegten Stellen
|
||||
```
|
||||
|
||||
Das heisst im Einzelnen: `ts-expect-error` 0, `ts-ignore` 0, `biome-ignore` 1
|
||||
(der eine Bestandsmarker), `as unknown as` 33.
|
||||
|
||||
### `biome.json` und Abhaengigkeiten
|
||||
|
||||
```
|
||||
### 4. biome.json
|
||||
biome.json unberuehrt
|
||||
|
||||
### 5. Abhaengigkeiten
|
||||
keine neuen Abhaengigkeiten, keine Versionsspruenge
|
||||
```
|
||||
|
||||
Geprueft ueber `git diff --stat HEAD` gegen `biome.json`, alle drei
|
||||
`package.json` und `pnpm-lock.yaml` — jede Ausgabe leer.
|
||||
|
||||
### Typlauf und Lint
|
||||
|
||||
```
|
||||
### 6. type-check / lint
|
||||
type-check 4/4, lint 5/5
|
||||
```
|
||||
|
||||
### Testsuiten
|
||||
|
||||
```
|
||||
$ pnpm --dir apps/api run test
|
||||
Test Files 72 passed (72)
|
||||
Tests 1143 passed (1143)
|
||||
Duration 8.05s
|
||||
|
||||
$ pnpm --dir apps/web run test
|
||||
Test Files 73 passed (73)
|
||||
Tests 531 passed (531)
|
||||
Duration 23.48s
|
||||
```
|
||||
|
||||
Unveraenderte Zahlen gegenueber dem Ausgang (72/1143 und 73/531).
|
||||
|
||||
### Mandantentrennungs-Erkenner, ausdruecklich einzeln
|
||||
|
||||
```
|
||||
$ pnpm --dir apps/api exec vitest run src/prisma/rls-access-inventory.spec.ts
|
||||
Test Files 1 passed (1)
|
||||
Tests 30 passed (30)
|
||||
Duration 557ms
|
||||
```
|
||||
|
||||
Das ist die Kontrolle aus T-M34-03. Sie war in Aufgabe 3b einmal rot (B-04) und
|
||||
wurde nicht durch Aufweichen, sondern durch eine andere Typschreibweise wieder
|
||||
gruen.
|
||||
|
||||
## Commits
|
||||
|
||||
| Commit | Aufgabe | `any` in `apps/api` danach |
|
||||
|---|---|---:|
|
||||
| `b188946` | 1 — Mandantenbindung entzaubert, 105 unnoetige Zusicherungen | 149 |
|
||||
| `f2fc39f` | 2a — gemeinsamer Aufrufer-Typ, aus den Signierstellen abgeleitet | 137 |
|
||||
| `7c9d7c1` | 2b — getypte Anfrage in elf Controllern, zwei Befunde gemeldet | 66 |
|
||||
| `52668c2` | 2c — Hochladewege getypt, 25 Zusicherungen fallen mit | 56 |
|
||||
| `32591b6` | 3a — 18 Fehlerfaenger auf `unknown`, mit echter Eingrenzung | 38 |
|
||||
| `3892c5f` | 3b — Prisma-nahe Formen getypt, Erkenner-Falle gemeldet | 31 |
|
||||
| `d8fb9ae` | 3c — Randschicht beurteilt, drei Befunde gemeldet | **15** |
|
||||
|
||||
Jeder Commit war fuer sich gruen: nach jedem lief `pnpm type-check` 4/4,
|
||||
`pnpm lint` 5/5 mit 0 Befunden der Schwere `error`, und beide Testsuiten mit
|
||||
unveraenderten Zahlen (D-05, D-06).
|
||||
|
||||
## Offene Punkte fuer den Menschen
|
||||
|
||||
Zwei der sieben Befunde brauchen eine Entscheidung, die diese Aufgabe nicht
|
||||
treffen durfte, weil beide das Verhalten aendern wuerden:
|
||||
|
||||
- **B-05** (`imap.provider.ts:78`): sollen Anhaenge mit
|
||||
`application/octet-stream` kuenftig auch ueber den Dateinamen aus
|
||||
Content-Disposition erkannt werden? Heute werden sie es nicht.
|
||||
- **B-06** (`imap.provider.ts:402`): soll die Postfach-Einstellung "STARTTLS"
|
||||
tatsaechlich einen Zwang bewirken? Heute wird die Option von imapflow
|
||||
verworfen.
|
||||
|
||||
Beide sind im Code markiert und stehen in der Zaehlung, verschwinden also nicht
|
||||
aus dem Blick.
|
||||
|
||||
## Self-Check
|
||||
|
||||
**BESTANDEN.**
|
||||
|
||||
Geprueft, nicht behauptet:
|
||||
|
||||
- Beide neu angelegten Dateien existieren auf der Platte
|
||||
(`apps/api/src/auth/types/auth-user.ts`,
|
||||
`apps/api/src/prisma/prisma-error.ts`).
|
||||
- Alle sieben genannten Commits sind in `git log` vorhanden.
|
||||
- `apps/api/src/tenant/tenant.guard.ts` ist ueber den gesamten Lauf
|
||||
(`git diff --stat 8d845e7..HEAD`) unveraendert — keine einzige Zeile.
|
||||
- Die 15 Zeilen der Restliste stammen aus der maschinellen Biome-Ausgabe, nicht
|
||||
aus dem Gedaechtnis, und stimmen eins zu eins mit dem Urteilsregister ueberein.
|
||||
- Die Aufteilung 252 + 21 + 15 ergibt 288.
|
||||
Reference in New Issue
Block a user