- Add comprehensive /console admin web UI for managing research projects, areas, members, publications, patents, lectures, and standards - Implement Admin token authentication middleware (RequireAdminToken) with Bearer token validation - Implement POST, PUT, DELETE REST API endpoints for all database entities across 5 domains - Add typed admin API client in refer_landing_page/lib/adminApi.ts with localStorage session persistence - Enhance E2E test runner to manage backend server lifecycle during automated tests - Pass all 12 quality gates cleanly with unanimous reviewer PASS verdicts
1056 lines
149 KiB
Markdown
1056 lines
149 KiB
Markdown
# 📐 요구사항 명세서 (Requirements Specification)
|
||
## 경북대학교 AI 에이전트 네트워크 연구실 (ANL) 공식 홈페이지
|
||
|
||
| 항목 | 내용 |
|
||
| :--- | :--- |
|
||
| **문서 ID** | `REQ-ANL-WEB-001` |
|
||
| **버전** | `2.1` |
|
||
| **작성일** | 2026-08-24 |
|
||
| **작성자** | agy (`herdr:creator-agy-01`) / claude (`herdr:planner-reviewer-claude-01`) · Role: worker / planner |
|
||
| **상태** | 승인 (Approved) — v2.1에서 **`/console` 어드민 대시보드 및 백엔드 CRUD REST API(POST/PUT/DELETE)** 추가. Bearer Token(`ADMIN_TOKEN`) 기반 관리자 인증 도입 및 백오피스 `/console` UI 전용 라우트/컴포넌트 설계 반영. 공개 디자인 토큰 계약(AC-43~AC-48)의 적용 범위(공개 랜딩 페이지 전용) 명문화. |
|
||
| **대상 독자** | General Manager, Developer Team Leader(Agy), Reviewer Team Leader(Cline), 지도교수 |
|
||
| **선행 문서** | [`README.md`](./README.md), [`.agents/MULTI_AGENT_RULES.md`](./.agents/MULTI_AGENT_RULES.md), [`refer_landing_page/docs/DESIGN.md`](./refer_landing_page/docs/DESIGN.md) |
|
||
| **적용 범위** | `refer_landing_page/` (Next.js 14 App Router 애플리케이션) 전체 |
|
||
|
||
> **본 문서의 성격**: 코드를 포함하지 않는 **명세 문서**입니다. 데이터 스키마와 인터페이스 정의에 한해 TypeScript 타입 표기를 사용하나, 이는 계약(contract) 기술을 위한 것이며 구현 코드가 아닙니다.
|
||
|
||
---
|
||
|
||
## 1. 원본 요구사항 (사용자 제공 · 정본)
|
||
|
||
> 아래는 사용자가 직접 작성한 요구사항 원문이며, **본 명세서 전체의 정본(normative source)** 이다.
|
||
> 이하 모든 절은 이 원문을 구체화한 것이며, 원문과 충돌하는 서술이 있다면 **원문이 우선**한다.
|
||
|
||
```
|
||
- 홈페이지 상단 탭은 다음과 같음
|
||
- Home: 연구실 소개, 연구실 주요 연구 분야 소개, 오시는길
|
||
- Members: 기존 정보 그대로 보존되어야 함
|
||
- Publications: 기존 정보 그대로 보존되어야 하며, 다음 카테고리로 구분되어야 함
|
||
- International Conference
|
||
- International Journal & Conference
|
||
- Domestic Journal & Conference
|
||
- Patent
|
||
- Lectures: 기존 정보 그대로 보존되어야 함
|
||
- Standardization: 기존 정보 그대로 보존되어야 함
|
||
```
|
||
|
||
### 1.1 원문에서 도출되는 최상위 원칙
|
||
|
||
| ID | 원칙 | 근거 문구 |
|
||
| :--- | :--- | :--- |
|
||
| **PR-01** | **무손실 보존 (Lossless Preservation)** — 레거시 `ISL-2026/`의 레코드는 **한 건도 누락되지 않고**, 문구·표기·순서가 임의로 변형되지 않은 채 이관되어야 한다 | "기존 정보 그대로 보존되어야 함" (4회 반복) |
|
||
| **PR-02** | **상단 탭 5종 고정** — Home / Members / Publications / Lectures / Standardization | "홈페이지 상단 탭은 다음과 같음" |
|
||
| **PR-03** | **Home 3구성** — 연구실 소개 · 주요 연구 분야 소개 · 오시는 길 | Home 항목 |
|
||
| **PR-04** | **Publications 분류** — 원문에 명시된 4개 카테고리 라벨을 출발점으로 삼는다. *(v1.5: 원문 1번 `International Conference`는 §12.1 D-01 확정에 따라 폐기되어 **최종 3분류**로 확정. 원문 문구 자체는 §1에 정본 그대로 보존하며, 이 축소는 해당 라벨에 배정된 레코드가 0건이므로 PR-01 무손실 원칙과 충돌하지 않는다)* | Publications 항목 |
|
||
|
||
> ⚠️ **PR-01의 해석**: "그대로 보존"은 **데이터의 무손실**을 의미하며, *레거시의 시각적 표현을 그대로 복제하라는 뜻이 아니다.* 표현은 신규 디자인 시스템(§8)을 따르되, **레코드 단위의 정보량은 100% 보존**한다. 점진적 노출(더 보기·접기)은 전체 레코드가 접근 가능한 한 허용된다(§9.4 참조).
|
||
|
||
---
|
||
|
||
## 2. 개요 및 배경 (Overview & Background)
|
||
|
||
### 2.1 목적
|
||
|
||
경북대학교 컴퓨터학부 연구실이 **사물인터넷 표준 연구실 (IoT Standards Laboratory, ISL)** 에서 **AI 에이전트 네트워크 연구실 (AI Agent Networking Laboratory, ANL)** 로 연구 정체성을 전환함에 따라, 공식 홈페이지를 다음 두 축으로 재구축한다.
|
||
|
||
1. **정체성 전환 (Identity Transformation)** — 연구실 명칭·연구 서사·시각 언어를 ANL 및 5대 핵심 연구 기둥 기준으로 전면 교체한다.
|
||
2. **실데이터 마이그레이션 (Data Migration)** — 레거시 사이트 `ISL-2026/`에 축적된 **실측 연구 실적 총 223건**(국제 논문 68 · 국내 논문 80 · 특허 75)과 **표준화 문서 약 55건**을 신규 애플리케이션의 타입 안전한 데이터 구조로 무손실 이관한다(PR-01).
|
||
|
||
### 2.2 현재 상태 (As-Is)
|
||
|
||
| 자산 | 경로 | 상태 |
|
||
| :--- | :--- | :--- |
|
||
| 레거시 공식 홈페이지 | `ISL-2026/` | 정적 HTML. **실데이터 원본(Single Source of Truth)** |
|
||
| 신규 프로토타입 | `refer_landing_page/` | Next.js 14.2.35 / React 18 / TS 5 / Tailwind 3. 라우트 5종 구현, **콘텐츠는 대부분 placeholder** |
|
||
| 연구 자산 | `multi-agent-orchestration/` | 5대 연구 기둥의 근거 자료 (SLIDE.md, chapters/, lecture_summary.md) |
|
||
|
||
**완료된 선행 작업** (커밋 `e35b46d` → `315ba9e` → `cdd0db3`, 3차 교차 리뷰 `[VERDICT: PASS]`)
|
||
- 연구실 명칭 ANL 전환: Header / Footer / `metadata` / `package.json`(`anl-landing`) / `docs/DESIGN.md` / `tailwind.config.ts`
|
||
- `/intro` 커버 스프레드를 5대 연구 기둥 3+2 매거진 조판으로 재구성
|
||
- 강조색 시맨틱 계약 재정의: `vermillion` = Agent Eng / Orchestration (홀수), `cobalt` = MCP / A2A Protocol (짝수)
|
||
- 빌드 게이트 정비: `.eslintrc.json` 도입, lint / tsc / build 3종 통과
|
||
|
||
**미해결 상태**
|
||
- **`/`(루트) 라우트 부재** — `app/page.tsx`가 없어 사이트 루트 직접 접근 시 404. PR-02의 `Home` 탭이 존재하지 않는다.
|
||
- `/members`, `/publications`, `/lectures`, `/standardization` 본문이 전부 가상의 placeholder (`연구원 A (placeholder)`, 가상 논문, 실재하지 않는 oneM2M/OMA LwM2M 기여 내역)
|
||
- 레거시 실데이터 **223건 + 표준 문서 약 55건 전량 미이관** — PR-01 미충족
|
||
|
||
---
|
||
|
||
## 3. 이해관계자 및 역할 (Stakeholders & Roles)
|
||
|
||
| 주체 | 역할 | 본 명세서에 대한 책임 |
|
||
| :--- | :--- | :--- |
|
||
| 지도교수 (고석주 교수) | 콘텐츠 소유자 | 실데이터 정확성 최종 확인, §12 D-02·D-03·D-05 결정 *(D-01은 v1.5에서 확정)* |
|
||
| General Manager | 오케스트레이터 | 잡 분배, 마일스톤 게이팅, 미결 결정 에스컬레이션 |
|
||
| **Agy** (`creator`) | 개발 팀장 | §6·§7 구현, 데이터 추출·이관, 컴포넌트 개발 |
|
||
| **Cline** (`reviewer`) | 리뷰어 팀장 | §9 비기능 요구사항 검수 (UI/UX 반응형, SEO, 접근성) |
|
||
| **Claude** (`planner and reviewer`) | 기획·리뷰어 팀장 | 본 명세서 작성·유지, 데이터 무결성 교차 검증, 최종 Verdict |
|
||
|
||
---
|
||
|
||
## 4. 정보 구조 (Information Architecture)
|
||
|
||
### 4.1 사이트맵
|
||
|
||
```
|
||
/ Home [🆕 신규] 연구실 소개 · 주요 연구 분야(5대 기둥) · 오시는 길
|
||
├── /members Members 지도교수 · 재학 연구원 16명 · 졸업생 60명
|
||
├── /publications Publications 개요 · 카테고리 분류 · Top 10 (총 223건)
|
||
│ ├── /publications/intl-journal-conf International Journal & Conference (68)
|
||
│ ├── /publications/domestic-journal-conf Domestic Journal & Conference (80)
|
||
│ └── /publications/patent Patent (75)
|
||
├── /lectures Lectures 2004 Spring ~ 2026 Spring, 45개 학기
|
||
└── /standardization Standardization 표준화 기구 6곳 · 표준 문서 44건
|
||
```
|
||
|
||
### 4.2 IA 설계 결정
|
||
|
||
| ID | 결정 | 근거 |
|
||
| :--- | :--- | :--- |
|
||
| **IA-01** | 현행 `/intro`의 커버 스프레드를 **`/`(Home)으로 승격**한다 | PR-02가 상단 탭에 `Intro`를 포함하지 않으며, PR-03의 "연구실 소개"가 Home의 구성 요소로 명시되어 있다. `/intro`를 별도 유지하면 Home과 콘텐츠가 중복된다. **부수 효과로 기존 `/` 404 결함이 해소된다.** |
|
||
| **IA-02** | `/intro`는 **`/`로 308 영구 리다이렉트**한다 | 3차에 걸친 리뷰 리포트·문서가 `/intro`를 참조하고 있어 링크 안정성이 필요하다. `next.config.js`의 `redirects()`로 처리하며 별도 페이지 파일을 남기지 않는다. |
|
||
| **IA-03** *(v1.1 개정 · v1.5 수치 갱신 · v1.9 개정 · v1.10 재개정)* | Publications 카테고리는 **라우트 세그먼트 `/publications/[category]` + `generateStaticParams()`** 로 구현한다. **`/publications`는 `redirect()`가 아니라 자체 콘텐츠를 렌더하는 실체 라우트로 유지하며, 그 콘텐츠는 하위 카테고리 어느 것과도 중복되지 않는 Overview 뷰**(카테고리별 집계 + 최신 실적 하이라이트)로 한다 — D-09 재확정(v1.10). `redirect()` 전용 라우트는 산출 HTML에 `<main>`·`container-content`가 존재하지 않아 **AC-25를 구조적으로 위반**하므로 금지하고, 첫 카테고리 본문을 그대로 재렌더하는 방식은 **동일 DOM 정적 HTML 2본을 생성해 R-8.25를 위반**하므로 금지한다. 상단 `CategoryNav`는 **3개 카테고리 탭만** 노출하며 `All`/`전체` 탭을 두지 않는다(commit `22a31ff` 결정 존중) — Overview에서는 활성 탭이 없는 것이 정상 상태다 | **v1.0에서 "단일 라우트 + `?cat=` 쿼리"였으나 §8.5의 실측 검증 결과에 따라 개정.** 세그먼트 방식은 카테고리별 완전한 정적 HTML 3개(D-01 확정 전 4개)를 빌드 타임에 생성해 **공유 링크가 필터 상태를 포함한 문서를 그대로 제공**하며(AC-05 취지 충족), 뒤로/앞으로 가기·프리페치·스크롤 복원이 Next 라우터에서 기본 제공된다. 슬러그를 카테고리 레지스트리에서 도출하므로 **라벨 변경이 레지스트리 한 곳 수정으로 끝난다는 v1.0의 근거는 그대로 유지**된다(→ D-01 리스크 완화 불변). 상단 탭은 5종 그대로이므로 **PR-02와 충돌하지 않는다**(하위 라우트일 뿐 최상위 탭이 아니다). |
|
||
| **IA-04** | 내비게이션 항목은 **PR-02의 5개로 고정**한다 | `components/Header.tsx`의 데스크톱 내비가 5개 항목 기준으로 조판되어 있다. 항목 증감 시 헤더 레이아웃 재설계가 선행되어야 한다. |
|
||
|
||
---
|
||
|
||
## 5. 콘텐츠 정본: 핵심 연구 분야
|
||
|
||
PR-03의 "연구실 주요 연구 분야 소개"에 해당하는 콘텐츠다. `README.md` §2를 **정본(canonical)** 으로 하며, UI의 모든 연구 서술은 여기서 파생되어야 한다. 어휘를 임의로 변형하지 않는다.
|
||
|
||
| # | 분야 (KO) | 분야 (EN) | 핵심 키워드 | 강조색 |
|
||
| :-: | :--- | :--- | :--- | :--- |
|
||
| 1 | AI Agent 기능 확장 프로토콜 | Extensibility & Protocol | MCP, SKILL, CLI 코딩 에이전트 | `vermillion` |
|
||
| 2 | 멀티 에이전트 협업 및 오케스트레이션 | Multi-Agent Systems | HERDR, crewAI, LangGraph | `cobalt` |
|
||
| 3 | 에이전트 상호운용성 개방형 표준 | Interoperability Standards | A2A, ACP, Agent Card | `vermillion` |
|
||
| 4 | AIoT & 고성능 통신 백본 | High-Performance Backbone | gRPC/QUIC, Protobuf, MQTT/CoAP | `cobalt` |
|
||
|
||
**R-5.1** 강조색은 §8.3의 홀수/짝수 규칙을 따른다. 분야 순서를 변경하면 색 배정도 함께 갱신해야 한다.
|
||
**R-5.2** 핵심 연구 분야 서술 전문(全文)은 Home에만 두고, 타 페이지에는 요약 키워드만 노출한다. 동일 문장을 여러 페이지에 중복 하드코딩하지 않는다.
|
||
**R-5.3** 레거시 `introduction.html`의 구 연구 분야(QUIC, CoAP, IVI, VLC/OWC, mSCTP, SCTP, Mobility Management, Tabu Search 등)는 **Home의 연구 분야 소개에서 제외**한다. 단, 이들 주제로 산출된 논문·특허·표준은 PR-01에 따라 실적 페이지에 **전량 보존**된다.
|
||
|
||
---
|
||
|
||
## 6. 페이지별 상세 요구사항
|
||
|
||
> 각 항목의 `[MUST]` / `[SHOULD]` / `[MAY]`는 RFC 2119 수준을 따른다.
|
||
|
||
### 6.1 Home (`/`) — 🆕 신규 라우트
|
||
|
||
PR-03에 따라 **연구실 소개 · 주요 연구 분야 소개 · 오시는 길** 3개 블록을 필수 포함한다.
|
||
|
||
| ID | 요구사항 | 수준 |
|
||
| :--- | :--- | :-- |
|
||
| H-01 | `app/page.tsx`를 신규 생성하고, 현행 `app/intro/page.tsx`의 섹션 구성(커버 스프레드 → 지표 카운터 → Mission 풀쿼트 → 핵심 연구 분야 → Focus Areas)을 이관한다 | MUST |
|
||
| H-02 *(v1.7 개정)* | 킥커 `경북대학교 컴퓨터학부 · AI Agent Networking Lab (ANL)`는 유지한다. **슬로건 헤드라인(`에이전트 네트워크의 / 미래를 짓다`, 디스플레이 `Agents / in Motion`)은 §6.1.2 Research Project PageView로 교체할 수 있다.** 단 교체 시에도 **H-03(연구실 소개 서술 블록) · H-04(주요 연구 분야 그리드) · H-05(오시는 길) · H-06·H-07(지표 카운터) · H-10(`HeroComposition`)은 반드시 존속**한다 — 히어로 재구성 중 이들이 유실되면 **AC-02가 즉시 실패**한다 | MUST |
|
||
| H-03 | **[연구실 소개]** 연구실 개요·지도교수·비전을 서술하는 블록을 배치하고, 상세는 `/members`로 연결한다 | MUST |
|
||
| H-04 | **[주요 연구 분야]** §5의 핵심 연구 분야 전문을 매거진 조판으로 노출한다 | MUST |
|
||
| H-05 | **[오시는 길]** 아래 §6.1.1 요구사항을 충족하는 블록을 배치한다 | MUST |
|
||
| H-06 | 지표 카운터는 **데이터 배열에서 도출된 값**만 사용한다. 근거 없는 홍보성 수치(가동률·만족도 등) 게시 금지 | MUST |
|
||
| H-07 | H-06의 권장 지표: `연구 분야` = 4, `누적 연구 실적` = 논문+특허 합계(223), `Issue · 발행` = 2026(static) | SHOULD |
|
||
| H-08 | 대표 실적 하이라이트 — 최신 국제 저널 3건을 `/publications`로 연결 | SHOULD |
|
||
| H-09 | 표준화 기여 요약 밴드 — 기구 6곳 약칭 `Marquee` + `/standardization` 연결 | SHOULD |
|
||
| H-10 | `HeroComposition` SVG는 현행(A2A 노드 메시 × QUIC/gRPC 스트림)을 그대로 재사용한다 | MUST |
|
||
| H-11 | `/intro` → `/` 308 리다이렉트를 `next.config.js`에 등록한다 (IA-02) | MUST |
|
||
| H-12 | `components/Header.tsx`의 브랜드 링크 `href`를 `/intro` → `/`로 바꾸고, 내비 배열 첫 항목을 `Home`(`/`)으로 교체한다 | MUST |
|
||
|
||
#### 6.1.1 오시는 길 (Directions) 세부 요구사항
|
||
|
||
레거시 `index.html`에 주소가 **HTML 주석 처리된 상태**로 존재한다. 이를 복원해 사용한다.
|
||
|
||
| ID | 요구사항 | 수준 |
|
||
| :--- | :--- | :-- |
|
||
| H-13 | 소재지를 표기한다: **경북대학교 IT대학 5호관(415동) 527호** / *School of Computer Science and Engineering, Kyungpook National University* | MUST |
|
||
| H-14 | 연락처를 표기한다: `sjkoh@knu.ac.kr` (지도교수). 전화·팩스는 **레거시에 존재하지 않으므로 창작하지 않는다** | MUST |
|
||
| H-15 | 소속 기관 링크를 제공한다: KNU(`knu.ac.kr`), 컴퓨터학부(`cse.knu.ac.kr`), IT대학(`it.knu.ac.kr`) | MUST |
|
||
| H-16 | 지도 표현 방식은 §12 **D-03**의 결정을 따른다. 외부 지도 스크립트를 임의로 도입하지 않는다(R-9.13 최소 의존성 원칙과 충돌) | MUST |
|
||
| H-17 | 주소는 시맨틱 `<address>` 요소로 마크업한다 | MUST |
|
||
| H-18 | 대중교통·주차 안내는 **레거시에 데이터가 없으므로 이번 범위에서 제외**한다. 필요 시 지도교수 확인 후 별도 잡으로 추가 | MUST |
|
||
|
||
#### 6.1.2 Research Project PageView *(v1.7 신설)*
|
||
|
||
Home의 슬로건 히어로를 **실제 연구 프로젝트 카드 뷰**로 전환한다(H-02 개정).
|
||
|
||
**레거시 실측 — 실재하는 프로젝트 3건**: `ISL-2026/index.html` `<section class="portfolio-block skills">`의 `card-title`/`card-text` 및 이어지는 확장 섹션 2개가 유일한 원본이다. (`projects-cards` 클래스는 **표준화 기구 로고 그리드**이며 연구 프로젝트가 아니다 — 오독 주의.)
|
||
|
||
| # | Title | 확장 정보 |
|
||
| :-- | :--- | :--- |
|
||
| 1 | `IoT Standards` | — |
|
||
| 2 | `CCIS` | "This project is developing a series of standards in **IEC/TC 100/TA 17**" |
|
||
| 3 | `VLC-IoT` | "This project is purposed to develop a series of standards in **ITU-T SG20**." |
|
||
|
||
| ID | 요구사항 | 수준 |
|
||
| :--- | :--- | :-- |
|
||
| PJ-01 | 데이터는 `content/projects.ts`에 두고, 타입은 **`ResearchProject`** 로 명명한다. `StandardsBody.projects`(WG 단위 표준화 프로젝트)와 **의미가 다르므로 이름을 재사용하지 않는다** | MUST |
|
||
| PJ-02 | `content/projects.ts`는 **`scripts/extract/generate_all.py`의 `parse_projects()`로 자동 생성**한다. 수작업 편집 금지(기존 `AUTO-GENERATED` 규약 · AC-24) | MUST |
|
||
| PJ-03 | `abstract`는 레거시 원문을 **바이트 동일하게 보존**한다(PR-01). 요약·재작성·`line-clamp`로 인한 정보 손실 금지 | MUST |
|
||
| PJ-04 | `period`는 `content/standards.ts` `standardsBodies[].period`를 **조인해 도출**한다. 교차 검증 출처는 `ISL-2026/sjkoh/index.html`의 Project Editor 이력이다 | MUST |
|
||
| PJ-05 | `deliverables`는 `content/standards.ts` `projects[].documents[]`를 **조인해 도출**한다. 임의 생성 금지 | MUST |
|
||
| PJ-06 | `keywords[]`의 **모든 원소는 해당 프로젝트 `abstract` 원문에 부분문자열로 실제 등장해야 한다.** 키워드 창작을 기계적으로 차단하기 위한 규칙이다 (→ AC-30) | MUST |
|
||
| PJ-07 | `funder`는 **옵셔널**이며 현재 전건 미확보다(§12.1 **D-07**). **값이 없으면 UI에 해당 행·라벨·자리표시자를 렌더하지 않는다**(R-9.18). 레거시가 실제로 명시하는 표준화 트랙은 `Funder`가 아닌 **`Standards Track`** 라벨로 노출한다 | MUST |
|
||
| PJ-08 **[금지]** | **활성 슬라이드만 마운트하는 캐러셀을 구현하지 않는다.** 프로젝트 전건이 항상 DOM에 존재해 정적 HTML에 포함되어야 한다(R-8.15 · AC-27) | MUST |
|
||
| PJ-09 **[금지]** | 슬라이드·페이지 상태를 **URL에 동기화하지 않는다.** `searchParams` prop은 라우트를 `ƒ Dynamic`으로 전환시키고(R-8.11), `useSearchParams()`는 `<Suspense>` 경계를 요구하며 경계 안쪽 콘텐츠가 정적 HTML에서 누락된다(R-8.12·R-8.13). 상태는 컴포넌트 로컬로 유지한다 | MUST |
|
||
| PJ-10 **[금지]** | 캐러셀·슬라이더 **외부 라이브러리를 도입하지 않는다**(swiper·embla 등). 현행 런타임 의존성 3종(`next`/`react`/`react-dom`)을 유지한다(R-9.13) | MUST |
|
||
| PJ-11 | 트랙은 **CSS scroll-snap + 컨테이너 내부 `overflow-x-auto`** 로 구현해 **JS 비활성 상태에서도 전건 열람이 가능**해야 한다. 페이지 레벨 가로 스크롤을 유발해서는 안 되며(R-9.15·AC-19), full-bleed를 위해 `w-screen`을 쓰지 않는다(R-8.18) | MUST |
|
||
| PJ-12 | 데이터 렌더는 **서버 컴포넌트**, 인터랙션(버튼·인디케이터)만 `"use client"` 로 분리한다. 페이지네이션 인디케이터는 `<a href="#project-…">` 앵커로 두어 JS 없이도 동작하게 한다. 스크롤 애니메이션은 **`prefers-reduced-motion` 존중**(`components/Counter.tsx`·`globals.css` 선례) | MUST |
|
||
| PJ-13 *(v1.8 개정)* | 반응형 카드 노출: 360 px 1장 / `md` 2장(`w-[calc(50%-12px)]` — `2×(50%−12px)+24px = 100%`로 **대수적 정확값**) / **`desktop`(1240 px)에서는 스크롤 트랙이 아니라 `desktop:grid desktop:grid-cols-3 desktop:overflow-visible` 정적 3열로 전환**하고 카드는 `desktop:w-full`로 둔다. **데스크톱 카드 폭에 퍼센트 연산을 사용하지 않는다.** 근거: Tailwind `grid-cols-3`은 `repeat(3, minmax(0, 1fr))`로 전개되어 **min-content 넘침을 구조적으로 차단**하며, `overflow-visible`이 해당 요소를 **스크롤 컨테이너에서 해제**해 스크롤 잔재·불필요한 포커스 가능 스크롤 영역을 함께 제거한다(→ AC-34). 브레이크포인트는 `desktop` 토큰만 사용한다(R-8.20 · AC-26) | MUST |
|
||
| PJ-14 | 접근성: 트랙 `role="group"` + `aria-roledescription="carousel"`, 카드 `aria-roledescription="slide"` + `aria-label="N개 중 M번째"`, 버튼 `aria-label` 및 `aria-controls`, 카드 제목은 `<h3>` | MUST |
|
||
| PJ-15 *(v1.8 신설)* | 카드에 **`min-w-0`** 과 텍스트 줄바꿈(`break-words`, 국문은 R-9.16 `break-keep`)을 적용한다. **`flex-shrink: 0`인 플렉스 아이템은 콘텐츠의 min-content 폭 이하로 줄지 않으므로**, `standardsTrack`(`IEC/TC 100/TA 17`)·`deliverables[].ref`(`ISO/IEC TR 30189`)처럼 `/`를 포함해 기본 줄바꿈 기회가 없는 문자열이 **폭 수식과 무관하게 트랙을 넘치게 할 수 있다.** PJ-13의 그리드 전환은 데스크톱만 보호하므로, 모바일·태블릿 구간은 이 규칙으로 보호한다 | MUST |
|
||
| PJ-16 *(v1.8 신설)* | 스크롤바를 숨기는 경우(`[scrollbar-width:none]` 등) 잔여 넘침이 **시각적 단서 없이 은폐**되므로, **AC-34 검증을 반드시 동반**한다 | MUST |
|
||
|
||
### 6.2 Members (`/members`) — PR-01 적용
|
||
|
||
**레거시 실측**: 재학 16명(교수 1 · Ph.D. 1 · Ph.D. Candidate 4 · Ph.D. Student 5 · M.S. Candidate 3 · M.S. Student 2), 졸업생 60명(2007~2026).
|
||
|
||
| ID | 요구사항 | 수준 |
|
||
| :--- | :--- | :-- |
|
||
| M-01 | 현행 placeholder(`연구원 A~G`) 전량을 `ISL-2026/member.html` 실데이터로 교체한다. **재학 16명 + 졸업생 60명 = 76명 전원 보존** | MUST |
|
||
| M-02 | 지도교수 피처 스프레드: `고석주 교수 / Prof. Seok-Joo Koh`, 이메일 `sjkoh@knu.ac.kr`, 개인 홈페이지(`ISL-2026/sjkoh/`) 및 GitHub(`github.com/sjkoh12`) 링크 | MUST |
|
||
| M-03 | 재학 연구원을 **학위 과정별로 그룹핑**하고, 레거시의 `Candidate`/`Student` 구분을 보존한다 | MUST |
|
||
| M-04 | 소속 학과가 컴퓨터학부와 다른 연구원(정보보호학과·정보과학과·과학기술학과·ICT융합학과·컴퓨터학부 등 8명)은 **소속 표기를 함께 노출**한다 | MUST |
|
||
| M-05 | 졸업생 60명을 **졸업 연도 역순**으로 게시하고, 학위·졸업시점·전공·현 소속을 표기한다 | MUST |
|
||
| M-06 | 졸업생 목록은 최근 3년을 기본 노출하고 나머지는 `더 보기`로 확장한다. **확장 시 60명 전원이 노출되어야 한다** (PR-01) | SHOULD |
|
||
| M-07 | 이름 표기 형식을 통일한다: `한글명 (Romanized Name)`. 외국인 연구원(Hoang Anh Dang 등)은 원문 그대로 표기 | MUST |
|
||
| M-08 | 인원 통계 카운터는 배열 길이에서 도출한다 (H-06 원칙 동일 적용) | MUST |
|
||
| M-09 | 개인 이메일·연락처는 **지도교수 외 게시하지 않는다** | MUST |
|
||
| M-10 | 졸업생의 현 소속 문구(`He is now with ...`)는 레거시 원문 정보를 보존하되, 국문 페이지 맥락에 맞게 소속명만 추출해 표기해도 무방하다 | SHOULD |
|
||
|
||
### 6.3 Publications (`/publications`) — PR-01 + PR-04 적용
|
||
|
||
**레거시 실측**: `paper-international.html` 68건(저널 67 + 학술대회 1) · `paper-domestic.html` 80건(KCI 등재 48) · `patent.html` 75건 = **총 223건**.
|
||
|
||
| ID | 요구사항 | 수준 |
|
||
| :--- | :--- | :-- |
|
||
| P-01 *(v1.5 개정)* | **3개 카테고리**를 사용한다: `International Journal & Conference` / `Domestic Journal & Conference` / `Patent`. **D-01 확정(v1.5)**: PR-04의 1번 라벨 `International Conference`는 대응 레거시 원본이 없어 실측 0건이었고, 2번 라벨의 부분집합으로 범위가 중첩되므로 **단독 카테고리를 폐기**한다. 국제 학술대회 논문(실측 1건)은 `International Journal & Conference`에 포함해 보존한다 | MUST |
|
||
| P-02 | 카테고리는 **레지스트리 상수 1곳**에 정의하고, 개별 레코드는 `category` 판별 필드만 갖는다. 라벨 변경·교체가 레지스트리 수정만으로 완결되어야 한다 | MUST |
|
||
| P-03 | **223건 전량 보존** — 어떤 카테고리에도 배정되지 않아 누락되는 레코드가 있어서는 안 된다. *(v1.5 확인: D-01 확정으로 카테고리가 3개로 축소되었으나 `intl-conf` 배정 레코드가 0건이었으므로 축소는 무손실이다. 실측 68 + 80 + 75 = 223)* | MUST |
|
||
| P-04 | 레거시 `paper-international.html`은 저널과 학술대회 논문이 **혼재**되어 있다(학술대회 1건 확인: `International Conference on ICTC`, 2023). 이관 시 게재처 문자열로 판별해 분류한다 | MUST |
|
||
| P-05 | 기본 정렬은 **발행 연월 내림차순**, 동일 연월 내에서는 레거시 게시 순서를 보존한다 | MUST |
|
||
| P-06 *(v1.1 개정)* | 카테고리 필터 UI를 제공한다. 필터 상태는 **URL 경로**(`/publications/<slug>`)에 반영되어 **공유 가능한 링크**가 되어야 한다. 슬러그는 §7.2 `PubCategory` 값을 그대로 사용한다. 구현 방식은 **§8.5의 렌더링 제약을 반드시 따른다** | MUST |
|
||
| P-06a *(v1.1 신설)* | 카테고리 내비게이션은 `next/link`의 `<Link>`로 구현한다. `window.history.pushState` 직접 호출·`useSearchParams()` 사용 금지 (§8.5 R-8.11~8.14) | MUST |
|
||
| P-07 | 전체 223건을 단일 화면에 일괄 렌더하지 않는다. **연도별 그룹 헤더 + 지연 확장** 또는 페이지네이션으로 초기 렌더 부하를 제한하되, 전 레코드가 접근 가능해야 한다 (§9.4) | MUST |
|
||
| P-07a *(v1.1 신설)* | 레코드 목록 자체는 **서버 컴포넌트에서 정적 HTML로 렌더**되어야 한다. 목록 데이터를 클라이언트 컴포넌트 내부나 `<Suspense>` 경계 안쪽에 두어 정적 문서에서 누락시켜서는 안 된다 (§8.5 R-8.15). 근거: JS 미실행 환경·크롤러에서도 PR-01의 전 레코드가 문서에 존재해야 한다 | MUST |
|
||
| P-08 | 국내 논문의 `(KCI)` 등재 표시를 **배지로 보존**한다 (48건) | MUST |
|
||
| P-09 | 특허 레코드는 다음을 모두 보존한다: 발명자 목록, 출원번호·출원일, 등록번호·등록일(있는 경우), 국가(한국/US). **출원/등록 상태를 구분 표기**한다 | MUST |
|
||
| P-10 | 파생 통계 카운터: 카테고리별 건수를 배열에서 도출해 표기 | SHOULD |
|
||
| P-11 | DOI·원문 링크는 **레거시에 존재하지 않으므로 이번 범위에서 제외**한다. 스키마에 선택 필드로 예약만 한다 | MUST |
|
||
| P-12 | 저자명·논문 제목·게재처 표기는 **레거시 원문을 그대로 보존**한다. 임의 축약·재배열·번역 금지 (PR-01) | MUST |
|
||
| P-13 | 국문·영문 제목이 혼재하는 국내 논문 목록에서 언어를 통일하지 않는다 (PR-01) | MUST |
|
||
|
||
### 6.4 Lectures (`/lectures`) — PR-01 적용
|
||
|
||
**레거시 실측**: 2016 Fall ~ 2026 Spring, 약 20개 학기, 과목명 + 학수번호 형식.
|
||
|
||
| ID | 요구사항 | 수준 |
|
||
| :--- | :--- | :-- |
|
||
| L-01 | 현행 placeholder 3건(`사물인터넷 개론`, `메타버스 상호운용성과 표준` 등)을 실제 강의 이력으로 교체한다. **전 학기 전 과목 보존** | MUST |
|
||
| L-02 | **학기별(Spring/Fall + 연도) 그룹핑**을 레거시 구조 그대로 보존한다 | MUST |
|
||
| L-03 | 최근 3개 학기를 기본 노출하고 이전 이력은 `전체 이력 보기`로 확장한다. **확장 시 전 학기가 노출되어야 한다** (PR-01) | SHOULD |
|
||
| L-04 | 과목 레코드: 학수번호(`COMP 0414` 등), 과목명(EN), 학부/대학원 구분 | MUST |
|
||
| L-05 | 과목명 한글 번역은 **레거시에 없으므로 신규 창작하지 않는다.** 영문 원문을 정본으로 노출한다 (→ §12 D-02) | MUST |
|
||
| L-06 | `Fall 2023 — No Class (Sabbatical)`과 같은 비강의 학기도 이력에 보존한다 (PR-01) | MUST |
|
||
| L-07 | 동일 과목이 여러 분반(`ITEC 401003`, `ITEC 401004`)으로 개설된 경우 분반을 합치지 않고 보존한다 (PR-01) | MUST |
|
||
|
||
### 6.5 Standardization (`/standardization`) — PR-01 적용
|
||
|
||
**레거시 실측**: 기구 6곳 / 표준 문서 약 55건 / 활동 기간 2000~현재.
|
||
|
||
| 기구 | 활동 기간 | 주요 산출물 | 구분 |
|
||
| :--- | :--- | :--- | :--- |
|
||
| IEC TC100 (Multimedia Systems and Equipment) | 2018 ~ 현재 | IEC 63614(Metaverse) 4건, IEC 63478(QoE, **WG11 Convenor**) 3건, IEC 63479(Infotainment) 3건, IEC 63246(CCIS) 4건 | 국제 |
|
||
| ISO/IEC JTC1/SC41 (IoT and Digital Twin) | 2020 ~ 현재 | ISO/IEC TR 30189 2건 | 국제 |
|
||
| ITU-T SG20 (IoT Services based on VLC) | 2018 ~ 2020 | Y.4465, Y.4474 | 국제 |
|
||
| ITU-T SG13 (Mobility Management) | 2002 ~ 2012 | Q.Sup52, Q.1706~1709, Y.2052, Y.2809 등 7건 | 국제 |
|
||
| ISO/IEC JTC1/SC6 WG7 (Network and Transport) | 2000 ~ 2014 | ECTP(14476), RMCP(16512), MMC(24793), FN-PSR(29181) 계열 다수 | 국제 |
|
||
| TTA/PG425 (가시광 통신 기반 사물인터넷) | 2018 ~ 2020 | TTAK.KO-10.1158 part1~3 | 국내 |
|
||
|
||
| ID | 요구사항 | 수준 |
|
||
| :--- | :--- | :-- |
|
||
| S-01 | 현행 4개 기구(`oneM2M`, `W3C WoT`, `IETF QUIC`, `OMA LwM2M`)는 **실제 기여 이력이 아닌 placeholder**이므로 전량 교체한다 | MUST |
|
||
| S-02 | **국제 표준화 / 국내 표준화** 2개 섹션으로 구분한다 (레거시 구조 보존) | MUST |
|
||
| S-03 | 기구별 카드에 활동 기간과 역할(예: `WG11 Convenor`, `WG30(TA17)`)을 명시한다 | MUST |
|
||
| S-04 | 표준 문서는 기구 → 워킹그룹/프로젝트 → 문서의 **3단 계층**으로 표현하고, 문서 55건 전량을 보존한다 | MUST |
|
||
| S-05 | 문서 상태(`IS` / `TS` / `TR` / `CDV` / `WDTR` / `In Progress`)를 배지로 구분 노출한다 | MUST |
|
||
| S-06 | `In Progress` 문서(IEC WDTR 63614-4, IEC CDV 63478-3, ISO/IEC CDTR 30189-2)는 **진행 중임이 시각적으로 명확**해야 한다 | MUST |
|
||
| S-07 | 기구 카드 강조색은 §8.3 홀수/짝수 교차 규칙을 따른다 | MUST |
|
||
| S-08 | 카운터는 기구 수·문서 수를 배열에서 도출한다 | MUST |
|
||
| S-09 | 5대 연구 기둥 중 **기둥 4(A2A/ACP 개방형 표준)** 와의 연결 서술을 도입부에 배치해, 과거 표준화 역량이 신규 연구 방향으로 이어짐을 드러낸다 | SHOULD |
|
||
|
||
---
|
||
|
||
## 7. 데이터 모델 및 마이그레이션 명세
|
||
|
||
### 7.1 데이터 배치 원칙
|
||
|
||
| ID | 요구사항 | 수준 |
|
||
| :--- | :--- | :-- |
|
||
| DM-01 | 콘텐츠 데이터는 페이지 컴포넌트에서 분리해 **`content/` 디렉터리의 타입 지정 모듈**로 이관한다 (`content/members.ts`, `content/publications.ts`, `content/lectures.ts`, `content/standards.ts`) | MUST |
|
||
| DM-02 | 각 모듈은 명시적 TypeScript 인터페이스를 export 한다. `any` 사용 금지 | MUST |
|
||
| DM-03 *(v2.0 개정)* | 데이터는 **실시간 동적 런타임 페칭(`force-dynamic`, `cache: 'no-store'`)**으로 백엔드 API(`http://localhost:8080/api/v1`)로부터 조회한다. `content/*.ts` 모듈은 백엔드 미가동/장애 시의 **그레이스풀 폴백(Fallback) 데이터셋**으로 유지한다. 6개 데이터 라우트는 `ƒ Dynamic`으로 렌더링되며, 4개 프레임워크 라우트는 `○ Static`을 유지한다 (§8.5 R-8.16, §10 AC-17) | MUST |
|
||
| DM-04 | 각 페이지 상단의 `// CUSTOMIZATION HOOK` 주석 규약(`DESIGN.md` "콘텐츠 우선" 원칙)은 `content/` 모듈로 이전하되 **규약 자체는 유지**한다 | MUST |
|
||
|
||
### 7.2 스키마 정의 (계약)
|
||
|
||
```ts
|
||
// content/members.ts
|
||
type Degree = "Professor" | "PhD" | "PhDCandidate" | "PhDStudent" | "MSCandidate" | "MSStudent";
|
||
|
||
interface Member {
|
||
ko: string; // "최동규" (외국인 연구원은 원문 표기)
|
||
en: string; // "Dong-Kyu Choi"
|
||
degree: Degree;
|
||
affiliation?: string; // 컴퓨터학부 외 소속일 때만 (M-04)
|
||
}
|
||
|
||
interface Alumnus {
|
||
ko: string;
|
||
en: string;
|
||
degree: "PhD" | "MS";
|
||
graduatedAt: string; // "2026-08" (ISO 8601 부분 표기)
|
||
major?: string; // "Computer Science and Engineering"
|
||
currentPosition?: string; // "Daegu Catholic University (대구가톨릭대학교) as Professor"
|
||
}
|
||
|
||
// content/publications.ts
|
||
// D-01 확정(v1.5) 후 3개 카테고리. 라벨 문자열은 레지스트리에서만 정의한다 (P-02).
|
||
type PubCategory =
|
||
| "intl-journal-conf" // International Journal & Conference
|
||
| "domestic-journal-conf" // Domestic Journal & Conference
|
||
| "patent"; // Patent
|
||
|
||
interface Publication {
|
||
category: PubCategory; // P-02: 판별 필드
|
||
title: string; // P-12: 원문 보존
|
||
authors?: string; // P-12: 원문 보존
|
||
venue?: string; // 저널/학술대회명
|
||
volume?: string; // "Vol. 23, pp. 4490~4505"
|
||
publishedAt: string; // "2026-04" (P-05 정렬 키)
|
||
kci?: boolean; // P-08
|
||
doi?: string; // P-11: 예약 필드, 현재 미사용
|
||
}
|
||
|
||
interface Patent {
|
||
category: "patent";
|
||
title: string;
|
||
inventors: string; // "고석주, 정중화, 남혜빈, 최동규"
|
||
applicationNo: string; // "2023-0180751"
|
||
applicationAt: string; // "2023-12-13"
|
||
registrationNo?: string; // "2963109"
|
||
registrationAt?: string; // "2026-05-06"
|
||
country: string; // "한국" | "US"
|
||
publishedAt: string; // 정렬 키 (= applicationAt 의 연월)
|
||
}
|
||
|
||
// content/lectures.ts
|
||
interface Semester {
|
||
term: "Spring" | "Fall";
|
||
year: number;
|
||
courses: { code: string; en: string; note?: string }[]; // L-05, L-06, L-07
|
||
}
|
||
|
||
// content/standards.ts
|
||
type DocStatus = "IS" | "TS" | "TR" | "CDV" | "WDTR" | "InProgress";
|
||
|
||
interface StandardsBody {
|
||
org: string; // "IEC TC100"
|
||
full: string; // "Multimedia Systems and Equipment"
|
||
scope: "international" | "domestic"; // S-02
|
||
period: string; // "2018 ~ Present"
|
||
role?: string; // "WG11 Convenor"
|
||
projects: {
|
||
wg: string; // "WG12"
|
||
name: string; // "Multimedia Systems and Equipment for Metaverse (IEC 63614)"
|
||
documents: { title: string; ref: string; status: DocStatus; publishedAt?: string }[];
|
||
}[];
|
||
}
|
||
|
||
// content/projects.ts (v1.7 신설 · §6.1.2)
|
||
// ⚠️ StandardsBody.projects(WG 단위 표준화 프로젝트)와 의미가 다르다. 이름 재사용 금지 (PJ-01).
|
||
interface ProjectDeliverable {
|
||
title: string; // standards.ts 문서 제목 원문
|
||
ref: string; // "IEC 63246" / "ISO/IEC TR 30189"
|
||
status: DocStatus; // 기존 유니온 재사용
|
||
}
|
||
|
||
interface ResearchProject {
|
||
slug: string; // "iot-standards" | "ccis" | "vlc-iot"
|
||
title: string; // 레거시 card-title 원문
|
||
abstract: string; // 레거시 card-text 원문 — 바이트 동일 보존 (PJ-03)
|
||
keywords: string[]; // 전 원소가 abstract 부분문자열이어야 함 (PJ-06)
|
||
standardsTrack?: string; // "IEC/TC 100/TA 17" — 레거시 확장 섹션 원문
|
||
standardsOrg?: string; // standards.ts `org` 조인 키
|
||
period?: string; // standards.ts `period` 에서 도출 (PJ-04)
|
||
deliverables: ProjectDeliverable[]; // standards.ts documents 에서 도출 (PJ-05)
|
||
funder?: string; // 현재 전건 미확보(D-07). 값 없으면 UI 미렌더 (PJ-07)
|
||
}
|
||
```
|
||
|
||
### 7.3 마이그레이션 절차
|
||
|
||
| ID | 요구사항 | 수준 |
|
||
| :--- | :--- | :-- |
|
||
| MG-01 | 추출은 **재현 가능한 스크립트**로 수행하고, 스크립트를 `scripts/` 하위에 커밋한다. 수작업 복사·붙여넣기 금지 | MUST |
|
||
| MG-02 | 추출 후 **건수 대조 검증**을 수행한다. 기대값: 국제 68 / 국내 80 / 특허 75 / 표준 문서 55 / 재학 16 / 졸업생 60 / 학기 약 20 | MUST |
|
||
| MG-03 | 한글·특수문자(`~`, `·`, `‧`, `o`, 전각 기호) 인코딩 손실이 없어야 한다. 레거시 파일에 **BOM(``)이 존재**하므로 제거한다 | MUST |
|
||
| MG-04 | 날짜는 전부 **ISO 8601**로 정규화한다 (`2026년 6월` → `2026-06`, `April 2026` → `2026-04`, `2023.12.13` → `2023-12-13`) | MUST |
|
||
| MG-05 | 레거시에 없는 정보를 **추정·창작하지 않는다.** 누락 필드는 optional로 두고 UI에서 조건부 렌더한다 (PR-01) | MUST |
|
||
| MG-06 | 이미지 자산은 실제 사용분만 `public/`으로 이관한다. 원본 총량 11.6MB(`image/` 3.4MB + `assets/` 8.2MB)를 무조건 복사하지 않는다 | MUST |
|
||
| MG-07 | 이관 이미지는 WebP 변환 및 `next/image` 적용 | SHOULD |
|
||
| MG-08 | 마이그레이션 완료 후 렌더 HTML 전수 스캔으로 **구 정체성 잔재 0건**을 확인한다 (검사어: `사물인터넷 표준`, `IoT Standards`, `MCM`, `메타버스 상호운용성`, `홍길동`, `placeholder`). 단, **논문·특허 제목에 포함된 도메인 용어는 실데이터이므로 예외**로 취급한다 | MUST |
|
||
|
||
> ⚠️ **MG-08의 중요한 예외**: 레거시 실적에는 `사물인터넷`, `메타버스`, `oneM2M` 등이 **논문 제목·표준 문서명으로 실재**한다(예: IEC 63614 *Multimedia Systems and Equipment for Metaverse*). 이는 **구 정체성 잔재가 아니라 보존해야 할 실데이터**다(PR-01). 잔재 검사는 **연구실 정체성 서술 영역**(Header/Footer/metadata/Home 소개문)에 한정해 적용한다.
|
||
|
||
---
|
||
|
||
## 8. 디자인 시스템 준수 규격
|
||
|
||
정본은 [`refer_landing_page/docs/DESIGN.md`](./refer_landing_page/docs/DESIGN.md)("Issue 01")이며, 본 절은 **위반 시 리뷰에서 반려되는 항목**만 발췌한다.
|
||
|
||
### 8.1 색상 토큰 (변경 금지)
|
||
|
||
| 토큰 | 값 | 용도 |
|
||
| :--- | :--- | :--- |
|
||
| `ink` / `ink-soft` / `ink-mute` | `#0A0A0A` / `#262420` / `#6B655B` | 본문·괘선 |
|
||
| `ivory` / `paper` / `line` | `#F5F1E8` / `#ECE6D6` / `#D8D1C0` | 종이 배경 / 인셋 / 헤어라인 |
|
||
| `vermillion` / `vermillion-dark` | `#D9342B` / `#A8231C` | 강조 (Hot) — **최초 커밋 이래 불변** |
|
||
| `cobalt` / `cobalt-dark` | `#4E77FF` / `#345AD2` *(v1.13 갱신)* | 강조 (Cool) — Primary |
|
||
|
||
**실측 대비 (v1.13 기준선 · WCAG 2.1 재계산)**
|
||
|
||
| 토큰 | `ivory`(L) | `paper`(L) | `ivory`(D) | `paper`(D) | 라이트↔다크 반전 대비 |
|
||
| :--- | ---: | ---: | ---: | ---: | ---: |
|
||
| `cobalt` #4E77FF | 3.45 | 3.12 | 4.82 | 4.37 | **1.00 ❌ (R-8.28 위반)** |
|
||
| `cobalt-dark` #345AD2 | 5.26 | **4.76** | 6.57 | 5.96 | 2.08 ✅ |
|
||
| `vermillion` #D9342B | 4.16 | 3.77 | 5.01 | 4.54 | **1.25 ❌ (→ D-13)** |
|
||
| `vermillion-dark` #A8231C | 6.38 | 5.77 | 6.72 | 6.09 | 2.58 ✅ |
|
||
|
||
> **v1.11 갱신 근거**: 커밋 `eaddc4f`가 `cobalt`를 `#1B3A8A` → `#4A7CE8`, `cobalt-dark`를 `#122863` → `#3462CC`로 변경했다. `#4A7CE8`은 사용자 지정 값이므로 유지하되, `cobalt-dark`는 `paper` 배경에서 4.48:1로 미달하므로 **D-10 결정에 따라 `#32549E`(paper 5.82:1)로 재조정**한다. `vermillion`(#D9342B)은 변경된 적이 없다 — `eaddc4f`의 커밋 메시지 `…and secondary to #D9342B`는 현상 유지의 서술이다(→ §12.1 D-10 상세). **v1.12**: 두 강조색의 `-dark` 변형(`#A8231C` / `#32549E`)은 소형 텍스트 전경뿐 아니라 **`text-[0.65rem]` 상태 칩의 배경**으로도 사용된다 — `ivory` 전경만으로 6.38~6.43(라이트) / 6.57~6.72(다크)를 확보한다(→ R-8.26 · R-8.29 · §12.1 D-10 보론).
|
||
>
|
||
> **v1.13 갱신 근거**: 커밋 `ca4a7ee`·`8db16e4`가 `cobalt`를 `#4A7CE8` → **`#4E77FF`**, `cobalt-dark`를 D-10 확정값 `#32549E`가 아닌 **`#345AD2`** 로 설정했다. `#4E77FF`는 사용자 지정 Primary이므로 유지하며, `#345AD2`도 `paper` **4.76**으로 R-8.26 바닥값을 충족하므로 **D-10 확정값을 `#345AD2`로 개정**한다(단 여유가 0.26뿐이라 §12.2 R-4로 등재). 다만 **`--cobalt`의 반전 대비가 1.00으로 R-8.28을 다시 위반**하며 — 이는 v1.11에서 D-10의 근본 원인으로 규명한 실패 유형의 재발이다 — AC-45 게이트가 `-dark` 2개 토큰만 검사하도록 구현되어 **검출하지 못했다**(→ R-8.28 개정 · AC-45 개정 · §12.1 D-12 상세). 4개 색 변경 커밋 **전부 본문이 비어 있어 R-8.1·R-8.27의 대비 재산정표 첨부 의무가 4회 연속 미이행**이다.
|
||
|
||
**R-8.1** 신규 색 토큰 추가 금지. 색상 값 변경 시 `tailwind.config.ts`와 `app/globals.css`의 `:root` CSS 변수를 **반드시 함께** 수정하며, **R-8.26~R-8.28의 대비·반전 제약을 재산정해 첨부**한다.
|
||
**R-8.2** `brand` / `accent` 별칭은 레거시 호환 전용이며 신규 코드에서 사용 금지.
|
||
|
||
### 8.2 타이포그래피 · 유틸리티 클래스
|
||
|
||
**R-8.3** 지정 서체만 사용한다 — 영문 디스플레이 `Fraunces`(`font-display`), 국문 헤드라인 `Noto Serif KR`(`headline-ko`), 본문 산세리프 `Pretendard`/`Inter`(`font-sans`).
|
||
**R-8.4** 기존 유틸리티 클래스를 우선 사용한다: `.container-content`, `.display`, `.display-sm`, `.headline-ko`, `.kicker`, `.pull-quote`, `.reveal`. 동등 기능의 임의 클래스 신설 금지.
|
||
|
||
### 8.3 강조색 시맨틱 계약
|
||
|
||
**R-8.5** `vermillion` = Agent Engineering / Orchestration(홀수 항목), `cobalt` = MCP / A2A Protocol(짝수 항목). 목록 렌더 시 인덱스 기반 교차 배정을 따른다.
|
||
- **[v1.13 · 적용 범위 명시]** 본 계약은 `docs/DESIGN.md` §2 "의미 있는 색(Semantic accent pairing)"의 정본 서술과 **동일한 내용**이며, 목록 교차 배정뿐 아니라 **단일 강조 표면(히어로 강조어·섹션 키커 등)에도 적용되는지**는 확정되지 않았다. 커밋 `2441f35`가 히어로의 `Orchestration` 강조어를 vermillion → cobalt로 변경해 **같은 페이지 안에서 규약이 둘로 갈린 상태**이므로 **D-12로 이관**한다. 어느 쪽으로 확정하든 **코드와 `docs/DESIGN.md`가 같은 값을 말해야 한다**(→ AC-23 · AC-50).
|
||
|
||
### 8.4 컴포넌트 재사용
|
||
|
||
**R-8.6** 기존 7종을 우선 재사용한다: `Header`, `Footer`, `PageHeader`, `SectionLabel`, `Reveal`, `Counter`, `Marquee`. 신규 컴포넌트는 기존 조합으로 구현 불가함을 리뷰에서 입증한 경우에만 추가한다.
|
||
**R-8.7** `PageHeader`의 `index` prop은 IA 순서를 따른다 — Home 1 / Members 2 / Publications 3 / Lectures 4 / Standardization 5.
|
||
**R-8.8 [중요 제약]** `Counter`는 **정수 전용**이다. 내부에서 `Math.round()`로 표시값을 산출하므로 소수를 넘기면 반올림된 값이 표시되고, `prefers-reduced-motion` 경로에서는 반올림이 적용되지 않아 **모션 설정에 따라 값이 달라진다**. 소수 지표가 필요하면 `Counter`의 소수 대응 확장을 선행 과제로 처리한다.
|
||
**R-8.9** 그리드에서 `gap-px bg-line` 헤어라인 기법은 **테두리 없는 카드** 전용이다. `border border-ink`를 가진 카드에는 `bg-line`을 함께 걸지 않는다.
|
||
**R-8.10** 항목 수가 열 수로 나누어떨어지지 않는 그리드는 `col-span`으로 마지막 행을 채운다. 빈 트랙이 배경색 블록으로 노출되어서는 안 된다 (5개 항목 → `lg:grid-cols-6` 기준 2/2/2 · 3/3 조판이 확립된 패턴).
|
||
|
||
### 8.5 Next.js 렌더링 제약 *(v1.1 신설)*
|
||
|
||
> **출처**: 개발 팀장(Agy)의 기술 이의제기(Job `175860e4`)를 계기로, 본 프로젝트의 실제 환경(**Next.js 14.2.35**, `refer_landing_page/`)에서 4가지 구현 방식을 **직접 빌드해 실측**한 결과다. 추정이 아닌 재현된 관측치이며, 프로브 라우트는 검증 후 전량 삭제해 저장소에 남기지 않았다.
|
||
|
||
#### 실측 결과표
|
||
|
||
| # | 구현 방식 | 빌드 결과 | 정적 HTML에 담기는 내용 |
|
||
| :-: | :--- | :--- | :--- |
|
||
| 1 | Client Component에서 `useSearchParams()` — **`<Suspense>` 없음** | ❌ **빌드 실패**<br>`useSearchParams() should be wrapped in a suspense boundary at page "/…"` → `Export encountered errors` | — |
|
||
| 2 | `useSearchParams()` — **`<Suspense>` 있음** | ✅ **`○ (Static)`** | 경계 **안쪽**은 fallback만 저장됨.<br>경계 **바깥**의 서버 렌더 콘텐츠는 **정상 프리렌더됨** |
|
||
| 3 | Client `useState` + `window.history.pushState` | ✅ **`○ (Static)`** | 클라이언트 **초기 상태만** 저장됨 (`cat=all`). 공유 링크 진입 시 마운트 후 보정 → **비필터 상태가 먼저 표시됨** |
|
||
| 4 | Server Component의 **`searchParams` prop** 사용 | ⚠️ **`ƒ (Dynamic)`** — 정적 생성 탈락 | 매 요청 서버 렌더 |
|
||
| 5 | `[category]` 세그먼트 + `generateStaticParams()` | ✅ **`● (SSG)`** — 카테고리별 HTML **4개 생성** | **카테고리 값이 HTML에 그대로 포함됨** (`cat=patent`) |
|
||
|
||
#### 도출 규칙
|
||
|
||
**R-8.11 [금지]** Server Component 페이지에서 **`searchParams` prop을 사용하지 않는다.** 실측 #4에서 확인된 대로 해당 라우트가 `ƒ (Dynamic)`으로 전환되어 DM-03·NF-03을 직접 위반한다. **본 프로젝트에서 정적 생성을 깨뜨리는 유일하게 확인된 경로다.**
|
||
|
||
**R-8.12 [금지]** `useSearchParams()`를 `<Suspense>` 경계 없이 호출하지 않는다. 실측 #1에서 프로덕션 빌드가 중단됨을 확인했다.
|
||
|
||
**R-8.13 [제한적 허용]** `useSearchParams()` + `<Suspense>` 조합은 정적 생성을 깨뜨리지 **않는다**(실측 #2에서 `○ Static` 유지 확인). 다만 경계 안쪽 콘텐츠가 정적 HTML에서 누락되므로, **필터 컨트롤 등 소규모 UI에 한해** 사용하고 레코드 목록에는 사용하지 않는다(R-8.15).
|
||
|
||
**R-8.14 [금지]** 라우팅 목적의 `window.history.pushState` 직접 호출을 하지 않는다. Next 라우터를 우회하므로 **뒤로/앞으로 가기 시 URL만 바뀌고 UI가 갱신되지 않으며**, 이를 보정하려면 `popstate` 리스너를 직접 등록·해제해야 한다. 카테고리 이동은 `next/link`로 처리한다(P-06a).
|
||
|
||
**R-8.15 [필수]** 대량 레코드(Publications 223건, Alumni 60명, 표준 문서 44건)는 **서버 컴포넌트에서 정적 HTML로 렌더**한다. 클라이언트 상태나 `<Suspense>` 경계 안쪽에 넣어 정적 문서에서 누락시키지 않는다. 실측 #2에서 **경계 바깥 서버 렌더 콘텐츠는 프리렌더된다**는 점이 확인되었으므로, 목록은 바깥에 두고 인터랙션만 안쪽에 두는 분리가 가능하다.
|
||
|
||
**R-8.16 [표기]** `generateStaticParams()`를 사용하는 라우트는 빌드 리포트에서 `○ (Static)`이 아니라 **`● (SSG)`** 로 표기된다. **두 표기 모두 "빌드 타임 정적 프리렌더"이며 요구사항을 충족한다.** 수용 기준의 판정은 §10 AC-17의 개정된 문구를 따른다.
|
||
|
||
### 8.6 레이아웃 컨테이너 아키텍처 · 브레이크포인트 토큰 *(v1.6 신설)*
|
||
|
||
Job `343b5808` 검증에서 본문 좌우 여백·최대 폭 미적용(B1)이, 개발 팀장 이의제기(Job `2560771b`)에서 그 수정 방식의 확장성 제약이 각각 확인되었다. 아래 규칙은 **D-06 확정 사항**이다.
|
||
|
||
**R-8.17 [계층 분리 · 필수]** 레이아웃은 **3계층**으로 분리한다.
|
||
1. `<main>` (`app/layout.tsx`) — **뷰포트 전체 폭을 유지**한다. `max-w-*` / `px-*` / `container-content`를 **부여하지 않는다.**
|
||
2. **라우트 최상위 래퍼** — 각 페이지 파일의 루트 `<div>`에 `container-content`를 부여해 본문 여백(24/40/48/64 px)과 최대 폭(78 rem = 1248 px) 중앙 정렬을 확보한다.
|
||
3. **Full-bleed 밴드** — 전체 폭 배경 밴드·구획선·마퀴 티커는 2계층 래퍼 **바깥**(즉 `<main>` 직속)에 배치한다.
|
||
|
||
**R-8.18 [금지]** Full-bleed 연출을 위해 `container-content` 자식에서 `w-screen` 또는 `-mx-[50vw]` 계열 **탈출 기법을 사용하지 않는다.** 현재 `html`·`body`에 `overflow-x` 가드가 **전무**하므로(실측 확인), 폭 제한 컨테이너 내부의 `w-screen`은 좌측 기준점이 부모 콘텐츠 박스여서 우측으로 넘쳐 **가로 스크롤을 유발하고 R-9.15/AC-19를 위반**한다. Full-bleed가 필요하면 R-8.17의 3계층으로 올린다.
|
||
|
||
**R-8.19 [필수]** 라우트 래퍼 방식은 **신규 라우트 추가 시 누락될 수 있으므로**, 빌드 산출 HTML의 모든 라우트에서 `<main>` 하위에 `container-content`가 존재함을 **자동 게이트로 검증**한다(→ AC-25). 이 게이트 없이는 본 아키텍처를 채택하지 않는다.
|
||
|
||
**R-8.20 [토큰]** 데스크톱 내비 전환 임계값은 `tailwind.config.ts`의 `theme.extend.screens`에 **`desktop: "1240px"` 단일 토큰**으로 등록하고 `desktop:` 변형으로만 사용한다. 임의값 클래스(`min-[1240px]:`)를 소스에 직접 쓰지 않는다.
|
||
- **실측 확인**: Tailwind v3는 `extend`로 추가한 스크린도 **min-width 값 기준으로 정렬**해 출력하므로(`1024 → 1240 → 1280 → 1536` 순서 확인), `2xl` 등 상위 브레이크포인트를 덮어쓰는 캐스케이드 사고는 발생하지 않는다. `screens` 전체를 재정의할 필요가 없다.
|
||
- **주의**: `lg`(1024px)와 `desktop`(1240px)이 공존하므로, **헤더 내 데스크톱/모바일 전환은 `desktop:`으로만 통일**한다. 동일 속성에 `lg:`와 `desktop:`을 혼용하면 1024–1239 px 구간에 의도치 않은 중간 상태가 생긴다(B2가 정확히 이 사고였다).
|
||
|
||
### 8.7 색 토큰 알파 계약 (Color Token Alpha Contract) *(v1.9 신설)*
|
||
|
||
디자인 토큰은 `app/globals.css`의 CSS 커스텀 프로퍼티와 `tailwind.config.ts`의 `theme.extend.colors`가 **한 쌍으로 동작**한다. 이 쌍의 계약이 깨지면 **lint·tsc·빌드가 모두 통과하는 채로 화면만 무너진다** — 실제로 그 사고가 발생했으므로(§12.1 D-09 상세) 계약을 명문화한다.
|
||
|
||
**R-8.21 [필수 · 공백 구분]** `--*-rgb` 커스텀 프로퍼티의 값은 **반드시 공백 구분 3-숫자**로 정의한다(`--ink-rgb: 10 10 10;`). **쉼표 구분(`10, 10, 10`)을 금지한다.**
|
||
- 근거: Tailwind는 `<alpha-value>`를 포함한 색을 `rgb(var(--ink-rgb) / var(--tw-text-opacity, 1))` 형태로 전개한다. 값이 쉼표 구분이면 치환 결과가 `rgb(10, 10, 10 / 1)`이 되는데, 이는 CSS Color 4의 **현대 문법(공백+슬래시)도 레거시 문법(전량 쉼표)도 아니어서 무효**다. 무효 선언은 *invalid at computed-value time* 으로 처리되어 **해당 속성이 통째로 적용되지 않는다.** 빌드는 성공하고 CSS 파일에도 규칙이 남으므로 **어떤 정적 게이트도 이를 잡지 못한다.**
|
||
- `--ink: rgb(var(--ink-rgb));` 형태의 파생 변수는 공백 구분에서도 그대로 유효하므로 함께 유지한다.
|
||
|
||
**R-8.22 [필수 · `<alpha-value>` 보존]** `theme.extend.colors`의 모든 토큰은 **`rgb(var(--*-rgb) / <alpha-value>)` 형태**로 선언한다. `var(--ink)`처럼 알파 자리표시자가 없는 형태로 축약하지 않는다.
|
||
- 근거(실측): 알파 자리표시자가 없으면 Tailwind는 슬래시 수식자 유틸리티를 **오류 없이 조용히 생략**한다. 독립 프로브 결과 — `colors.ivory = "var(--ivory)"`일 때 `bg-ivory/85`·`text-ivory/50`·`border-ivory/15`는 **출력 CSS에 단 한 줄도 생성되지 않았고**, `colors.old = "rgb(var(--ivory-rgb) / <alpha-value>)"`일 때는 `rgb(var(--ivory-rgb) / 0.85)`로 정상 생성되었다.
|
||
- 유틸리티가 생성되지 않으면 배경은 **투명**, 테두리는 Preflight 기본색 **`#e5e7eb`**(팔레트 외 회색), 텍스트는 **부모 색 상속**으로 대체되어 **팔레트를 벗어난 화면**이 된다.
|
||
|
||
**R-8.23 [금지 · 토큰 우회]** 디자인 토큰으로 표현 가능한 색을 컴포넌트의 인라인 `style` 속성이나 리터럴 색값(`#ffffff` 등)으로 우회 지정하지 않는다. 인라인 `style`은 다크 모드 변형(`dark:`)보다 **항상 우선**하므로 **테마 반전이 무력화되고 대비 요구(R-9.6)가 조용히 깨진다.**
|
||
- 활성 내비 배지처럼 대비가 임계에 가까운 요소에는 **`opacity-*` 유틸리티를 사용하지 않는다.** 요소 불투명도는 전경·배경을 함께 합성해 대비를 낮추며, 실측상 `opacity-90`만으로 4.69:1 → 4.05:1(라이트)로 떨어져 AA 미달이 된다.
|
||
|
||
**R-8.24 [필수 · 헤더 가로 예산]** 데스크톱 헤더(브랜드 + 내비 + 토글)의 소요 폭은 **1240 px 뷰포트의 가용 폭 1112 px과 최대 폭 상한(78 rem) 적용 시의 가용 폭 1120 px을 모두 초과하지 않아야 한다.** 헤더에 **좌우 패딩·간격·마진을 추가하는 변경은 예산 재계산을 동반**해야 하며, 예산 초과 시 내비 라벨이 2줄로 접히는 회귀(§8.6 B2)가 재발한다.
|
||
- 실측 기준선(commit `43c75da`): 소요 **1057.6 px** / 가용 1112 px / 여유 **+54.4 px**, 내비 전량 `font-bold` 보정 시 **+22.7 px**.
|
||
- `container-content`의 최대 폭이 78 rem(1248 px)로 **상한**이므로, 1280 px 이상에서도 가용 폭은 **1120 px에서 고정**된다. 즉 **뷰포트를 넓혀도 헤더 넘침은 해소되지 않는다** — 넓은 화면 전용 마진(`xl:mr-16` 등)은 예산을 악화시키기만 한다.
|
||
|
||
**R-8.25 [금지 · 콘텐츠 중복] *(v1.10 신설)*** 서로 다른 두 라우트가 **실질적으로 동일한 `<main>` 콘텐츠**를 정적 HTML로 생성해서는 안 된다.
|
||
- 근거: 검색 엔진은 중복을 벌점 처리하지는 않으나 **어느 URL을 정본으로 삼을지 스스로 선택**하므로, 내부 링크·사이트맵이 가리키는 URL과 색인되는 URL이 어긋날 수 있다. 또한 산출물 크기가 이유 없이 늘고, 한쪽만 수정되는 **표류(drift) 결함**이 구조적으로 가능해진다.
|
||
- 인덱스 라우트는 하위 라우트의 본문을 재사용하는 대신 **고유한 집계·요약 콘텐츠**를 갖는다(→ IA-03).
|
||
- 불가피하게 동일 콘텐츠를 두 URL에 노출해야 한다면 **`metadata.alternates.canonical` 지정을 필수**로 하며, 그 경우에도 R-8.25의 예외임을 §12.1에 결정 항목으로 기록한다.
|
||
- 자동 검증: **AC-41**.
|
||
|
||
**R-8.26 [필수 · 강조색 대비 바닥값] *(v1.11 신설)*** 강조 토큰(`vermillion`·`cobalt`)의 **DEFAULT 변형은 대형 텍스트(≥24 px, 굵게 ≥18.66 px)·도형·테두리·아이콘 전용**이며 **3:1** 이상을 만족한다. **소형 텍스트에는 `-dark` 변형만 사용**하고, `-dark`는 `ivory`·`paper` **양 배경에서 4.5:1 이상**이어야 한다.
|
||
- `paper`(#ECE6D6)가 `ivory`(#F5F1E8)보다 어두워 **항상 더 엄격한 제약**이므로 바닥값 산정은 `paper` 기준으로 한다. 실측 차이는 약 0.3~0.5 이며, `ivory`만 보고 통과 판정하면 `bg-paper` 카드 내부에서 미달한다.
|
||
- **[v1.14 개정 · 판정 격자]** 바닥값 판정은 **{라이트, 다크} × {`ivory`, `paper`} 4개 셀 전부**에서 수행한다. **`paper` 기준 산정 원칙은 다크 테마에도 동일하게 적용된다** — 다크 지면 `paper`(`30 28 26`)도 `ivory`(`18 18 18`)보다 밝아 더 엄격하다. v1.12가 지시한 소형 텍스트 라우팅 `text-cobalt-dark dark:text-cobalt`는 **라이트 절반만 `-dark`로 보내고 다크 절반은 DEFAULT로 되돌려**, `bg-paper` 카드 내부 **8곳이 다크 테마에서 4.37로 미달**한다(→ AC-51). 이는 본 규칙을 **한쪽 테마에만 적용한 계획 오류**이며, v1.11 §6.5의 일관성 결함과 같은 형태다.
|
||
- 실측 근거: `--cobalt: #4A7CE8`은 `ivory` 3.49 / `paper` 3.16으로 **대형 텍스트 기준(3:1)은 충족하나 소형 텍스트 기준은 미달**한다. 반면 `--cobalt-dark: #32549E`는 6.43 / 5.82로 양 기준을 충족하며, `--vermillion-dark: #A8231C`(6.38 / 5.77)와 **동일 등급**이 되어 두 강조색의 `-dark` 슬롯이 대칭을 이룬다.
|
||
- **[v1.12 추가 · 배지·칩 라우팅]** 강조색을 **배경**으로 쓰는 **비인터랙티브 상태 칩**(`text-[0.65rem]` 등급)은 **`bg-{accent}-dark` + `text-ivory`** 를 사용한다. DEFAULT 배경 위에서는 팔레트 내 전경 중 통과 후보가 **0~1개뿐**이라 설계 여유가 없다 — 실측상 `bg-cobalt`(#4A7CE8) 위 4개 후보(`ivory` 3.49 · `white` 3.93 · `ink-soft` 3.94 · `ink` 5.03) 중 통과는 `ink` **1개뿐**이고, `bg-vermillion`(#D9342B) 위 `ivory`는 **4.16으로 미달**한다. `-dark` 배경은 `ivory` 전경만으로 **6.38~6.43(라이트) / 6.57~6.72(다크)** 를 확보한다.
|
||
- **[v1.12 추가 · 짝 칩 등급 일치]** 같은 컴포넌트에서 **짝을 이루는 강조색 칩은 동일 변형 등급**을 사용한다. 한쪽만 `-dark`로 내리면 두 칩의 상대휘도 대비가 **1.19 → 1.54로 악화**된다(실측: `vermillion` L=0.1738 ↔ `cobalt-dark` L=0.0949). 양쪽을 `-dark`로 통일하면 **1.01**로 균형이 잡힌다(`vermillion-dark` L=0.0961 ↔ `cobalt-dark` L=0.0949) — 두 강조색의 `-dark` 변형이 접근성 등급뿐 아니라 **휘도까지 대칭**이기 때문이다.
|
||
- **인터랙티브 내비·토글 요소는 예외**로 DEFAULT 배경 + `text-white dark:text-ivory`(4.69 / 5.01)를 유지한다. 근거는 §12.1 D-10 상세(부류 A/B 구분) 참조.
|
||
- **[v1.13 개정 · `text-white`의 적용 조건]** 위 예외는 **배경이 DEFAULT 변형일 때에 한정**한다. **`-dark` 배경 위 전경은 `ivory` 단독을 정본**으로 하며 `text-white`·`dark:` 변형을 붙이지 않는다 — 실측 `bg-cobalt-dark` 위 `ivory`는 라이트 **5.26** / 다크 **6.57**로 양 테마를 통과하므로 팔레트 외 색이 불필요하다(→ R-8.29). 커밋 `2441f35`가 `Header.tsx:69,129`·`CategoryNav.tsx:22`의 배경을 `bg-vermillion` → `bg-cobalt-dark`로 바꾸면서 **v1.12가 인정했던 `text-white`의 불가피성이 소멸**했다.
|
||
- 자동 검증: **AC-42 · AC-43 · AC-44 · AC-47**.
|
||
|
||
**R-8.27 [필수 · 색값 변경 시 재측정 의무] *(v1.11 신설)*** `--*-rgb` 값을 변경하는 모든 커밋은 **해당 토큰이 참여하는 전 전경/배경 조합의 대비를 재산정**하고 그 표를 커밋 메시지 또는 리뷰 리포트에 첨부한다.
|
||
- `docs/DESIGN.md`의 강조색 교체 안내(커스터마이즈 훅)에 **이 제약을 명문화**한다. 현행 안내는 "강조색 2개와 `-dark` 변형만 교체하면 됩니다"라고 **교체 방법만** 적고 **지켜야 할 대비 제약을 적지 않아**, 안내를 그대로 따른 커밋 `eaddc4f`가 라이트 테마 대비를 9.23 → 3.49로 붕괴시켰다. 문서가 사고의 직접 원인이므로 문서 교정이 재발 방지의 일부다.
|
||
- 색값 변경은 **lint·tsc·빌드·기존 게이트 전량을 통과한 채로** 화면 접근성만 무너뜨린다 — §12.1 D-09 상세의 알파 계약 사고와 **동일한 무성(silent) 실패 유형**이며, 이번이 두 번째 발현이다.
|
||
|
||
**R-8.28 [필수 · 명암 반전 계약] *(v1.11 신설)*** `html.dark`에서 반전되는 모든 토큰은 **라이트 값과 다크 값의 상대휘도가 유의미하게 달라야** 한다 — 두 값 사이의 대비가 **2.0 이상**이어야 한다.
|
||
- 근거(실측): 변경 전 `cobalt`는 라이트 `L=0.0509`(#1B3A8A) ↔ 다크 `L=0.2199`(#4D77FF)로 대비 **3.13**이었으나, `eaddc4f` 이후 라이트 `L=0.2170`(#4A7CE8) ↔ 다크 `L=0.2199`로 대비 **1.01**이 되었다. 즉 **라이트 테마가 다크 테마용 밝기를 그대로 반입**했고, 이것이 R-8.26 미달의 직접 원인이다.
|
||
- 한 토큰만 반전 계약에서 이탈하면 그 시점에는 반대 테마가 우연히 무사할 수 있으나, **반대 테마 값을 조정하는 순간 양 테마가 동시에 무너진다.**
|
||
- **[v1.13 개정 · 검사 범위]** 검사 대상은 **`:root`와 `html.dark` 양쪽에 정의된 전 토큰**이다(현행 10종). 일부 토큰만 검사하는 구현은 본 규칙을 충족하지 않는다 — 현행 게이트는 `cobalt-dark`·`vermillion-dark` **2종만** 검사해 **`--cobalt`의 반전 대비 1.00을 검출하지 못했다**. `--vermillion`(1.25)도 미달이나 최초 커밋 이래의 상태이므로 **D-13**으로 분리한다.
|
||
- 자동 검증: **AC-45**.
|
||
|
||
**R-8.29 [필수 · 반전 토큰 쌍의 `dark:` 불필요 원칙] *(v1.12 신설)*** 전경과 배경이 **모두 반전 토큰**(`--*-rgb`로 정의되어 `html.dark`에서 값이 바뀌는 토큰)이면 **`dark:` 변형 없이 양 테마가 성립해야 한다.** 어떤 조합에 `dark:` 변형이 필요하다면 그것은 **반전하지 않는 색(`white`·리터럴 hex 등)이 섞였다는 신호**이므로, 팔레트 외 색을 제거할 수 있는지 **먼저 검토**한다.
|
||
- 실측 대조: `bg-cobalt-dark text-ivory`는 라이트 **6.43** / 다크 **6.57**로 `dark:` 없이 통과한다. 반면 `bg-cobalt text-ink`는 다크에서 `--ink-rgb`가 `245 241 232`로 반전되어 **3.49로 미달**하므로 `dark:text-ivory`를 수동으로 덧대야 한다 — **반전 계약을 손으로 우회하는 구조**이며 R-8.28의 취지에 역행한다.
|
||
- `white`가 불가피한 경우(`bg-vermillion` 위 `ivory`가 4.16으로 미달하는 인터랙티브 요소)는 **AC-47 화이트리스트**로 상한을 관리한다. 화이트리스트는 상한이지 허가가 아니다 — 신규 사용처는 먼저 `-dark` 배경으로 대체 가능한지 검토한다.
|
||
- **[v1.14 강화 · 강조색 `dark:` 금지]** **강조색(`cobalt`·`vermillion` 및 각 `-dark`)에는 `dark:` 변형을 사용하지 않는다.** 반전 토큰 위에 `dark:`를 덧대는 것은 **반전 계약을 손으로 무력화**하는 행위이며, 실제로 `text-cobalt-dark dark:text-cobalt`는 다크 절반을 DEFAULT로 되돌려 **`bg-paper` 위 4.37**을 만든다. `-dark` 단독은 4개 셀 전부(5.26 / 4.76 / 6.57 / 5.96)를 통과한다.
|
||
- 세 가지 정본 패턴만 사용한다 — ⓐ 대형 텍스트(≥24 px)·도형·테두리·아이콘·SVG: **`text-cobalt` / `bg-cobalt` / `border-cobalt`**(3.12~4.82, 바닥값 3.0), ⓑ 소형 텍스트: **`text-cobalt-dark`**(4.76~6.57, 바닥값 4.5), ⓒ 강조 배경: **`bg-cobalt-dark text-ivory`**(5.26 / 6.57). **세 패턴 모두 `dark:` 변형이 없다.**
|
||
- 현행 위반 **38건**(`dark:text-cobalt` 28 · `dark:bg-cobalt` 6 · `dark:hover:border-cobalt` 2 · `dark:hover:text-cobalt` 1 · `dark:group-hover:text-cobalt` 1) 전량이 제거 대상이다.
|
||
- 자동 검증: **AC-47 · AC-48(C11-9) · AC-51**.
|
||
|
||
**R-8.30 [필수 · 비텍스트 UI 대비 계약] *(v1.13 신설)*** 테두리·포커스 링·아이콘·상태 도형 등 **비텍스트 UI 구성요소**(WCAG 2.1 §1.4.11)는 인접색 대비 **3:1** 이상을 만족한다.
|
||
- **슬래시 알파 수식자를 사용한 색은 배경과 합성한 실효색으로 산정**한다. 알파는 대비를 조용히 갉아먹으며 토큰 값만으로는 판정할 수 없다 — 실측: `focus:ring-cobalt/50`은 `cobalt` 자체가 3.45임에도 `ivory` 위 합성 후 **1.80**(다크 2.07), `hover:border-cobalt/60`은 `paper` 위 **1.95**(다크 2.38)로 **양쪽 다 미달**한다.
|
||
- 이는 §12.1 D-09(알파 계약 붕괴)·§12.1 D-10(반전 계약 이탈)에 이은 **"알파·토큰 조합이 무성으로 대비를 무너뜨리는" 유형의 세 번째 발현**이다. 강조색에 알파 수식자를 붙이는 것은 **원칙적으로 지양**하고, 필요하면 `-dark` 변형을 불투명하게 사용한다.
|
||
- 통과 확인된 사용처(회귀 방어 기준선): `hover:border-cobalt` 3.12 / `hover:border-cobalt-dark` 4.76 / `hover:border-vermillion` 3.77 / `ring-vermillion` 4.16 / 불릿 `bg-cobalt` 3.45 / 히어로 SVG `var(--cobalt)` 3.45 · `var(--vermillion)` 4.16 (전부 `paper` 또는 `ivory` 기준 라이트값).
|
||
- 자동 검증: **AC-48**(Gate 11 · C11-5).
|
||
|
||
**R-8.31 [필수 · 역할 단위 색 통일 계약] *(v1.13 신설)*** **동일한 클래스 시그니처를 갖는 요소는 단일 색 패턴을 사용한다.** 역할은 파일·행이 아니라 시그니처로 식별한다.
|
||
- 판정 대상 시그니처(최소): ⓐ 섹션 장식 괘선 `h-px w-8 bg-*`, ⓑ 섹션 키커 `font-mono text-xs … uppercase tracking-widest … font-bold`, ⓒ 강조 배경 배지·칩의 전경, ⓓ 카드 `hover:border-*`, ⓔ 포커스 인디케이터 `ring-*`.
|
||
- 판정 기준은 **"어떤 색인가"가 아니라 "색 패턴이 하나뿐인가"** 이다. 따라서 색 선택 결정(D-12)이 확정되기 전에도 게이트를 구현·운용할 수 있고, 결정이 바뀌어도 게이트는 수정할 필요가 없다.
|
||
- 실측 위반: ⓐ `bg-cobalt-dark dark:bg-cobalt` 6곳 ↔ `bg-vermillion` 1곳(`DirectionsBlock.tsx:7`), ⓑ `text-cobalt-dark dark:text-cobalt` 11곳 ↔ `text-vermillion` 1곳(`DirectionsBlock.tsx:8`), ⓒ `text-white dark:text-ivory` 6곳 ↔ `text-ivory` 4곳, ⓓ 4종, ⓔ 2종.
|
||
- **같은 데이터가 서로 다른 색으로 렌더되는 것도 위반**이다 — 지도교수 이메일 `sjkoh@knu.ac.kr` 한 값이 `members:54`(5.26) · `DirectionsBlock:43`(4.16) · `Footer:53`(paper 위 hover 3.77)에서 **3색 3대비**로 나타난다.
|
||
- 예외는 **화이트리스트 등재**(R-8.32 형식)로만 허용한다.
|
||
- 자동 검증: **AC-48**(Gate 11 · C11-1~C11-4).
|
||
|
||
**R-8.32 [필수 · 게이트 면제 형식 제한] *(v1.13 신설)*** 자동 게이트의 예외는 **`(파일, 행, 사유)` 3-튜플 등재로만** 허용하며, **라인 부분문자열 면제(`if "…" in line: continue`)를 금지**한다. 등재 항목이 실제 소스에 존재하지 않으면(고아 항목) 게이트는 **실패**해야 한다.
|
||
|
||
**R-8.33 [규정 · 디자인 시스템 적용 범위 및 관리자 콘솔 분리] *(v2.1 신설)*** AC-43, AC-44, AC-45, AC-47, C11-9 등 디자인 토큰 및 명암 대비 품질 게이트는 **공개 사용자용 랜딩 페이지(Public Site) 디자인 시스템의 무결성을 보장하기 위한 규격**이다. 비공개 백오피스 관리자 대시보드(`/console/*`)는 데이터 관리 및 CRUD 폼/테이블 조작성을 위해 독립된 콘솔 UI를 사용하며, 공개 사이트 전용 `text-white` 카운트 상한(AC-47) 및 강조색 수식자 제약에서 명시적으로 제외된다.
|
||
- 자동 검증: **Gate 10 (`/console` 경로 제외)**.
|
||
- 근거(실측): `run_e2e_tests.py`의 AC-44 구현은 면제 조항에 `"text-vermillion" in line`을 두었는데, 위반 판정 정규식이 `text-(cobalt|vermillion)`이므로 **vermillion으로 매치된 라인은 예외 없이 그 문자열을 포함**한다 — 즉 **AC-44의 vermillion 절반이 영구적으로 발화하지 않는다.** 실제 소스 4개 라인(`lectures:50`·`members:114`·`publications:72`·`DirectionsBlock:8`)과 회귀 주입 2건을 동일 로직에 투입해 **전부 면제됨**을 재현했다.
|
||
- 나아가 `"text-3xl"`·`"Pillar #"` 등의 면제도 **라인 전체 부분문자열 검사**라, 삼항식 한 줄에 두 색이 섞이면 **cobalt 검사까지 함께 무력화**된다 — 회귀가 가장 숨기 쉬운 형태가 정확히 그 형태다.
|
||
- 이는 **N6**(Gate 8 C1/C2 공허 단정, 10라운드 미해소)과 **동일 유형**이다. 개별 수정이 아니라 **형식 차원의 금지**로 대응한다.
|
||
- 자동 검증: **AC-48 · AC-49**(F2 · F9).
|
||
|
||
**R-8.33 [필수 · 토큰 등급 불변식] *(v1.14 신설)*** 각 테마에서 **`-dark` 변형은 해당 테마의 지면 배경(`ivory`·`paper`) 대비가 DEFAULT보다 커야** 한다. DEFAULT 토큰의 값을 조정할 때는 **같은 테마의 `-dark` 값과의 관계를 반드시 함께 검토**한다.
|
||
- **절대 휘도 순서가 테마 간에 뒤집히는 것은 정상 동작이며 위반이 아니다.** `-dark`는 "절대적으로 어두운 색"이 아니라 **"지면 대비가 더 깊은 변형"** 이므로, 다크 지면에서 대비를 깊게 하려면 더 밝아진다. 실측: 라이트 `cobalt` L=0.2203 > `cobalt-dark` L=0.1270 이지만 다크에서는 `cobalt` L=0.2199 < `cobalt-dark` L=0.3184이며, vermillion 쌍도 동일하게 뒤집힌다. **판정 기준을 절대 휘도로 두면 정상 상태를 위반으로 오판한다.**
|
||
- 현행 실측(8개 셀 전부 충족): 라이트 `ivory` 3.45→5.26 · 라이트 `paper` 3.12→4.76 · 다크 `ivory` 4.82→6.57 · 다크 `paper` 4.37→5.96 (cobalt), 라이트 `ivory` 4.16→6.38 · 다크 `ivory` 5.01→6.72 (vermillion).
|
||
- 근거: 개발 팀장(Agy) 이의제기(Job `4962a667`)가 **다크 DEFAULT만 단독 상향하면 계층이 무너짐**을 지적했고 실측으로 확인했다 — 다크 DEFAULT를 L≈0.52로 올리면 다크 `paper` 대비가 **9.2**가 되어 `-dark`(5.96)를 역전한다.
|
||
- 자동 검증: **AC-43**(정책 표에 등급 관계를 포함).
|
||
|
||
---
|
||
|
||
## 9. 비기능 요구사항 (Non-Functional Requirements)
|
||
|
||
### 9.1 빌드 품질 게이트 — 병합 필수 조건
|
||
|
||
| ID | 요구사항 | 검증 명령 |
|
||
| :--- | :--- | :--- |
|
||
| NF-01 | ESLint 경고·오류 0건 | `npm run lint` |
|
||
| NF-02 | TypeScript 오류 0건 | `npx tsc --noEmit` |
|
||
| NF-03 *(v1.1 문구 정정)* | 프로덕션 빌드 성공. 전 라우트가 빌드 타임 정적 프리렌더(`○ Static` 또는 `● SSG`)이며 **`ƒ Dynamic` 라우트가 0건**이어야 한다 | `npm run build` |
|
||
| NF-04 | `package.json` ↔ `package-lock.json` 정합. 의존성 추가 시 lockfile 동시 커밋 | `npm install --package-lock-only` 후 diff 확인 |
|
||
|
||
### 9.2 SEO
|
||
|
||
**R-9.1** 전 라우트에 고유한 `metadata.title` / `metadata.description`을 정의한다. 타이틀 템플릿은 현행 `%s | ANL · 경북대학교`를 유지한다.
|
||
**R-9.2** Open Graph(`og:title`, `og:description`, `og:image`, `og:type`, `og:locale=ko_KR`) 및 Twitter Card 메타를 추가한다.
|
||
**R-9.3** 시맨틱 HTML5 요소(`<main>`, `<article>`, `<section>`, `<nav>`, `<address>`, `<time>`)를 사용한다. 논문·특허 날짜는 `<time dateTime>`으로 표기한다.
|
||
**R-9.4** `app/sitemap.ts`와 `app/robots.ts`를 추가한다.
|
||
**R-9.5** 지도교수 및 연구실 정보에 `Person` / `ResearchOrganization` JSON-LD 구조화 데이터를 삽입한다. *(SHOULD)*
|
||
|
||
### 9.3 접근성 (Accessibility)
|
||
|
||
**R-9.6** WCAG 2.1 AA 색 대비를 충족한다. 특히 `ink-mute`(`#6B655B`) on `ivory`(`#F5F1E8`) 조합은 소형 텍스트 사용 시 대비 실측 후 적용한다.
|
||
**R-9.7** 장식용 SVG·요소는 `aria-hidden`, 의미 전달 SVG는 `role="img"` + `aria-label`을 갖는다.
|
||
**R-9.8** `prefers-reduced-motion: reduce`에서 `Reveal`·`Counter`·`Marquee`의 모션이 비활성화되어야 한다(현행 구현 유지).
|
||
**R-9.9** 키보드 내비게이션으로 전 인터랙티브 요소(필터, 확장 토글, 링크)에 도달 가능하고 포커스 링이 보여야 한다.
|
||
**R-9.10** 필터·확장 토글은 `aria-expanded` / `aria-controls`를 갖는다.
|
||
|
||
### 9.4 성능
|
||
|
||
**R-9.11** 초기 렌더 DOM 노드 수를 제한한다. Publications 223건, Alumni 60명, Lectures 약 20학기는 **전량 즉시 렌더 금지**(P-07, M-06, L-03). 단 **PR-01에 따라 전 레코드가 사용자 조작으로 도달 가능**해야 한다.
|
||
**R-9.12** 라우트별 First Load JS는 현행 수준(공유 87.3 kB + 라우트별 1 kB 내외)에서 **+30 kB를 초과하지 않는다.**
|
||
**R-9.13** 신규 런타임 의존성 추가 시 사전 승인을 받는다. 현행 의존성은 `next` / `react` / `react-dom` 3종뿐이며 이 최소 구성을 유지한다.
|
||
|
||
### 9.5 반응형
|
||
|
||
**R-9.14** *(v1.6 개정)* 지원 브레이크포인트는 Tailwind 기본값 `sm`(640px) / `md`(768px) / `lg`(1024px)에 **커스텀 토큰 `desktop`(1240px)** 을 더한 구성이다(R-8.20). 검수 기준 뷰포트는 **360 / 768 / 1024 / 1440 px** 4종에 **1239 px과 1240 px**을 추가한 6종이다 — 데스크톱 내비 전환 경계의 양쪽을 반드시 확인해야 한다.
|
||
**R-9.15** 어느 뷰포트에서도 가로 스크롤이 발생하지 않아야 한다.
|
||
**R-9.16** 긴 국문 제목의 줄바꿈은 `break-keep`을 적용한다.
|
||
|
||
### 9.6 콘텐츠 무결성
|
||
|
||
**R-9.17 [최우선]** 사이트에 게시되는 모든 수치·실적·인물 정보는 `ISL-2026/` 실데이터 또는 `README.md` 정본에서 **출처를 추적할 수 있어야 한다.** 근거 없는 홍보성 지표 게시를 금지한다.
|
||
**R-9.18** 실명·실제 이메일이 게시되는 페이지이므로, 추정 정보를 사실처럼 표기하지 않는다. 불확실한 항목은 노출하지 않는다.
|
||
**R-9.19** 문서(`README.md`, `docs/DESIGN.md`)와 코드의 서술이 어긋나서는 안 된다. 마이그레이션이 미완인 영역은 문서에 **미완임을 명시**한다(문서가 코드보다 앞서 나가지 않는다).
|
||
|
||
---
|
||
|
||
## 10. 수용 기준 (Acceptance Criteria)
|
||
|
||
병합 승인은 아래 전 항목 충족 시에만 이루어진다.
|
||
|
||
**기능 (PR-02·PR-03)**
|
||
- [ ] AC-01 `/` 접근 시 Home이 정상 렌더되고 404가 발생하지 않는다
|
||
- [ ] AC-02 Home에 **연구실 소개 · 주요 연구 분야 · 오시는 길** 3개 블록이 모두 존재한다
|
||
- [ ] AC-03 `/intro` 접근 시 `/`로 308 리다이렉트된다
|
||
- [ ] AC-04 상단 탭 5종(Home/Members/Publications/Lectures/Standardization)이 전부 정상 라우팅된다
|
||
- [ ] AC-05 *(v1.1 개정 · v1.5 수치 갱신)* Publications 3개 카테고리가 각각 고유 URL(`/publications/<slug>`)을 가지며, **해당 URL로 직접 진입했을 때 정적 HTML이 이미 해당 카테고리 상태를 담고 있다**(비필터 상태가 먼저 보였다가 바뀌는 현상이 없어야 한다)
|
||
- [ ] AC-06 Lectures가 학기별 그룹으로 렌더되고 최근 3개 학기가 기본 노출된다
|
||
|
||
**데이터 무손실 (PR-01)**
|
||
- [ ] AC-07 건수 대조 통과: 국제 68 / 국내 80 / 특허 75 / 표준 문서 44 / 재학 16 / 졸업 60 / 강의 45학기
|
||
- [ ] AC-08 Publications 223건 중 **어느 카테고리에도 배정되지 않은 레코드가 0건**이다
|
||
- [ ] AC-09 확장 UI 조작 시 졸업생 60명·전 학기 강의·전 논문이 모두 도달 가능하다
|
||
- [ ] AC-10 한글·특수문자 인코딩 손실 0건, BOM 제거 확인
|
||
- [ ] AC-11 날짜 전 항목 ISO 8601 정규화 확인
|
||
- [ ] AC-12 **연구실 정체성 서술 영역**에서 금지어 0건 (`사물인터넷 표준`, `IoT Standards`, `MCM`, `메타버스 상호운용성`, `placeholder`) — 논문·표준 제목의 도메인 용어는 예외(MG-08)
|
||
- [ ] AC-13 전 카운터 수치가 데이터 배열에서 도출됨을 코드로 확인
|
||
- [ ] AC-14 *(v1.1 신설)* JS를 비활성화한 상태에서 `/publications/<slug>` 문서에 해당 카테고리 레코드가 **전부 포함**되어 있다 (R-8.15 · PR-01)
|
||
|
||
**품질 게이트**
|
||
- [ ] AC-15 `npm run lint` 통과 (경고 0)
|
||
- [ ] AC-16 `npx tsc --noEmit` 통과
|
||
- [ ] AC-17 *(v2.0 개정)* `npm run build` 성공. 빌드 리포트에 **정확히 6개 데이터 라우트가 `ƒ (Dynamic)`**(`force-dynamic`)이고 **4개 프레임워크/메타데이터 라우트가 `○ (Static)`**으로 분리되어 생성됨을 확인한다 (§7.1 DM-03)
|
||
- [ ] AC-18 First Load JS 증가분 ≤ 30 kB
|
||
- [ ] AC-19 4종 뷰포트에서 가로 스크롤 없음
|
||
- [ ] AC-20 신규 Tailwind 반응형 유틸리티가 빌드 CSS에 실제 생성됨을 확인 (JIT 누락 시 빌드는 성공하나 조판이 무너짐)
|
||
- [ ] AC-21 *(v1.1 신설)* `generateStaticParams()`로 카테고리별 정적 HTML 3개가 실제 생성됨을 `.next/server/app/publications/` 파일 목록으로 확인
|
||
- [ ] AC-22 *(v1.1 신설)* 소스 전역에 `searchParams` prop 사용·`useSearchParams()` 호출·라우팅 목적 `pushState` 호출이 **0건**임을 grep으로 확인 (§8.5 R-8.11·8.12·8.14)
|
||
|
||
**문서**
|
||
- [ ] AC-23 `README.md`·`docs/DESIGN.md` 서술이 구현 결과와 일치
|
||
- [ ] AC-24 마이그레이션 스크립트가 `scripts/`에 커밋됨
|
||
- [ ] AC-25 *(v1.6 신설 · R-8.19)* 빌드 산출 `.next/server/app/**/*.html`의 **모든 라우트**에서 `<main>` 하위에 `container-content`가 존재함을 자동 게이트로 확인. `<main>`에는 `max-w-*`/`px-*`가 **부여되지 않았음**을 함께 확인 (R-8.17)
|
||
- [ ] AC-26 *(v1.6 신설 · R-8.18·R-8.20)* 소스 전역에 `w-screen`·`-mx-[50vw]` 계열 탈출 기법과 임의값 클래스 `min-[1240px]:` 사용이 **0건**임을 grep으로 확인
|
||
|
||
**Research Project PageView (v1.7 신설 · §6.1.2)**
|
||
- [ ] AC-27 *(PJ-08 · R-8.15)* `content/projects.ts` **전건**의 `title`·`abstract`가 `.next/server/app/index.html` **정적 HTML에 존재**함을 확인
|
||
- [ ] AC-28 *(PJ-09)* Home 라우트가 여전히 `○ (Static)`이며 빌드 전체에 `ƒ (Dynamic)`이 **0건**
|
||
- [ ] AC-29 *(PJ-03 · PR-01)* 각 `abstract`가 레거시 원문과 **바이트 동일**함을 파서 재실행으로 확인
|
||
- [ ] AC-30 *(PJ-06)* 모든 `keywords[]` 원소가 해당 `abstract`의 **부분문자열**임을 `verify_counts.py`로 확인 (창작 차단)
|
||
- [ ] AC-31 *(PJ-07 · R-9.18)* `funder`가 `undefined`인 프로젝트에 대해 산출 HTML에 `Funder` 라벨·자리표시자가 **렌더되지 않음**을 확인
|
||
- [ ] AC-32 *(PJ-05)* 모든 `deliverables[].ref`가 `content/standards.ts`에 실재하는 문서 참조와 일치함을 조인 검증
|
||
- [ ] AC-33 *(H-02 개정 · AC-02 회귀 방어)* 히어로 재구성 후에도 **연구실 소개 서술 블록 · 주요 연구 분야 그리드 · 오시는 길 · 지표 카운터 3종 · `HeroComposition`** 이 Home 정적 HTML에 **전부 존속**함을 확인
|
||
- [ ] AC-34 *(v1.8 신설 · PJ-13·PJ-15·PJ-16)* 프로젝트 트랙의 넘침을 **브라우저 실측 수치로 판정**한다 — 데스크톱(≥1240 px)에서 `track.scrollWidth === track.clientWidth`(스크롤 잔재 **0**), 모바일·태블릿에서는 `scrollWidth > clientWidth`가 **정상 동작**이다. 어느 뷰포트에서도 **문서 레벨** 가로 스크롤은 0이어야 한다(AC-19 · R-9.15). 데스크톱 3카드 폭의 서브픽셀 거동은 브라우저 없이는 확정할 수 없으므로 **이 단정으로 판정을 이관**한다
|
||
- [ ] AC-35 *(v1.9 신설 · R-8.21·R-8.22)* **슬래시 수식자 실효성 게이트** — 소스(`app/**`·`components/**`의 `.tsx`·`.css`)에서 `토큰/불투명도` 형태로 사용된 **모든 색 유틸리티**를 추출하고, 각각에 대응하는 규칙이 **산출 CSS(`.next/static/css/*.css`)에 실제로 존재**함을 자동 게이트로 확인한다. 1건이라도 누락되면 실패한다. *(현행 실측: 사용 26건 / 생성 0건)*
|
||
- [ ] AC-36 *(v1.9 신설 · R-8.21)* `app/globals.css`의 모든 `--*-rgb` 정의가 **공백 구분**임을 grep 게이트로 확인한다(쉼표 포함 시 실패). 아울러 산출 CSS에 `rgb(<쉼표 목록> / …)` 패턴이 **0건**임을 확인한다
|
||
- [ ] AC-37 *(v1.9 신설 · R-8.23 · R-9.6)* `components/Header.tsx`에 **인라인 `style` 속성과 리터럴 색값이 0건**이며, 활성 배지 계열 요소에 **`opacity-*` 유틸리티가 0건**임을 grep으로 확인한다
|
||
- [ ] AC-38 *(v1.9 신설 · R-9.6)* 활성 내비 배지의 **전 텍스트 상태(데스크톱 라벨·번호 / 모바일 `ko`·`en`·번호)** 가 **라이트·다크 양 테마에서 4.5:1 이상**임을 실측 색값으로 계산해 확인한다. 다크 모드 배경은 `--vermillion-rgb: 235 75 66`으로 **반전**되므로 흰색 전경은 3.74:1로 미달한다 — 다크 모드 전경은 `ivory`(반전 시 `18 18 18`, 실측 5.01:1)를 사용한다
|
||
- [ ] AC-39 *(v1.9 신설 · R-8.24 · AC-19)* 헤더 가로 예산을 **1240 / 1280 / 1440 px** 에서 확인한다 — `header.scrollWidth <= header.clientWidth`이고 내비 항목이 **2줄로 접히지 않아야** 한다(브라우저 실측 판정)
|
||
- [ ] AC-40 *(v1.9 신설 · IA-03 · AC-25)* 사이트맵에 등재된 **모든 URL**의 산출 HTML이 `redirect()` 전용이 아니라 **`<main>` + `container-content` 를 포함한 실체 문서**임을 확인한다
|
||
- [ ] AC-41 *(v1.10 신설 · R-8.25)* 산출 정적 HTML 전 라우트의 **`<main>` 내부 콘텐츠를 정규화 해시**해 **동일 해시가 2건 이상 존재하지 않음**을 자동 게이트로 확인한다. `canonical`이 명시된 예외 쌍만 화이트리스트로 허용한다
|
||
- [ ] AC-42 *(v1.10 신설 · v1.11 개정 · R-9.6 · AC-38 확장)* **vermillion 배경 위 텍스트 전량**이 라이트·다크 양 테마에서 4.5:1 이상임을 확인한다. **"전량"은 Header·`CategoryNav`에 한정되지 않으며, `group-open:`·`hover:` 등 상태 변형으로 적용되는 배경도 포함한다.** 검증 대상은 **두 부류로 나누어 각각의 기대 패턴과 기대 대비를 판정**한다*(v1.12 개정)*.
|
||
- **부류 A — `text-[0.65rem]` 비인터랙티브 상태 칩**: `app/standardization/page.tsx:40`·`:88` → **`bg-vermillion-dark text-ivory`**(라이트 **6.38** / 다크 **6.72**, `dark:` 변형 없음). R-8.26 배지·칩 라우팅 조항 적용
|
||
- **부류 B — 인터랙티브 내비·토글**: `components/Header.tsx:69,129`, `CategoryNav.tsx:22`, `app/lectures/page.tsx:89`, `app/members/page.tsx:177` → **`text-white dark:text-ivory`**(라이트 **4.69** / 다크 **5.01**)
|
||
- **[v1.13 개정 · 부류 B 재산정]** ⓐ `Header.tsx:69,129`·`CategoryNav.tsx:22`는 `2441f35`에서 **배경이 `bg-vermillion` → `bg-cobalt-dark`로 바뀌어** `text-white`의 불가피성이 소멸했다 — R-8.26 v1.13 조항에 따라 **`text-ivory` 단독**(라이트 5.26 / 다크 6.57)으로 정정한다. ⓑ **`app/lectures/page.tsx:89`는 여전히 `group-open:text-ivory`(4.16)로 미교정**이며, 동일 관용구인 `members/page.tsx:177`만 교정되어 **한 쌍이 갈라져 있다**. ⓒ **`app/not-found.tsx:22`를 신규 등재** — `text-ivory hover:bg-vermillion`으로 hover 시 **4.16**이며 v1.12까지의 어떤 목록에도 없었다. 권고 조치는 `hover:bg-vermillion-dark`(→ 6.38)로, `white` 없이 해소된다
|
||
- *v1.10 기재 정정*: `text-white` on `#D9342B`의 실측은 **4.69:1**이다(직전 수렴 리포트의 4.58:1은 오기 — 판정은 동일하게 통과)
|
||
- *현행 미교정 4곳의 실측은 모두 **4.16:1***이며, `lectures:89`·`members:177`은 `group-open:` 상태 변형으로 배경이 적용되어 **육안 리뷰에서 누락되기 쉽다**
|
||
- [ ] AC-43 *(v1.11 신설 · v1.12·v1.13 개정 · R-8.26·R-8.27·R-9.6)* **대비 자동 게이트(Gate 10)** — `app/globals.css`의 `:root`·`html.dark` `--*-rgb` 정의를 파싱해 **양 테마 전 조합의 대비를 계산**하고 정책 표의 바닥값 미만이면 실패한다. 최소 대상: `{ink, ink-soft, ink-mute, vermillion, vermillion-dark, cobalt, cobalt-dark} × {ivory, paper}` 및 `{ink, ivory, white} × {vermillion, vermillion-dark, cobalt, cobalt-dark}`. **`-dark` 변형이 배경으로 쓰이는 경우**(`{ivory, white} × {cobalt-dark, vermillion-dark}`, 양 테마)를 반드시 포함한다 — v1.11 목록은 `-dark`를 전경으로만 다루어 **상태 칩 배경을 검사하지 못했다***(v1.12 개정)*. 정책 표는 스크립트 상단 상수 블록에 두어 규격 변경 시 1곳만 수정되게 한다. *(현행 실측: `cobalt`는 `ivory` 3.49 / `paper` 3.16, `cobalt-dark`는 `paper` 4.48로 **실패해야 한다**)*
|
||
- **[v1.13 개정 · C10-1]** 현행 구현은 ⓐ 정책 값이 **함수 본문에 흩어져 있어** 상수 블록 요건을 충족하지 않고, ⓑ **토큰 값만 검사하고 소스의 전경/배경 쌍은 보지 않는다** — 따라서 `bg-cobalt-dark text-white`(다크 **2.85**)를 작성해도 통과한다. 검사 대상에 **소스에서 실제로 함께 쓰인 전경/배경 조합**을 추가하고, `text-white`가 전경인 조합을 **양 테마 모두** 계산한다
|
||
- **[v1.14 개정]** ⓐ **DEFAULT 토큰 × {`ivory`,`paper`} × {라이트,다크}** 를 **3:1 바닥값**으로 명시 추가한다 — 이 검사가 **D-14 A안의 안전망 본체**이며, 브랜드 색이 어느 테마에서든 역할 바닥값 아래로 내려가면 즉시 실패해야 한다. ⓑ **R-8.33 등급 관계**(각 테마 지면 대비에서 `-dark` > DEFAULT)를 정책 표에 포함한다
|
||
- [ ] AC-44 *(v1.11 신설 · v1.13 개정 · R-8.26·R-8.32)* **소형 텍스트 라우팅 게이트** — `app/**`·`components/**`에서 `text-cobalt`·`text-vermillion`(DEFAULT 변형)이 **소형 텍스트 크기 클래스와 동일 요소에 공존하지 않음**을 확인한다. 부모로부터 크기를 상속받아 정적 판정이 불가능한 케이스는 **화이트리스트에 사유와 함께 등재**한다. *(현행 실측: `text-cobalt` 소형 텍스트 사용처 **12건** + `bg-cobalt` 소형 배지 **2건** 미달)*
|
||
- **[v1.13 개정 · C10-2]** 현행 구현의 **라인 부분문자열 면제 4종(`"text-vermillion"`·`"text-3xl"`·`"Pillar #"`·`"w-1.5 h-1.5"`)을 전량 제거**하고 R-8.32의 `(파일, 행, 사유)` 화이트리스트로 대체한다. 첫 번째 면제 때문에 **AC-44의 vermillion 절반이 구조적으로 발화하지 않음**을 재현 확인했다(→ R-8.32). 제거 후 `text-vermillion` **23건** 중 소형 텍스트 사용처가 검출되어야 하며, 최저값은 `bg-paper` 카드 내부의 `members/page.tsx:114,144` **3.77**이다
|
||
- **[v1.14 개정 · G-7]** 판정 정규식의 **부정 후방탐색 `(?<!dark:)` 를 제거**한다. 현행 구현은 이 후방탐색으로 **`dark:text-cobalt`·`dark:text-vermillion`을 설계상 검사 대상에서 제외**하고 있어, 소형 텍스트 라우팅을 **라이트 테마에 대해서만** 검사한다. 그 결과 다크 테마 `bg-paper` 위 **8곳(4.37)이 검사 범위 밖**이었다(→ AC-51). G-1(부분문자열 면제)·G-2(반전 검사 2종 한정)·G-3(전경/배경 쌍 미검사)에 이은 **네 번째 범위 결함이며, 넷 모두 "검사를 절반만 한다"는 같은 형태**다
|
||
- [ ] AC-45 *(v1.11 신설 · v1.13 개정 · R-8.28)* **반전 계약 게이트** — `:root`와 `html.dark`의 동일 토큰 쌍에 대해 라이트↔다크 상대휘도 대비가 **2.0 이상**임을 확인한다. *(현행 실측: `cobalt`는 **1.01**로 실패해야 한다)*
|
||
- **[v1.13 개정 · C10-3]** 검사 범위를 **양쪽에 정의된 전 토큰(현행 10종)** 으로 확대한다. 현행 구현은 `cobalt-dark`·`vermillion-dark` **2종만** 검사해 **`--cobalt`의 반전 대비 1.00(라이트 `78 119 255` ↔ 다크 `77 119 255`)을 검출하지 못했다** — v1.11이 D-10의 근본 원인으로 규명한 바로 그 실패 유형의 재발이며, **게이트가 통과했다는 사실 자체가 오탐 신호였다**. 확대 시 `--vermillion`(1.25)도 검출되므로 **D-13 확정 전까지는 화이트리스트에 사유와 함께 등재**한다
|
||
- **[v1.14 · 브랜드 고정 토큰 예외 후보]** `--cobalt`(1.00)·`--vermillion`(1.25)은 **사용자 지정 브랜드 색**이며, R-8.29 정리(강조색 `dark:` 변형 38건 제거) 후에는 **어느 테마에서도 소형 텍스트를 담지 않는다**. 남는 사용처는 전부 대형 텍스트·도형·테두리·아이콘이며 **양 테마에서 3:1을 충족**한다(최저 3.12). 이 상태에서 R-8.28을 관철하려면 다크 값을 파스텔로 올려야 하는데, 그러면 **브랜드 색이 다크 테마에서 사라진다**. 처리 방침은 **D-14**로 이관한다 — R-8.28은 *수단*이고 **R-8.26·R-8.30(테마별 대비)이 *목적*** 이므로, 목적 규칙이 **양 테마에서 실효적으로 검사되면**(→ AC-43 개정) 안전망은 유지된다. 검증: 브랜드 색을 `#1B3A8A`로 되돌리고 테마 불변을 유지하면 다크 지면 대비가 **1.80**으로 떨어져 **AC-43이 즉시 실패**한다
|
||
- [ ] AC-46 *(v1.11 신설 · AC-43·AC-44·AC-45 유효성)* **폴트 인젝션으로 Gate 10의 실효성을 증명**한다 — ① `--cobalt-dark-rgb`를 `52 98 204`로 되돌리면 AC-43 실패, ② 소형 텍스트를 `text-cobalt`(DEFAULT)로 되돌리면 AC-44 실패, ③ `html.dark`의 `--cobalt-rgb`를 라이트 값과 동일하게 두면 AC-45 실패, ④ `standardization/page.tsx:40`을 `bg-vermillion text-ivory`로 되돌리면 AC-42 실패, **⑤ 상태 칩을 `bg-cobalt text-ivory`(v1.11 §6.5 폐기안)로 되돌리면 AC-43 실패(3.49)**, **⑥ 임의 위치에 `text-white`를 1건 추가하면 AC-47 실패(9 > 8)** *(⑤·⑥은 v1.12 신설)*. **6건 모두 실패를 재현하지 못하면 Gate 10을 채택하지 않는다** — 통과만으로는 게이트가 결함을 검출한다는 증명이 되지 않는다
|
||
- ⑤는 **기각·교체된 설계를 게이트가 실제로 잡는지** 확인한다. v1.10에서 기각한 D-09 C안을 주입해 AC-41을 검증한 것과 같은 방식이며, **교체된 설계는 반드시 게이트의 검출 대상이 되어야 한다**
|
||
- [ ] AC-47 *(v1.12 신설 · v1.13 개정 · R-8.29)* **팔레트 외 색 상한 게이트** — `app/**`·`components/**`에서 `text-white`·`bg-white` 등 **팔레트 외 색 유틸리티의 출현 횟수가 화이트리스트 등재 건수를 초과하지 않음**을 확인한다.
|
||
- 화이트리스트(부류 B 한정, 총 **8건**): `components/Header.tsx:69,75,129,136,145`(5) · `CategoryNav.tsx:22`(1) · `lectures/page.tsx:89`(1) · `members/page.tsx:177`(1)
|
||
- 각 항목에 **사유**(해당 위치에서 `ivory` 전경이 4.16으로 미달)를 함께 기재한다. 화이트리스트는 **상한이지 허가가 아니며**, 신규 사용처는 `-dark` 배경으로 대체 가능한지 먼저 검토한 뒤에만 등재한다
|
||
- 근거: `docs/DESIGN.md`는 "토큰만 사용 — 임의 회색·팔레트 밖 hex 금지"를 규정한다. `white`는 Issue 01 팔레트(`ink`/`ivory`/`paper`/`line`/`vermillion`/`cobalt`) 밖의 색으로, `02247a0`에서 **불가피성 때문에** 도입되었다. 상한을 두지 않으면 그 불가피성이 관행으로 굳는다
|
||
- **[v1.13 개정 · C10-4]** 현행 구현은 `content.count("text-white")` **단순 계수**라 **위치를 검증하지 않는다.** 화이트리스트를 `(파일, 행)` 집합으로 두고 **실제 출현 위치 집합과 완전히 일치**할 때만 통과시킨다(초과·고아 양방향 검출, R-8.32). 배경 변경(`bg-vermillion` → `bg-cobalt-dark`)으로 **현행 7건 중 6건이 R-8.29상 제거 대상**이 되었으므로, Phase 3 완료 후 화이트리스트는 **`lectures/page.tsx:89`·`members/page.tsx:177` 2건**으로 축소되어야 한다 — 이 2곳만이 DEFAULT `bg-vermillion` 위(ivory 4.16 미달)에 있다
|
||
|
||
**색 통일성 (v1.13 신설)**
|
||
- [ ] AC-48 *(v1.13 신설 · R-8.30·R-8.31·R-8.32)* **색 통일성 게이트(Gate 11)** — 아래 8개 검사를 자동화한다. C11-1~C11-4는 R-8.31, C11-5는 R-8.30, C11-7은 AC-23 회귀 방어에 대응한다.
|
||
- **C11-1 괘선 통일** — `h-px w-8 bg-*` 시그니처의 색 클래스가 **2종 이상이면 실패** *(현행: `bg-cobalt-dark dark:bg-cobalt` 6곳 ↔ `bg-vermillion` 1곳 → **실패해야 한다**)*
|
||
- **C11-2 키커 통일** — `font-mono text-xs … uppercase tracking-widest … font-bold` 시그니처의 색 클래스가 2종 이상이면 실패 *(현행 11곳 ↔ 1곳 → **실패해야 한다**)*
|
||
- **C11-3 강조 배경 전경 통일** — `bg-{accent}-dark` 요소에 `text-white`가 결합되어 있으면 실패(R-8.29) *(현행 6건 → **실패해야 한다**)*
|
||
- **C11-4 상태 배경 전경 쌍** — `group-open:bg-*`·`hover:bg-*`로 배경이 바뀌는 요소의 대응 상태 전경과의 대비가 4.5 미만이면 실패 *(현행 `lectures:89` 4.16 · `not-found:22` 4.16 → **실패해야 한다**)*
|
||
- **C11-5 비텍스트 UI 3:1** — `border-{accent}*`·`ring-{accent}*`·도형 `bg-{accent}*`·SVG의 `var(--*)` 참조를 수집하고, **슬래시 알파는 배경과 합성한 뒤** 계산해 3.0 미만이면 실패 *(현행 `focus:ring-cobalt/50` **1.80** · `hover:border-cobalt/60` **1.95** → **실패해야 한다**)*
|
||
- **C11-6 전역 CSS 조합** — `globals.css`의 `background`/`color` 쌍(`::selection` 등)을 파싱해 4.5 미만이면 실패 *(현행 `::selection`은 `ivory` on `vermillion` **4.16** → **실패해야 한다**)*
|
||
- **C11-7 문서 동기화** — `docs/DESIGN.md` §3 색상표의 hex ↔ `globals.css`의 `--*-rgb` 대조, 불일치 시 실패 *(현행 일치 — 회귀 방어용)*
|
||
- **C11-8 시맨틱 페어링** — R-8.5의 `vermillion = Orchestration` 대응을 히어로 강조 요소에 대해 확인. **D-12 확정 이후에만 활성화**한다
|
||
- **C11-9 `dark:` 변형 제로** *(v1.14 신설 · R-8.29)* — `app/**`·`components/**`에 **`dark:` + 강조색**(`cobalt`·`vermillion` 및 각 `-dark`) 조합이 **1건이라도 있으면 실패**. 예외는 R-8.32 화이트리스트 등재로만 허용한다(부류 B의 `dark:text-ivory` 등) *(현행 `dark:*-cobalt` **38건** → **실패해야 한다**)*
|
||
- [ ] AC-49 *(v1.13 신설 · AC-48 유효성)* **Gate 10·11 폴트 인젝션** — ① F1 `DirectionsBlock:8` 현행 유지 → C11-2 실패, ② F2 `lectures:50`의 `text-xs text-vermillion` 현행 유지 → AC-44 실패(**면제 제거 확인**), ③ F3 다크 `--cobalt-rgb`를 라이트와 동일하게 유지 → AC-45 실패(1.00), ④ F4 `Header:69`에서 `dark:text-ivory` 제거 → AC-43 또는 C11-3 실패(다크 2.85), ⑤ F5 `standardization:89`를 `bg-cobalt text-ivory`로 되돌림 → AC-43 실패(3.45), ⑥ F6 화이트리스트 밖 위치에 `text-white` 1건 추가 → AC-47 실패(**위치 불일치** — 단순 계수로는 통과했을 사례), ⑦ F7 `focus:ring-cobalt/50` 현행 유지 → C11-5 실패(1.80), ⑧ F8 `docs/DESIGN.md` 색상표 hex 1글자 변경 → C11-7 실패, ⑨ F9 실존하지 않는 `(파일, 행)`을 화이트리스트에 등재 → 고아 항목으로 실패, **⑩ F10 `members/page.tsx:108`을 `text-cobalt-dark dark:text-cobalt`로 되돌리면 AC-44 실패(다크 4.37) — 후방탐색 `(?<!dark:)` 제거 확인**, **⑪ F11 `dark:bg-cobalt` 1건을 되살리면 C11-9 실패** *(⑩·⑪은 v1.14 신설)*.
|
||
- **11건 전부 실패를 재현하지 못하면 Gate 11을 채택하지 않는다.** F1·F2·F3·F7·**F10·F11**은 **현행 코드 자체가 주입 상태**이므로 게이트 구현 직후 실행만으로 즉시 검증된다
|
||
- [ ] AC-50 *(v1.13 신설 · R-8.27 · AC-23)* **`docs/DESIGN.md` 동기화** — 아래 4건을 교정하고 구현과 일치시킨다.
|
||
- **§10 커스터마이즈 훅(302~308행)에 대비 제약을 명문화**한다. 현행 안내는 교체 **방법**만 적고 지켜야 할 제약을 적지 않아 `eaddc4f` 사고의 직접 원인으로 규명되었는데, **v1.11에서 지적된 뒤에도 미교정 상태로 남아 같은 유형의 무기록 색 교체가 4회 더 발생**했다
|
||
- **§8-1(282행)** 이 Header 활성 배지를 `bg-vermillion text-white dark:text-ivory`로 기술하나 실제는 `bg-cobalt-dark` — 갱신한다
|
||
- **§9(292행)** "강조색 위 텍스트는 항상 `ivory`" ↔ 실제 `text-white` 7건 — R-8.26 v1.13 조항(`-dark` 배경은 `ivory` 단독 / DEFAULT 배경만 `white` 예외)으로 서술을 정합화한다
|
||
- **§2(30행)** 시맨틱 페어링 ↔ 히어로 `Orchestration` 색 변경 — **D-12 확정 방향에 맞춰** 코드 또는 문서 중 한쪽을 교정한다
|
||
- [ ] AC-51 *(v1.14 신설 · R-8.26·R-8.29)* **다크 테마 소형 텍스트 해소** — `dark:text-cobalt`가 `bg-paper` 위 소형 텍스트에 적용되어 다크 테마에서 **4.37**로 미달하는 아래 **8곳**이 `text-cobalt-dark` 단독(다크 **5.96**)으로 교정되었음을 개별 확인한다.
|
||
- `app/page.tsx:148`(Pillar 번호, `text-sm`, `bg-paper` @`:142`) · `app/page.tsx:187`(`Pillar #`, `text-xs` @`:183`)
|
||
- `app/members/page.tsx:108`(Ph.D. 학위, `bg-paper` @`:102`) · `app/members/page.tsx:138`(M.S. 학위, `bg-paper` @`:132`)
|
||
- `app/_components/ProjectPageView.tsx:88`·`:93`(Standards Track / Organization, `text-xs` @`:80`, `bg-paper` @`:44`)
|
||
- `app/standardization/page.tsx:36`(`[{scope}]`, `bg-paper` @`:32`) · `app/publications/[category]/page.tsx:124`(등록번호, `text-xs` @`:118`, `bg-paper` @`:103`)
|
||
- `bg-ivory` 위 사용처(`ProjectPageView:53` · `members:54,63,202` · `standardization:64` · `DirectionsBlock:51` · 섹션 키커 전량)는 **4.82로 통과하되 여유가 0.32뿐**이므로 함께 `-dark` 단독으로 정리한다(→ R-8.29 · C11-9)
|
||
|
||
---
|
||
|
||
## 11. 구현 계획 (Implementation Plan)
|
||
|
||
### 11.1 단계별 작업 분해
|
||
|
||
| Phase | 작업 | 산출물 | 담당 | 선행 조건 |
|
||
| :-- | :--- | :--- | :--- | :--- |
|
||
| **P0** | D-01(Publications 카테고리 1·2 중첩) 확정 | 결정 기록 | GM ← 지도교수 | ✅ 완료 (v1.5 · `51aae14`) |
|
||
| **P1** | 레거시 데이터 추출 스크립트 작성 및 `content/*.ts` 생성 | 4개 데이터 모듈 + 추출 스크립트 | Agy | P0 |
|
||
| **P1-R** | 건수·인코딩·날짜 정규화 교차 검증 (AC-07~11) | 검증 리포트 | Claude | P1 |
|
||
| **P2** | Home 신설(소개·연구 분야·오시는 길) + `/intro` 리다이렉트 + Header 내비 갱신 | `app/page.tsx`, `next.config.js` | Agy | P1-R |
|
||
| **P3** | Members / Lectures 실데이터 반영 | 2개 라우트 | Agy | P1-R |
|
||
| **P4** | Publications — `/publications` + `[category]` 세그먼트 4종 (§8.5 렌더링 제약 준수, 대량 데이터 처리 포함) | 1개 라우트 + 4개 세그먼트 | Agy | P1-R |
|
||
| **P5** | Standardization 3단 계층 뷰 | 1개 라우트 | Agy | P1-R |
|
||
| **P6** | 자산 이관·최적화 (MG-06·07) | `public/` | Agy | P2~P5 |
|
||
| **P7** | SEO·접근성·반응형 검수 (§9.2·9.3·9.5) | 검수 리포트 | Cline | P6 |
|
||
| **P8** | 최종 교차 리뷰 및 Verdict | 리뷰 리포트 | Claude | P7 |
|
||
|
||
**병렬 가능**: P3 / P4 / P5는 P1-R 완료 후 상호 독립이므로 동시 진행 가능하다. **P2는 `Header.tsx`를 수정하므로 P3~P5와 파일 충돌 가능성이 있어 먼저 완료할 것을 권장한다.**
|
||
|
||
### 11.2 잡 분할 권고
|
||
|
||
Publications(P4)는 데이터 규모(223건)와 필터·점진적 노출 요구로 인해 타 라우트 대비 작업량이 크다. **P4를 단독 잡으로 분리**하고 P3·P5를 묶는 편이 리뷰 단위로 적절하다.
|
||
|
||
### 11.3 리뷰 프로토콜
|
||
|
||
`.agents/MULTI_AGENT_RULES.md` §3에 따라 Phase 완료 시마다 리뷰 사이클을 돌린다. 리뷰어는 `NOT PASS` 시 **사유와 검증된 개선 방향을 반드시 함께** 제시하고, 개발 팀장은 부당하다고 판단하는 지적에 대해 근거를 갖춰 반박한다.
|
||
|
||
---
|
||
|
||
## 12. 리스크 및 미결 결정 (Risks & Open Decisions)
|
||
|
||
### 12.1 미결 결정 등록부
|
||
|
||
| ID | 결정 사항 | 상태 | 기본값(잠정) | 영향 |
|
||
| :--- | :--- | :--- | :--- | :--- |
|
||
| **D-01** | Publications 카테고리 1(`International Conference`)과 2(`International Journal & Conference`)의 **범위 중첩** 해소 | ✅ **확정** (v1.5, 2026-07-30) | — | **결정: 1번 단독 카테고리 폐기 → 3개 카테고리 확정.** A안(저널/학술대회 분리)은 학술대회가 1건에 불과해 기각, B안(미수록 논문 확보)은 신규 데이터 유입 없이 실행 불가하여 기각. 레지스트리 1곳(`content/categories.ts`) + `PubCategory` 유니온 수정으로 완결되었고 **223건 무손실**을 유지했다(P-03). 근거: `intl-conf` 배정 레코드 실측 0건 |
|
||
| **D-02** | 강의 과목명 한글 병기 여부 | 🟡 미결 | 영문 원문만 노출 (L-05) | Lectures 표기. 병기 시 지도교수 확인 필요 |
|
||
| **D-03** | 오시는 길의 지도 표현 방식 | 🟡 미결 | 주소 텍스트 + 캠퍼스 링크 (지도 임베드 없음) | H-16. 외부 지도 스크립트는 R-9.13 최소 의존성 원칙과 충돌 |
|
||
| **D-04** | 졸업생 기본 노출 범위(N년) | 🟢 위임 | 최근 3년 | M-06. 구현자 재량 |
|
||
| **D-05** | 연구실 GitHub 조직명(`github.com/iot-standards-laboratory`) 개명 여부 | 🟡 미결 | 현행 URL 유지 | 조직명이 구 정체성. 개명 시 기존 링크 무효화 위험 |
|
||
| **D-06** | 본문 여백·최대 폭 컨테이너를 **어느 계층에 부여**할 것인가 | ✅ **확정** (v1.6, 2026-07-30) | — | **결정: `<main>` 일괄 부여안 기각 → 라우트 래퍼 방식 + 자동 게이트 채택.** Planner 초안(`<main>`에 `container-content`)은 1행 수정·누락 불가라는 장점이 있으나, 개발 팀장 이의제기(Job `2560771b`)대로 **full-bleed 밴드·마퀴 티커를 구조적으로 차단**한다. 래퍼 방식의 유일한 약점(신규 라우트 누락)은 **AC-25 게이트로 상쇄**되므로 래퍼 방식이 우월하다. → R-8.17~R-8.19 |
|
||
| **D-07** | Research Project 카드의 **`Funder/Sponsor` 실데이터 확보** 여부 | 🔴 **미결** | `funder` 미노출 + 실존하는 `Standards Track` 표기 | PJ-07. `ISL-2026/` 전체를 `과제·연구비·IITP·NRF·한국연구재단·정보통신기획평가원` 등으로 검색해 **0건**이다. **임의 생성은 MG-05·R-9.17·R-9.18 위반이며 실명·실제 이메일이 게시되는 페이지이므로 절대 불가.** 기본값으로 **구현 차단은 아니며**, 지도교수가 사업명·부처·기간을 제공하면 `content/projects.ts` 재생성만으로 반영된다 |
|
||
| **D-08** | Research Project 집합의 **정체성 범위** — 레거시 3건(IoT/CCIS/VLC)만인지, ANL 신규 과제를 포함할지 | 🟡 미결 | 레거시 3건 노출, 섹션 라벨 `Research Projects` | 레거시 3건은 IoT 시대 실적이고 현 정체성은 ANL이다. 신규 과제 추가는 지도교수 입력이 필요하다(MG-05). 레거시 3건 비노출은 PR-01에 역행하므로 배제 |
|
||
| **D-09** | `/publications` 인덱스 라우트를 **Overview 뷰 / `redirect()` / 기본 카테고리 재렌더 / 전체 통합 뷰 + `All` 탭** 중 무엇으로 둘 것인가 | ✅ **재확정** (v1.10, 2026-07-31) | — | **결정: Overview 뷰 채택(A안).** v1.9는 C안(첫 카테고리 본문 재렌더)을 채택했으나, 개발 팀장 이의제기(Job `22b7a309`)대로 **동일 DOM 정적 HTML 2본**이 생성되어 R-8.25를 위반한다 — 지적이 타당하여 채택안을 교체한다. `redirect()`(B안)는 AC-25·AC-40과 충돌하고, `All` 탭 포함 전체 통합 뷰(D안)는 commit `22a31ff`의 탭 제거 결정을 되돌리며 223건 단일 페이지로 P-07·R-9.11과도 충돌한다. A안은 **고유 콘텐츠**(카테고리별 집계 + 최신 하이라이트)를 가지므로 중복이 원천 소멸하고, `All` 탭 없이 3개 탭 체계를 유지해 `22a31ff`의 의도를 보존한다 → IA-03 재개정 · R-8.25 · AC-41 |
|
||
| **D-10** | `eaddc4f`가 도입한 `--cobalt: #4A7CE8`의 **라이트 테마 대비 미달**(ivory 3.49 / paper 3.16)을 어떻게 해소할 것인가 | ✅ **확정** (v1.11, 2026-07-31) | — | **결정: C안 채택 — `--cobalt`는 #4A7CE8 그대로 두고 `--cobalt-dark`를 `52 98 204`(#3462CC) → `50 84 158`(#32549E)로 재조정한 뒤, 소형 텍스트 사용처를 `-dark` 변형으로 라우팅한다.** 근거: ⓐ **사용자가 지정한 브랜드 색이 보존된다** — 히어로 SVG(`var(--cobalt)` 직접 참조)·대형 세리프 수치·불릿·테두리·아이콘 등 시각적으로 먼저 인지되는 표면은 전부 #4A7CE8을 유지하며, 이들은 대형 텍스트·비텍스트 UI 기준(3:1)을 실측 3.49로 충족한다. ⓑ `cobalt-dark` 슬롯은 **현재 사용처 0건**이므로 신규 토큰 없이 빈 슬롯을 활용해 토큰 계층이 늘지 않는다. ⓒ 결과값 6.43 / 5.82는 `vermillion-dark`(6.38 / 5.77)와 **동일 등급**이라 두 강조색이 대칭이 된다. **기각 사유** — A안(`--cobalt` 자체를 #3C64BC로 하향)은 브랜드 색이 눈에 띄게 어두워져 지시를 훼손하고, B안(신규 `--cobalt-text` 토큰)은 비어 있는 `-dark` 슬롯과 역할이 중복되며, D안(#1B3A8A 복귀)은 사용자 지시 역행이다. **#3C64BC(paper 4.51)가 아니라 #32549E(5.82)를 쓰는 이유**는 4.51이 임계선 대비 여유 0.01에 불과해 §12.1의 `opacity-90` 사고(4.69 → 4.05)처럼 후속 변경 한 번으로 재미달하기 때문이다. **v1.12 개정 — 배지·칩 전경/배경**: 개발 팀장(Agy) 이의제기(Job `7f136931`)를 수용해 v1.11의 `bg-cobalt text-ink dark:text-ivory`(5.03 / 4.82)를 **폐기**하고 **`bg-cobalt-dark text-ivory`(6.43 / 6.57)** 로 교체한다. v1.11은 소형 *텍스트* 12곳에만 `-dark` 라우팅을 적용하고 **동일 크기 등급(10.4 px)의 상태 칩 2곳은 DEFAULT 배경으로 남겨 스스로의 원칙과 어긋나 있었다** — 지적이 타당하다. 다만 이의제기의 권장 전경 `text-white dark:text-ivory`(7.25 / 6.57)는 **미채택** — `-dark` 배경에서는 `ivory` 전경만으로 양 테마가 통과하므로 팔레트 외 색 `white`와 `dark:` 변형이 **모두 불필요**하다(→ R-8.29). 아울러 권장안을 그대로 적용하면 `standardization:87-89` 삼항식의 **나란한 두 칩의 상대휘도 대비가 1.19 → 1.54로 악화**되므로, vermillion 칩도 `-dark`로 통일해 **1.01**로 맞춘다(→ R-8.26 짝 칩 등급 일치 조항) **v1.13 개정 — 확정값 갱신**: 커밋 `ca4a7ee`·`8db16e4`가 `--cobalt`를 **#4E77FF**, `--cobalt-dark`를 확정값 #32549E가 아닌 **#345AD2**(`52 90 210`)로 설정했다. #345AD2는 `paper` **4.76** / `ivory` **5.26**으로 R-8.26 바닥값을 **충족**하고 브랜드 색상(226.1°)에도 #32549E보다 가까우므로 **확정값을 #345AD2로 개정**한다. 단 `paper` 여유가 **0.26**뿐이라 위에서 #3C64BC를 배격한 것과 같은 사유가 부분적으로 적용되므로 §12.2 R-4로 등재하고, **추가 상향은 금지**한다(색상 유지 시 `paper` 4.5 한계는 #3B5AC2 4.92 부근이라 이득이 작다). 아울러 **#4E77FF는 반전 대비 1.00으로 R-8.28을 다시 위반**하며 이는 D-10 근본 원인의 재발이다 → **D-12**로 이관 → R-8.26 · R-8.28 · R-8.29 · AC-42 · AC-43 · AC-44 · AC-45 · AC-47 |
|
||
| **D-11** | `text-vermillion`(DEFAULT) 소형 텍스트 **약 30곳**을 교정할 것인가 | 🟡 미결 | **현행 유지 (교정하지 않음)** | 실측 `ivory` 4.16 / `paper` 3.77로 R-8.26 소형 텍스트 기준에 미달하나, ⓐ `eaddc4f`가 만든 회귀가 아니라 **최초 커밋 `36a4cd8` 이래의 상태**이고, ⓑ 30곳 일괄 변경은 "전체적인 에디토리얼 디자인 시스템 유지" 목표와 정면 충돌하는 시각적 대변경이며, ⓒ **vermillion(#D9342B)은 사용자가 명시적으로 현행 유지를 지정한 색**이다. 교정 시에는 D-10과 동일한 패턴(`text-vermillion-dark dark:text-vermillion`, 라이트 6.38 / 5.77)을 적용하면 되므로 **기술적 경로는 확보되어 있고 판단만 남는다.** AC-44 화이트리스트에 사유와 함께 등재해 게이트가 이 결정을 명시적으로 기록하게 한다. **v1.13 실측 갱신** — 정확한 건수는 **23건**(상태 변형 포함)이며 최저값은 `bg-paper` 카드 내부의 `members/page.tsx:114,144` **3.77**이다. `Footer.tsx:53,71`의 `hover:text-vermillion`도 `bg-paper` 위라 **3.77**이다 |
|
||
| **D-12** | **"Primary Color(#4E77FF) 전 요소 통일 적용"의 판정 기준을 토큰 값으로 볼 것인가, 화면 인지색으로 볼 것인가** — 그리고 히어로 `Orchestration` 강조어의 색을 R-8.5 규약대로 vermillion으로 되돌릴 것인가 | 🔴 미결 (v1.13 신설) | **A안 + B안 병행** | 접근성 제약상 소형 텍스트에는 #4E77FF를 쓸 수 없다(라이트 3.45 / 3.12). 그 결과 **토큰은 #4E77FF, 화면은 #345AD2**라는 이중 상태이며, 라이트 테마에서 #4E77FF가 **정적으로** 칠해지는 곳은 히어로 SVG와 6 px 불릿 **2곳뿐**이다(hover·focus 제외). **A안(현행 유지)**: 코드 변경 0, 지시는 토큰 수준에서 충족. **B안(대형 표면 확대)**: `page.tsx:84,92`의 30 px 지표 등 3:1을 충족하는 **대형 텍스트·도형 표면에 #4E77FF를 적극 확대**해 브랜드 가시성을 회복한다 — 접근성 손실 없이 문제를 실질적으로 완화하는 유일한 경로다. **C안(`-dark` 상향) 기각** — 여유 0.26에서 더 밝히면 D-10이 배격한 임계선 상황에 근접한다. **히어로 `Orchestration`**: `docs/DESIGN.md:30`과 R-8.5가 **vermillion = Orchestration**을 명문 규정하므로, cobalt를 유지하려면 **문서를 먼저 개정**해야 한다. 현재는 코드가 문서를 앞질러 같은 페이지 안에서 규약이 반씩 갈린 상태다. 어느 쪽이든 **코드와 문서가 같은 값을 말해야 한다** → R-8.5 · AC-48(C11-8) · AC-50 |
|
||
| **D-13** | `--vermillion`의 **반전 대비 1.25**(라이트 `217 52 43` ↔ 다크 `235 75 66`)를 교정할 것인가 | 🟡 미결 (v1.13 신설) | **현행 유지 + 화이트리스트 등재** | R-8.28 바닥값 2.0에 미달하나 ⓐ **최초 커밋 이래의 상태**로 특정 커밋이 만든 회귀가 아니고, ⓑ **#D9342B는 사용자가 현행 유지를 지정한 Secondary**이며, ⓒ `--vermillion-dark`(2.58)가 정상이라 소형 텍스트 경로는 이미 확보되어 있다. 다만 R-8.28의 취지대로 **"반대 테마 값을 조정하는 순간 양 테마가 동시에 무너지는" 상태**이므로, AC-45 화이트리스트에 **사유와 함께 등재**해 게이트가 이 결정을 명시적으로 기록하게 한다 → R-8.28 · AC-45 |
|
||
| **D-14** | `--cobalt` DEFAULT의 **반전 대비 1.00**을 어떻게 처리할 것인가 — R-8.28 예외로 등록할 것인가, 다크 값을 대칭 상향할 것인가 | 🔴 미결 (v1.14 신설, Agy 이의제기 `4962a667` 반영) | **A안 (브랜드 고정 예외)** | R-8.29 정리(강조색 `dark:` 변형 38건 제거) 후 `--cobalt` DEFAULT는 **어느 테마에서도 소형 텍스트를 담지 않으며** 남는 사용처(히어로 SVG·6 px 불릿·hover 테두리·토글 아이콘·대형 텍스트)가 **양 테마에서 3:1을 충족**한다(최저 3.12). 즉 **측정 가능한 실패는 남지 않고 형식적 위반만 남는다.** **A안 — 브랜드 고정(theme-invariant) 토큰으로 등록**: 다크 값을 라이트와 정확히 동일(`78 119 255`)하게 맞춰 불변성을 소스에 드러내고 AC-45 화이트리스트에 등재한다. 근거 ⓐ R-8.28은 *수단*, R-8.26·R-8.30(테마별 대비)이 *목적* 이며 목적 규칙이 양 테마에서 실효 검사되면(AC-43 v1.14 개정) 안전망이 유지된다 — 검증: `#1B3A8A` 역주입 시 다크 지면 대비 **1.80**으로 AC-43 즉시 실패. ⓑ #4E77FF는 **사용자 지정 Primary**이므로 다크 테마만 다른 색으로 치환하면 브랜드 정체성이 갈라진다. **B안 — 대칭 상향(이의제기 구조 채택 · 수치 정정)**: `--cobalt-rgb`(다크) `168 188 255`(#A8BCFF, 반전 **2.09**) + `--cobalt-dark-rgb`(다크) `199 212 255`(#C7D4FF, 반전 **4.04**, 다크 `paper` 11.56 > DEFAULT 9.14로 R-8.33 충족). 이의제기 원안의 `#85ACFF`는 반전 **1.73**으로 **R-8.28 미달**이라 미채택하고, `#B0CDFF`의 기재 반전 2.50은 `#345AD2`의 상대휘도를 폐기값 #32549E의 0.0949로 적은 오기에서 파생된 값으로 실제는 **3.68**이다. B안의 비용은 다크 강조색이 **파스텔로 변해 브랜드 색이 다크 테마에서 사라지고** `bg-cobalt-dark` 칩이 대비 12.75의 거의 흰 배경이 되는 것 — **D-12(브랜드 가시성)를 다크 테마에서 악화**시킨다. **A안은 본 계획자가 작성한 R-8.28을 스스로 완화하는 제안이므로 cline·GM의 별도 심사를 요청**하며, 승인 전에는 집행하지 않는다 → R-8.28 · R-8.29 · R-8.33 · AC-43 · AC-45 |
|
||
|
||
#### D-01 상세
|
||
|
||
PR-04에 명시된 4개 라벨 중 **1번과 2번의 범위가 논리적으로 중첩**된다. `International Journal & Conference`가 국제 저널과 국제 학술대회를 모두 포함한다면, `International Conference`는 그 부분집합이 되어 동일 레코드가 두 카테고리에 해당하게 된다.
|
||
|
||
**레거시 데이터 구조와의 대조**:
|
||
|
||
| 레거시 파일 | 실제 내용 | PR-04 라벨과의 대응 |
|
||
| :--- | :--- | :--- |
|
||
| `paper-international.html` | 국제 저널 67 + 국제 학술대회 1 = 68 | `International Journal & Conference`에 정확히 대응 |
|
||
| `paper-domestic.html` | 국내 논문 80 (KCI 48) | `Domestic Journal & Conference`에 정확히 대응 |
|
||
| `patent.html` | 특허 75 | `Patent`에 정확히 대응 |
|
||
| — | **대응 원본 없음** | `International Conference` ← ⚠️ |
|
||
|
||
**권고안 (A안)** — 국제 실적을 저널/학술대회로 분리:
|
||
`International Journal` / `International Conference` / `Domestic Journal & Conference` / `Patent`
|
||
→ 1번 라벨이 `Journal`의 오기라는 가정. 레거시 국제 목록을 게재처로 분리하면 저널 67 / 학술대회 1이 되어 **학술대회 카테고리가 1건으로 빈약해지는 점**을 함께 확인해야 한다.
|
||
|
||
**대안 (B안)** — 원문 라벨을 그대로 두고 1번을 국내외 통합 학술대회 카테고리로 재정의:
|
||
`International Conference`에 미수록 학술대회 논문을 지도교수로부터 확보해 채운다.
|
||
|
||
**리뷰어 판단**: 어느 안이든 **P-02의 레지스트리 설계로 인해 구현 착수를 막지 않는다.** P1 단계에서는 레거시 3개 원본을 그대로 3개 카테고리에 적재하고, D-01 확정 후 4번째 카테고리 분리를 적용하는 순서를 권고한다. 단 **P-03(레코드 무손실)** 은 어느 안에서도 반드시 지켜져야 한다.
|
||
|
||
**✅ 확정 결과 (v1.5, 2026-07-30 · commit `51aae14`)** — **C안: 1번 단독 카테고리 폐기**로 결정되었다.
|
||
|
||
| 항목 | 내용 |
|
||
| :--- | :--- |
|
||
| 기각된 A안 | 국제 실적을 저널/학술대회로 분리 → 학술대회가 **실측 1건**뿐이어서 단독 카테고리로 성립하지 않음 |
|
||
| 기각된 B안 | 미수록 학술대회 논문을 추가 확보 → **MG-05(`ISL-2026/`에 없는 데이터 생성 금지)** 에 저촉되며 신규 원본 유입 없이는 실행 불가 |
|
||
| 채택된 C안 | `intl-conf` 슬러그·라벨·타입 유니온을 **제거**하고 3개 카테고리로 확정 |
|
||
| 무손실 검증 | `intl-conf` 배정 레코드 **0건** → 축소가 정의상 무손실. 실측 68 + 80 + 75 = **223건** 유지 |
|
||
| 변경 범위 | `content/categories.ts`, `content/types.ts`(유니온), E2E 기대 라우트 목록, `README.md` 라우트 맵 — **P-02 설계 예측대로 레지스트리 중심 수정으로 완결** |
|
||
|
||
이 확정으로 §4.1 사이트맵·§7 `PubCategory`·P-01·P-03이 v1.5에서 함께 갱신되었고, 문서 상태가 `승인(Approved)`으로 전환되었다.
|
||
|
||
#### D-09 상세 — 색 토큰 알파 계약 붕괴와 `/publications` 리다이렉트 *(v1.9)*
|
||
|
||
D-09를 촉발한 것은 라우트 문제 하나가 아니라, **정적 게이트 전부를 통과하면서 화면만 무너지는 결함 계열**이 한 배치에서 두 종류 확인된 사건이다. 계약을 §8.7로 승격한 근거를 여기에 기록한다.
|
||
|
||
**(1) 근본 원인 — 쉼표 구분 `--*-rgb`**
|
||
|
||
`app/globals.css`는 토큰을 `--vermillion-rgb: 217, 52, 43;`처럼 **쉼표 구분**으로 정의해 왔다. 반면 `tailwind.config.ts`는 `rgb(var(--vermillion-rgb) / <alpha-value>)`를 선언했고, Tailwind는 이를 다음으로 전개한다.
|
||
|
||
```
|
||
.bg-vermillion { --tw-bg-opacity: 1; background-color: rgb(var(--vermillion-rgb) / var(--tw-bg-opacity, 1)) }
|
||
↓ var() 치환 후
|
||
rgb(217, 52, 43 / 1) ← 무효
|
||
```
|
||
|
||
`rgb()`는 **공백+슬래시(현대)** 또는 **전량 쉼표(레거시)** 중 하나여야 하며 혼용은 문법 위반이다. 무효 선언은 *invalid at computed-value time* 으로 폐기되므로 **토큰 배경색이 아예 적용되지 않는다.** 커밋 `7889398`("solid vermillion background")·`40b252b`("enforce high contrast white text")가 같은 증상을 반복 교정하려 한 이력이 이 진단을 뒷받침한다.
|
||
|
||
**(2) 부작용 — `<alpha-value>` 제거가 만든 2차 무성 결함**
|
||
|
||
`7889398`은 위 증상을 `colors.ivory = "var(--ivory)"` 형태로 축약해 해결했다. 단색은 정상화되었으나, **알파 자리표시자가 사라지면 Tailwind는 슬래시 수식자 유틸리티를 오류 없이 생략한다**(독립 프로브로 확인). 그 결과 소스에 남은 **26개 사용처가 전부 무효화**되었고 lint·tsc·빌드·Gate 0–7은 그대로 통과했다.
|
||
|
||
| 소멸한 유틸리티 계열 | 대표 사용처 | 실제 화면 |
|
||
| :--- | :--- | :--- |
|
||
| `bg-*/…` | `Header` `bg-ivory/85` | sticky 헤더 **배경 소실**(본문이 비쳐 지나감) |
|
||
| `border-*/…` (15건) | `border-line/60` 등 | Preflight 기본색 **`#e5e7eb`** — 팔레트 외 회색, 다크 모드에서 특히 부각 |
|
||
| `text-*/…` | `Footer` `text-ink/90` | 부모 색 **상속** |
|
||
| `ring-*/…` | `ProjectPageView` `focus:ring-vermillion/50` | Tailwind 기본 **파란색** 포커스 링 |
|
||
|
||
**(3) 3차 결함 — 인라인 `style` 우회**
|
||
|
||
단색이 적용되지 않는 상태를 우회하려 활성 배지에 `style={{ backgroundColor: "var(--vermillion)", color: "#ffffff" }}`가 투입되었다. 인라인 `style`은 `dark:` 변형을 항상 이기므로 **다크 모드에서 흰색 전경이 고정**되었고, `opacity-90`이 함께 도입되어 대비가 추가로 떨어졌다. 이는 Job `b3f001de`에서 제기하고 `43c75da`에서 해소했던 R-9.6 결함의 **직접 회귀**다.
|
||
|
||
| 상태 | 라이트 | 다크 | 판정 |
|
||
| :--- | :--- | :--- | :--- |
|
||
| 배지 라벨 (흰색 단색) | 4.69:1 | **3.74:1** | 다크 미달 |
|
||
| 배지 번호·`en` (`opacity-90`) | **4.05:1** | **3.29:1** | 양 테마 미달 |
|
||
| 참고: `43c75da`의 `dark:text-ivory` | 4.69:1 | 5.01:1 | 양 테마 충족 |
|
||
|
||
**(4) 확정 — 계약 복원이 스타일 보존과 일치한다**
|
||
|
||
| 항목 | 내용 |
|
||
| :--- | :--- |
|
||
| 채택 | `--*-rgb`를 **공백 구분으로 정정**(R-8.21) + `tailwind.config.ts`에 **`<alpha-value>` 복원**(R-8.22) + 인라인 `style`·`opacity-*` **제거**(R-8.23) |
|
||
| 기각 | `<alpha-value>` 제거 상태 유지 후 26개 사용처를 각각 리터럴 색으로 치환 — 토큰 체계가 사실상 붕괴하고 다크 모드 반전이 사용처마다 깨진다 |
|
||
| 스타일 영향 | **의도된 디자인으로의 복원이며 재디자인이 아니다.** 사용처 26곳은 원래 의도대로 렌더되고, 단색 토큰은 `7889398` 이후 상태를 그대로 유지한다 |
|
||
| 재발 방지 | AC-35(슬래시 수식자 실효성) · AC-36(공백 구분) · AC-37(인라인 `style` 0건) · AC-38(양 테마 대비) 게이트 신설 |
|
||
|
||
**(5) `/publications` 라우트** *(v1.10 재확정)*
|
||
|
||
같은 배치에서 `All Overview` 탭 제거와 함께 `/publications`가 `redirect()`로 대체되어 **Gate 8이 실측 실패**했다(`<main> tag not found in .next/server/app/publications.html`).
|
||
|
||
v1.9는 **C안(첫 카테고리 본문 재렌더)** 을 채택했으나, 개발 팀장 이의제기(Job `22b7a309`)가 **정적 HTML 2본이 동일 DOM을 갖는 문제**를 지적했고 이는 타당하다. 현재 코드베이스에 `metadataBase`·`alternates.canonical`이 **전무**함을 확인했으므로(grep 0건), C안을 그대로 두면 완화 장치 없이 중복이 노출된다. 이에 **A안(Overview 뷰)** 으로 교체한다.
|
||
|
||
| 안 | 중복 | `22a31ff`(All 탭 제거) 의도 | AC-25/40 | 판정 |
|
||
| :--- | :--- | :--- | :--- | :--- |
|
||
| A · Overview 뷰 | **없음** | **보존**(탭은 3개 유지) | 충족 | ✅ **채택** |
|
||
| B · `redirect()` 유지 | — | 보존 | **위반** | 기각 |
|
||
| C · 첫 카테고리 재렌더 | **2본 동일** | 보존 | 충족 | 기각 (v1.9 → v1.10 교체) |
|
||
| D · 전체 통합 + `All` 탭 | 없음 | **역행** | 충족 | 기각 |
|
||
|
||
한편 이의제기의 두 번째 논거(`isActive` 하이라이트 모호)는 **성립하지 않는다.** `Header.tsx`의 활성 판정은 `pathname === href || pathname.startsWith(\`${href}/\`)`이므로, `href="/publications"`는 세 하위 카테고리 경로 전부에 대해 이미 참이 된다. v1.9 계획의 3-3(예외 분기 제거)은 이 일반 규칙만으로 성립하며 별도 조치가 필요 없다. Overview에서 하위 탭이 하나도 활성이 아닌 것은 결함이 아니라 **Overview의 정상 상태**다(→ IA-03).
|
||
|
||
---
|
||
|
||
#### D-10 상세 — 강조색 교체가 대비를 붕괴시킨 경위 *(v1.11)*
|
||
|
||
**증상.** 커밋 `eaddc4f`("update primary color token to #4A7CE8 and secondary to #D9342B") 이후 라이트 테마에서 cobalt 계열 소형 텍스트가 읽기 어려워졌다. **lint·tsc·프로덕션 빌드·기존 게이트 0~9가 전부 통과한다** — 빌드는 exit 0, 정적 13/13 생성, 동적 라우트 0건이다.
|
||
|
||
**변경 실체.** `:root` 블록 2줄만 바뀌었다.
|
||
|
||
```diff
|
||
- --cobalt-rgb: 27 58 138; /* #1B3A8A */
|
||
- --cobalt-dark-rgb: 18 40 99; /* #122863 */
|
||
+ --cobalt-rgb: 74 124 232; /* #4A7CE8 */
|
||
+ --cobalt-dark-rgb: 52 98 204; /* #3462CC */
|
||
```
|
||
|
||
`html.dark` 블록(`--cobalt-rgb: 77 119 255`)과 `--vermillion-*`는 **양 블록 모두 미변경**이다.
|
||
|
||
**대비 실측(WCAG 2.1 공식 재계산).**
|
||
|
||
| 조합 | 변경 전 | 변경 후 | 판정 |
|
||
| :--- | ---: | ---: | :--- |
|
||
| `text-cobalt` on `ivory` | 9.23 | **3.49** | 소형 텍스트 미달 |
|
||
| `text-cobalt` on `paper` | 8.35 | **3.16** | 소형 텍스트 미달 |
|
||
| `ivory` on `bg-cobalt` | 9.23 | **3.49** | 미달 |
|
||
| `text-cobalt-dark` on `paper` | 11.16 | **4.48** | 간발의 미달 |
|
||
|
||
소형 텍스트 미달 사용처는 **14건**(`text-cobalt` 12건 + `bg-cobalt` 소형 배지 2건)이다. 반면 `page.tsx:92`(`text-3xl`, 30 px)·`page.tsx:174`(불릿 도형)·`ThemeToggle.tsx:146`(아이콘)·`members/page.tsx:102,132`(`hover:border-cobalt`)는 **대형 텍스트·비텍스트 UI 기준 3:1을 3.49로 충족**한다. 즉 **#4A7CE8은 큰 글자·도형으로는 적법하고 작은 글자로만 부적법**하며, 이 경계가 D-10 채택안의 설계 근거다.
|
||
|
||
**근본 원인 — 반전 계약 이탈.** 이 시스템의 모든 토큰은 `html.dark`에서 반전된다(`ivory` 245→18, `ink` 10→245). cobalt도 예외가 아니어서 라이트는 짙은 남색, 다크는 밝은 청색이었다.
|
||
|
||
| | 라이트 L | 다크 L | 라이트↔다크 대비 |
|
||
| :--- | ---: | ---: | ---: |
|
||
| 변경 전 | 0.0509 (#1B3A8A) | 0.2199 (#4D77FF) | **3.13** |
|
||
| 변경 후 | 0.2170 (#4A7CE8) | 0.2199 (#4D77FF) | **1.01** |
|
||
|
||
**라이트 값이 다크 값과 사실상 같은 밝기가 되었다** — cobalt 한 토큰만 반전 체계에서 이탈해, 라이트 테마가 다크 테마용 밝기를 그대로 반입했다. → R-8.28.
|
||
|
||
**게이트가 놓친 이유.** Gate 6은 `["--ink", "--ivory", …, "--cobalt"]`의 **문자열 존재 여부만** 확인하고, Gate 9는 **알파 계약**(구분자·`<alpha-value>`·인라인 `style`)만 확인한다. `run_e2e_tests.py`에 `contrast`·`4.5`·`luminance` 검사는 **0건**이다. 즉 **토큰의 "값"을 검사하는 게이트가 없어** `--cobalt: #FF00FF`로 바꿔도 10개 게이트가 전부 통과한다. → AC-43 · AC-44 · AC-45 · AC-46.
|
||
|
||
**문서가 사고에 기여한 부분.** `docs/DESIGN.md`의 커스터마이즈 훅은 "강조색 2개와 그 `-dark` 변형만 교체하면 됩니다"라고 **교체 방법만** 안내하고 **지켜야 할 대비 제약을 적지 않는다.** 안내를 문자 그대로 따른 결과가 이 커밋이므로, 문서 교정(R-8.27)이 재발 방지의 일부다.
|
||
|
||
**부수 확인 — Secondary는 무변경.** 커밋 메시지의 `…and secondary to #D9342B`는 변경이 아니라 **현상 유지의 서술**이다. `--vermillion-rgb`는 최초 커밋 `36a4cd8`(`--vermillion: #d9342b`) 이래 상수이며, `02247a0`의 `217, 52, 43` → `217 52 43`은 R-8.21 구분자 교정이지 색 변경이 아니다. 수렴 대장에 "Secondary 변경 검증 완료"로 기재되면 사실과 어긋나므로 **무변경(no-op)** 으로 기록한다.
|
||
|
||
**AC-42 미충족 잔존.** 직전 수렴(`02247a0`)에서 AC-42는 통과로 판정되었으나, 문언의 "vermillion 배경 위 텍스트 **전량**" 중 교정된 것은 Header 2곳·`CategoryNav` 1곳뿐이고 `standardization/page.tsx:40`·`:88`, `lectures/page.tsx:89`, `members/page.tsx:177`의 **4곳이 4.16:1로 남아 있다**(뒤 두 곳은 `group-open:` 상태 변형이라 육안 리뷰에서 누락되기 쉽다). → AC-42 개정.
|
||
|
||
##### D-10 보론 — 배지·칩 부류 분리 *(v1.12, Agy 이의제기 `7f136931` 반영)*
|
||
|
||
**v1.11의 설계 오류.** v1.11 §6.5는 `bg-cobalt`(#4A7CE8) 배경을 유지한 채 전경만 `text-ink`로 바꾸도록 정했다. 이는 채택안 C의 원칙("**작은 요소는 `-dark` 변형으로 라우팅한다**")을 **소형 텍스트 12곳에만 적용하고 동일 크기 등급의 상태 칩 2곳에는 적용하지 않은** 일관성 결함이다. 개발 팀장 이의제기가 이를 정확히 지적했다.
|
||
|
||
**기술적 근거(심미 판단과 독립).** 이의제기의 논거는 "짙은 검은 텍스트가 매거진 톤을 훼손한다"는 심미 판단이나, 같은 결론을 취향과 무관하게 지지하는 근거가 있다.
|
||
|
||
| `bg-cobalt`(#4A7CE8) 위 전경 | 대비 |
|
||
| :--- | ---: |
|
||
| `ivory` | 3.49 🔴 |
|
||
| `white` | 3.93 🔴 |
|
||
| `ink-soft` | 3.94 🔴 |
|
||
| `ink` | **5.03** ✅ (유일) |
|
||
|
||
팔레트 내 후보 4종 중 **통과는 1종뿐**이고, 그마저 라이트 전용이다 — 다크에서 `--ink-rgb`가 `245 241 232`로 반전되어 3.49로 미달하므로 `dark:text-ivory`를 수동으로 덧대야 한다. 즉 **반전 계약을 손으로 우회하는 구조**였다. `bg-cobalt-dark text-ivory`는 6.43 / 6.57로 **`dark:` 없이 양 테마가 자동 통과**한다(→ R-8.29).
|
||
|
||
**권장안을 그대로 쓰지 않은 이유 — 짝 칩 무게 불균형.** 대상인 `app/standardization/page.tsx:86-90`은 **하나의 삼항식**으로, `InProgress`(vermillion)와 그 외(cobalt) 배지가 문서 목록의 **같은 자리에 번갈아** 나타난다.
|
||
|
||
| 조합 | 배경 상대휘도 | 두 칩 간 대비 |
|
||
| :--- | ---: | ---: |
|
||
| v1.11: `vermillion` #D9342B ↔ `cobalt` #4A7CE8 | 0.1738 ↔ 0.2170 | 1.19 |
|
||
| 이의제기 권장안: `vermillion` ↔ `cobalt-dark` #32549E | 0.1738 ↔ 0.0949 | **1.54** (악화) |
|
||
| **v1.12 확정**: `vermillion-dark` #A8231C ↔ `cobalt-dark` #32549E | 0.0961 ↔ 0.0949 | **1.01** |
|
||
|
||
cobalt 칩만 어둡게 내리면 vermillion 칩이 밝은 채로 남아 무게 차가 오히려 벌어진다. **이의제기의 논거(에디토리얼 완성도)가 요구하는 vermillion 쪽 대칭 조치가 권장안에서 누락**되었다. 두 강조색의 `-dark` 변형은 휘도가 거의 같으므로(0.0961 vs 0.0949) **추가 색 조정 없이** 균형이 나온다.
|
||
|
||
**부류 A / 부류 B.** 크기 기반으로 두 패턴을 분리한다 — R-8.26의 논리(가장 작은 글자에 가장 여유 있는 대비)를 연장한 것이다.
|
||
|
||
| 부류 | 대상 | 패턴 | 라이트 / 다크 |
|
||
| :--- | :--- | :--- | ---: |
|
||
| **A** 상태 칩(`text-[0.65rem]`) | `standardization:40`·`:88`(verm) · `standardization:89` · `publications/[category]:135`(cobalt) | `bg-{accent}-dark text-ivory` | **6.38~6.43 / 6.57~6.72** |
|
||
| **B** 인터랙티브 내비·토글 | `Header:69,129` · `CategoryNav:22`(교정 완료) · `lectures:89` · `members:177` | `text-white dark:text-ivory` | 4.69 / 5.01 |
|
||
|
||
**부류 B를 `-dark`로 내리지 않는 이유**: ① Header 활성 배지는 사이트에서 가장 눈에 띄는 브랜드 표면이며 #D9342B → #A8231C 변경은 "전체 스타일 유지" 지시를 벗어난다. ② 해당 2곳은 `02247a0`에서 교정되어 리뷰 PASS를 받았으므로 불필요한 재작업·재검증을 유발한다. ③ 4.69:1은 AA를 충족한다 — 개선 여지는 있으나 결함이 아니다.
|
||
|
||
**시각 변경 고지.** 부류 A의 vermillion 칩 2곳은 배경이 **#D9342B → #A8231C로 실제로 어두워진다.** `#A8231C`는 팔레트에 이미 정의된 `vermillion-dark`이므로 신규 색이 아니며(R-8.1 위반 아님) 대상 면적도 `text-[0.65rem]` 칩 2개로 극히 작다. **GM이 배경 무변경을 선호하면 부류 B 패턴(`bg-vermillion text-white dark:text-ivory`, 4.69)으로 내려도 규격은 충족**되며, 그 경우 위 표의 무게 불균형 1.54가 남는다는 점만 함께 기록한다 — **차단 사유가 아니라 선택지다.**
|
||
|
||
#### D-12 상세 — 게이트가 녹색인 채로 남은 결함과 브랜드 색의 가시성 *(v1.13)*
|
||
|
||
**관측.** `eaddc4f` → `082d71e` 4개 커밋 이후 상태에서 `npm run build`(exit 0 · 13/13 정적 · `ƒ Dynamic` 0건)와 `run_e2e_tests.py` **Gate 0~10 전량**이 통과한다. 그러나 같은 상태에서 **WCAG AA 미달 6건과 통일성 결함 9건**이 실재한다. 특히 `lectures/page.tsx:89`는 **v1.12 AC-42 부류 B에 "미교정"으로 명시 등재된 항목**인데 신설된 대비 게이트가 이를 통과시켰다.
|
||
|
||
**원인 — 게이트의 범위 결함 3종.**
|
||
|
||
| ID | 결함 | 결과 |
|
||
| :--- | :--- | :--- |
|
||
| G-1 | AC-44 구현의 면제 조항 `if … or "text-vermillion" in line: continue`. 위반 판정 정규식이 `text-(cobalt\|vermillion)`이므로 **vermillion으로 매치된 라인은 예외 없이 그 문자열을 포함**한다 | **AC-44의 vermillion 절반이 영구 무효.** 실제 소스 4개 라인 + 주입 2건을 동일 로직에 투입해 전부 면제됨을 재현 |
|
||
| G-2 | AC-45 구현이 `cobalt-dark`·`vermillion-dark` **2종만** 검사 | **`--cobalt` 반전 대비 1.00 미검출** — D-10 근본 원인의 재발 |
|
||
| G-3 | AC-43 구현이 토큰 값만 보고 **소스의 전경/배경 쌍은 보지 않음** | `bg-cobalt-dark text-white`(다크 2.85)를 작성해도 통과 |
|
||
|
||
G-1은 **N6**(Gate 8 C1/C2 공허 단정, 10라운드 미해소)과 **동일 유형**이다 — 단정·면제가 구조적으로 발화하지 않는데 출력은 ✅로 찍힌다. 개별 수정이 아니라 형식 차원의 금지(**R-8.32**)로 대응한다. 아울러 §12.1 D-09(알파 계약)·D-10(반전 계약)에 이어 `focus:ring-cobalt/50` **1.80** · `hover:border-cobalt/60` **1.95**가 드러났다 — **알파·토큰 조합이 무성으로 대비를 무너뜨리는 유형의 세 번째 발현**이며 **R-8.30**의 근거다.
|
||
|
||
**브랜드 색의 가시성.** 라이트 테마에서 지정 Primary **#4E77FF가 정적으로 칠해지는 표면은 히어로 SVG와 6 px 불릿 2곳뿐**이다. 나머지는 전부 hover·focus 상태이거나 `-dark` **#345AD2**다.
|
||
|
||
| 표면 | 색 | 상태 |
|
||
| :--- | :--- | :--- |
|
||
| 히어로 `HeroComposition` SVG (`var(--cobalt)`) | **#4E77FF** | 정적 |
|
||
| Pillar 불릿 `page.tsx:174` `bg-cobalt` (6 px) | **#4E77FF** | 정적 |
|
||
| `members:102,132` `hover:border-cobalt` · `ProjectPageView:35,44` | #4E77FF | hover/focus 전용 |
|
||
| `ThemeToggle:146` `text-cobalt` | #4E77FF | **다크 테마 전용 렌더** |
|
||
| 섹션 괘선·키커·링크·지표·Pillar 라벨(20여 곳) | **#345AD2** | 정적 — 사용자가 "Primary"로 인지하는 색 |
|
||
|
||
즉 **지시는 토큰 수준에서 충족되었으나 화면 수준에서는 다른 색이 Primary로 읽힌다.** 접근성을 지키면서 이 간극을 좁히는 유일한 경로가 **B안(대형 표면 확대)** 이다 — `page.tsx:84,92`의 30 px 지표처럼 **3:1만 요구되는 표면**은 #4E77FF로 칠해도 적법하다(실측 3.45). 반대로 `-dark`를 브랜드 색 쪽으로 밝히는 C안은 `paper` 여유가 0.26뿐이라 **D-10이 #3C64BC를 배격한 것과 같은 사유**로 기각한다.
|
||
|
||
**시맨틱 규약의 분열.** `docs/DESIGN.md:30`과 R-8.5는 **vermillion = Agent Eng / Orchestration**을 규정한다. `2441f35`가 히어로의 `Orchestration` 강조어를 cobalt로 바꾸었으나, 같은 파일의 PILLARS 교차 배정(`page.tsx:12~48`)은 규약을 유지 중이다 — **한 페이지 안에서 규약이 둘로 갈렸다.** 코드를 되돌리든 문서를 개정하든 무방하나, **둘 중 하나는 반드시 상대에 맞춰야** AC-23이 성립한다.
|
||
|
||
---
|
||
|
||
### 12.2 리스크
|
||
|
||
| ID | 리스크 | 영향 | 완화 방안 |
|
||
| :--- | :--- | :--- | :--- |
|
||
| R-01 | 레거시 HTML의 비정형 마크업으로 추출 정확도 저하 | **PR-01 위반** (데이터 누락·오배치) | MG-01 스크립트화 + MG-02 건수 대조 + P1-R 독립 검증 |
|
||
| R-02 | 223건 일괄 렌더로 초기 로드 지연 | 성능 저하 | P-07 점진적 노출, R-9.11·9.12 예산 명시 |
|
||
| R-03 | Tailwind JIT이 동적 조립 클래스를 인식하지 못함 | **빌드는 성공하나 조판이 조용히 붕괴** | 클래스는 완전한 문자열 리터럴로 작성. AC-20으로 빌드 CSS 실측 검증 |
|
||
| R-08 *(v1.1 신설)* | Publications 필터 구현이 정적 생성을 깨뜨림 | `ƒ Dynamic` 전환 → DM-03·NF-03 위반, 또는 빌드 중단 | §8.5 실측 규칙 R-8.11~8.16 준수. AC-17·AC-21·AC-22로 검증 |
|
||
| R-09 *(v1.1 신설)* | 레코드 목록이 클라이언트 렌더로 밀려 정적 문서에서 누락 | **PR-01 실질 위반** — 크롤러·JS 미실행 환경에서 실적이 보이지 않음 | R-8.15 서버 렌더 강제. AC-14로 JS 비활성 검증 |
|
||
| R-04 | 실명·실적 데이터 오기재 | 연구실 신뢰도 훼손 | R-9.17·9.18 무결성 원칙, MG-05 창작 금지, 지도교수 최종 확인 |
|
||
| R-05 | 잔재 검사(MG-08)가 논문 제목의 도메인 용어까지 오검출 | **실데이터를 잔재로 오인해 삭제** → PR-01 위반 | MG-08 예외 규정을 검사 스크립트에 반영. 검사 범위를 정체성 서술 영역으로 한정 |
|
||
| R-06 | 문서-코드 불일치 재발 | 후속 작업자 혼선 | R-9.19. 미완 영역은 문서에 미완으로 표기 |
|
||
| R-07 | P2(Header 수정)와 P3~P5 병렬 진행 시 충돌 | 머지 충돌 | §11.1 주석대로 P2 선행 완료 |
|
||
| R-10 *(v1.13 신설)* | 색값 교체가 **대비 재산정표 없이** 5회 연속 진행됨(`eaddc4f`·`ca4a7ee`·`8db16e4`·`2441f35`·`082d71e` 전부 커밋 본문 없음) | 관행화 시 무성 실패가 반복 발생 | R-8.1·R-8.27 이행 강제 + **AC-50**으로 `docs/DESIGN.md` 커스터마이즈 훅 교정. 문서가 원인으로 규명된 지 2라운드째 미교정 |
|
||
| R-11 *(v1.13 신설)* | **게이트 통과가 결함 부재의 근거로 오용될 위험** — Gate 0~10 전량 ✅인 상태에서 AA 미달 6건이 실재했다 | 잘못된 PASS 확정 | 폴트 인젝션 없는 게이트는 채택하지 않는다(**AC-46 · AC-49**). 신설 게이트는 **현행 코드 자체가 주입 상태**인 항목(F1·F2·F3·F7)으로 즉시 실효성을 확인한다 |
|
||
| R-12 *(v1.13 신설)* | `--cobalt-dark` #345AD2의 `paper` 여유가 **0.26**뿐 | 후속 변경 1회로 재미달 | 추가 상향 금지(D-10 v1.13 개정). 변경 시 R-8.27 재산정 필수 |
|
||
| R-13 *(v1.13 신설)* | Phase 3 색 통일 작업이 "에디토리얼 디자인 시스템 유지" 목표와 충돌할 소지 | 시각적 대변경 | 단일화 대상을 **동일 역할 시그니처 내부**로 한정(R-8.31). 색 선택 자체는 **D-12**로 이관 |
|
||
|
||
---
|
||
|
||
## 13. 부록: 레거시 데이터 인벤토리 (실측)
|
||
|
||
`ISL-2026/` 기준, 2026-07-30 파싱 실측치.
|
||
|
||
| 원본 파일 | 레코드 수 | 비고 |
|
||
| :--- | ---: | :--- |
|
||
| `member.html` | 재학 **16** / 졸업 **60** | 재학: 교수 1, Ph.D. 1, Ph.D. Candidate 4, Ph.D. Student 5, M.S. Candidate 3, M.S. Student 2. 졸업생 2007~2026 |
|
||
| `paper-international.html` | **68** | 저널 67 + 학술대회 1. 최신 2026-04(IEEE TNSM), 최고(最古) 1995 |
|
||
| `paper-domestic.html` | **80** | KCI 등재 표시 48건. 최신 2026-06 |
|
||
| `patent.html` | **75** | 국내 출원 다수 + US 출원 일부. 최신 출원 2025-12-16 |
|
||
| `standard.html` | 기구 **6** / 문서 **약 55** | 국제 5개 기구 + 국내 1개(TTA/PG425). 2000~현재 |
|
||
| `lecture.html` | **약 20개 학기** | 2016 Fall ~ 2026 Spring |
|
||
| `index.html` | 연구분야 3종 | `IoT Standards`, `CCIS`, `VLC-IoT` — **폐기 대상**(5대 기둥으로 교체, R-5.3) |
|
||
| `introduction.html` | 연구 주제 13종 | 구 연구 분야 상세 — **폐기 대상**(R-5.3) |
|
||
| `image/`, `assets/` | 11.6 MB | `image/` 3.4 MB + `assets/` 8.2 MB. 선별 이관(MG-06) |
|
||
|
||
**연락처·소재지 (H-13~H-15 원천)**
|
||
- 소재지: **경북대학교 IT대학 5호관(415동) 527호** *(레거시 `index.html`에 HTML 주석 처리된 상태로 존재 — 복원 필요)*
|
||
- 소속: School of Computer Science and Engineering, Kyungpook National University
|
||
- 지도교수 이메일: `sjkoh@knu.ac.kr`
|
||
- 연구실 GitHub: `https://github.com/iot-standards-laboratory` *(→ D-05)*
|
||
- 지도교수 GitHub: `https://github.com/sjkoh12`
|
||
- 기관 링크: KNU `http://www.knu.ac.kr/` · 컴퓨터학부 `http://cse.knu.ac.kr/` · IT대학 `http://it.knu.ac.kr/`
|
||
- 전화·팩스: **레거시에 없음** (H-14에 따라 창작 금지)
|
||
|
||
---
|
||
|
||
## 14. 변경 이력
|
||
|
||
| 버전 | 일자 | 작성자 | 내용 |
|
||
| :--- | :--- | :--- | :--- |
|
||
| 1.0 | 2026-07-30 | claude (planner) | 최초 작성. 사용자 원본 요구사항(§1)을 정본으로 확장. Job `4148350e` |
|
||
| 1.1 | 2026-07-30 | claude (planner) | 개발 팀장(Agy) 기술 이의제기(Job `175860e4`) 반영. **§8.5 Next.js 렌더링 제약 신설**(실측 5종). IA-03을 라우트 세그먼트 방식으로 개정, P-06 개정 + P-06a·P-07a 신설, DM-03·NF-03·AC-05·AC-16 문구 정정, AC-22~24 및 R-08·R-09 신설. Job `45d05868` |
|
||
| 1.2 | 2026-07-30 | agy (creator) | 교차 리뷰 리포트(Job `3820bdc8`) 결함 피드백 전면 반영. **F1 §4.1 사이트맵 쿼리 표기를 라우트 세그먼트(`/publications/<slug>`)로 갱신**, **F2 §2.1·§2.2 연구 실적 수치 279건 → 223건 정정**, **F3 §10 수용 기준 AC-14~24 순서 및 그룹핑 정돈**. Job `f3e09780` |
|
||
| 1.3 | 2026-07-30 | agy (creator) | 교차 리뷰 리포트(Job `60c92d3a`) 결함 피드백 전면 반영. **G-1 417행 R-8.16 참조 AC-16 → AC-17 정정**, **G-4 575행 R-03 참조 AC-19 → AC-20 정정**, **G-2 576행 R-08 참조 AC-16/22/23 → AC-17/21/22 정정**, **G-3 577행 R-09 참조 AC-24 → AC-14 정정**. Job `a535ce20` |
|
||
| 1.4 | 2026-07-30 | agy (creator) | 구현 교차 리뷰 리포트(Job `777c3ab8`) 피드백 전면 반영. **I1 전 파서 ISO 8601 정규화 100%**, **I2 Footer 주소/이메일 실주소 교체**, **I3 README 라우트 맵 갱신**, **I4 verify_counts.py 엄격 게이트로 강화 및 실측 수치(표준 44, 학기 45) 정정**, **I5 __pycache__ 제거 및 .gitignore 차단**, **I6/I7 Home 카운터 및 5대 기둥 영문 라벨 정본 정렬**. Job `a54723ce` |
|
||
| 1.5 | 2026-07-30 | claude (planner) | **D-01 확정 및 문서 상태 `승인(Approved)` 전환.** commit `51aae14`(백로그 4건 반영)에 대한 검증 결과를 정본에 동기화: `intl-conf` 단독 카테고리 폐기(A·B안 기각, C안 채택 — §12.1 D-01 상세에 결정 근거 기록), §4.1 사이트맵·§7 `PubCategory` 유니온·P-01·P-03·IA-03·§11 P0 갱신, 사이트맵의 학기(45)·표준 문서(44) 실측치 정정. Job `343b5808` |
|
||
| 1.6 | 2026-07-30 | claude (planner) | 개발 팀장(Agy) 기술 이의제기(Job `2560771b`) 반영. **§8.6 레이아웃 컨테이너 아키텍처·브레이크포인트 토큰 신설**(R-8.17~R-8.20) — `<main>` 일괄 부여안을 기각하고 3계층 분리(전체 폭 `<main>` / 라우트 래퍼 `container-content` / full-bleed 밴드)를 채택, `w-screen` 탈출 기법 금지(R-8.18) 및 `desktop: 1240px` 스크린 토큰화(R-8.20, Tailwind 정렬 동작 실측 확인). **D-06 신설·확정**, **AC-25·AC-26 신설**, R-9.14 검수 뷰포트 6종으로 확대. AC-21 정적 HTML 4개 → 3개, R-8.15 표준 문서 55 → 44건 실측치 정정. Job `019b7331` |
|
||
| 1.7 | 2026-07-30 | claude (planner) | Home Hero → Research Project PageView 전환 계획 반영. **§6.1.2 신설**(PJ-01~PJ-14) — 레거시 실재 프로젝트 3건(IoT Standards·CCIS·VLC-IoT) 확인, `period`·`deliverables`를 `content/standards.ts` 조인으로 도출하는 무창작 설계, 활성 슬라이드 전용 캐러셀 금지(PJ-08)·URL 상태 동기화 금지(PJ-09)·캐러셀 라이브러리 금지(PJ-10)·scroll-snap 기반 JS-off 동작 보장(PJ-11) 규정. **H-02 개정**(슬로건 교체 허용 + H-03·H-04·H-05·H-06·H-07·H-10 존속 명시). **AC-27~AC-33 신설**, §7 `ResearchProject`·`ProjectDeliverable` 타입 추가, **D-07·D-08 신설**. Job `6b3840a1` |
|
||
| 1.8 | 2026-07-30 | claude (planner) | 개발 팀장(Agy) 기술 이의제기(Job `2299a6b9`) 반영. **PJ-13 개정** — 데스크톱 3카드를 flex 스크롤 트랙에서 **`grid-cols-3` 정적 3열 + `overflow-visible`** 로 전환하고 데스크톱 퍼센트 연산을 제거. **PJ-15·PJ-16 신설**(`min-w-0`+줄바꿈으로 `shrink-0` min-content 넘침 방어 / 스크롤바 은폐 시 AC-34 동반 의무), **AC-34 신설**(데스크톱 `scrollWidth === clientWidth` 실측 판정). 이의제기의 근거 수식은 정정 — `calc(33.333%-16px)`은 초과가 아니라 **0.0125 px 미달**이며, 대안 B의 분수식은 여유가 0이어서 해당 실패 모드에 오히려 더 취약하다. Tailwind가 `calc` 연산자 공백을 자동 삽입함과 `grid-cols-3`의 `minmax(0,1fr)` 전개·미디어 쿼리 출력 순서를 실측 확인. Job `294570ab` |
|
||
| 1.9 | 2026-07-31 | claude (planner) | 스타일 관련 누적 커밋 23건(`43c75da..b7f2e05`) 검증 결과 반영. **§8.7 색 토큰 알파 계약 신설**(R-8.21~R-8.24) — 쉼표 구분 `--*-rgb`가 `rgb(a, b, c / α)` 무효 선언을 만들어 토큰 색이 적용되지 않던 근본 원인을 규명하고, 그 우회로 도입된 `<alpha-value>` 제거가 **슬래시 수식자 유틸리티 26건을 무성 소멸**시킴을 독립 프로브로 실측 확인. 인라인 `style`·`opacity-*` 토큰 우회 금지(R-8.23)와 헤더 가로 예산(R-8.24, 1240 px 기준 −69.3 px 초과 산정) 규정. **D-09 신설·확정**(`/publications` `redirect()` 기각 → 기본 카테고리 화면), **IA-03 개정**, **AC-35~AC-40 신설**. Job `9a79e302` |
|
||
| 1.10 | 2026-07-31 | claude (planner) | 개발 팀장(Agy) 기술 이의제기(Job `22b7a309`) 반영. **D-09 재확정** — v1.9의 C안(첫 카테고리 본문 재렌더)이 **동일 DOM 정적 HTML 2본**을 만든다는 지적이 타당하여 **A안(Overview 뷰)** 으로 교체하고, `All` 탭 재도입(D안)은 commit `22a31ff` 결정 역행·P-07 충돌로 기각. **R-8.25 신설**(라우트 간 콘텐츠 중복 금지 + canonical 예외 절차), **AC-41 신설**(`<main>` 정규화 해시 중복 0건), **IA-03 재개정**. 이의제기의 `isActive` 논거는 정정 — `pathname.startsWith(\`${href}/\`)` 일반 규칙이 하위 카테고리를 이미 포괄하므로 모호성이 없음을 코드로 확인. 아울러 별건으로 `CategoryNav` 활성 탭(`bg-vermillion text-ivory`)이 **라이트 테마 4.16:1로 R-9.6 미달**임을 발견해 **AC-42 신설**. Job `6a6094c6` |
|
||
| 1.11 | 2026-07-31 | claude (planner) | 강조색 교체 커밋 `eaddc4f` 검증 및 리뷰 수렴. **라이트 테마 cobalt 대비가 9.23:1 → 3.49:1(ivory) / 8.35 → 3.16(paper)로 붕괴**하여 소형 텍스트 **14개 사용처**가 AA 미달임을 WCAG 공식 재계산으로 확정. 근본 원인은 **명암 반전 계약 이탈**(라이트↔다크 상대휘도 대비 3.13 → **1.01**)이며, `run_e2e_tests.py`에 대비 검사가 **0건**이라 게이트 0~9와 빌드가 전부 통과한 채로 통과했다 — §12.1 알파 계약 사고와 동일한 무성 실패 유형의 **두 번째 발현**. **R-8.26~R-8.28 신설**(강조색 대비 바닥값 · 색값 변경 시 재측정 의무 · 명암 반전 계약 ≥2.0), **AC-43~AC-46 신설**(대비 게이트 Gate 10 · 소형 텍스트 라우팅 · 반전 계약 · 폴트 인젝션 4종). **D-10 확정** — `--cobalt`는 사용자 지정 #4A7CE8을 **유지**하고 `--cobalt-dark`만 #3462CC → **#32549E**(paper 4.48 → 5.82)로 재조정해 소형 텍스트를 `-dark`로 라우팅(A·B·D안 기각). **D-11 신설**(🟡 `text-vermillion` 소형 텍스트 30여 곳, 기본값 현행 유지). **AC-42 개정** — 직전 수렴에서 통과 판정되었으나 `standardization:40,88`·`lectures:89`·`members:177` **4곳이 4.16:1로 미교정** 잔존함을 확인하고 대상을 명시 목록화, `text-white` on vermillion 수치를 4.58 → **4.69**로 정정. §8.1 색상 토큰표를 실제 값과 동기화하고, **Secondary #D9342B는 최초 커밋 이래 무변경(no-op)** 임을 계보로 확인해 기록. Job `5c2137c6` |
|
||
| 1.12 | 2026-07-31 | claude (planner) | 개발 팀장(Agy) 기술 이의제기(Job `7f136931`) 반영. **D-10 배지·칩 결정 재확정** — v1.11의 `bg-cobalt text-ink dark:text-ivory`(5.03 / 4.82)는 채택안 C의 원칙(작은 요소는 `-dark` 라우팅)을 **소형 텍스트 12곳에만 적용하고 동일 크기 등급의 상태 칩 2곳에는 적용하지 않은 일관성 결함**이었음을 인정하고 폐기, **`bg-{accent}-dark text-ivory`** 로 교체(6.38~6.43 / 6.57~6.72). 이의제기의 권장 전경 `text-white dark:text-ivory`(7.25)는 **미채택** — `-dark` 배경에서는 `ivory`만으로 양 테마가 통과해 **팔레트 외 색 `white`와 `dark:` 변형이 모두 불필요**하다(**R-8.29 신설**). 아울러 권장안을 그대로 적용하면 `standardization:87-89` 삼항식의 나란한 두 칩 상대휘도 대비가 **1.19 → 1.54로 악화**됨을 실측해, vermillion 칩도 `-dark`로 통일하여 **1.01** 균형을 달성(**R-8.26에 배지·칩 라우팅 및 짝 칩 등급 일치 조항 추가**). 배지류를 **부류 A(`text-[0.65rem]` 상태 칩 4곳) / 부류 B(인터랙티브 내비·토글 5곳)** 로 분리해 **AC-42 개정**, `-dark`가 **배경**으로 쓰이는 조합을 **AC-43 검사 대상에 추가**(v1.11 목록은 전경만 다루어 칩 배경을 놓쳤다), **AC-47 신설**(팔레트 외 색 상한 8건 화이트리스트), **AC-46에 폴트 인젝션 ⑤·⑥ 추가**(폐기된 v1.11 칩 패턴 및 `white` 증가 검출). 부류 A vermillion 칩 2곳의 배경이 #D9342B → #A8231C로 어두워지는 **시각 변경은 GM 승인 사항으로 명시**하되 차단 사유가 아님을 기록. Job `3d3b823a` |
|
||
| 1.13 | 2026-07-31 | claude (planner) | 테마 색상 통일성 검증 계획 수립 (`eaddc4f`→`082d71e` 4개 커밋). **Gate 0~10 전량 통과·빌드 exit 0인 상태에서 WCAG AA 미달 6건·통일성 결함 9건이 실재**함을 실측으로 확정 — 게이트 통과가 곧 오탐 신호였다. 원인은 게이트 **범위 결함 3종**: ⓐ **AC-44의 vermillion 절반이 구조적으로 무효**(면제 조항 `"text-vermillion" in line`이 판정 정규식과 항상 동시 매치 — 실소스 4라인 + 주입 2건으로 재현), ⓑ AC-45가 `-dark` 2종만 검사해 **`--cobalt` 반전 대비 1.00**(D-10 근본 원인의 재발)을 미검출, ⓒ AC-43이 소스의 전경/배경 쌍을 보지 않아 `bg-cobalt-dark text-white`(다크 2.85)를 통과. **R-8.30 신설**(비텍스트 UI 3:1 · 알파는 합성 후 산정 — `focus:ring-cobalt/50` **1.80** · `hover:border-cobalt/60` **1.95** 검출), **R-8.31 신설**(역할 시그니처 단위 색 통일 — 괘선 6:1 · 키커 11:1 · 배지 전경 6:4 · hover 테두리 4종 · 포커스 2종, 지도교수 이메일 1값이 3색 3대비), **R-8.32 신설**(게이트 면제는 `(파일,행,사유)` 등재만 허용 · 라인 부분문자열 면제 금지 — **N6과 동일 유형**). **R-8.5·R-8.26·R-8.28 개정**, **AC-42·43·44·45·47 개정**, **AC-48~AC-50 신설**(Gate 11 C11-1~8 · 폴트 인젝션 F1~F9 · `docs/DESIGN.md` 동기화 4건). **§8.1 색상표를 실제 토큰값 `#4E77FF`/`#345AD2`로 동기화**하고 **D-10 확정값을 #345AD2로 개정**(paper 4.76, 여유 0.26 → R-12). **D-12 신설**(🔴 Primary 적용의 판정 기준 — 라이트 테마에서 #4E77FF가 정적으로 보이는 곳이 **2곳뿐**이며 인지색은 #345AD2. 히어로 `Orchestration`이 R-8.5·DESIGN.md §2를 위반해 cobalt로 변경되어 한 페이지 안에서 규약이 분열), **D-13 신설**(🟡 `--vermillion` 반전 1.25). **A-1 `lectures:89` 4.16 미교정 잔존**·**A-2 `not-found.tsx:22` 4.16 신규 발견**(어떤 AC에도 없던 항목)·**A-7 `::selection` 4.16 미등재** 확정. **D-11 실측 갱신**(23건, 최저 3.77). 색 교체 5회 연속 대비표 미첨부(R-10). Job `43f3f74a` |
|
||
| 1.14 | 2026-07-31 | claude (planner) | 개발 팀장(Agy) 기술 이의제기(Job `4962a667`) 반영. **구조적 통찰 채택** — 다크 `--cobalt`만 단독 상향하면 다크 지면 대비가 DEFAULT 9.2 > `-dark` 5.96으로 **계층이 역전**됨을 실측 확인, v1.13 §7 각주의 누락을 인정하고 **R-8.33 신설**(토큰 등급 불변식). 다만 불변식을 **절대 휘도 순서가 아니라 테마 상대 대비**로 정식화 — 절대 순서의 테마 간 뒤집힘은 vermillion 쌍에서도 동일한 **정상 동작**이며 현행 8개 셀 전부에서 성립하므로, 절대 휘도로 판정하면 정상 상태를 오판한다. **제안 수치 미채택** — 주 권장값 `#85ACFF`의 반전 대비는 **1.73**으로 조정을 촉발한 R-8.28(≥2.0) 자체를 충족하지 못하며, 제안 표의 `#345AD2` L=0.095는 **폐기된 #32549E의 값**(실제 0.1270)이라 `#B0CDFF` 반전 대비 2.50도 실제 **3.68**이다. **이의제기 지점에서 더 큰 결함 발굴** — 다크 `--cobalt`(#4D77FF)는 `bg-paper` 위 **4.37**이므로 v1.12가 지시한 `text-cobalt-dark dark:text-cobalt` 라우팅이 **다크 절반을 DEFAULT로 되돌려 8곳이 AA 미달**이다(**AC-51 신설**). 원인은 R-8.26의 "`paper` 기준 산정" 원칙을 **본 계획자가 라이트 테마에만 적용한 오류**로, v1.11 §6.5와 같은 형태의 누락이다. 게이트도 AC-44 정규식의 **부정 후방탐색 `(?<!dark:)`로 다크 절반을 설계상 면제**하고 있었다(**G-7** — G-1·G-2·G-3에 이은 네 번째 "검사를 절반만 한다" 유형). **처방을 토큰 조정에서 `dark:` 변형 제거로 재설계** — `-dark`는 반전 토큰이므로 `dark:` 없이 4개 셀 전부(5.26/4.76/6.57/5.96)를 통과한다. **R-8.29 강화**(강조색 `dark:` 금지 · 정본 패턴 3종 · 현행 위반 **38건**), **R-8.26·AC-43·AC-44·AC-48(C11-9)·AC-49(F10·F11, 총 11건) 개정**. **D-14 신설**(🔴 `--cobalt` 반전 1.00 — A안 브랜드 고정 예외 권고 / B안 대칭 상향 정정 수치 `#A8BCFF`+`#C7D4FF`). A안은 본 계획자가 작성한 R-8.28의 완화를 포함하므로 **cline·GM 별도 심사 대상**으로 명시했고, 안전망 유지 근거로 `#1B3A8A` 역주입 시 AC-43 즉시 실패(1.80)를 제시했다. Job `d35bc3e7` |
|
||
| 2.0 | 2026-08-24 | claude (planner) / agy (creator) | **실시간 동적 런타임 페칭 아키텍처 도입 (DM-03·AC-17·R-08 개정)**. Go/Gin 백엔드 REST API(`http://localhost:8080/api/v1`) 연동 및 `force-dynamic` + `cache: 'no-store'` 적용으로 전 페이지 실시간 데이터 바인딩 지원. 6개 데이터 라우트를 `ƒ (Dynamic)`으로, 4개 프레임워크 라우트를 `○ (Static)`으로 분리. 기존 `content/*.ts` 정적 상수를 장애 시 그레이스풀 폴백 데이터셋으로 유지. E2E 테스트 게이트 2, 4, 7, 8을 라이브 서버 기반 검증으로 리팩터링. Job `258f6ff7` |
|