관리자 Material 레일·반응형 데이터 UI 회귀
고정 입력과 OSS 권위
Section titled “고정 입력과 OSS 권위”| 항목 | 고정값 |
|---|---|
| frontend revision | fbed8f864542ddd26d6756e368a003795c669adf |
| frontend tree | 05f0343c0db9de667d35eba53ccc6b2add59fa80 |
| production build digest | sha256:1c0e8c638d866f77e4bd51cb35d176e4b455d6b8ee01ce2ad5256cb52f5d3052 |
| Astro | 7.1.0 |
| MUI Material / Icons | 9.2.0 |
| TanStack React Table | 8.21.3 |
| capture / conversion | Playwright CLI 0.1.17, HeadlessChrome 146.0.0.0, Sharp 0.34.5 lossless |
| environment | local production Astro build · route interception 없음 · mock network 없음 |
MUI 9.2.0에는 native Navigation Rail component가 없다. 따라서 이 화면은 native rail이라고 과장하지 않고, Google Material 3 지침을 MUI permanent/temporary Drawer와 list primitive로 구성한 M3-informed rail이다. table과 card는 TanStack의 같은 getRowModel()을 소비한다. 현재 component capability, 결손, MIT 라이선스, upgrade trigger는 관리자 Material navigation·data UI trap sheet에 고정했다.
실제 폭 기준
Section titled “실제 폭 기준”Navigation은 viewport, data collection은 자신의 container를 기준으로 판단한다.
| 경계 | navigation | data mode |
|---|---|---|
| viewport 0–599px | app bar + temporary drawer 296px | 각 collection 폭에 따름 |
| viewport 600px 이상 | permanent rail 88px / expanded 280px | 각 collection 폭에 따름 |
| standard collection 0–899px | 해당 없음 | 별도 vertical card collection |
| standard collection 900px 이상 | 해당 없음 | semantic table |
| wide collection 0–1119px | 해당 없음 | 별도 vertical card collection |
| wide collection 1120px 이상 | 해당 없음 | semantic table |
따라서 1440px viewport라도 rail을 280px로 확장해 content container가 좁아지면 열이 많은 출산정보·일일 리포트는 card로 바뀐다. table을 억지로 줄이거나 horizontal scroll 안에 숨기지 않는다.
| viewport / rail | navigation / body offset | table group | card group / card | width invariant |
|---|---|---|---|---|
| 390x844 | app bar, drawer 296px | 0 | 4 / 19 | 390 = 390 |
| 599x420 | app bar, body offset 0 | 0 | 4 / 19 | 599 = 599 |
| 600x420 | rail 88px, body offset 88px | 0 | 4 / 19 | 600 = 600 |
| 1024x900 | rail 88px, body offset 88px | 0 | 4 / 19 | 1024 = 1024 |
| 1440x900 collapsed | rail 88px, body offset 88px | 4 | 0 / 0 | 1440 = 1440 |
| 1440x900 expanded | rail 280px, body offset 280px | 2 | 2 / 10 | 1440 = 1440 |
expanded 상태에서 rail right는 280px, heading left는 312px였다. rail이 본문 앞 192px를 덮던 overlay 결함과 600–899px의 빈 88px gutter가 모두 재현되지 않았다.
실제 브라우저 전이
Section titled “실제 브라우저 전이”

599/600 navigation 경계
Section titled “599/600 navigation 경계”

table을 대체하는 세로 card
Section titled “table을 대체하는 세로 card”





1440px rail 정적 frame 보기


A→Z 재검증 절차
Section titled “A→Z 재검증 절차”- A — 범위 고정 fixture UI regression이며 actor·business acceptance가 아님을 먼저 고정한다.
- B — revision 고정 clean frontend revision, tree, production build digest가 위 표와 같은지 확인한다.
- C — OSS 권위 확인 Material adaptive navigation, MUI v9 Drawer/container query, TanStack v8 공식 문서를 확인한다.
- D — focused behavior test AdminNavigation, AdminShell, AdminResponsiveDataCollection과 dashboard 관련 6개 test file, 12개 test를 통과시킨다.
- E — full frontend gate 전체 89개 file, 563개 test와 lint, Astro check를 통과시킨다.
- F — production build Astro build를 통과시키고 dist 정렬 hash를 기록한다.
- G — local runtime Node standalone production output을 loopback에서 실행한다.
- H — browser 격리 새 Playwright session을 열고 route interception과 mock을 추가하지 않는다.
- I — 599 compact boundary app bar, body offset 0, table 0, card group 4, horizontal overflow 0을 확인한다.
- J — 600 rail boundary permanent rail 88px와 body offset 88px가 동시에 시작하는지 확인한다.
- K — medium collection 1024px에서 네 collection이 모두 card이고 table은 0인지 확인한다.
- L — wide collapsed 1440px collapsed에서 rail/body 88px, table 4, card group 0인지 확인한다.
- M — expanded reflow 실제 toggle로 rail/body를 280px로 바꾸고 rail right 280px보다 heading left가 큰지 확인한다.
- N — container response 같은 1440px에서 standard table 2개는 남고 wide collection 2개만 card 10개로 바뀌는지 확인한다.
- O — mobile drawer Enter로 열고 Escape로 닫은 뒤 focus가 menu button으로 돌아오는지 확인한다.
- P — navigation destination dashboard와 신규 지점 개설 두 실제 목적지가 모두 HTTP 200인지 검사한다.
- Q — width invariant 각 viewport에서 documentWidth와 clientWidth가 viewport width와 같은지 검사한다.
- R — mutually exclusive mode 각 collection에서 table과 card group이 동시에 보이지 않는지 검사한다.
- S — shared row model desktop table과 narrow card가 같은 TanStack getRowModel()을 소비하는지 source/test로 확인한다.
- T — semantic table desktop table에 head/body와 실제 caption이 있는지 확인한다.
- U — console 전체 전환 뒤 browser console error와 warning이 각각 0인지 확인한다.
- V — CSP / Emotion nonce style-src-elem의 self·nonce, style-src-attr의 unsafe-inline 분리와 header/DOM nonce 일치를 확인한다.
- W — privacy masking 식별·출산 fixture가 있는 두 capture는 PNG 작성 전에 안전한 Korean placeholder로 바꾼다.
- X — lossless WebP Sharp effort 6 lossless로 metadata를 제거한 10개 static·2개 animated WebP를 만든다.
- Y — manifest gate viewport와 element-crop 크기, asset hash, frame source/order, privacy review, canonical exclusion을 검사한다.
- Z — 범위 판정 UI regression만 PASS로 기록하고 phase·migration 완료 판정은 바꾸지 않는다.
CSP·privacy·machine evidence
Section titled “CSP·privacy·machine evidence”| 검사 | 관측 |
|---|---|
| response cache | private, no-store |
| CSP | style-src-elem self + request nonce, style-src-attr unsafe-inline |
| nonce | header 24 chars, DOM unique 1, header/DOM match true |
| Emotion style | style element 176, nonce style element 174 |
| browser | console error 0, warning 0, dead navigation 0 |
| accessibility interaction | Enter open, Escape close, focus return |
| privacy | capture-time opaque safe placeholders, production data false, unmasked person data false |
Machine SSOT는 docs/evidence/admin-material-responsive-ui/manifest.json, privacy 판정은 같은 디렉터리의 privacy-review.md다. checker는 genuine WebP bytes/hash/frame count뿐 아니라 viewport 크기와 element crop 크기를 분리해 검사하고, animation source 순서와 container-threshold 관측도 고정한다.
canonical docs/evidence/visual-evidence.json에는 이 fixture 회귀를 scenario/feature/step으로 추가하지 않았다. canonical actor registry가 요구하는 실제 actor outcome을 가장하지 않기 위해서다.
pnpm test:admin-material-evidence pnpm docs:admin-material-evidence:check pnpm docs:visual-evidence:check pnpm docs:check pnpm docs:build
영구 capture harness는 추가하지 않았다. 기존 Playwright CLI와 frontend-pinned Sharp가 이미 capture/conversion capability를 소유한다. 이 페이지의 A→Z와 manifest가 재캡처 입력을, 별도 checker가 게시 산출물의 불변성을 소유한다.