Local RAG MVP
퍼블리싱 가이드 챗봇
이렇게 검색해 보세요
문장으로 길게 묻기보다 핵심 용어를 넣으면 더 잘 찾습니다. 예: 이미지 alt, 색 대비, 모달 접근성, form label, 배포 체크리스트
질문 예시 모음
컴포넌트 질문
SCSS 질문
검사와 리뷰 질문
코드 검사
HTML 일부를 붙여넣거나 `.html` 파일을 선택해 접근성 기본 항목을 확인합니다.
배포 전 체크리스트
작업 흐름에 맞춰 기본 구조, 상호작용, 화면 품질, 검사 결과를 차례대로 확인합니다.
WORK TOOLS
바로 쓰는 작업 도구
페이지 유형별 체크리스트
작업 화면에 맞는 기본 검수 항목을 빠르게 생성합니다.
리뷰 메모
검토 내용을 전달하기 쉬운 요청 문장으로 정리합니다.
작업 시작 전
마크업 기본
폼과 입력
컴포넌트 상호작용
반응형과 화면 품질
검사 결과 재확인
기준 소스
자주 쓰는 HTML, CSS/SCSS, JS 기본 소스를 복사해서 시작점으로 사용할 수 있습니다.
HTML 기준
기본 HTML 구조
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>페이지 제목</title>
</head>
<body>
<header>...</header>
<main id="main">...</main>
<footer>...</footer>
</body>
</html>
접근 가능한 버튼
<button type="button">저장</button>
<button type="button" aria-label="닫기">
<span aria-hidden="true">×</span>
</button>
폼 label 연결
<label for="email">이메일</label>
<input id="email" name="email" type="email" autocomplete="email">
<p id="email-error" class="error-message">이메일 형식을 확인해 주세요.</p>
<input aria-describedby="email-error">
이미지 alt
<img src="event-banner.jpg" alt="여름 할인 이벤트 안내">
<img src="decor-line.svg" alt="">
CSS/SCSS 기준
스킵 링크와 sr-only
<a class="skip-link" href="#main">본문 바로가기</a>
.skip-link {
position: absolute;
left: 16px;
top: -48px;
}
.skip-link:focus {
top: 16px;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
}
컴포넌트 상태 클래스
.accordion {
border: 1px solid #dfe3e6;
}
.accordion.is-open .accordion__panel {
display: block;
}
.accordion__button:focus-visible {
outline: 3px solid #1a73e8;
outline-offset: 2px;
}
SCSS 변수와 breakpoint
$breakpoint-tablet: 768px;
$breakpoint-desktop: 1024px;
$color-focus: #1a73e8;
@mixin tablet {
@media (min-width: $breakpoint-tablet) {
@content;
}
}
.card {
padding: 16px;
@include tablet {
padding: 24px;
}
}
SCSS 폴더 구조
scss/
abstracts/
_variables.scss
_tokens.scss
_mixins.scss
_z-index.scss
base/
_font.scss
_root.scss
_reset.scss
_accessibility.scss
layout/
_common-inner.scss
_header.scss
_footer.scss
components/
_button.scss
_form.scss
_modal.scss
_popup.scss
_table.scss
templates/
_template-base.scss
_image-template.scss
_text-template.scss
_sub-page.scss
sections/
_visual.scss
_info.scss
_directions.scss
editor/
_design-edit-page.scss
_selection.scss
_design-util.scss
style.scss
SCSS 공통 mixin
$breakpoint-pc: 1024px;
@mixin pc {
@media screen and (min-width: $breakpoint-pc) {
@content;
}
}
@mixin public-mode {
html:not(.design-edit-page) & {
@content;
}
}
@mixin public-pc {
@include pc {
html:not(.design-edit-page) & {
@content;
}
}
}
@mixin editor-mode {
html.design-edit-page & {
@content;
}
}
SCSS mixin 모음
@mixin font-style(
$size,
$weight: 400,
$line-height: 1.5,
$letter-spacing: 0,
$color: null
) {
font-size: $size;
font-weight: $weight;
line-height: $line-height;
letter-spacing: $letter-spacing;
@if $color != null {
color: $color;
}
}
@mixin position($position: absolute, $top: null, $right: null, $bottom: null, $left: null) {
position: $position;
@if $top != null { top: $top; }
@if $right != null { right: $right; }
@if $bottom != null { bottom: $bottom; }
@if $left != null { left: $left; }
}
@mixin center-x($position: absolute) {
position: $position;
left: 50%;
transform: translateX(-50%);
}
@mixin center-y($position: absolute) {
position: $position;
top: 50%;
transform: translateY(-50%);
}
@mixin center($position: absolute) {
position: $position;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
@mixin flex($direction: null, $justify: null, $align: null, $gap: null) {
display: flex;
@if $direction != null { flex-direction: $direction; }
@if $justify != null { justify-content: $justify; }
@if $align != null { align-items: $align; }
@if $gap != null { gap: $gap; }
}
@mixin bg-image($url, $size: cover, $position: center) {
background-image: url($url);
background-repeat: no-repeat;
background-position: $position;
background-size: $size;
}
@mixin reset-list {
margin: 0;
padding: 0;
list-style: none;
}
@mixin ellipsis($lines: 1) {
overflow: hidden;
text-overflow: ellipsis;
@if $lines == 1 {
white-space: nowrap;
} @else {
display: -webkit-box;
-webkit-line-clamp: $lines;
-webkit-box-orient: vertical;
}
}
@mixin size($width, $height: $width) {
width: $width;
height: $height;
}
SCSS 실무 mixin 예시
@use 'sass:math';
@function strip-unit($value) {
@if type-of($value) == 'number' and not unitless($value) {
@return math.div($value, $value * 0 + 1);
}
@return $value;
}
$breakpoints: (
mobile: 480px,
tablet: 768px,
desktop: 1024px,
wide: 1280px
);
@mixin respond-to($name) {
$width: map-get($breakpoints, $name);
@if $width == null {
@error 'Unknown breakpoint: #{$name}';
}
@media (min-width: $width) {
@content;
}
}
@mixin fluid-type($min-size, $max-size, $min-vw: 360px, $max-vw: 1200px) {
font-size: clamp(
$min-size,
calc(#{$min-size} + (#{strip-unit($max-size)} - #{strip-unit($min-size)}) * ((100vw - #{$min-vw}) / (#{strip-unit($max-vw)} - #{strip-unit($min-vw)}))),
$max-size
);
}
@mixin aspect-ratio-box($width, $height) {
aspect-ratio: #{$width} / #{$height};
@supports not (aspect-ratio: 1 / 1) {
position: relative;
&::before {
content: '';
display: block;
padding-top: calc($height / $width * 100%);
}
> * {
position: absolute;
inset: 0;
}
}
}
@mixin absolute-fill {
position: absolute;
inset: 0;
}
@mixin hover-supported {
@media (hover: hover) and (pointer: fine) {
@content;
}
}
@mixin reduced-motion {
@media (prefers-reduced-motion: reduce) {
@content;
}
}
@mixin touch-target($size: 44px) {
min-width: $size;
min-height: $size;
}
SCSS 접근성 유틸
$color-focus: #1a73e8;
@mixin focus-ring {
outline: 3px solid $color-focus;
outline-offset: 2px;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
}
.skip-link {
position: absolute;
left: 16px;
top: -48px;
z-index: 1000;
&:focus {
top: 16px;
@include focus-ring;
}
}
SCSS 컴포넌트 예시
.accordion {
border: 1px solid $color-border;
&__button {
width: 100%;
min-height: 44px;
text-align: left;
&:focus-visible {
@include focus-ring;
}
}
&__panel {
padding: 16px;
}
&:not(.is-open) &__panel {
display: none;
}
&.is-open &__button {
font-weight: 700;
}
}
SCSS style.scss 조립
@use 'abstracts/variables';
@use 'abstracts/tokens';
@use 'abstracts/mixins';
@use 'base/font';
@use 'base/root';
@use 'base/reset';
@use 'base/accessibility';
@use 'layout/common-inner';
@use 'layout/header';
@use 'layout/footer';
@use 'components/button';
@use 'components/form';
@use 'components/modal';
@use 'components/popup';
@use 'templates/template-base';
@use 'sections/visual';
@use 'sections/info';
@use 'editor/design-edit-page';
JS 기준
모달 포커스 복귀
const openButton = document.querySelector('[data-modal-open]');
const closeButton = document.querySelector('[data-modal-close]');
const modal = document.querySelector('[data-modal]');
let lastFocusedElement = null;
function openModal() {
lastFocusedElement = document.activeElement;
modal.hidden = false;
closeButton.focus();
}
function closeModal() {
modal.hidden = true;
lastFocusedElement?.focus();
}
openButton.addEventListener('click', openModal);
closeButton.addEventListener('click', closeModal);
aria-expanded 토글
const button = document.querySelector('[data-toggle-button]');
const panel = document.querySelector('[data-toggle-panel]');
button.addEventListener('click', () => {
const isOpen = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', String(!isOpen));
panel.hidden = isOpen;
});
사용법
실행 방법
PowerShell에서 프로젝트 폴더로 이동한 뒤 서버를 실행합니다.
cd "C:\Users\User\Documents\New project"
& 'C:\Users\User\.cache\codex-runtimes\codex-primary-runtime\dependencies\node\bin\node.exe' server.js
브라우저에서 http://localhost:3000을 엽니다. 서버를 끄려면 PowerShell에서 Ctrl + C를 누릅니다.
작업 흐름
- 작업 시작 전에는 체크리스트 탭에서 확인할 기준을 먼저 봅니다.
- 구현 중 헷갈리는 규칙은 가이드 질문 탭에서 짧은 핵심어로 검색합니다.
- 마크업을 작성한 뒤 코드 검사 탭에 HTML을 붙여넣거나 파일을 선택합니다.
- 검사 결과의 가이드 보기 버튼으로 관련 규칙을 다시 확인합니다.
- 마무리 전에 체크리스트 탭으로 돌아와 누락된 항목을 점검합니다.
바로 적용할 기준
참고자료를 열기 전에 회사 지침의 기본값으로 먼저 적용할 규칙입니다.
- 접근성: WCAG 2.2 AA를 기본 목표로 둡니다.
- ARIA: 기본 HTML로 해결되면 ARIA를 추가하지 않습니다.
- 컴포넌트: 모달, 탭, 아코디언, 드롭다운은 WAI-ARIA APG의 키보드 패턴을 먼저 확인합니다.
- HTML: `a`는 이동, `button`은 실행에 사용하고 클릭 가능한 `div`, `span`은 만들지 않습니다.
- 폼: 폼 오류는 label, 설명, 오류 메시지를 함께 연결합니다.
- SCSS: SCSS nesting은 3단계 이하로 제한합니다.
- 리뷰: 자동 검사에서 오류가 없어도 색 대비, 포커스 이동, 키보드 조작은 수동 확인합니다.
필수 참고자료
회사 지침을 만들거나 퍼블리싱 중 판단이 필요할 때 먼저 확인할 자료입니다.
WCAG 2.2
접근성 최종 기준. 색 대비, 키보드, 오류 메시지, 포커스 기준을 정할 때 봅니다.
WAI-ARIA APG
모달, 탭, 아코디언, 드롭다운의 ARIA와 키보드 패턴을 확인합니다.
MDN Web Docs
HTML, CSS, JS 속성의 기본 의미와 사용법을 확인합니다.
NHN TOAST UI FE Guide
HTML/CSS/Sass 코딩 컨벤션, SCSS nesting, class 작성 기준을 잡을 때 봅니다.
GOV.UK Design System
폼, 오류 메시지, 버튼, 테이블 같은 기본 UI 기준을 만들 때 참고합니다.
GitHub Primer
Dialog, Tooltip, FormControl, Pagination, TreeView 같은 개발자/관리자 UI를 참고합니다.
TOAST UI Components
Grid, Date Picker, Pagination, Select Box, Tree 같은 업무용 컴포넌트 기준을 볼 때 씁니다.
NAVER egjs
캐러셀, 무한 스크롤, 터치/마우스 상호작용 기준을 만들 때 참고합니다.
검색 팁
긴 문장보다 핵심어가 잘 잡힙니다.
이미지 alt색 대비모달 접근성form label폼 오류 메시지button link 구분배포 전 접근성 체크리스트
챗봇 질문 예시
아래처럼 핵심어와 목적을 함께 넣으면 답을 더 잘 찾습니다.
SCSS 파일은 어떻게 나누면 좋아?모달 접근성에서 확인할 것은 뭐야?드롭다운은 어떻게 마크업해?검사 결과는 어떻게 다시 확인해?회사 CSS 분석 내용 보여줘
검색이 안 될 때
질문을 더 짧게 바꾸거나, 문서에 해당 내용이 있는지 확인합니다. 표현만 다른 경우에는 src/search.js의 동의어 목록에 추가하면 됩니다.
문서 추가 위치
챗봇 답변은 docs/guide/ 안의 Markdown 문서에서 나옵니다. 프로젝트 규칙이 생기면 이 폴더의 문서를 먼저 수정하세요.