From 93367a239f59ce434cd02cfdfb3d88d4c59e4158 Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Wed, 2 Sep 2026 22:12:58 +0200 Subject: [PATCH] fix(housekeeping): require reasons for destructive changes --- .../content/commands/content-commands.ts | 1 + .../content/pages/content-command-form.tsx | 14 +++--- .../content/pages/content-pages.test.tsx | 30 ++++++++++++ .../content/services/mutations.test.ts | 48 +++++++++++++++++++ .../domains/content/services/mutations.ts | 16 +++++++ .../economy/commands/economy-commands.ts | 1 + .../economy/pages/economy-command-form.tsx | 12 +++-- .../economy/pages/economy-pages.test.tsx | 41 +++++++++++++++- .../economy/services/mutations.test.ts | 48 +++++++++++++++++++ .../domains/economy/services/mutations.ts | 16 +++++++ .../foundation/commands/confirmation.test.ts | 23 ++++++++- .../foundation/commands/confirmation.ts | 15 ++++-- .../foundation/commands/dispatcher.test.ts | 47 ++++++++++++++++++ .../foundation/commands/dispatcher.ts | 2 + .../foundation/commands/reason-policy.ts | 23 +++++++++ .../foundation/commands/registry.ts | 1 + 16 files changed, 323 insertions(+), 15 deletions(-) create mode 100644 src/features/housekeeping/foundation/commands/reason-policy.ts diff --git a/src/features/housekeeping/domains/content/commands/content-commands.ts b/src/features/housekeeping/domains/content/commands/content-commands.ts index ef28887f..3c83b4ff 100644 --- a/src/features/housekeeping/domains/content/commands/content-commands.ts +++ b/src/features/housekeeping/domains/content/commands/content-commands.ts @@ -174,6 +174,7 @@ export function createContentCommands( { correlationId: context.correlationId, expectedActorId: context.capability.actor.id, + ...(context.reason === undefined ? {} : { reason: context.reason }), }, operation, input, diff --git a/src/features/housekeeping/domains/content/pages/content-command-form.tsx b/src/features/housekeeping/domains/content/pages/content-command-form.tsx index 09f3303e..c0315aa3 100644 --- a/src/features/housekeeping/domains/content/pages/content-command-form.tsx +++ b/src/features/housekeeping/domains/content/pages/content-command-form.tsx @@ -1,6 +1,7 @@ "use client"; import { useActionState, useId } from "react"; +import { requiresHousekeepingReason } from "../../../foundation/commands/reason-policy"; import type { HousekeepingResult } from "../../../foundation/contracts"; export interface ContentCommandField { @@ -135,11 +136,11 @@ export async function submitContentCommandForm( formData: FormData, ): Promise { const fields = configuration.fields ?? []; - const submittedValues = readSubmittedValues( - fields, + const reasonRequired = requiresHousekeepingReason( configuration.requiresReason ?? false, - formData, + configuration.input, ); + const submittedValues = readSubmittedValues(fields, reasonRequired, formData); const submittedFields = fields.flatMap((field) => { const value = parseField(field, formData); return value === OMIT_FIELD ? [] : [[field.name, value] as const]; @@ -158,7 +159,7 @@ export async function submitContentCommandForm( const result = await executeHousekeepingCommand({ commandId: configuration.commandId, input, - ...(configuration.requiresReason ? { reason } : {}), + ...(reasonRequired ? { reason } : {}), }); return { result, values: result.ok ? {} : submittedValues }; } @@ -190,12 +191,13 @@ export function ContentCommandForm({ requiresReason = false, }: ContentCommandFormProps) { const formId = useId(); + const reasonRequired = requiresHousekeepingReason(requiresReason, input); const [state, submit, pending] = useActionState( submitContentCommandForm.bind(null, { commandId, input, fields, - requiresReason, + requiresReason: reasonRequired, }), initialState, ); @@ -342,7 +344,7 @@ export function ContentCommandForm({ ); })} - {requiresReason ? ( + {reasonRequired ? (