- 로그인/회원가입/아이디찾기/비밀번호재설정 (세션 기반) - 대시보드(주차별 진도 체크리스트), 학습 문서 뷰어(17종), 과제 제출/멘토 피드백 - 코딩 기초·개발 환경 설치 가이드 학습 페이지 - 전 소스 한국어 학습 주석 — 수습생 교육용 저장소 - Docker 배포 구성 (Caddy + Spring Boot + PG + Gitea) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
443 lines
40 KiB
HTML
443 lines
40 KiB
HTML
<title>수습용 실전 티켓 풀 20 · AWESOMEDEV</title>
|
|
<style>
|
|
:root {
|
|
--paper: #FAFBFD; --card: #FFFFFF; --ink: #101A28; --ink-soft: #46536A;
|
|
--ink-faint: #7B8798; --line: #E4E8F0; --line-soft: #EFF2F7;
|
|
--primary: #2159C5; --primary-soft: #E5EDFB; --primary-deep: #163F8F;
|
|
--amber: #B9772A; --amber-soft: #F6EBDA; --amber-line: #E4C79A;
|
|
--teal: #0E8C86; --teal-soft: #E0F1EF;
|
|
--rose: #B4463C; --rose-soft: #F7E7E4;
|
|
--code-bg: #F1F4F9;
|
|
--shadow: 0 1px 2px rgba(16,26,40,.05), 0 8px 24px -12px rgba(16,26,40,.16);
|
|
--radius: 14px;
|
|
}
|
|
@media (prefers-color-scheme: dark) {
|
|
:root {
|
|
--paper: #0B1017; --card: #131A24; --ink: #E8EDF4; --ink-soft: #A4B0C0;
|
|
--ink-faint: #74808F; --line: #263140; --line-soft: #1C242F;
|
|
--primary: #6AA0F0; --primary-soft: #172A44; --primary-deep: #AECBF8;
|
|
--amber: #DBA25C; --amber-soft: #2C2318; --amber-line: #4A3B23;
|
|
--teal: #4FC7BE; --teal-soft: #14302E; --rose: #E08A80; --rose-soft: #331E1B;
|
|
--code-bg: #161E28;
|
|
--shadow: 0 1px 2px rgba(0,0,0,.35), 0 10px 30px -14px rgba(0,0,0,.65);
|
|
}
|
|
}
|
|
:root[data-theme="light"] {
|
|
--paper: #FAFBFD; --card: #FFFFFF; --ink: #101A28; --ink-soft: #46536A;
|
|
--ink-faint: #7B8798; --line: #E4E8F0; --line-soft: #EFF2F7;
|
|
--primary: #2159C5; --primary-soft: #E5EDFB; --primary-deep: #163F8F;
|
|
--amber: #B9772A; --amber-soft: #F6EBDA; --amber-line: #E4C79A;
|
|
--teal: #0E8C86; --teal-soft: #E0F1EF; --rose: #B4463C; --rose-soft: #F7E7E4;
|
|
--code-bg: #F1F4F9;
|
|
--shadow: 0 1px 2px rgba(16,26,40,.05), 0 8px 24px -12px rgba(16,26,40,.16);
|
|
}
|
|
:root[data-theme="dark"] {
|
|
--paper: #0B1017; --card: #131A24; --ink: #E8EDF4; --ink-soft: #A4B0C0;
|
|
--ink-faint: #74808F; --line: #263140; --line-soft: #1C242F;
|
|
--primary: #6AA0F0; --primary-soft: #172A44; --primary-deep: #AECBF8;
|
|
--amber: #DBA25C; --amber-soft: #2C2318; --amber-line: #4A3B23;
|
|
--teal: #4FC7BE; --teal-soft: #14302E; --rose: #E08A80; --rose-soft: #331E1B;
|
|
--code-bg: #161E28;
|
|
--shadow: 0 1px 2px rgba(0,0,0,.35), 0 10px 30px -14px rgba(0,0,0,.65);
|
|
}
|
|
* { box-sizing: border-box; }
|
|
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
|
|
body { margin: 0; background: var(--paper); color: var(--ink);
|
|
font-family: "Pretendard","Apple SD Gothic Neo","Malgun Gothic","Noto Sans KR",system-ui,sans-serif;
|
|
line-height: 1.7; -webkit-font-smoothing: antialiased; letter-spacing: -0.01em; }
|
|
.wrap { max-width: 880px; margin: 0 auto; padding: clamp(20px,4vw,48px); }
|
|
.eyebrow { font-size: 12px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--primary); display: flex; align-items: center; gap: 10px; }
|
|
.eyebrow::before { content:""; width: 22px; height: 2px; background: currentColor; border-radius: 2px; }
|
|
header.mast { border: 1px solid var(--line); border-radius: var(--radius);
|
|
background: radial-gradient(120% 140% at 100% 0%, var(--primary-soft) 0%, transparent 55%), var(--card);
|
|
box-shadow: var(--shadow); padding: clamp(26px,4vw,42px); }
|
|
.wordmark { font-size: 13px; font-weight: 800; letter-spacing: 0.22em; text-transform: uppercase; color: var(--ink-soft); }
|
|
.wordmark b { color: var(--primary); }
|
|
header.mast h1 { font-size: clamp(27px,5.4vw,40px); line-height: 1.15; margin: 16px 0 0; font-weight: 800; letter-spacing: -0.03em; text-wrap: balance; }
|
|
header.mast .lede { margin: 16px 0 0; font-size: clamp(15px,2.4vw,17px); color: var(--ink-soft); max-width: 58ch; }
|
|
.mast-meta { margin-top: 22px; display: flex; flex-wrap: wrap; gap: 10px; }
|
|
.chip { font-size: 13px; font-weight: 600; color: var(--ink-soft); background: var(--paper); border: 1px solid var(--line); padding: 6px 12px; border-radius: 999px; display: inline-flex; align-items: center; gap: 7px; }
|
|
.chip .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--primary); }
|
|
section { margin-top: clamp(30px,5vw,46px); scroll-margin-top: 20px; }
|
|
section > h2 { font-size: clamp(20px,3.4vw,25px); font-weight: 800; letter-spacing: -0.025em; margin: 12px 0 0; text-wrap: balance; }
|
|
section > .sub { color: var(--ink-soft); margin: 9px 0 0; font-size: 15px; max-width: 64ch; }
|
|
.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); padding: clamp(18px,3vw,26px); }
|
|
.mt { margin-top: 16px; }
|
|
p { margin: 0; } strong { font-weight: 700; }
|
|
|
|
/* criteria */
|
|
.crit { display: grid; gap: 12px; }
|
|
.crit li { list-style: none; display: grid; grid-template-columns: 26px 1fr; gap: 12px; font-size: 14.5px; color: var(--ink-soft); }
|
|
.crit .n { width: 22px; height: 22px; border-radius: 6px; background: var(--primary); color: #fff; font-weight: 800; font-size: 12px; display: grid; place-items: center; margin-top: 3px; }
|
|
@media (prefers-color-scheme: dark){ .crit .n { color:#0B1017; } }
|
|
:root[data-theme="dark"] .crit .n { color:#0B1017; }
|
|
.crit b { color: var(--ink); font-weight: 700; }
|
|
.nono { border: 1px solid color-mix(in srgb,var(--rose) 30%,transparent); background: var(--rose-soft); border-radius: 10px; padding: 13px 16px; margin-top: 14px; }
|
|
.nono p { font-size: 13.5px; color: var(--ink-soft); } .nono b { color: var(--rose); }
|
|
|
|
/* category divider */
|
|
.cat-div { margin-top: clamp(36px,6vw,52px); display: grid; grid-template-columns: auto 1fr; gap: 18px; align-items: center; }
|
|
.cat-badge { width: 58px; height: 58px; border-radius: 14px; background: var(--primary); color: #fff; display: grid; place-items: center; font-size: 24px; box-shadow: var(--shadow); }
|
|
@media (prefers-color-scheme: dark){ .cat-badge { color:#0B1017; } }
|
|
:root[data-theme="dark"] .cat-badge { color:#0B1017; }
|
|
.cat-badge.be { background: var(--teal); } .cat-badge.q { background: var(--amber); } .cat-badge.dz { background: var(--rose); }
|
|
.cat-div h2 { margin: 0; font-size: clamp(21px,3.6vw,27px); font-weight: 800; letter-spacing: -0.025em; }
|
|
.cat-div .dm { margin-top: 3px; color: var(--ink-soft); font-size: 14px; }
|
|
|
|
/* ticket card */
|
|
.ticket { margin-top: 16px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--card); box-shadow: var(--shadow); overflow: hidden; }
|
|
.tk-head { padding: 14px 20px; border-bottom: 1px solid var(--line-soft); background: var(--primary-soft); display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
|
|
.tk-head .id { font-size: 11px; font-weight: 800; letter-spacing: 0.06em; color: var(--primary); font-variant-numeric: tabular-nums; }
|
|
.tk-head h3 { margin: 3px 0 0; font-size: 16.5px; font-weight: 800; letter-spacing: -0.015em; }
|
|
.tk-meta { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
|
|
.diff { font-size: 12px; font-weight: 800; padding: 4px 11px; border-radius: 999px; white-space: nowrap; }
|
|
.diff.d1 { color: var(--teal); background: var(--teal-soft); }
|
|
.diff.d2 { color: var(--amber); background: var(--amber-soft); }
|
|
.dur { font-size: 12px; font-weight: 700; color: var(--ink-faint); white-space: nowrap; }
|
|
.tk-body { padding: 16px 20px; display: grid; gap: 12px; }
|
|
.tk-body .row { display: grid; grid-template-columns: 86px 1fr; gap: 12px; align-items: start; font-size: 14px; }
|
|
.tk-body .row .lab { font-size: 11px; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase; padding-top: 3px; }
|
|
.row.what .lab { color: var(--primary); } .row.find .lab { color: var(--teal); }
|
|
.row.dod .lab { color: var(--amber); } .row.prep .lab { color: var(--ink-faint); }
|
|
.tk-body .row .txt { color: var(--ink-soft); } .tk-body .row .txt b { color: var(--ink); font-weight: 600; }
|
|
|
|
/* form template */
|
|
.tpl { border: 1px solid var(--amber-line); background: var(--code-bg); border-radius: 10px; overflow: hidden; }
|
|
.tpl .cap { font-size: 11.5px; font-weight: 800; letter-spacing: 0.04em; color: var(--amber); background: var(--amber-soft); padding: 7px 15px; border-bottom: 1px solid var(--amber-line); text-transform: uppercase; }
|
|
.tpl pre { margin: 0; padding: 14px 16px; font-family: "SF Mono","Cascadia Code","Consolas",ui-monospace,monospace; font-size: 13px; line-height: 1.7; color: var(--ink); white-space: pre-wrap; word-break: break-word; letter-spacing: 0; }
|
|
.tpl .hl { color: var(--primary); font-weight: 600; }
|
|
|
|
/* tracker */
|
|
.tblwrap { overflow-x: auto; margin-top: 16px; border: 1px solid var(--line); border-radius: 12px; }
|
|
table { width: 100%; border-collapse: collapse; font-size: 13.5px; min-width: 560px; }
|
|
th, td { text-align: left; padding: 11px 13px; border-bottom: 1px solid var(--line-soft); }
|
|
thead th { font-size: 11.5px; letter-spacing: 0.03em; text-transform: uppercase; color: var(--ink-faint); background: var(--paper); white-space: nowrap; }
|
|
tbody tr:last-child td { border-bottom: 0; }
|
|
td .fill { display: inline-block; min-width: 70px; border-bottom: 1.5px dashed var(--line); }
|
|
td.num { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--primary); white-space: nowrap; }
|
|
|
|
footer { margin-top: 46px; padding-top: 22px; border-top: 1px solid var(--line); color: var(--ink-faint); font-size: 13px; display: flex; justify-content: space-between; flex-wrap: wrap; gap: 8px; }
|
|
@media (max-width:560px){ .tk-body .row { grid-template-columns: 70px 1fr; gap: 8px; } }
|
|
@media print { body{background:#fff;} .card,header.mast,.ticket,.cat-badge{box-shadow:none;} .ticket{break-inside:avoid;} td .fill{border-color:#999;} }
|
|
</style>
|
|
|
|
<div class="wrap">
|
|
|
|
<header class="mast">
|
|
<div class="wordmark"><b>AWESOMEDEV</b> · 수습 실전 티켓 풀</div>
|
|
<h1>실전 티켓 풀 20<br>템플릿 & 아이디어 카탈로그</h1>
|
|
<p class="lede">5~6주차에 수습생에게 줄 실전 티켓을 미리 준비하는 문서예요. 아래 20개는 <strong>어떤 프로젝트에나 있는 안전한 티켓 패턴</strong>이고, 각 패턴마다 "우리 프로젝트에서 찾는 법"이 붙어 있어요. 멘토가 실제 코드에서 해당 건을 찾아 뒤쪽 양식으로 구체화하면 티켓 풀이 완성됩니다.</p>
|
|
<div class="mast-meta">
|
|
<span class="chip"><span class="dot"></span>프론트 7 · 백엔드 6 · 품질 4 · 디자인 3</span>
|
|
<span class="chip"><span class="dot"></span>난이도 ★(반나절~1일) · ★★(2~3일)</span>
|
|
<span class="chip"><span class="dot"></span>멘토용 · D-7까지 구체화</span>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Selection criteria -->
|
|
<section id="criteria">
|
|
<div class="eyebrow">티켓 고르는 기준</div>
|
|
<h2>수습용 티켓의 4가지 조건</h2>
|
|
<div class="card mt">
|
|
<ul class="crit" style="margin:0;padding:0;">
|
|
<li><span class="n">1</span><div><b>망가뜨려도 복구 쉬운 것.</b> 롤백 가능하고, 스테이징에서 검증 가능하고, 결제·인증·개인정보 같은 민감 영역이 아닐 것.</div></li>
|
|
<li><span class="n">2</span><div><b>범위가 한 문장으로 설명되는 것.</b> "이 화면의 이 부분을 이렇게" — 파일 3~4개 이내로 끝나는 크기. 아키텍처를 이해해야만 하는 건 아직 아님.</div></li>
|
|
<li><span class="n">3</span><div><b>완료 조건(DoD)을 명확히 쓸 수 있는 것.</b> "되면 이렇게 보인다/동작한다"를 미리 적을 수 없으면 수습용이 아님.</div></li>
|
|
<li><span class="n">4</span><div><b>실제로 가치 있는 것.</b> 연습용 가짜 일이 아니라, 머지되면 정말 제품이 나아지는 일. (이게 동기부여의 핵심이에요)</div></li>
|
|
</ul>
|
|
<div class="nono">
|
|
<p><b>주지 말 것:</b> 운영 DB 마이그레이션 · 인증/권한 로직 · 결제 · 배포 설정 · 고객사 SLA가 걸린 긴급 건 · "리팩터링 알아서" 같은 범위 무한 티켓.</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- FRONTEND -->
|
|
<div class="cat-div" id="fe">
|
|
<div class="cat-badge">🖥️</div>
|
|
<div><h2>프론트엔드 (React) — 7개</h2><div class="dm">화면에서 보이는 것부터. 결과가 눈에 보여서 첫 실전에 가장 좋아요.</div></div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">FE-01</div><h3>빈 상태(Empty State) 화면 추가</h3></div><div class="tk-meta"><span class="diff d1">★</span><span class="dur">0.5~1일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">데이터가 없을 때 휑하게 비는 목록/테이블에 "아직 항목이 없어요 + 안내 문구/버튼"을 보여주기.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">각 화면에서 데이터 0건으로 조회해 보기. <code>.map()</code> 돌리는 목록 중 <b>length가 0일 때 분기가 없는 곳</b>이 후보.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">0건일 때 지정된 문구·아이콘 노출, 1건 이상이면 기존과 동일, 스크린샷 첨부된 PR.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">대상 화면 지정, 문구 확정(디자이너 수습생과 협업시키면 좋음).</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">FE-02</div><h3>로딩 표시(스피너/스켈레톤) 추가</h3></div><div class="tk-meta"><span class="diff d1">★</span><span class="dur">0.5~1일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">API 응답을 기다리는 동안 아무것도 안 보이는 화면에 로딩 상태 표시 넣기.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">네트워크를 느리게(개발자도구 throttling) 하고 화면 이동 — <b>흰 화면이나 깜빡임이 보이는 곳</b>이 후보.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">로딩 중 표시 노출, 로드 완료 시 자연스럽게 교체, 에러 시 로딩이 무한히 남지 않음.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">기존 공용 로딩 컴포넌트가 있으면 알려주기(새로 만들지 재사용할지).</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">FE-03</div><h3>폼 입력 유효성 검사 보강</h3></div><div class="tk-meta"><span class="diff d1">★</span><span class="dur">1일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">빈 값·형식 오류를 제출 후에야 알려주는 폼에, 입력 시점 안내 메시지 추가(예: 이메일 형식, 필수값).</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">각 폼에 일부러 빈 값/이상한 값 넣고 제출해 보기 — <b>서버 에러로만 알게 되는 폼</b>이 후보.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">정의된 규칙별 에러 문구 노출, 통과 시 정상 제출, 에러 문구는 한국어로 친절하게.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">검사 규칙 목록 확정(무엇을 필수로, 어떤 형식으로).</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">FE-04</div><h3>목록 정렬/필터 옵션 추가</h3></div><div class="tk-meta"><span class="diff d2">★★</span><span class="dur">2일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">있는 목록 화면에 정렬(최신순/이름순) 또는 필터(상태별) 드롭다운 1개 추가.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">운영/관리 화면 중 <b>항목이 20개 이상 쌓이는 목록</b>에서 사용자가 스크롤로만 찾는 곳.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">옵션 변경 시 목록 갱신, 새로고침해도 기본값 정상, 기존 기능 회귀 없음.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">정렬/필터 기준 확정, 서버 쿼리 지원 여부 확인(클라이언트 정렬로 충분한지).</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">FE-05</div><h3>에러 화면/토스트 메시지 개선</h3></div><div class="tk-meta"><span class="diff d1">★</span><span class="dur">0.5~1일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">"Error" 또는 영문 원문이 그대로 뜨는 실패 메시지를, 사용자가 이해할 한국어 안내로 교체.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">서버 꺼두고/네트워크 끊고 주요 동작 실행 — <b>알 수 없는 문구가 뜨는 곳</b> 수집.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">실패 상황별 지정 문구 노출, 콘솔 에러는 유지(디버깅용), 문구 목록 문서화.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">상황별 문구 톤 가이드 한 줄(사과·원인·해결 순).</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">FE-06</div><h3>모바일 화면 깨짐 수정</h3></div><div class="tk-meta"><span class="diff d2">★★</span><span class="dur">1~2일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">좁은 화면에서 넘치거나 겹치는 요소(테이블·버튼 줄바꿈 등) 1~2군데 반응형 수정.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">개발자도구 모바일 뷰(375px)로 주요 화면 전부 훑기 — <b>가로 스크롤 생기는 곳</b>이 후보.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">375px·768px·데스크톱 3구간 스크린샷 첨부, 기존 데스크톱 레이아웃 변화 없음.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">깨지는 화면 목록 미리 수집(학생이 찾는 것부터 시키면 반나절 추가).</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">FE-07</div><h3>공통 컴포넌트로 중복 UI 정리</h3></div><div class="tk-meta"><span class="diff d2">★★</span><span class="dur">2~3일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">거의 똑같은 버튼/카드/모달이 여러 파일에 복붙돼 있는 것을 컴포넌트 1개로 추출해 교체.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">비슷한 JSX 덩어리를 검색(클래스명·문구로 grep) — <b>3곳 이상 반복되는 블록</b>이 후보.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">추출한 컴포넌트 1개 + 기존 사용처 전부 교체, 화면 픽셀 변화 없음(전후 스크린샷).</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">대상 지정 필수(범위 폭주 방지). props 설계는 착수 계획서에서 함께 리뷰.</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- BACKEND -->
|
|
<div class="cat-div" id="be">
|
|
<div class="cat-badge be">⚙️</div>
|
|
<div><h2>백엔드 (Spring Boot) — 6개</h2><div class="dm">서버 쪽 안전 지대. 응답·검증·로그처럼 되돌리기 쉬운 것 위주.</div></div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">BE-01</div><h3>API 응답에 필드 1개 추가</h3></div><div class="tk-meta"><span class="diff d1">★</span><span class="dur">1일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">화면에서 필요해진 값(예: 등록일, 개수, 상태명)을 기존 조회 API 응답에 추가하고 프론트 반영까지.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">프론트에서 <b>두 번 요청해서 조합하거나, 하드코딩으로 때운 값</b>이 있는 화면의 API가 후보.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">응답 DTO에 필드 추가, 기존 호출부 회귀 없음, 화면에 값 표시, API 문서/주석 갱신.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">추가할 필드와 출처(어느 테이블/계산) 지정.</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">BE-02</div><h3>요청 검증(Validation) 보강</h3></div><div class="tk-meta"><span class="diff d1">★</span><span class="dur">1일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">이상한 값(음수, 빈 문자열, 초과 길이)이 들어와도 500으로 터지는 API에 검증 어노테이션과 400 응답 추가.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">등록/수정 API에 일부러 이상한 값 보내 보기 — <b>500이 뜨는 곳</b>이 후보.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">정의된 규칙 위반 시 400 + 명확한 메시지, 정상 값은 기존대로, 테스트 1개 추가.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">검증 규칙 표(필드·규칙·에러 메시지) 초안.</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">BE-03</div><h3>에러 로그 메시지 개선</h3></div><div class="tk-meta"><span class="diff d1">★</span><span class="dur">0.5~1일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">"error occurred" 수준의 로그에 무엇이/어떤 값으로/왜 실패했는지 문맥 추가 (단, 개인정보는 제외).</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">최근 장애/문의 때 <b>로그 보고도 원인을 몰랐던 지점</b>을 선임에게 물어 수집.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">지정 지점 로그에 식별자·원인 포함, 개인정보(전화번호 등) 마스킹 확인.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">개인정보 로깅 금지 규칙 브리핑(이 티켓이 보안 교육 기회).</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">BE-04</div><h3>조회 API 신규 작성 (단순 CRUD의 R)</h3></div><div class="tk-meta"><span class="diff d2">★★</span><span class="dur">2~3일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">기존 테이블에서 조건으로 조회하는 GET API 1개를 컨트롤러→서비스→리포지토리 계층대로 신규 작성.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">관리/통계 화면에서 <b>"이 목록도 보고 싶다"고 미뤄둔 요구</b>가 후보 (신규 화면과 세트로 주면 FE 수습생과 협업 티켓이 됨).</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">API 동작(페이징 포함 여부 명시), 계층 구조 준수, 테스트 1개, API 명세 공유.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">대상 테이블·조건·응답 형태 스펙 한 장. 참고할 기존 유사 API 지정.</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">BE-05</div><h3>매직 넘버/하드코딩 값 설정으로 추출</h3></div><div class="tk-meta"><span class="diff d1">★</span><span class="dur">1일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">코드에 박힌 숫자·문자열(페이지 크기, 제한 횟수, 안내 문구)을 상수/설정 파일로 추출.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">서비스 코드에서 <b>의미를 알 수 없는 숫자 리터럴</b> grep — 선임이 "이건 바뀔 수 있는 값"이라고 확인해준 것만.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">동작 변화 없음(값 동일), 상수 이름이 의미를 설명, 어디서 왜 쓰는지 주석.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">추출 대상 목록 지정(전체 수색은 범위 폭주).</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">BE-06</div><h3>느린 조회 1건 개선 (N+1 / 불필요 조회 제거)</h3></div><div class="tk-meta"><span class="diff d2">★★</span><span class="dur">2~3일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">목록 조회 시 항목마다 추가 쿼리가 나가는 지점 1개를 한 번에 가져오도록 개선.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">쿼리 로그 켜고 목록 화면 열기 — <b>같은 모양 쿼리가 수십 번 반복</b>되는 곳이 후보.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">쿼리 수 전/후 비교 기록(예: 51→2), 결과 데이터 동일함 검증, 개선 설명 PR에 작성.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">대상 지점 확정 필수. JPA 페치 전략을 함께 리뷰(혼자 두면 위험한 티켓).</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- QUALITY -->
|
|
<div class="cat-div" id="q">
|
|
<div class="cat-badge q">🧪</div>
|
|
<div><h2>품질 · 테스트 · 문서 — 4개</h2><div class="dm">티가 덜 나지만 팀이 정말 고마워하는 일. 코드 이해 훈련으로도 최고예요.</div></div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">QA-01</div><h3>버그 재현 → 수정 → 회귀 테스트</h3></div><div class="tk-meta"><span class="diff d2">★★</span><span class="dur">2~3일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">알려진 경미한 버그 1개를 재현 절차 문서화 → 원인 찾아 수정 → 재발 방지 테스트 추가.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">이슈 트래커/메모에 쌓인 <b>"급하지 않은 버그"</b> 목록에서 데이터 파손 위험 없는 것.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">재현 절차 문서, 수정 PR, 실패했다가 통과하는 테스트 1개.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">버그 후보 2~3개 골라두기(1개는 막힐 경우의 교체용).</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">QA-02</div><h3>핵심 함수에 단위 테스트 추가</h3></div><div class="tk-meta"><span class="diff d1">★</span><span class="dur">1~2일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">테스트가 없는 계산/변환 함수(금액 포맷, 날짜 계산, 상태 판정 등)에 정상·경계·예외 케이스 테스트 작성.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt"><b>if 분기가 3개 이상인데 테스트 0개인 함수</b>를 서비스 코드에서 찾기.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">케이스 5개 이상(경계값 포함), 전부 통과, 테스트 이름만 봐도 뭘 검증하는지 알 것.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">대상 함수 지정 + 기존 테스트 파일 1개를 본보기로 알려주기.</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">QA-03</div><h3>README / 로컬 실행 가이드 현행화</h3></div><div class="tk-meta"><span class="diff d1">★</span><span class="dur">1일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">본인이 1주차에 환경 세팅하며 막혔던 지점을 살려, 실행 가이드를 "처음 온 사람도 따라 하면 되는" 상태로 갱신.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">본인의 <b>1주차 세팅 메모</b>가 그대로 재료. (이 티켓은 사실상 준비돼 있음)</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">문서만 보고 다른 수습생이 클린 세팅 성공(상호 검증), 시크릿 값은 문서에 안 씀.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">문서 위치 지정, 시크릿 기재 금지 재강조.</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">QA-04</div><h3>미사용 코드/주석 정리 (지정 범위)</h3></div><div class="tk-meta"><span class="diff d1">★</span><span class="dur">0.5~1일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">멘토가 지정한 폴더 안에서 주석 처리된 죽은 코드, 안 쓰는 import, 미사용 함수 제거.</span></div>
|
|
<div class="row find"><span class="lab">찾는 법</span><span class="txt">에디터/린트의 <b>unused 경고</b> + 주석 블록 검색. 삭제 전 "정말 안 쓰나" 확인 방법을 배우는 게 포인트.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">빌드·테스트 통과, 삭제 목록을 PR 설명에 정리, 확신 없는 건 삭제 대신 질문.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">범위 폴더 지정(전체 수색 금지), 리뷰 꼼꼼히.</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- DESIGN -->
|
|
<div class="cat-div" id="dz">
|
|
<div class="cat-badge dz">🎨</div>
|
|
<div><h2>디자이너 티켓 — 3개</h2><div class="dm">디자인 수습생용. 개발 수습생의 FE 티켓과 짝지으면 협업 훈련이 됩니다.</div></div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">DZ-01</div><h3>빈 상태·에러 상태 디자인 세트</h3></div><div class="tk-meta"><span class="diff d1">★</span><span class="dur">1~2일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">FE-01·FE-05와 짝: 빈 상태/에러 상태의 일러스트·문구·레이아웃을 디자인하고 개발자에게 핸드오프.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">시안 + 문구 + 간격/색 명세, 개발 구현 결과가 시안과 일치하는지 확인까지.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">기존 디자인 톤 참고 자료 전달.</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">DZ-02</div><h3>화면 1개 UX 개선 제안 → 반영</h3></div><div class="tk-meta"><span class="diff d2">★★</span><span class="dur">2~3일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">2주차 UI 인벤토리에서 찾은 불편 지점 1개를 개선 시안으로 만들고, 팀 리뷰 통과분을 개발 티켓으로 넘기기.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">현행 문제 정의 → 개선 시안(2안) → 선택안 핸드오프 문서 → 구현 확인.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">개선 후보 화면 2~3개 승인해 두기(고객사 승인 필요 화면 제외).</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ticket">
|
|
<div class="tk-head"><div><div class="id">DZ-03</div><h3>UI 컴포넌트 정리표 (미니 디자인 시스템)</h3></div><div class="tk-meta"><span class="diff d2">★★</span><span class="dur">2~3일</span></div></div>
|
|
<div class="tk-body">
|
|
<div class="row what"><span class="lab">무엇을</span><span class="txt">서비스에서 쓰이는 버튼·입력·카드·색·글자 크기를 한 장으로 정리한 "컴포넌트 정리표" 제작 — FE-07(공통 컴포넌트화)의 근거 자료가 됨.</span></div>
|
|
<div class="row dod"><span class="lab">완료 조건</span><span class="txt">컴포넌트별 변형 수 집계, 통일 제안 포함, 팀 공유 발표 10분.</span></div>
|
|
<div class="row prep"><span class="lab">멘토 준비</span><span class="txt">범위(화면 몇 개까지) 지정.</span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Ticket form -->
|
|
<section id="form">
|
|
<div class="eyebrow">구체화 양식</div>
|
|
<h2>티켓 작성 양식 — 이 틀로 실제 티켓을 만드세요</h2>
|
|
<p class="sub">위 패턴에서 찾은 실제 건을 이 양식으로 옮기면 수습생에게 바로 줄 수 있는 티켓이 됩니다. 이슈 트래커에 그대로 복붙해도 돼요.</p>
|
|
<div class="card mt">
|
|
<div class="tpl">
|
|
<div class="cap">수습 티켓 양식 (복사해서 사용)</div>
|
|
<pre><span class="hl">[제목]</span> (패턴ID) 화면/기능 — 한 줄 요약
|
|
예: (FE-01) 알림 목록 — 빈 상태 화면 추가
|
|
|
|
<span class="hl">[배경]</span> 왜 필요한가 (1~2문장)
|
|
<span class="hl">[할 일]</span> 무엇을 어떻게 (구체적으로)
|
|
<span class="hl">[범위]</span> 건드릴 파일/영역 · 건드리지 말 것
|
|
<span class="hl">[완료 조건]</span>
|
|
- [ ] 조건 1 (눈으로 확인 가능하게)
|
|
- [ ] 조건 2
|
|
- [ ] PR에 전/후 스크린샷 또는 테스트
|
|
<span class="hl">[참고]</span> 비슷한 기존 코드 위치, 참고 문서
|
|
<span class="hl">[난이도/예상]</span> ★ or ★★ / 예상 소요
|
|
<span class="hl">[멘토]</span> 담당 멘토 이름</pre>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Tracker -->
|
|
<section id="tracker">
|
|
<div class="eyebrow">배정 트래커</div>
|
|
<h2>티켓 풀 현황판</h2>
|
|
<p class="sub">D-7까지 각 패턴을 실제 건으로 구체화하고, 5~6주차에 배정하면서 채워 나가세요. 학생 1명당 5~6주 동안 2~4건이 적당해요.</p>
|
|
<div class="tblwrap">
|
|
<table>
|
|
<thead><tr><th>패턴</th><th>실제 티켓 제목</th><th>구체화</th><th>배정 대상</th><th>배정일</th><th>상태</th></tr></thead>
|
|
<tbody>
|
|
<tr><td class="num">FE-01</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">FE-02</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">FE-03</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">FE-04</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">FE-05</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">FE-06</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">FE-07</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">BE-01</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">BE-02</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">BE-03</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">BE-04</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">BE-05</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">BE-06</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">QA-01</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">QA-02</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">QA-03</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">QA-04</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">DZ-01</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">DZ-02</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
<tr><td class="num">DZ-03</td><td><span class="fill"></span></td><td>☐</td><td><span class="fill"></span></td><td><span class="fill"></span></td><td><span class="fill"></span></td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="card mt" style="font-size:14px;color:var(--ink-soft);">
|
|
<b style="color:var(--ink);">배정 팁</b> — 첫 티켓(5주차)은 ★로 시작해 성공 경험을 만들고, 6주차에 ★★로 올리세요. FE-01+DZ-01, FE-07+DZ-03, BE-04+FE(신규 화면)처럼 <b style="color:var(--primary);">짝 티켓</b>으로 주면 협업 평가 재료가 생깁니다. 고객사 코드 반영이 어려운 경우, 사내 도구·내부 프로젝트에서 같은 패턴을 찾아도 좋아요.
|
|
</div>
|
|
</section>
|
|
|
|
<footer>
|
|
<span>AWESOMEDEV · 수습 실전 티켓 풀 템플릿 (멘토용)</span>
|
|
<span>2026 · 5~6주차 강의안·평가 루브릭과 함께 사용</span>
|
|
</footer>
|
|
|
|
</div>
|