- 발행일
클래스 팔레트 20종이 다섯 파일에 복사돼 있고 Redux는 import만 남았다 — 경력기술서의 "Redux"를 코드로 다시 확인하기
클래스 팔레트 20종이 다섯 파일에 복사돼 있고 Redux는 import만 남았다
이 글은 2026년 9월에 당시 코드를 다시 보며 정리한 것입니다. 저장소는 퇴사 전에 스냅샷으로 보관한 것이라 커밋 이력이 없고, 경력기술서와 당시 쓴 지원서·이력서에 적은 담당 범위와 코드를 대조해 썼습니다. 날짜는 코드에 남은 시기 단서 기준입니다.
경력기술서2022-08-05산업 AI 솔루션 프론트엔드 2021 ~ 2022 경력 기술서산업 AI 솔루션 기업에서 관세청 불법 복제품 판독 시스템과 공항 보안 검색 판독 시스템의 화면을 맡았던 기록입니다. 판독 화면, 웹소켓 실시간 판독, React SPA 전환, 납품처별 설정, 통계 시각화가 핵심이고, 항목마다 근거가 되는 글을 링크해 두었습니다.의 공항 보안 검색 판독 시스템 항목에 기술 스택을 "JavaScript, React, Redux, Bootstrap, WebSocket"이라고 적었습니다. 이 글을 쓰려고 스냅샷을 열었을 때 제일 먼저 확인하고 싶었던 게 그 Redux였어요. package.json에는 redux·react-redux·redux-persist가 다 있습니다. 그런데 앱을 감싸는 자리는 이렇게 돼 있었습니다.
// import {createStore} from "redux";
// import {Provider} from "react-redux";
// import rootReducer from "./modules";
// …
// const store = createStore(rootReducer)
// const persist = persistStore(store)
ReactDOM.render(
<React.StrictMode>
<App/>
</React.StrictMode>,
document.getElementById('root')
);
Provider가 없습니다. useSelector를 import한 파일이 셋 있는데 호출은 0건이에요. 이 스냅샷의 앱은 Redux 없이 돌아갑니다.
리듀서는 있다, 다만 안 붙어 있다
src/modules/에는 리듀서 넷과 combineReducers, redux-persist 설정까지 갖춰져 있습니다.
const persistConfig = {
key: "root",
storage,
whitelist: ["subHeaderConfig", "settingPostConfig", "statisticsConfig"]
}
export const rootReducer = combineReducers({ subHeaderConfig, settingPostConfig, statisticsConfig })
리듀서 하나를 열어 보면 상태 전환 case가 주석 처리돼 있고, 그 위에 이유가 한 줄 있습니다.
//일단 물품리스트를 기억하기 위헤서는 이렇게.. 주석처리를 해야..
// case airportServerTarget:
// return { target: airportTarget }
물품 리스트를 유지하려면 주석 처리를 해야 했다는 것, 즉 사용자가 체크한 클래스 목록을 새로고침 뒤에도 유지하려다 리듀서 쪽에서 막혔고, 그 자리를 다른 방법으로 대신했다는 뜻으로 읽힙니다. 그 다른 방법이 localStorage입니다.
localStorage.setItem('statusTarget', JSON.stringify([{
code: "All",
check: true,
name: "전체"
}, ...AIRPORT]))
localStorage.setItem('searchTarget', JSON.stringify([{
code: "All",
check: true,
name: "전체"
}, ...AIRPORT]))
통계 화면과 검색 화면이 각각 어떤 클래스를 켜 두었는지를 localStorage에 JSON으로 통째로 넣습니다. redux-persist가 하려던 일을 손으로 한 셈이에요. 2022년 중반에 쓴 지원서에 "통계 작업 시에 데이터 값을 기억할 수 있도록 설계"라는 항목이 있는데, 이 statusTarget이 그 설계의 결과로 읽힙니다. 그러니까 체크 목록을 새로고침 뒤에도 남기는 일은 제 담당이었고, 그걸 리듀서가 아니라 localStorage로 푼 것도 그 안의 일이에요. 다만 Redux를 붙였다가 뗀 건지, 붙이려다 만 건지는 이 한 시점의 코드로는 알 수 없습니다. 주석 처리된 코드가 남아 있으니 붙어 있던 적이 있을 가능성이 크지만, 그렇다고 단정하지는 않겠습니다.
팔레트가 다섯 파일에 있다
판정 클래스는 코드 한 글자에 이름과 색이 붙은 객체입니다.
const AIRPORT = [
{code: "A", check: true, name: "총기류", color: "#e32218"},
{code: "B", check: true, name: "칼류", color: "#838a48"},
{code: "C", check: true, name: "가위류", color: "#036e3d"},
// … T까지 20종
이 배열이 App.js에만 넷 있습니다. 납품처별로 AIRPORT·AIRPORT_ENHANCED·ENTERPRISE·INTEGRATION. 서버가 내려 주는 target 값으로 이 중 하나를 골라 localStorage에 심어요.
왜 납품처 단위로 갈랐는지는 지원서에 적혀 있습니다. 2022년 5월 이후 납품이 여러 곳으로 늘면서 "너무나 다양한 요구사항 탓에 기본 제품의 틀이 많이 망가져 있어서 확장성은 고려하기 힘들 것으로 판단이 되어, CONFIG 값에 맞추어 설계하던 행동들을 우선 TARGET을 대상으로 구분을 하였다"고 썼어요. 설정 항목 하나하나(config)에 분기를 거는 대신 납품처(target)를 먼저 가르고 그 아래에 클래스 표를 한 벌씩 두기로 한 것이고, App.js의 배열 넷이 그 결정의 모양입니다. TARGET으로 가른 것은 제가 한 일이고, 그 결과로 같은 표가 납품처 수만큼 복사됐습니다.
그런데 리듀서 파일 넷(configReducer·settingPostConfig·statisticsConfig·subHeaderConfig)에도 같은 배열이 또 있습니다. "총기류"로 찾으면 다섯 파일이 나오고, 첫 색 #e32218은 App.js에서만 여섯 번 나옵니다. 리듀서 안의 것은 리듀서가 안 붙어 있으니 어디서도 읽히지 않아요. 같은 표가 다섯 벌인데 살아 있는 건 한 벌입니다. 리듀서 쪽 사본까지 제가 만든 것인지는 프런트 셋이 같이 만진 코드라 가르지 못합니다.
색 자체는 화면에서 다르게 옵니다. 메인 화면의 판독 박스 색은 이 배열이 아니라 서버 get_settings 응답에서 코드로 조회합니다.
const setIconBackgroundColor = (icon) => {
for (let i = 0; i < settingColor.length; i++) {
if (settingColor[i].code === icon) {
return settingColor[i].color
}
}
}
그러니까 색의 정본은 서버 설정이고, 프런트의 팔레트 다섯 벌은 "체크 목록의 초기값"으로만 쓰입니다. 경력기술서 2.3절에 "옵션을 설정으로 뺐다"고 적은 건 이 서버 설정 쪽 이야기이고, 프런트 안의 복사본 다섯 벌은 그 문장에 안 들어 있습니다.
경력기술서와 어긋나는 한 줄
정리하면 경력기술서의 "Redux"는 이 스냅샷 기준으로는 설치돼 있고 리듀서 파일도 있지만 앱에 연결돼 있지 않은 상태입니다. 재직 중에 쓴 지원서의 기술 스택 줄은 "React, HTML, CSS, JS"였고 Redux가 없었어요. 퇴사 뒤에 쓴 경력기술서에는 들어 있는데, 무엇을 근거로 넣었는지는 남아 있지 않습니다. 기술 스택 줄에 넣을 만큼 썼는지를 코드로 다시 보면, 이 시점에는 아니었습니다. 경력기술서 본문은 그대로 두고 이 글에서 정정합니다.
검증
- 날짜 근거: 스냅샷 커밋 2022-07-24 두 개, 코드 안 날짜 문자열
2021-12-23·2022-04-01. 지원서는 TARGET 구분을 2022년 5월 이후로 적고 있습니다. 리듀서가 언제 주석 처리됐는지는 알 수 없습니다. - 경력기술서·지원서·이력서와 대조:
| 경력기술서 | 코드 | 지원서·이력서 | 판정 |
|---|---|---|---|
| 기술 스택 Redux | package.json에 있음, Provider·createStore 주석, useSelector 호출 0건 | 지원서 스택 줄에 Redux 없음 | 이 시점에는 미사용 |
| 2.3 옵션을 설정으로 | 박스 색·임계값·표시 여부는 서버 get_settings에서 조회 | 지원서 "설정의 thres 값을 직접 작성", 이력서 담당 "설정" | 일치 |
| 2.3 카메라 위치·2D/3D 설정 | 해당 코드 없음 | 언급 없음 | 이 저장소에서 확인 안 됨 |
| (언급 없음) | 팔레트 배열이 App.js 4벌 | 지원서 "CONFIG 대신 TARGET으로 구분" | 본인 작업, 경력기술서에만 없음 |
| (언급 없음) | 리듀서 파일 4개에 같은 팔레트 | 언급 없음 | 누구 것인지 불명 |
| (언급 없음) | statusTarget·searchTarget을 localStorage에 | 지원서 "통계 작업 시 데이터 값을 기억할 수 있도록 설계" | 본인 작업 |
- 이 글을 쓰며 센 것:
"총기류"5개 파일,useSelectorimport 3·호출 0,App.js팔레트 배열 4개.
남은 것 · 한계
- 한 시점의 스냅샷입니다. Redux가 붙어 있던 기간이 있었는지, 누가 뗐는지 알 수 없습니다. 경력기술서의 스택 표기가 어느 시점에는 맞았을 가능성을 부정하지는 못합니다. 다만 제가 보관한 마지막 상태에서는 아니었습니다.
- 팔레트 다섯 벌 중 넷은 죽은 코드인데 지우지 않았습니다. TARGET으로 가른 건 제 결정이었으니 그 결과로 생긴 사본을 정리할 사람도 저였는데, 스냅샷 시점까지 그대로였습니다. 리듀서 쪽 사본은 프런트 셋 중 누구 것인지 모릅니다.
- 리듀서에서 막힌 이유가 주석 한 줄뿐입니다.
redux-persist의whitelist까지 써 놓고 왜 체크 목록 유지가 안 됐는지, 그때 무엇을 시도했는지 남아 있지 않습니다. - 같은 종류의 문제를 나중에 두 번 더 만났습니다. 색 이름이 여러 곳에 흩어져 있을 때 어디가 정본인지를 팔레트에 없는 색은 조용히 안 칠해진다2026-08-24팔레트에 없는 색은 조용히 안 칠해진다 — 색 클래스 142곳 정리와 대비 감사토큰에 없는 색 이름은 빌드 오류가 아니라 그냥 안 칠해집니다. 그렇게 죽어 있던 클래스 142곳을 토큰으로 바꾸고, 다시 들어오면 빌드를 세우는 가드를 붙였어요. 이어서 팔레트 안에 있는 색들의 명도 대비를 재봤더니 회색 스케일이 통째로 한 칸 밝아 입력 경계와 회색 글자가 기준 미달이었습니다. 못 고치기로 한 35곳도 이유와 함께 적었습니다.에서, 같은 낱말이 96개 파일에 복사돼 있을 때 어디까지 바꿀지를 용어 하나를 96개 파일 667곳에서 바꿨다2026-08-13용어 하나를 96개 파일 667곳에서 바꿨다 — 그리고 일부러 안 바꾼 세 경계화면에서 쓰는 용어가 분류체계에서 개념체계로 바뀌었습니다. 템플릿·뷰·매니저·폼·JS·e2e·문서까지 96개 파일 667곳을 치환했는데, 정작 중요한 판단은 어디서 멈출지였어요. 코드 식별자·URL·DB 데이터 값 세 곳은 일부러 안 건드렸고, 그 대가로 코드와 화면이 서로 다른 말을 하게 됐습니다.에서 다뤘습니다. 2022년의 저는 다섯 벌이 있다는 것 자체를 세어 보지 않았습니다.
관련 글: 산업 AI 솔루션 기업 프런트엔드 2021–20222022-08-05산업 AI 솔루션 프론트엔드 2021 ~ 2022 경력 기술서산업 AI 솔루션 기업에서 관세청 불법 복제품 판독 시스템과 공항 보안 검색 판독 시스템의 화면을 맡았던 기록입니다. 판독 화면, 웹소켓 실시간 판독, React SPA 전환, 납품처별 설정, 통계 시각화가 핵심이고, 항목마다 근거가 되는 글을 링크해 두었습니다. · 팔레트에 없는 색은 조용히 안 칠해진다2026-08-24팔레트에 없는 색은 조용히 안 칠해진다 — 색 클래스 142곳 정리와 대비 감사토큰에 없는 색 이름은 빌드 오류가 아니라 그냥 안 칠해집니다. 그렇게 죽어 있던 클래스 142곳을 토큰으로 바꾸고, 다시 들어오면 빌드를 세우는 가드를 붙였어요. 이어서 팔레트 안에 있는 색들의 명도 대비를 재봤더니 회색 스케일이 통째로 한 칸 밝아 입력 경계와 회색 글자가 기준 미달이었습니다. 못 고치기로 한 35곳도 이유와 함께 적었습니다. · 용어 하나를 96개 파일 667곳에서 바꿨다2026-08-13용어 하나를 96개 파일 667곳에서 바꿨다 — 그리고 일부러 안 바꾼 세 경계화면에서 쓰는 용어가 분류체계에서 개념체계로 바뀌었습니다. 템플릿·뷰·매니저·폼·JS·e2e·문서까지 96개 파일 667곳을 치환했는데, 정작 중요한 판단은 어디서 멈출지였어요. 코드 식별자·URL·DB 데이터 값 세 곳은 일부러 안 건드렸고, 그 대가로 코드와 화면이 서로 다른 말을 하게 됐습니다. · 일정에 담은 장소를 컴포넌트 state에서 스토어로 옮겼다2024-11-20일정에 담은 장소를 컴포넌트 state에서 스토어로 옮겼다 — userId를 nickname으로 바꾸던 날일정 만들기 화면에서 담은 장소 목록은 컴포넌트 안의 state였고, 서버 응답과 부모 props 두 곳에서 그 state를 덮어쓰고 있었습니다. 서버가 userId 대신 nickname을 주기로 한 날, 그 목록을 zustand 스토어로 옮겼어요. 상태의 주인을 하나로 만든 건 맞는데, 같은 커밋에서 드래그 항목 컴포넌트를 부모 함수 안으로 옮겼고 스토어 훅 이름을 이미 있는 것과 똑같이 지었습니다. 둘 다 지금까지 남아 있습니다. · 메인 화면의 판독 박스는 서버 설정 셋이 그린다2022-04-01메인 화면의 판독 박스는 서버 설정 셋이 그린다 — 색·임계값·켜짐을 화면 열두 곳이 각자 물었다공항 보안 검색 판독 화면에서 AI가 찾은 물체 상자는 클래스마다 색·임계값·표시 여부 세 값으로 그려집니다. 당시 지원서를 보면 임계값을 직접 입력하는 것과 레이블 위치·상자 표시 옵션은 납품처 한 곳의 요구로 들어온 것이었어요. 그 세 값은 서버 설정 한 벌에서 오는데, 화면 쪽 열두 파일이 각자 같은 주소를 부르고 같은 조회 함수를 복사해 갖고 있었습니다. 보일지와 울릴지를 정하는 경계 비교가 파일마다 달랐던 것까지, 남은 코드로만 되짚었습니다. · 카테고리 하나에 폴더 하나 — 복붙 열한 벌2020-11-22카테고리 하나에 폴더 하나 — 복붙 열한 벌졸업작품 큐피트의 운동 화면은 부위 7개, 패션 화면은 성별·시즌 4개였습니다. 그걸 폴더 열한 개로 만들었어요. 목록 컴포넌트끼리 공백을 빼고 비교하면 다른 줄이 다섯 줄이고, 라우트 17개 중 11개가 이 복제 화면입니다. 하루에 1,235줄을 넣고 16분 뒤 312줄을 지운 밤의 기록입니다. · 번역 키를 한국어 원문으로 썼다2022-11-27번역 키를 한국어 원문으로 썼다 — 5,091줄 리소스 파일의 대가숙박 큐레이션 플랫폼의 번역 리소스는 TypeScript 객체 한 파일 5,091줄이었고, 키의 상당수가 "가격 범위"처럼 한국어 원문이었습니다. 한국어 키는 한국어 리소스를 거의 안 써도 되게 해 주지만, 그 대가로 영어 리소스가 한국어의 2.7배가 됐고 일본어에는 빠진 키가 1,539개였어요. 경력기술서에 적은 "JSON 관리·동적 로딩"은 코드에 없었습니다.