V13-FE-006: consolidate approved UI and contract hardening
deploy / deploy (push) Successful in 1m52s
deploy / notify (push) Successful in 1s

This commit is contained in:
2026-08-13 02:41:00 +09:00
parent d79edae546
commit 3f293d8aa8
1278 changed files with 14384 additions and 1664 deletions
@@ -0,0 +1,33 @@
import { z } from 'zod'
import { getKbxField, type KbxKnownFieldKey } from '@kbx/contracts'
/**
* Structural client validation derived from the canonical KBX field dictionary.
* Domain/state rules intentionally remain in the Vertical Slice / server Domain.
*/
export function kbxTextSchema(key: KbxKnownFieldKey) {
const field = getKbxField(key)
let schema = z.string().trim()
if ('maxLength' in field && typeof field.maxLength === 'number') {
schema = schema.max(field.maxLength, `${field.label}은(는) ${field.maxLength}자 이내로 입력하세요.`)
}
return schema
}
export function kbxRequiredTextSchema(key: KbxKnownFieldKey, message?: string) {
const field = getKbxField(key)
return kbxTextSchema(key).min(1, message ?? `${field.label}을(를) 입력하세요.`)
}
export function kbxNullableEntityIdSchema(key: KbxKnownFieldKey, message?: string) {
const field = getKbxField(key)
return z.string().nullable().refine(value => Boolean(value), message ?? `${field.label}을(를) 선택하세요.`)
}
export function kbxDecimalSchema(key: KbxKnownFieldKey) {
const field = getKbxField(key)
if (!['integer', 'decimal', 'quantity', 'money'].includes(field.dataType)) {
throw new Error(`${key} is not numeric in the KBX field dictionary.`)
}
return z.number()
}