Files
qrcode-generator/src/lib/duplicates.ts
T
Florian Wilde 60f46bcdb5 Warnung vor doppelt abgelegten statischen Codes
Ein statischer Code traegt seinen Inhalt selbst — zweimal derselbe Inhalt
ergibt zweimal exakt dasselbe Bild. Bisher entstand der zweite Eintrag
stillschweigend.

Das Anlegen antwortet nun mit 409 und nennt den vorhandenen Eintrag samt
Namen und Datum; die Oberflaeche zeigt das als Warnung mit dem Knopf
"Trotzdem ablegen". Eine Rueckfrage, keine Sperre — zwei Fassungen
desselben Codes koennen gewollt sein.

Verglichen wird Typ und Inhalt innerhalb der Gruppe, nicht die Gestaltung.
Dynamische Codes bleiben aussen vor: zwei Kurz-Links auf dasselbe Ziel
sind der Normalfall, sobald getrennt gezaehlt werden soll.

ApiError traegt dafuer jetzt Status und Antwortkoerper — eine gemeldete
Dublette ist keine Sackgasse, sondern eine Rueckfrage.

Refs #6
2026-08-21 02:53:23 +02:00

62 lines
1.9 KiB
TypeScript

import "server-only";
import { toJsonInput } from "@/lib/codes";
import { prisma } from "@/lib/db";
/**
* Dublettenprüfung für statische Codes.
*
* Ein statischer Code trägt seinen Inhalt selbst — zweimal derselbe Inhalt
* ergibt zweimal exakt dasselbe Bild. Solche Einträge sind nicht falsch, aber
* sie fluten die Liste, und beim Wiederfinden weiß niemand mehr, welcher der
* beiden gemeint war.
*
* Bewusst **nur** für statische Codes: Zwei dynamische Codes mit demselben
* Ziel sind ein üblicher Fall — zwei Kampagnen, zwei Kurz-Links, getrennte
* Zähler. Da wäre eine Warnung nur lästig.
*
* Bewusst **ohne** die Gestaltung: Verglichen wird der Inhalt. Derselbe Inhalt
* einmal in Schwarz-Weiß für den Druck und einmal in Hausfarben ist zwar
* bewusst zweimal angelegt — aber eben auch zweimal derselbe Code. Die
* Warnung sagt das und lässt sich übergehen.
*/
export type StaticDuplicate = {
id: string;
label: string | null;
createdAt: string;
};
/**
* Sucht einen bereits abgelegten statischen Code mit gleichem Typ und
* gleichem Inhalt in derselben Gruppe — den zuletzt angelegten.
*
* Die Gruppe grenzt bewusst ein: Ein Treffer aus einer fremden Gruppe wäre
* nicht bloß nutzlos, er verriete auch deren Bestand.
*/
export async function findStaticDuplicate(
groupId: string,
type: string,
data: Record<string, unknown>,
): Promise<StaticDuplicate | null> {
const treffer = await prisma.qrCode.findFirst({
where: {
mode: "static",
type,
groupId,
// Postgres vergleicht jsonb nach Struktur, nicht nach Schreibweise —
// Schlüsselreihenfolge und Leerzeichen spielen keine Rolle.
data: { equals: toJsonInput(data) },
},
orderBy: { createdAt: "desc" },
select: { id: true, label: true, createdAt: true },
});
if (!treffer) return null;
return {
id: treffer.id,
label: treffer.label,
createdAt: treffer.createdAt.toISOString(),
};
}