refactor(quick-260921-bi2): maschinelle Lint-Fixe und toten Code abbauen

- Aufgabe 2: vier sichere Biome-Regeln (useImportType pfadgebunden auf
  apps/web+packages, noUselessEscapeInRegex, useConst,
  useExponentiationOperator) sowie fuenf ungesicherte Regeln
  (useNodejsImportProtocol, useLiteralKeys, useOptionalChain, useTemplate,
  useParseIntRadix) angewendet und den gesamten Diff von Hand gelesen
  (ldap.service.ts zeichenweise gegen Gross-/Kleinschreibung der
  AD-Merkmale, auth.service.ts/jwt.strategy.ts gegen Durchwinken bei
  fehlender Sitzung geprueft)
- noUselessSwitchCase bleibt bewusst stehen (tender-normalizer.service.ts:60,
  die Fallmarke dokumentiert Absicht)
- Toter Code (D-03): fuenf folgenlose Auffangvariablen entfernt, eine
  nicht benutzte Funktion (forSystemQuery, Pruefskript) entfernt, ein
  positionsgebundener Dekoratorparameter umbenannt (current-user.decorator.ts),
  fuenf Symptomfunde entfernt und als Folgeaufgaben zu melden (siehe unten)
- Sechs weitere, im Plan nicht namentlich gelistete aber
  gleich-kategorische Dead-Code-Fundstellen in Testdateien zusaetzlich
  bereinigt (groups.service.spec.ts, cert-manager.test.tsx,
  ldap.service.spec.ts, prisma-tenant.extension.spec.ts x3) — noetig, um
  die vom Plan selbst verlangten Nullstaende bei noUnusedVariables/
  noUnusedImports/noUnusedFunctionParameters zu erreichen

Dekoratordaten aus apps/api unveraendert (593 Zeilen, sha256 6e1583f1...).
Endstand 620 Befunde (541 echt, 79 Test) statt der im Plan geschaetzten
621/542 — eine Differenz von 1, weil das Streichen des Namens aus
`catch (e: any)` in calendar.service.ts (Symptom-Fix) den dort ebenfalls
gemeldeten noExplicitAny-Befund miteliminiert; das ist eine erwuenschte
Nebenwirkung, keine Regression. Fehlerstufe 0, beide Testlaeufe
punktgleich gruen (69/1124, 66/459), pnpm type-check 4/4, pnpm lint
--force 5/5.

Folgeaufgaben aus D-03 (nicht in diesem Vorgang behoben):
- force-password-change.interceptor.ts: Freigabeliste prueft nur den Pfad,
  nicht die HTTP-Methode
- change-password/page.tsx: nach erzwungenem Wechsel bleibt die Person auf
  der Seite stehen (keine Weiterleitung, keine Aktualisierung der
  Benutzerablage)
- VehicleTable.tsx: Loeschschaltflaeche hat keinen Besetztzustand, laesst
  sich doppelt ausloesen
- SplitTab.tsx: downloadAllAsZip erhielt eine ungenutzte
  Uebersetzungsfunktion, Hinweis auf fest verdrahtete Texte im Zip-Pfad

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
This commit is contained in:
2026-09-21 08:58:32 +02:00
parent 8d1c8f320b
commit 636fe0df8f
56 changed files with 126 additions and 147 deletions
+25 -25
View File
@@ -322,13 +322,13 @@ export class LdapService {
const dn = entry.dn;
const isOu = /^ou=/i.test(dn);
const record = entry as unknown as Record<string, unknown>;
const rawName = isOu ? record['ou'] : record['cn'];
const rawName = isOu ? record.ou : record.cn;
const name = Array.isArray(rawName)
? String(rawName[0])
: rawName
? String(rawName)
: dn;
const guidValue = record['objectGUID'];
const guidValue = record.objectGUID;
const guidHex =
!isOu && Buffer.isBuffer(guidValue)
? guidValue.toString('hex')
@@ -401,7 +401,7 @@ export class LdapService {
mappedData[mapping.tesseraField] = String(resolved);
}
}
return { username: mappedData['username']?.toLowerCase(), mappedData };
return { username: mappedData.username?.toLowerCase(), mappedData };
}
/**
@@ -483,13 +483,13 @@ export class LdapService {
if (existing) {
let emailToWrite: string | undefined;
let emailConflict: LdapEmailConflict | undefined;
if (mappedData['email']) {
if (mappedData.email) {
const decision = await this.resolveEmailForWrite(
mappedData['email'],
mappedData.email,
existing.id,
);
if (decision.collides) {
emailConflict = { account: username, email: mappedData['email'] };
emailConflict = { account: username, email: mappedData.email };
} else {
emailToWrite = decision.email;
}
@@ -498,11 +498,11 @@ export class LdapService {
await tenantPrisma.user.update({
where: { id: existing.id },
data: {
...(mappedData['displayName'] && {
displayName: mappedData['displayName'],
...(mappedData.displayName && {
displayName: mappedData.displayName,
}),
...(emailToWrite && { email: emailToWrite }),
...(mappedData['username'] && { username }),
...(mappedData.username && { username }),
ldapDn: dn,
isActive: true,
},
@@ -511,16 +511,16 @@ export class LdapService {
}
let createEmail: string | undefined =
mappedData['email'] || `${username}@ldap.local`;
mappedData.email || `${username}@ldap.local`;
let emailConflict: LdapEmailConflict | undefined;
if (mappedData['email']) {
if (mappedData.email) {
const decision = await this.resolveEmailForWrite(
mappedData['email'],
mappedData.email,
null,
);
if (decision.collides) {
createEmail = undefined;
emailConflict = { account: username, email: mappedData['email'] };
emailConflict = { account: username, email: mappedData.email };
} else {
createEmail = decision.email;
}
@@ -529,7 +529,7 @@ export class LdapService {
await this.userService.create({
username,
...(createEmail && { email: createEmail }),
displayName: mappedData['displayName'],
displayName: mappedData.displayName,
role: 'USER',
tenantId,
ldapDn: dn,
@@ -592,9 +592,9 @@ export class LdapService {
const entries = Array.from(entriesByDn.values()).map((entry) => ({
dn: entry.dn,
username: first(entry['sAMAccountName']),
displayName: first(entry['displayName']) || first(entry['cn']),
email: first(entry['mail']),
username: first(entry.sAMAccountName),
displayName: first(entry.displayName) || first(entry.cn),
email: first(entry.mail),
}));
// Flag entries already present for this tenant (by ldapDn or username) in
@@ -724,10 +724,10 @@ export class LdapService {
// account is still created and counted, this manual-import path's
// display stays as-is.
let createEmail: string | undefined =
mappedData['email'] || `${username}@ldap.local`;
if (mappedData['email']) {
mappedData.email || `${username}@ldap.local`;
if (mappedData.email) {
const decision = await this.resolveEmailForWrite(
mappedData['email'],
mappedData.email,
null,
);
createEmail = decision.collides ? undefined : decision.email;
@@ -736,7 +736,7 @@ export class LdapService {
await this.userService.create({
username,
...(createEmail && { email: createEmail }),
displayName: mappedData['displayName'],
displayName: mappedData.displayName,
role: 'USER',
tenantId,
ldapDn: dn,
@@ -813,14 +813,14 @@ export class LdapService {
const entry = searchEntries[0];
const record = entry as unknown as Record<string, unknown>;
const guidValue = record['objectGUID'];
const guidValue = record.objectGUID;
if (!Buffer.isBuffer(guidValue)) {
result.errors.push(`${dn}: objectGUID not readable`);
continue;
}
const ldapObjectGuid = guidValue.toString('hex');
const rawName = record['cn'];
const rawName = record.cn;
const name = Array.isArray(rawName)
? String(rawName[0])
: rawName
@@ -1436,7 +1436,7 @@ export class LdapService {
string,
unknown
>;
const backfillGuid = backfillRecord['objectGUID'];
const backfillGuid = backfillRecord.objectGUID;
if (!Buffer.isBuffer(backfillGuid)) {
result.errors.push(
`Gruppe ${group.name}: Alt-Bindung ${group.ldapDn} ohne lesbaren objectGUID`,
@@ -1492,7 +1492,7 @@ export class LdapService {
if (hit) {
// 3. Rename/DN reconciliation (SC-3).
const hitRecord = hit as unknown as Record<string, unknown>;
const rawName = hitRecord['cn'];
const rawName = hitRecord.cn;
const name = Array.isArray(rawName)
? String(rawName[0])
: rawName