Validation Pattern

Zod-based validation on both frontend and backend, with mandatory XSS sanitization for all user-facing text.

Dual Validation

SideToolPurpose
BackendOpenAPIHono + ZodRoute input validation (source of truth)
Frontendreact-hook-form + @hookform/resolvers/zodForm validation (UX feedback)

Shared validation constants: shared/validation-constants.ts (field lengths, regex patterns).

XSS Sanitization Helpers

backend/src/lib/sanitization-helpers.ts provides DOMPurify-based helpers:

HelperPurposeExample
strictTextField(maxLen)Strips ALL HTMLNames, labels, notes
sanitizedLocalizedText(maxLen)Required bilingual {de, en}Entity names
optionalSanitizedLocalizedText(maxLen)Optional bilingual {de, en}Descriptions
richTextLocalizedText(maxLen)Admin-only rich textSystem templates

Sanitization Levels

LevelAllowed TagsUse Case
STRICTNone (strips all HTML)99% of fields
BASIC_FORMATTING<b>, <i>, <em>, <strong>, <br>Limited formatting
RICH_TEXTExtended setAdmin-only, never user input

Usage Rules

  • Raw z.string() ONLY for non-user-facing values (tokens, emails, system keys, regex patterns)
  • NEVER configure ALLOWED_TAGS via environment variables
  • NEVER use inline purify.sanitize() calls — always use the helpers
  • NEVER use RICH_TEXT level for user-submitted content

LocalizedText Validation

All bilingual fields use the LocalizedText pattern:

const schema = z.object({
  name: sanitizedLocalizedText(100),
  description: optionalSanitizedLocalizedText(1000),
});

Enforcement: pre-commit hook + validator script + CI quality-checks.yml.

Zod Version

Locked to 4.1.13 due to incompatibility between @hookform/resolvers@5.2.2 and Zod 4.2.x.

See Also