프로토타입 유지보수 (Prototype Maintenance)
이 스킬은 기존 프로토타입을 여러 차례의 제품 반복 과정에서 더 쉽게 수정할 수 있도록 만드는 데 사용합니다.
목표는 제품을 재설계하는 것이 아닙니다. 현재의 동작과 시각적 방향성을 유지하면서 유지보수성, 파일 소유권 명확성, 검증 속도를 개선합니다.
범위 및 인수인계
- 이 스킬은 기존 프로토타입의 지속적인 구조적 반복과 소유권 매핑에 사용하세요. 최초 정적 분할 또는 패키징에는 사용 가능한 경우
static-prototype-splitter를 사용하세요. 이는 필수 종속성이 아닙니다. - 소규모 복사, 레이아웃 또는 동작 요청에는 디렉토리 전체를 개편할 필요가 없습니다. 요청과 관련된 책임만 분할하세요.
- 기존 진입 파일명, 프레임워크, 스크립트 모델, 미리보기 워크플로우를 유지하세요. 아래
app.html레이아웃은 예시일 뿐, 이름 변경 요구사항이 아닙니다. - 파일 교체, 설정, 종속성, 네트워크 액세스, 로컬 서버, 저장된 데이터에 대한 사용자의 권한 규칙을 따르세요. 이 스킬이 해당 권한을 부여하지는 않습니다.
트리거 시점
사용자가 다음을 요청할 때 이 스킬을 트리거하세요:
- 추후 프로토타입 수정 속도 향상
- 페이지, 컴포넌트, 필드, 모달, 스토어 또는 데이터 레이어별로 JS 분할
- 기본, 레이아웃, 페이지, 컴포넌트, 모달, 필드 범위별로 CSS 분할
- 모의 데이터, 시드 데이터, 스키마, 상태/스토어 로직 분리
- 프로토타입 유지보수 README 생성 또는 업데이트
- 향후 요청을 파일에 매핑하는 CHANGE-MAP 생성 또는 업데이트
- 기존 인터랙티브 프로토타입 최적화 지속
- 결합 미리보기를 유지하면서 분할된 파일이 함께 유지보수 가능하도록 만들기
- 향후 프로토타입 변경이 이루어져야 할 위치 설명
기본 원칙
- 사용자의 언어와 프로토타입의 기존 용어를 따르세요.
- 편집 전에 현재 진입점과 활성 스크립트 참조를 읽으세요.
- 사용자가 재설계를 요청하지 않는 한 원래의 시각적 디자인과 상호작용 의도를 유지하세요.
- 명시적으로 요청되지 않는 한 모든 것을 프레임워크로 다시 작성하지 마세요.
- 두 번째로 분기된 구현을 피하세요. 결합 미리보기는 공유/분할된 모듈을 로드하거나 이들로부터 생성되어야 합니다.
- 변경 사항은 유지보수성과 요청된 제품 동작에 집중하세요.
- 새 파일이 단순히 추가되었다고 분할이 완료된 것이 아닙니다. 각 분할은 이전 파일의 책임을 줄여 향후 편집 시 하나의 명확한 소유자가 있어야 합니다.
- 관련 없는 변경 사항은 그대로 유지하고 원래 입력 및 대체된 파일을 보존하세요. 승인된 편집은 활성 구현에 집중하고, 레거시 파일을 삭제하거나 승인 없이 보호된 문서를 교체하지 마세요.
- 변경 후에는 실용적인 범위 내에서 구문과 주요 미리보기 상호작용을 검증하세요.
권장 구조
프로젝트에 맞게 이름을 조정하되, 정적 인터랙티브 프로토타입에는 다음 형태를 선호합니다:
prototype/
├── app.html
├── README-prototype.md
├── CHANGE-MAP.md
├── assets/
│ ├── css/
│ │ ├── base.css
│ │ ├── layout.css
│ │ ├── components.css
│ │ ├── modals.css
│ │ ├── fields.css
│ │ └── pages/
│ │ ├── home.css
│ │ ├── editor.css
│ │ └── fill.css
│ └── js/
│ └── app/
│ ├── core.js
│ ├── runtime.js
│ ├── pages/
│ ├── components/
│ ├── fields/
│ ├── modals/
│ ├── data/
│ ├── store/
│ └── utils/
└── pages/
└── ...
프로토타입 도메인이 다른 경우 동등한 이름을 사용하세요. 중요한 것은 책임 분할입니다.
소규모 프로토타입의 경우 더 평평한 구조도 괜찮습니다. 자주 변경되는 프로토타입의 경우 위의 디렉토리 구조를 선호하여 각 향후 요청이 소규모 파일에 매핑되도록 하세요.
레이어 책임
진입 레이어 (Entry Layer)
현재 결합 미리보기 진입점을 유지하세요. app.html은 아래 사용된 예시 이름입니다.
포함해야 할 내용:
- 장치 프레임 또는 미리보기 셸 (있는 경우)
- 루트 컨테이너
- CSS 링크
- 순서가 지정된 스크립트 참조
대부분의 비즈니스 로직을 포함해서는 안 됩니다.
페이지 레이어 (Page Layer)
페이지 렌더링 및 페이지별 레이아웃에 페이지 파일을 사용합니다:
- 홈/목록/검색/탭
- 편집기/생성/편집 페이지
- 작성/미리보기/제출/상세 페이지
- 로그인/등록/온보딩 페이지
- 설정/계정 페이지
사용자가 페이지 레이아웃이나 페이지 복사를 변경하도록 요청하면 여기서 시작합니다.
하나의 페이지 파일에 자주 편집되는 여러 하위 뷰가 포함된 경우 다시 분할합니다. 예:
pages/home/
├── index.js
├── search.js
├── my-forms.js
└── submitted.js
필드 또는 컴포넌트 레이어 (Field Or Component Layer)
반복되는 UI 블록에 필드/컴포넌트 파일을 사용합니다:
- 필드 유형 레이블
- 필드 기본값
- 편집기의 필드 미리보기
- 작성 페이지 컨트롤
- 업로드/이미지/파일/라디오/체크박스/OCR/날짜 렌더러
사용자가 하나의 요소 유형을 변경하도록 요청하면 전체 앱을 먼저 검색하지 마세요. 필드 구성 및 렌더러 파일부터 시작합니다.
프로토타입에 많은 폼 컨트롤이나 반복되는 카드가 있는 경우 레지스트리를 선호합니다:
fields/
├── registry.js
├── text.js
├── image.js
├── file.js
├── options.js
└── ocr.js
모달 레이어 (Modal Layer)
다음 항목에 모달 파일을 사용합니다:
- 필드 설정 시트
- 유형 선택기 시트
- 정렬 서랍
- 확인 대화상자
- 요소 추가 라이브러리 시트
가능하면 모달 상태를 로컬로 유지하고, 확인 작업 후에만 데이터를 커밋합니다.
데이터 레이어 (Data Layer)
데이터를 스토어 동작과 분리합니다.
data/를 사용하는 경우:
- 모의 템플릿
- 업종/카테고리 목록
- 필드 유형 정의
- 데모 사용자 및 예제
- 시드 레코드 및 픽스처
store/를 사용하는 경우:
- 로컬 스토리지 키
- 폼 저장/삭제/업데이트
- 제출 레코드 저장/삭제/업데이트
- 데이터 정규화 및 마이그레이션
프로토타입이 매우 작지 않은 이상 스토리지 규칙을 페이지 렌더러에 혼합하지 마세요.
기존 로컬 데이터가 이미 존재할 수 있는 경우 해당 키와 사용자 편집 내용을 보존하세요. 안정적인 ID로 누락된 시드 레코드만 추가하고 시딩이 멱등성을 가지도록 하세요. 편집된 레코드를 덮어쓰거나, 항목을 중복하거나, 다시 로드할 때 로컬 스토리지를 재설정하지 마세요. 스키마 마이그레이션은 별도의 승인된 작업으로 취급하고 문서화된 복구 경로를 제공하세요.
CSS 레이어 (CSS Layer)
단순히 크기가 아니라 소유권을 기준으로 CSS를 분할하세요:
base.css: 변수, 리셋, 타이포그래피layout.css: 셸, 장치 프레임, 페이지 컨테이너, 그리드 기본 요소components.css: 버튼, 입력, 카드, 탭, 칩modals.css: 시트, 서랍, 확인 대화상자, 토스트fields.css: 필드 컨트롤 및 폼 요소 미리보기pages/*.css: 페이지별 레이아웃 및 예외
선택자가 여러 페이지에서 재사용되는 경우 components 또는 fields에 유지합니다. 특정 페이지에 한정된 경우 해당 페이지 CSS로 이동합니다.
변경 맵 레이어 (Change Map Layer)
여러 차례의 편집이 예상되는 프로토타입에는 CHANGE-MAP.md를 추가합니다.
일반적인 사용자 요청을 파일에 직접 매핑해야 합니다:
# 변경 맵 (Change Map)
## 페이지 (Pages)
- 홈 페이지: assets/js/app/pages/home/index.js
- 템플릿 페이지: assets/js/app/pages/templates/index.js
- 폼 편집기: assets/js/app/pages/editor/index.js
## 필드 (Fields)
- 이미지 업로드 필드: assets/js/app/fields/image.js
- 파일 업로드 필드: assets/js/app/fields/file.js
- 라디오/체크박스 필드: assets/js/app/fields/options.js
## 모달 (Modals)
- 필드 설정 모달: assets/js/app/modals/field-settings.js
- 정렬 서랍: assets/js/app/modals/sort.js
## 데이터 (Data)
- 템플릿 데이터: assets/js/app/data/templates.js
- 업종 카테고리: assets/js/app/data/industries.js
## 스타일 (Styles)
- 템플릿 페이지 스타일: assets/css/pages/templates.css
- 필드 스타일: assets/css/fields.css
CHANGE-MAP을 간결하게 유지하세요. 제품 문서가 아닌 편집 인덱스입니다.
런타임 레이어 (Runtime Layer)
런타임 파일을 사용하는 경우:
- 라우터/렌더 디스패치
- 이벤트 위임
- 제스처 처리
- 액션 디스패치
- 부트스트래핑
런타임이 커지면 상호작용 유형별로 분할하되, 하나의 명확한 진입점을 유지하세요.
유지보수 README
요청 시 프로토타입 루트에 README-prototype.md를 추가하거나 업데이트합니다.
포함할 내용:
- 전체 미리보기 진입점
- 로컬 미리보기 URL 및 예약된 포트 (있는 경우)
- 페이지-파일 맵
- 필드/컴포넌트-파일 맵
- 모달-파일 맵
- 데이터 레이어 위치
- CSS 레이어 위치
- CHANGE-MAP 위치
- 변경 후 새로고침 및 검증 방법
- "업로드 이미지 필드 변경" 또는 "폼 제출 페이지 변경"과 같은 일반적인 향후 변경 예시
간결하고 유용하게 유지하세요. 프로토타입을 유지보수하는 사람을 위한 문서이지, 긴 개발 일기가 아닙니다.
워크플로우
-
활성 진입 파일 검사.
rg --files,grep및 대상 읽기 사용.- 결합 미리보기에서 실제로 로드된 스크립트 확인.
- 기존 분할 파일이 활성 상태라고 가정하지 마세요.
-
현재 소유권 식별.
- 페이지 렌더러.
- 필드 렌더러/구성.
- 모달/서랍.
- 스토어/데이터 헬퍼.
- 런타임/이벤트 핸들러.
-
신중하게 분할.
- 동작 보존이 중요할 때는 먼저 기계적 추출을 선호.
app.html에서 스크립트 로딩 순서를 명시적으로 유지.- 사용자가 동작 변경도 요청하지 않는 한 분할 중 동작 변경을 피함.
- 모듈을 추출한 후에는 이전 파일에서 해당 책임을 제거하거나 축소. 동일한 페이지, 컴포넌트, 모달, 데이터 세트 또는 CSS 선택자에 대해 두 개의 활성 소유자를 남기지 마세요.
- 사용자가 삭제를 확인하지 않는 한 레거시 결합 파일을 삭제하지 말고 사용되지 않은 상태로 둠.
- 기존의 클래식 스크립트 또는 ES 모듈 모델 유지. 함수 이동 후 로드 순서, 내보내기, 인라인 이벤트 핸들러 확인.
- 뷰 마운트/언마운트 책임을 명시적으로. 뷰를 떠날 때 사용하지 않는 리스너와 타이머를 제거하여 반복 탐색이 작업을 중복하지 않도록 함.
-
데이터가 증가할 때 데이터 분할.
- 큰 모의 데이터를 페이지 렌더러 및 스토어 파일 밖으로 이동.
- 시드 픽스처를 결정론적이고 스캔하기 쉽게 유지.
- 가능하면 새 시드 데이터를 기존 로컬 데이터에 병합.
- 데이터가
data/로 이동된 경우 스토어/상태 파일이 중복 활성 복사본을 유지하지 않고 해당 데이터를 소비하도록 함.
-
시각적 변경이 느려질 때 CSS 분할.
- base/layout/components/pages로 시작.
- 페이지 전용 선택자를 페이지 CSS로 이동.
- 재사용 가능한 컨트롤을 components 또는 fields CSS로 이동.
- 선택자를 이동한 후, 이전 전역 스타일시트에서 중복 활성 선택자를 제거. 단, 공유 컴포넌트 스타일로 의도적으로 유지하는 경우는 예외.
- 캐스케이드 순서와 반응형 중단점 유지.
url(...), 글꼴, 가져오기 경로를 새 파일 위치에 상대적으로 리베이스.
-
README 및 CHANGE-MAP 업데이트 또는 생성.
- 최종 활성 구조 문서화.
- 일반적인 향후 요청에 대해 편집할 파일을 명확히 함.
- 로컬 미리보기 URL, 예약된 포트, 캐시 무효화 지침이 관련된 경우 포함.
-
검증.
- 프로토타입이 실제로 소유한 JavaScript 파일을 재귀적으로 확인. 중첩된 페이지/컴포넌트 파일 포함. Python과 Node를 이미 사용할 수 있는 경우, 이 예시는
assets/js아래의.js,.mjs,.cjs를 확인합니다. 루트는 프로젝트에 맞게 조정하세요. 실행만을 위해 런타임을 설치하지 마세요.python3 - <<'PY_CHECK' from pathlib import Path import subprocess import sys root = Path("assets/js") files = sorted(p for p in root.rglob("*") if p.is_file() and p.suffix in {".js", ".mjs", ".cjs"} and not {"node_modules", "vendor", ".git"}.intersection(p.parts)) if not files: sys.exit("JavaScript 파일을 찾을 수 없습니다. 확인 루트를 검증하세요.") failed = False for path in files: failed |= subprocess.run(["node", "--check", str(path)]).returncode != 0 sys.exit(1 if failed else 0) PY_CHECK - 프레임워크 프로젝트 또는 다른 모듈 모드의 경우 기존 프로젝트 검사를 사용하세요. 구문 통과가 브라우저 동작을 증명하지는 않습니다.
- 결합 미리보기를 엽니다.
- 영향을 받는 동작을 기준선과 비교합니다. 앞으로/뒤로 탐색, 편집된 뷰 재방문, 모달 확인/취소, 해당되는 경우 새로고침 후 저장된 상태를 포함합니다.
- 실용적인 범위 내에서 브라우저 콘솔 오류를 확인합니다.
- 프로토타입이 실제로 소유한 JavaScript 파일을 재귀적으로 확인. 중첩된 페이지/컴포넌트 파일 포함. Python과 Node를 이미 사용할 수 있는 경우, 이 예시는
분할 세분화 규칙
과소 분할과 과잉 분할을 모두 방지하기 위해 다음 규칙을 사용합니다:
- 파일이 관련 없는 요청으로 반복 편집되는 경우 분할.
- 페이지에 독립적으로 변경되는 여러 하위 뷰가 포함된 경우 하위 뷰 분할.
- 모의 데이터가 주변 로직보다 더 많은 공간을 차지하는 경우
data/로 이동. - 여러 필드/컨트롤 유형이 독립적으로 변경될 때
fields/를 고려. 단순히 개수를 맞추기 위해 분할하지는 마세요. - 대화상자나 서랍에 별도의 상태 또는 유지보수 요구사항이 있을 때
modals/를 고려. - CSS 변경 시 큰 전역 스타일시트를 검색해야 하는 경우 페이지 및 컴포넌트별로 분할.
- 파일이 안정적이고 거의 편집되지 않는 경우 미관상 분할하지 마세요.
검증 도우미
정적 프로토타입의 경우 단순하고 종속성이 없는 검증을 선호합니다:
- JS 구문 확인에
node --check사용. - 캐시 무효화를 위해
app.html?t=20261109-153000과 같은 실제 값을 대체하세요. URL에 문자 그대로 입력된Date.now()는 고정 문자열입니다. HTML 쿼리 단독으로는 별도로 캐시된 JS/CSS를 새로고침하지 않으므로 필요 시 브라우저 캐시 제어 또는 기존 에셋 버전 관리 전략을 사용하세요. - 사용자가 포트를 선택한 경우 로컬 미리보기 포트를 안정적으로 유지.
- 구조적 리팩토링 후 브라우저에서 변경된 상호작용을 검증.
- 호환되는 정적 페이지의 경우 직접 파일 열기도 허용됩니다. 가져온 조각 및 브라우저 ES 모듈은 일반적으로 HTTP가 필요합니다. 열기 모드를 문서화하고 사용 가능한 기존 미리보기 서버를 재사용하세요. 새 서버를 시작하는 것은 사용자의 권한 규칙을 따릅니다.
응답 스타일
완료 시 사용자에게 다음을 알립니다:
- 분할되거나 문서화된 내용
- 활성 진입 파일
- 가장 중요한 새 파일 경로
- README-prototype.md 또는 CHANGE-MAP.md가 생성 또는 업데이트되었는지 여부
- 완료된 검증
- 의도적으로 그대로 둔 레거시 파일
최종 응답을 간결하고 실용적으로 유지합니다.