라이프스타일
할 일 필터 구현
start에서 Active/Completed 필터를 구현하고 데이터 형식과 정상 및 경계 사례를 검증합니다.
읽는 데 약 14분 · 실습 30 분

이 글의 목차
Codex 학습 목차로 돌아가기Codex 학습 센터: 전체 튜토리얼 목차설치와 첫 작업부터 MD 지침과 고급 연동까지 60개 강의, 열 개 단원을 계획합니다. 수준, 환경, 목표, 명령으로 다음 글을 찾고 미게시 항목의 상태를 확인할 수 있습니다.전체 글 읽기
목표와 준비
이 단락의 학습 자료: 코드 이해기존 코드베이스 이해읽기 흐름으로 진입점, 데이터 흐름, 테스트를 찾아 파일 근거가 있는 프로젝트 지도를 만듭니다.전체 글 읽기
PlanPlan 모드로 구현 전 계획하기Plan 모드는 범위와 접근법을 결정할 때 유용합니다. 결과물은 구현 계획이며 완성된 코드는 아닙니다. 입력, 출력, 제한과 검증 방법이 포함되었는지 확인합니다.전체 글 읽기은 계획 검토가 중심이었습니다. 이번에는 실패에서 완성까지 증거를 봅니다. 한 줄 표시뿐 아니라 숨겨진 데이터 유지/순서/같은 제목의 식별을 확인합니다.
1단계: 미완성 기준 만들기
ZIP start 다섯 파일을 새 codex-feature-lab으로 복사합니다. expected/이전 수정을 사용하지 않고 Windows PowerShell은 Get-Location, macOS/Linux는 pwd로 경로를 확인합니다. 원본을 남기고 기존 테스트 2통과1실패를 확인합니다.
node --test core.test.mjs
선택지/change 이벤트가 이미 있음을 확인합니다. 부족한 것은 visibleTasks이며 UI 재작성/framework는 필요 없습니다. 프런트 파일명이라도 변경 시작이 화면인 것은 아닙니다. 실패를 남기고 assertion 삭제를 수정으로 삼지 않습니다.
2단계: 사례로 완료 조건 고정
다음을 filter.test.mjs로 추가하고 기존 테스트는 덮어쓰지 않습니다. 동명 Read의 a/c ID와 순서, All 전체 유지, 세 빈 목록을 확인합니다. 동결 입력으로 직접 변경도 쉽게 탐지합니다.
import test from "node:test";
import assert from "node:assert/strict";
import { visibleTasks } from "./core.mjs";
const tasks = Object.freeze([
Object.freeze({ id: "a", title: "Read", completed: true }),
Object.freeze({ id: "b", title: "Build", completed: false }),
Object.freeze({ id: "c", title: "Read", completed: true }),
]);
const ids = (items) => items.map((item) => item.id);
test("filters preserve identity and order with duplicate titles", () => {
assert.deepEqual(ids(visibleTasks(tasks, "active")), ["b"]);
assert.deepEqual(ids(visibleTasks(tasks, "completed")), ["a", "c"]);
assert.deepEqual(ids(tasks), ["a", "b", "c"]);
});
test("All retains every task without changing its completion state", () => {
assert.deepEqual(ids(visibleTasks(tasks, "all")), ["a", "b", "c"]);
assert.deepEqual(tasks.map((task) => task.completed), [true, false, true]);
});
test("every filter accepts an empty list", () => {
for (const filter of ["all", "active", "completed"]) {
assert.deepEqual(visibleTasks(Object.freeze([]), filter), []);
}
});
node --test core.test.mjs filter.test.mjs
start는 4통과2실패이며 기존 필터와 새 첫 테스트가 실패합니다. All/빈 입력은 원래 통과합니다. 새 테스트 탐지력을 확인합니다. 구문/파일 누락은 준비 오류로 예상한 기능 실패와 구분합니다.
3단계: 최소 기능 변경 구현
데스크톱은 codex-feature-lab을 로컬 프로젝트로 추가해 작업을 만들고, CLI는 같은 실습 경로에서 codex를 실행합니다. 경로를 확인한 뒤 전체 요청을 보냅니다. 이제 core.mjs만 변경 가능하며 새 테스트도 고정입니다. 다른 변경은 구체적 이유를 요청하고 전체 정리를 맡기지 않습니다. 글만으로 추측하지 말고 테스트를 읽게 합니다.
Implement the missing filters in this codex-feature-lab.
Read index.html, app.js, core.mjs, core.test.mjs and filter.test.mjs first.
Modify only visibleTasks in core.mjs: all keeps every task, active returns unfinished tasks, completed returns finished tasks. Preserve original order, IDs and input data. Do not edit tests, add dependencies or change UI/storage.
Run node --test core.test.mjs filter.test.mjs. Inspect the final diff and report actual results and any unperformed browser checks. Stop and explain if the requested scope cannot satisfy the tests. Do not publish or deploy.
filter는 원래 객체를 고른 새 배열을 만들고 객체를 바꾸지 않습니다. All은 원배열을 반환해도 되며 불필요한 깊은 복사는 요구하지 않습니다. !task.completed와 task.completed 차이를 이해해 확인합니다.
export function visibleTasks(tasks, filter) {
if (filter === "active") return tasks.filter((task) => !task.completed);
if (filter === "completed") return tasks.filter((task) => task.completed);
return tasks;
}
4단계: 데이터, 화면, 범위 검증
같은 명령으로 6통과를 확인합니다. 원래 다섯 파일은 core.mjs만 변경, filter.test.mjs만 추가입니다. 삭제된 assertion은 복원해 재시험하고 무관한 추가도 확인합니다. 구현 완료와 검수 완료는 따로 기록합니다.
실습에서 Windows는 py -m http.server 4173 --bind 127.0.0.1, macOS/Linux는 python3로 시작하고 http://127.0.0.1:4173을 엽니다. 자신의 이전 미리 보기 충돌만 해결합니다. HTML 직접 열기는 module 제한이 있으므로 이전 화면이면 경로/새로 고침을 확인합니다.
필요한 이전 실습 기록을 보존하고 About this exercise의 Reset practice data를 누릅니다. All tasks에서 빈 목록을 확인한 뒤 Read/Build/Read를 추가하고 첫째/셋째를 완료합니다. 표와 All 전체를 확인하고 동명은 원래 위치/상태로 구분합니다. 첫째 완료를 해제하면 Completed는 원래 셋째만, Active는 원래 첫째와 Build입니다. All과 새로 고침으로 저장도 확인합니다.
| 확인점 | All | Active | Completed |
|---|---|---|---|
| 원래 첫째/셋째 완료 | Read, Build, Read | Build | Read, Read |
| 원래 첫째 완료 해제 | Read, Build, Read | Read, Build | 원래 셋째 Read |
| 실습 데이터 리셋 후 | 비어 있음 | 비어 있음 | 비어 있음 |
반례 확인: 전체 개수와 같은 제목의 작업
Read, Build, Read 세 개 중 첫 번째와 세 번째를 완료하면 All/Active/Completed의 표시 행은 3/1/2지만 개수 표시는 모두 1 active / 3 total이어야 합니다. 첫 번째 완료를 취소하면 행은 3/2/1, 개수 표시는 모두 2 active / 3 total이 됩니다. app.js는 전체 tasks를 셉니다. 핵심 필터 테스트 통과만으로 화면 개수를 검증할 수 없으므로 실제 UI 결과를 별도로 기록합니다.
여섯 테스트가 통과하면 수정된 core.mjs를 연습 폴더 밖에 복사해 둡니다. Completed 분기만 아래 잘못된 행으로 임시 교체하고 두 테스트 파일을 실행합니다. 완료 상태로 필터링한 뒤 title로 중복을 제거하여 ID c가 사라지므로 5개 통과, 1개 실패가 예상됩니다. 원래 테스트 세 개만 실행하면 두 작업의 제목이 달라 여전히 통과합니다. 실패한 실제 ID를 확인한 뒤 저장한 수정본으로 core.mjs를 즉시 복원하면 테스트 파일을 바꾸지 않고 6개 통과, 0개 실패로 돌아와야 합니다.
if (filter === "completed") return tasks.filter((task) => task.completed).filter((task, index, selected) => selected.findIndex((other) => other.title === task.title) === index);
반례가 통과하면 filter.test.mjs가 실행됐는지, 세 번째 작업이 다른 ID의 Read인지, 수정한 복사본을 테스트했는지 확인합니다. 구문 또는 모듈 누락 오류라면 파일을 복원하고 교체 위치를 확인하세요. 이는 중복 제거 결함을 잡았다는 증거가 아닙니다. 이 연습은 테스트 범위를 확인하며 UI 수정이나 오류 버전 커밋은 필요하지 않습니다.
실패 해결, 전달과 복원
사라지면 선택 결과를 tasks/저장에 다시 넣었는지, 동명 오류면 ID 대신 title을 썼는지 봅니다. 핵심 통과인데 화면이 오래되면 import/HTTP/캐시를 확인하고 표의 실패 행/재현 순서를 전달합니다.
6개 테스트/화면 사례/최종 차이/미실행을 전달합니다. 반복은 미리 보기 종료 후 core.mjs만 start로 복원하며 새 테스트 포함은 4통과2실패, 기존만은 2통과1실패입니다. 명령 차이를 구분합니다. 그림 1은 사례 고정, 2는 제한 변경, 3은 회귀/복원이며 독자의 Codex 실행을 주장하지 않습니다.
Codex 학습 목차로 돌아가기Codex 학습 센터: 전체 튜토리얼 목차설치와 첫 작업부터 MD 지침과 고급 연동까지 60개 강의, 열 개 단원을 계획합니다. 수준, 환경, 목표, 명령으로 다음 글을 찾고 미게시 항목의 상태를 확인할 수 있습니다.전체 글 읽기
자세한 설명 보기
Three numbered stages: identify the starting point, perform the exercise, and verify the result. Original illustration, not a product screenshot.


같은 주제의 글
라이프스타일
Codex 학습 센터: 전체 튜토리얼 목차
설치와 첫 작업부터 MD 지침과 고급 연동까지 60개 강의, 열 개 단원을 계획합니다. 수준, 환경, 목표, 명령으로 다음 글을 찾고 미게시 항목의 상태를 확인할 수 있습니다.
라이프스타일
Worktree와 작업 격리
Worktree는 하나의 Git 저장소에 다른 브랜치의 작업 폴더를 만듭니다. 파일이 분리되어도 DB, 포트와 외부 서비스는 공유될 수 있습니다.
라이프스타일
실습: 작은 웹사이트 만들기
brief.md에서 Small Steps 할 일 사이트를 계획하고 추가·완료·삭제·필터·로컬 저장을 구현합니다. HTML·CSS·데이터 함수·화면 이벤트·시험을 분리하고 Node와 브라우저로 검증한 뒤 재시작·복원 인계 기록을 남깁니다.
라이프스타일
사용량과 효율: 재작업 줄이기
조건, 모델 선택, 시간, 결과를 기록해 불필요한 재시도와 과도한 문맥을 줄입니다.
이 글을 인용한 글
최신 여행 소식·가이드

가이드도쿄
도쿄 어디에 묵을까? 신주쿠·우에노·도쿄역·시부야·아사쿠사·이케부쿠로·긴자 일곱 지역 비교: 공항 교통, 숙박세, 짐 배송까지
도쿄 어디에 묵을까? 신주쿠, 우에노, 도쿄역, 시부야, 아사쿠사, 이케부쿠로, 긴자 일곱 지역을 같은 기준으로 비교한다. 나리타·하네다 공항에서 오는 방법, 교통 노선, 주변의 볼거리, 동네 분위기, 적합한 여행자를 비교표와 야마노테선 안내도로 살펴보고, 2026년 9월에 확인한 도쿄도 숙박세(2027년 4월부터 3%)와 공항 택배로 짐을 보내는 규정도 정리했다.
- 예산
- 호텔

가이드도쿄
도쿄 교통패스 선택법: Suica/Welcome Suica, Tokyo Subway Ticket, JR Pass는 살 만할까?
도쿄를 처음 여행한다면 먼저 1인당 IC 카드 한 장으로 탈 때마다 결제한다(Welcome Suica는 보증금이 없고 28일간 유효). 하루에 지하철을 4번 이상 타면 2,000엔짜리 Tokyo Subway Ticket 72시간권을 추가하고, 간사이에 가지 않고 도쿄만 여행한다면 JR Pass는 반드시 손해다. TOURIST PASMO, iPhone의 Suica, 도쿄 Metro 하루권의 이용 가능·불가 범위를 결정도로 비교한다. 가격은 2026년 9월 확인.
- 교통
- 예산

가이드도쿄
도쿄 디즈니랜드·디즈니씨 가이드: 티켓 가격, 판타지 스프링스 Fantasy Springs, 디즈니 프리미어 액세스 DPA와 스탠바이 패스 이용법, 첫 방문에는 어느 파크가 좋을까
도쿄 디즈니 하루짜리 패스포트는 변동 가격제로, 2026년 9월에는 평일 대부분이 9,900엔, 주말이 10,900엔이다. 공식 홈페이지에서 매일 14:00에 두 달 뒤 같은 날짜의 티켓을 판매한다. 무료 프라이오리티 패스는 공식 서비스 목록에서 빠져 대기 시간을 줄이는 방법은 유료 디즈니 프리미어 액세스(한 사람당 한 번 1,000~3,500엔)뿐이다. 운영 시간, 25주년 행사, 스탠바이 패스, 엔트리 리퀘스트, 판타지 스프링스 이용법, 첫 방문 때 디즈니랜드와 디즈니씨 중 어디를 고를지도 담았다. 2026년 9월 공식 홈페이지에서 확인했다.
- 추천 일정
- 가족 여행