diff --git a/.jules/palette.md b/.jules/palette.md index bd0f73248..d271f45aa 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -57,3 +57,6 @@ ## 2026-07-30 - Add window.confirm for destructive actions **Learning:** Destructive actions like deleting groups and edge relationships previously occurred immediately without user confirmation. **Action:** Always wrap delete operations with window.confirm() dialogs and ensure corresponding tests successfully mock window.confirm. +## 2026-08-30 - Fix RTL DOM Bleed Causing Extraneous Rendered Components +**Learning:** In frontend Vitest tests, the guidance now treats "Found multiple elements" as a duplicate-match symptom rather than proof of failed auto-cleanup, requires inspecting the rendered DOM/query scope first, and uses explicit cleanup only when cross-test bleed is actually verified. +**Action:** Always inspect the rendered DOM and query scope when debugging multiple-elements errors, applying explicit cleanup only as a verified last resort for actual state bleed. diff --git a/CHANGELOG.md b/CHANGELOG.md index 35613431a..1b52c47bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## Unreleased +- [FE] ♿ **필수 모달 입력 검증 정합화**: 필수 입력 표시를 공유 `--color-danger` 토큰 기반 컴포넌트로 통일하고, 관계 제약조건/업무 그룹 이름의 공백-only 입력을 저장하지 않으며 고객이 다음에 입력해야 할 값을 브라우저 검증 메시지로 안내합니다. - [BE] 🔒 **Cryptography 50+ 보안 경계 갱신**: `pyproject.toml`과 두 hash-locked 요구사항 파일을 동일한 Cryptography 50+ 해석으로 정합화하여 PKCS#7 오류·타이밍 구분으로 인한 CVE-2026-69247 완화를 실제 설치·검증 경로에 반영했습니다. - [FE] ⚡ **검색 노드 참조 안정화 및 순차 스냅샷 폴링**: 같은 정규화 검색어와 원본 테이블 데이터에는 장식된 `node.data` 참조를 재사용하여 드래그 중 불필요한 하위 렌더링과 할당을 줄입니다. 스냅샷 폴링은 이전 요청이 끝난 뒤에만 다음 요청을 예약하며, 선택 변경·언마운트 후 도착한 오래된 성공 또는 실패 응답을 무시합니다. - [BE] 🔒 **공유 export 전 경로 redaction**: 공개 share의 SQL / index-design / reversing-spec export에서 코멘트·`example_value`를 제거합니다. 단위 테스트로 누출을 차단합니다. diff --git a/docs/doctoring/required-modal-field-validation.md b/docs/doctoring/required-modal-field-validation.md new file mode 100644 index 000000000..b0b8cbb96 --- /dev/null +++ b/docs/doctoring/required-modal-field-validation.md @@ -0,0 +1,35 @@ +# Required modal field validation + +## Buyer problem + +Several modal forms displayed a visual required marker while the executable constraint did not match it. In particular, relationship labels and business-group names could contain only whitespace: HTML `required` treats the empty string as missing, but whitespace is still a non-empty value. That mismatch made the UI promise stricter validation than the form actually enforced. + +## Product contract + +- Native `required` remains the semantic baseline for every mandatory text input in this slice. +- Relationship labels and business-group names additionally reject whitespace-only values before the mutation callback runs. +- Empty relationship and group names receive the same actionable Korean guidance through the input's native invalid event; whitespace-only values receive equivalent guidance through the explicit trim guard. +- The business-group form also renders linked guidance while its Add action is disabled, so the customer can see the next action without needing to trigger an unavailable submit control. +- Changing either value clears the stale custom validity message immediately. +- The visual `*` is centralized in `RequiredIndicator`, uses the existing `--color-danger` token, and is `aria-hidden="true"` because the input itself carries the required semantics. +- No API, database, persistence, authorization, or deployment contract changes. + +## Design and accessibility authority + +Fresh Figma evidence on 2026-08-30 confirms file `csnpEEJfmqFWB0vNUoTkWA`, page `190:2` (`Design System — Storybook Contract`), frame `190:40` (`Design Token Authority`), including `--color-danger = #b91c1c` and the instruction to change runtime source first, keep Storybook exact-value tests green, then resync Figma. The paired executable Storybook token inventory is currently owned by PR #944 at exact head `ffcf653e78306563797262678a4313c8215a5932` and renders exact token values as text while marking decorative previews `aria-hidden`. + +This PR reuses that shared token contract rather than adding a local color. It does not claim a current Storybook component-state story for required-field validation: the protected base does not yet contain #944. Therefore design acceptance remains fail-closed until the required-field state is represented against the then-current paired Figma and Storybook authority before merge. + +## Verification + +Focused tests pin semantic `required` state for add-table, relationship, group, table-title, column-name, and column-type inputs; empty and whitespace-only validation guidance; whitespace-only mutation blocking; linked visible group guidance; clearing stale custom validity; and the decorative marker's exclusion from the accessibility tree. Existing modal coverage continues to exercise valid submit/cancel/delete flows. + +## Standards traceability + +The HTML Standard defines `required` as a boolean constraint and treats a required mutable input whose value is the empty string as missing. The same standard exposes `setCustomValidity()` and `reportValidity()` for constraints beyond the native empty-string rule. WAI-ARIA 1.2 specifies that elements with `aria-hidden="true"` should not be included in the accessibility tree; the marker is non-focusable decoration, not the semantic source of required state. + +### References + +WHATWG. (2026). *HTML Standard*. Retrieved August 30, 2026, from https://html.spec.whatwg.org/ + +World Wide Web Consortium. (2023). *Accessible Rich Internet Applications (WAI-ARIA) 1.2* (W3C Recommendation, June 6, 2023). https://www.w3.org/TR/wai-aria-1.2/ diff --git a/frontend/CHANGELOG.md b/frontend/CHANGELOG.md index c78944c31..0846fc3cd 100644 --- a/frontend/CHANGELOG.md +++ b/frontend/CHANGELOG.md @@ -6,5 +6,8 @@ - **테스트 추가**: 프론트엔드 테스트 커버리지 100% 목표 달성을 위해 `cardinality.ts`, `types.ts`, `export.ts` 의 미달성 분기 및 함수 테스트 추가 (`cardinality_extra.test.ts` 등). - `.gitignore` 파일에 `coverage/` 폴더를 추가하여 불필요한 테스트 아티팩트가 커밋되지 않도록 보완. +### Fixed +- 필수 모달 필드의 시각적 표시와 실제 `required`/공백 검증을 정합화하고, 유효하지 않은 관계·그룹 이름에는 고객이 다음에 입력할 값을 설명하는 검증 메시지를 제공합니다. + ### Security - `postcss` 트랜지티브 의존성을 `overrides`로 `^8.5.18`(8.5.25로 해석)에 고정해 GHSA-r28c-9q8g-f849(High, source-map 자동 로딩의 경로 순회를 통한 임의 `.map` 노출)을 제거했습니다. postcss는 Vite 빌드 툴체인 전용 트랜지티브 의존성으로 배포 런타임 경로에 없으며, 조치 후 `npm audit --audit-level=high` → High 이상 취약점 0건. 변경 범위는 `frontend/package.json`의 `overrides` 맵(`postcss` 항목 추가)과 재생성된 `frontend/package-lock.json`이며, 애플리케이션 소스는 수정하지 않았습니다. diff --git a/frontend/src/components/modals/AddTableModal.tsx b/frontend/src/components/modals/AddTableModal.tsx index 024bde03f..ffacd364c 100644 --- a/frontend/src/components/modals/AddTableModal.tsx +++ b/frontend/src/components/modals/AddTableModal.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { RequiredIndicator } from './RequiredIndicator'; import { useDialogAccessibility } from './useDialogAccessibility'; interface AddTableModalProps { @@ -9,6 +10,7 @@ interface AddTableModalProps { onAddTableSubmit: () => void; } +/** Renders the add-table dialog with native required-name semantics. */ export function AddTableModal({ isOpen, newTableName, @@ -61,7 +63,9 @@ export function AddTableModal({ >