Aktenzeichen-Muster je Vorlage, Startskript für die Entwicklung

Richtigstellung zuerst: der vorige Commit trägt die Nachricht "Nichts davon
gebaut", enthält aber bereits die Schema-Änderung an CaseTemplate und
CaseCounter. Ein abgebrochener Aufruf hatte die Datei schon geschrieben, und
das nachfolgende `git add -A` hat sie mitgenommen. Die Nachricht war damit
falsch. Hier ist die Änderung vollständig und geprüft.

Das Muster des Aktenzeichens gehört zur Vorlage: Präfix und Stellenzahl je
Fallart, ein Nummernkreis je Präfix und Jahr. Die Abteilung führt gewachsene
Präfixe wie AKT-PA-2026-62843 neben dem AfiS-2026-0042 aus dem Glossar.

Die Migration ist von Hand geschrieben, weil der Wechsel des Primärschlüssels
auf CaseCounter den bestehenden Zähler erhalten muss: eine zurückgesetzte
Nummer wäre ein doppeltes Aktenzeichen. Vorher und nachher geprüft.

parseCaseNumber zerlegt von hinten, damit Präfixe mit Bindestrich funktionieren.
Ein Test belegt, dass AKT-PA und AfiS getrennte Nummernkreise führen.

Dazu start.sh für die lokale Entwicklung, solange der Dockge-Stack nicht läuft:
Datenbank hochfahren, Migrationen, Grundzustand, Worker und Web. Mit
--ohne-worker für Arbeit ohne Discord und --nur-db für die Datenbank allein.
This commit is contained in:
Harlekin
2026-09-02 12:10:34 +02:00
parent 4d926ee603
commit 66ad19c456
6 changed files with 259 additions and 28 deletions
+45
View File
@@ -89,6 +89,51 @@ suite('Schreibgrenzen der Freigabestufe', () => {
expect(new Set(nummern).size).toBe(nummern.length)
})
it('führt je Präfix einen eigenen Nummernkreis', async () => {
// Die Abteilung nutzt gewachsene Präfixe wie AKT-PA neben dem AfiS aus dem
// Glossar. Zwei Fallarten dürfen sich dabei nicht in die Quere kommen.
const { createCase } = await import('@/lib/cases/service')
await db.caseTemplate.create({
data: {
key: `${marke}-personal`,
version: 1,
name: 'Personalvorgang',
fields: [],
numberPrefix: 'AKT-PA',
numberPadding: 5,
},
})
const ersteA = await createCase(perms(5, VOLL), {
title: 'Personalvorgang eins',
classification: 1,
templateKey: `${marke}-personal`,
})
const zweiteA = await createCase(perms(5, VOLL), {
title: 'Personalvorgang zwei',
classification: 1,
templateKey: `${marke}-personal`,
})
const jahr = new Date().getFullYear()
expect(ersteA.caseNumber).toMatch(new RegExp(`^AKT-PA-${jahr}-\\d{5}$`))
expect(zweiteA.caseNumber).toMatch(new RegExp(`^AKT-PA-${jahr}-\\d{5}$`))
const { parseCaseNumber } = await import('@/lib/cases/caseNumber')
const eins = parseCaseNumber(ersteA.caseNumber)
const zwei = parseCaseNumber(zweiteA.caseNumber)
expect(eins?.prefix).toBe('AKT-PA')
expect(zwei!.number).toBe(eins!.number + 1)
// Der AfiS-Kreis läuft davon unberührt weiter.
const afis = await createCase(perms(5, VOLL), {
title: 'Ermittlung',
classification: 1,
templateKey: `${marke}-vorlage`,
})
expect(parseCaseNumber(afis.caseNumber)?.prefix).toBe('AfiS')
})
it('gibt einer zu niedrigen Stufe nicht einmal die Existenz preis', async () => {
const { createCase, loadVisibleCase } = await import('@/lib/cases/service')
const geheim = await createCase(perms(5, VOLL), {