feat(housekeeping): deliver content vertical

This commit is contained in:
2026-08-30 01:54:43 +02:00
parent bdab924bdf
commit fd68819d9b
67 changed files with 5742 additions and 1916 deletions
@@ -0,0 +1,84 @@
import "server-only";
import { z } from "zod";
import { PERMS } from "@/lib/permission-slugs";
import type { HousekeepingCommand } from "../../../foundation/commands/registry";
import { anyCapability } from "../../../foundation/contracts";
import {
type ContentMutationOperation,
type ContentMutationService,
contentMutationService,
} from "../services/mutations";
const CONTENT_COMMAND_DEFINITIONS = [
["content.editorial.article.change", "article.change", PERMS.NEWS_EDIT],
["content.media.ad.change", "ad.change", PERMS.PAGES_EDIT],
["content.media.banner.change", "banner.change", PERMS.BANNERS_EDIT],
["content.engagement.event-type.change", "event-type.change", PERMS.EVENTS_EDIT],
["content.engagement.event.change", "event.change", PERMS.EVENTS_EDIT],
["content.engagement.event-prize.change", "event-prize.change", PERMS.EVENTS_EDIT],
["content.engagement.event-winner.add", "event-winner.add", PERMS.EVENTS_EDIT],
["content.engagement.poll.change", "poll.change", PERMS.POLLS_EDIT],
["content.engagement.poll-question.change", "poll-question.change", PERMS.POLLS_EDIT],
["content.media.photo.delete", "photo.delete", PERMS.PAGES_EDIT],
["content.media.asset.upload", "media.upload", PERMS.PAGES_EDIT],
["content.media.asset.delete", "media.delete", PERMS.PAGES_EDIT],
["content.editorial.navigation.update", "navigation.update", PERMS.SETTINGS_EDIT],
["content.editorial.tag.change", "tag.change", PERMS.PAGES_EDIT],
["content.engagement.prefix.change", "prefix.change", PERMS.PREFIXES_EDIT],
["content.engagement.prefix-blacklist.change", "prefix-blacklist.change", PERMS.PREFIXES_EDIT],
["content.engagement.prefix-settings.update", "prefix-settings.update", PERMS.PREFIXES_EDIT],
["content.help.question.change", "help-question.change", PERMS.PAGES_EDIT],
["content.editorial.writeable-box.change", "writeable-box.change", PERMS.PAGES_EDIT],
["content.help.email-template.change", "email-template.change", PERMS.PAGES_EDIT],
["content.brand.theme.update", "theme.update", PERMS.SETTINGS_EDIT],
["content.brand.theme.apply-preset", "theme.apply-preset", PERMS.SETTINGS_EDIT],
["content.brand.theme.custom-change", "theme.custom-change", PERMS.SETTINGS_EDIT],
["content.brand.theme.apply-custom", "theme.apply-custom", PERMS.SETTINGS_EDIT],
["content.brand.favicon.save", "favicon.save", PERMS.SETTINGS_EDIT],
["content.brand.favicon.delete", "favicon.delete", PERMS.SETTINGS_EDIT],
["content.brand.logo.save", "logo.save", PERMS.SETTINGS_EDIT],
["content.localization.cms.save", "translation.cms.save", PERMS.SETTINGS_EDIT],
["content.localization.client.save", "translation.client.save", PERMS.SETTINGS_EDIT],
["content.localization.emulator.save", "translation.emulator.save", PERMS.SETTINGS_EDIT],
] as const;
export const CONTENT_COMMAND_IDS = CONTENT_COMMAND_DEFINITIONS.map(
([id]) => id,
) as ReadonlyArray<(typeof CONTENT_COMMAND_DEFINITIONS)[number][0]>;
type ContentCommand = HousekeepingCommand<Record<string, unknown>, unknown> & {
readonly operation: ContentMutationOperation;
};
const commandInput = z.object({}).catchall(z.unknown());
export function createContentCommands(
service: Pick<ContentMutationService, "execute">,
): readonly ContentCommand[] {
return CONTENT_COMMAND_DEFINITIONS.map(
([id, operation, permission]): ContentCommand => ({
id,
owner: "content",
operation,
risk: "sensitive",
capability: anyCapability(permission),
input: commandInput,
requiresReason:
id.startsWith("content.brand.") ||
id.startsWith("content.localization."),
rateLimit: { attempts: 10, windowMs: 60_000 },
execute: (context, input) =>
service.execute(
{
correlationId: context.correlationId,
expectedActorId: context.capability.actor.id,
},
operation,
input,
),
}),
);
}
export const CONTENT_COMMANDS = createContentCommands(contentMutationService);