feat(plan): validate dynamic category keys, resolve audit label from DB

- Replace hardcoded planCategoryEnum z.enum with z.string().trim().min(1)
- Add assertActiveCategory() helper that rejects inactive/unknown keys
- Add resolveCategoryLabel() helper that resolves the Czech label from plan_categories DB table, falling back to built-in map
- Change PlanAuditDescriptionInput.category -> categoryLabel (pre-resolved string)
- Update buildPlanAuditDescription to use opts.categoryLabel directly
- Update all 6 buildPlanAuditDescription call sites in plan.service.ts to await resolveCategoryLabel(row.category)
- Add category validation in createEntry, updateEntry, createOverride, updateOverride
- Update planAuditDescription tests to pass categoryLabel instead of category

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-06 00:41:50 +02:00
parent c983747418
commit a55356d417
4 changed files with 61 additions and 30 deletions

View File

@@ -24,7 +24,7 @@ describe("buildPlanAuditDescription", () => {
it("describes a multi-day entry with project", () => {
const desc = buildPlanAuditDescription({
userName: "Jan Novák",
category: "work",
categoryLabel: "Práce",
projectName: "Rekonstrukce haly",
dateFrom: "2026-06-08",
dateTo: "2026-06-12",
@@ -37,7 +37,7 @@ describe("buildPlanAuditDescription", () => {
it("collapses a single-day range to one date", () => {
const desc = buildPlanAuditDescription({
userName: "Jan Novák",
category: "work",
categoryLabel: "Práce",
projectName: "Rekonstrukce haly",
dateFrom: "2026-06-08",
dateTo: "2026-06-08",
@@ -48,7 +48,7 @@ describe("buildPlanAuditDescription", () => {
it("omits the project segment when there is no project", () => {
const desc = buildPlanAuditDescription({
userName: "Petr Svoboda",
category: "leave",
categoryLabel: "Dovolená",
projectName: null,
dateFrom: "2026-06-10",
dateTo: "2026-06-10",
@@ -59,7 +59,7 @@ describe("buildPlanAuditDescription", () => {
it("appends the emergency-edit note when force is set", () => {
const desc = buildPlanAuditDescription({
userName: "Jan Novák",
category: "work",
categoryLabel: "Práce",
projectName: null,
dateFrom: "2026-01-02",
dateTo: "2026-01-02",
@@ -71,7 +71,7 @@ describe("buildPlanAuditDescription", () => {
it("appends a custom suffix (e.g. replaced override)", () => {
const desc = buildPlanAuditDescription({
userName: "Jan Novák",
category: "sick",
categoryLabel: "Nemoc",
projectName: null,
dateFrom: "2026-06-10",
dateTo: "2026-06-10",
@@ -85,7 +85,7 @@ describe("buildPlanAuditDescription", () => {
it("treats a whitespace-only project name as no project", () => {
const desc = buildPlanAuditDescription({
userName: "Jan Novák",
category: "work",
categoryLabel: "Práce",
projectName: " ",
dateFrom: "2026-06-08",
dateTo: "2026-06-08",