#NestJS (66)

📚 NestJS + Refine 풀스택 트러블슈팅

외부 뷰어 리포트 4탭 N+1 — 14초 응답을 2초로

외부 뷰어 리포트 토큰 한 줄로 들어가는 공개 페이지의 4탭 단일 응답이 최대 14.4초까지 늘어났다. Prisma `include` 만 의심하다 진짜 범인을 놓쳤다. 두 층의 N+1 — 4탭 빌더 6 건의 순차 await + 일별·주별 for 루프 안 `findMany` 반복 — 을 Promise.all 병렬화 + 단일 findMany + 메모리 그룹핑으로 풀어 55 개 쿼리를 10 개로, p95 응답을 ~2.3 초로 끌어내린 트러블슈팅을 정리한다.

NestJSPrisma성능최적화
📚 NestJS + Refine 풀스택 트러블슈팅

외부 뷰어 리포트 인사이트 — 활동 데이터를 자연어로 바꾸기

외부 뷰어가 보는 4탭 리포트에 차트 옆으로 한 줄 자연어 메시지를 붙이는 인사이트 시스템 도입 머지를 정리한다. AI 호출 없이 결정성을 보장하는 룰 기반 메시지 생성기, 5 + 4 + 5 = 14종 긍정 규칙, 빈 데이터 폴백 카피 4종, 4탭별 메시지 슬롯 배치 — 같은 dev 머지 사이클 안에서 응답 표준 + 룰 + 폴백을 동시에 굳힌 설계 흐름과 트레이드오프를 기록한다.

NestJSTypeScript리포트
📚 NestJS + Refine 풀스택 트러블슈팅

외부 뷰어 리포트 v1→v2 토큰 전환 — 가장 길었던 하루

도입 단계 머지가 같은 날 밤 사용자 검토 1회로 폐기된 사고. Parent / ParentStudent / ParentInvitation 3 모델 + 회원가입 단일 트랜잭션 + 별도 JWT 시크릿 흐름 전부 삭제, StudentReport 1 모델 + nanoid 21자 공개 토큰 + 7일 만료 정책으로 같은 dev 머지 사이클 안에 갈아엎은 BE -2,099 / +563 + FE -1,475 / +968 의 갈아엎기 비용과 결정 사유, 사후 평가를 정리한다.

NestJSPrisma토큰 인증
📚 NestJS + Refine 풀스택 트러블슈팅

보호자 외부 뷰어 대시보드 — 모바일 앱·초대 토큰 회원가입

회원 레포트와 같은 데이터를 보호자(외부 뷰어) 그릇으로 옮기는 별도 앱 도입 머지. 모바일 우선 컨테이너(max-w-[430px]), Parent/ParentStudent/ParentInvitation 3 신규 모델, 초대 토큰 + 회원가입 단일 트랜잭션(4 write), 별도 JWT 시크릿(1h access / 30d refresh), 전화번호 = 로그인 ID 결정을 같은 dev 머지 사이클 4시간 안에 BE + FE Mock + FE 인증 연동까지 묶은 도입 단계 마일스톤이다.

NestJSPrismaJWT
📚 NestJS + Refine 풀스택 트러블슈팅

회원 레포트 5탭 API 설계 — 인사이트 3파트 구조

관리자 페이지 회원 레포트 페이지를 5탭(개요·학습 분석·지표 분석·레벨 이력·상세 기록)으로 설계한 머지. 신규 4 API + 기존 1 API 재사용, 공통 기간 필터, 인사이트 3파트(긍정/격려/개선) 구조, 학습 진도 집계 단위를 묶음에서 콘텐츠로 바꾼 결정, 상세 기록의 드릴다운 3계층(과제→묶음→콘텐츠) 응답 표준을 정리한다. NestJS + Prisma 환경에서 명세 우선·FE Mock 선행 워크플로우로 BE 구현 전 사용자 검토를 확보한 도입 단계 마일스톤이다.

NestJSPrismaAPI 설계
📚 NestJS + Refine 풀스택 트러블슈팅

재화 시스템 첫 머지 — 코인 지갑과 거래 원장(Wallet API)

회원 활동 동기 부여용 코인 지갑을 도입한 첫 머지. Prisma 단일 트랜잭션 안에서 잔액 변경과 거래 원장을 함께 기록하고, balanceAfter는 감사용으로 불변 처리한다. 도입 단계(스키마 + Domain Service + Debug API 4개 + 단위 테스트 18개)와 같은 dev 머지 사이클에 함께 들어간 노출 단계 Wallet API 3개(잔액 조회/입금/출금)의 결정·코드·트레이드오프를 정리한다. NestJS + Prisma 환경에서 통화 시스템을 첫 머지로 옮길 때의 스키마 분리, 응답 표준화, 옵셔널 멱등성, 클라이언트 신뢰 모델을 다룬다.

NestJSPrisma통화 시스템
📚 NestJS + Refine 풀스택 트러블슈팅

콘텐츠 후보 선택 3차 최적화 — 단일 쿼리로 옮기기

회원이 번들에서 콘텐츠 1건을 고를 때마다 호출되는 후보 추천 API는 4단계 폴백(level+metric → 유사 지표 → level only → 전체)이 각각 별도 쿼리를 내던 구조였다. 본 글은 페널티 기반 순위 조정으로 제외 로직을 비우고(v2.1.5), 레벨 콘텐츠를 한 번만 조회해 메모리 풀로 옮긴 뒤, FB0~FB2 폴백을 모두 인메모리 필터로 처리해 4,670ms를 2,340ms로 떨어뜨린 3차 최적화 마일스톤을 정리한다. NestJS + Prisma 환경에서 다단계 폴백 쿼리를 단일 쿼리 + 메모리 필터링 패턴으로 옮길 때의 결정·코드·트레이드오프를 다룬다.

NestJSPrisma성능 최적화
📚 NestJS + Refine 풀스택 트러블슈팅

NestJS 권한 가드 — 목록은 막고 상세는 뚫린 날

운영자가 본인 담당 클래스 1개만 떠야 하는데 모든 클래스가 떴다. 목록 API에 operatorId 필터를 깔고 끝낸 줄 알았는데, 직접 URL로 미담당 클래스 ID를 두드리니 상세·수정·승인 5개 엔드포인트가 그대로 200을 돌려줬다. 원인은 JWT payload.sub(User ID)와 Operator 테이블 id(Operator ID)의 분리 + validateClassAccess 헬퍼 부재 둘이었다. 라운드 한 번에 BE → QA → 추가 BE → QA 재검증으로 닫은 NestJS ForbiddenException + Prisma classOperator.findFirst 패턴을 정리한다.

NestJSPrismaJWT
📚 NestJS + Refine 풀스택 트러블슈팅

Problem 종속 끊기 — 1,891개 마이그레이션과 단위 테스트 38건

이전 편의 배치고사 MVP 머지가 가능했던 것은 같은 날 오후에 Problem 모델의 콘텐츠 종속을 먼저 끊었기 때문이다. 본 작업은 Problem 테이블이 ContentItem에 종속돼 재사용 불가하던 구조를 끊고, 1,891개 문제를 신 스키마로 옮기고, Admin/Student 8 엔드포인트와 단위 테스트 38건을 한 머지에 묶은 마일스톤이다. 스키마·마이그레이션·API·테스트가 한 dev 머지 사이클에 들어간 BE 작업 기록을 정리한다.

NestJSPrismaProblem
📚 NestJS + Refine 풀스택 트러블슈팅

배치고사 MVP 후속 — 명세를 코드로 옮기고 레거시 571줄을 일괄 삭제하다

이전 편에서 배치고사 명세를 자동 레벨 배치 폐기로 정리했다. 같은 날 저녁 그 명세를 실제 코드·테스트·시드 데이터로 한 번에 옮긴 마일스톤이다. 도메인·응용 갱신, Legacy 컨트롤러 3개 + 도메인 서비스 3개 + DTO 9건 571줄 삭제, 단위 테스트 22개, 회원 시드 보강, QA E2E 5 시나리오까지 5개 커밋이 한 머지 사이클에 들어간 운영 기록을 정리한다.

NestJSPrisma배치고사
📚 NestJS + Refine 풀스택 트러블슈팅

Unity Lobby + 배치고사 씬 통합 — 두 클라이언트가 같은 회원을 보는 첫 빌드

Unity 네이티브 클라이언트의 Lobby 씬과 배치고사 씬을 같은 빌드 안에 묶었다. NestJS 응답 모델과 Unity C# 모델의 필드명 불일치, NetworkManager 단일 진입점 래퍼, AuthGuard 패턴, 배치고사 완료 시 첫 숙제 자동 발행 체인, contentUrl 전체 경로 정책까지 6가지 설계 결정과 트레이드오프를 정리한다.

UnityNestJSVuplex
📚 NestJS + Refine 풀스택 트러블슈팅

타이머가 NaN:NaN으로 떴다 — Bundle API 응답 누락 필드와 비어 있는 콘텐츠 후보

QA Round 2에서 EC-3 엣지 케이스가 잡은 타이머 NaN:NaN 버그. 같은 컴포넌트가 같은 코드로 한 화면에서 정상, 다른 화면에서 NaN:NaN으로 뜨던 패턴이다. 원인은 BE 응답 DTO에서 한 필드 누락 + FE 무방어 + seed 데이터 부족 세 가지의 합이었다. 응답 스키마 검증과 콘텐츠 후보 0건 방어를 같이 깐 라운드 회고.

ReactTypeScriptNestJS
📚 NestJS + Refine 풀스택 트러블슈팅

킥오프 배치 첫 구현 — 매시 전체 EXPIRED 사고와 Winston 도입

첫 배치 작업으로 짠 NestJS 킥오프 배치(@nestjs/schedule)가 @Cron('EVERY_HOUR') + findExpiredAssignments() 시간 체크 누락 두 함정에 걸려 모든 ACTIVE 숙제를 매시간 EXPIRED로 굳혀 버린 사고를 복기한다. fix는 두 줄(시간 비교 + cron 표현식)이었지만, 사고가 일어났는데도 콘솔이 흘러가 흔적이 없었던 점이 더 컸다. 콘솔 일변도에서 Winston 파일 로깅(daily-rotate, app/error 분리, GCP severity) 으로 갈아탄 결정과 설정 전문을 정리한다.

NestJSCronBatch
📚 NestJS + Refine 풀스택 트러블슈팅

지표 누계 시스템 — TOP5 순위를 INSERT 전용 스냅샷으로 굳히기

다섯 개 지표의 점수를 가중평균으로 0~100 범위에 수렴시키던 설계를 폐기하고, 누계 점수를 매 묶음 완료마다 INSERT 전용으로 쌓아 distinct로 최신 1행씩 읽어 TOP1~5 순위를 굳히는 스냅샷 시스템을 짠다. 결정 5건, 트레이드오프, 두 진입점(배치고사 완료·묶음 완료)에서의 호출 패턴, 회복성 try-catch까지 코드 인용으로 정리한다.

NestJSPrismaSnapshot
📚 NestJS + Refine 풀스택 트러블슈팅

콘텐츠 브릿지 10종 통합 완료 — 같은 규격으로 묶기

Unity WebView 안에서 동작하는 웹 콘텐츠 10종을 같은 PostMessage 브릿지 규격으로 묶는 마일스톤 작업을 정리한다. bridge/ 폴더 하드카피와 useProblemResults 훅으로 콘텐츠별 차이를 흡수하고, 통계 필드 8개·2개·contentType·problems 배열을 네 차례에 걸쳐 점진적으로 확장하면서 마주친 400 Bad Request·accuracyPct 재정의·시간 정확도 변환 로직 회수의 결정 사유와 트레이드오프를 기록한다.

Content BridgePostMessageWebView
📚 NestJS + Refine 풀스택 트러블슈팅

NestJS Swagger 일괄 적용 — 35개 컨트롤러 + DTO 22개

Swagger UI는 멀쩡한데 모듈마다 빠진 데코레이터·interface DTO 때문에 API 문서가 실제 동작과 어긋났다. 35개 컨트롤러에 @ApiTags·@ApiBearerAuth를 일괄 적용하고, 한 모듈의 9개 메서드·22개 DTO를 interface에서 class로 한 번에 정리했다. 모듈별 점진 적용을 거절하고 일괄 적용을 택한 트레이드오프와 적용 패턴을 정리한다.

NestJSSwaggerOpenAPI
📚 NestJS + Refine 풀스택 트러블슈팅

디버깅용 운영 API 7개 — Unity 만료 테스트 30분 대기를 0초로

Unity 클라이언트 QA에서 할당 만료를 보려고 30분을 기다리거나 DB를 직접 건드리던 흐름을 운영용 디버그 API 7개로 흡수했다. PLATFORM_ADMIN 단독 권한·환경 토글·멱등 reset 같은 설계 결정과 후속 개선(loginId 쿼리, createNewAssignment 옵션)까지의 트레이드오프를 정리한다.

NestJS디버깅 API운영 도구
📚 NestJS + Refine 풀스택 트러블슈팅

JWT Guard 적용 — request.user undefined부터 jwt malformed까지

활동 로그 인터셉터에서 request.user가 undefined로 잡혔다. 원인을 파고드니 JwtAuthGuard 구현 누락, Auth Service와 Guard 간 JWT_SECRET 불일치, FE의 base64(JSON) Mock 토큰까지 3중 함정이 차례로 드러났다. 새벽 3시 임시 우회부터 다음 날 17시 정상화까지의 디버깅 흐름과 NestJS 글로벌 Guard·명시적 secret 검증·실제 BE API 시드 패턴을 정리한다.

NestJSJWTGuard
📚 NestJS + Refine 풀스택 트러블슈팅

교육과정 구조 리팩토링 — 3필드 분리와 폴백 결정기

교육과정 목표를 Member 한 곳에만 두면 운영 비용이 폭증한다. Prisma 두 컬럼 추가 + 도메인 서비스 한 메서드로 Member → Class → 분기 기본값 3계층 폴백을 한 곳에 모은 리팩토링. 응답에 출처(curriculumSource)를 함께 실어 운영자 UI도 한 화면에 결론을 보여준다.

NestJSPrismaPostgreSQL
📚 NestJS + Refine 풀스택 트러블슈팅

멀티테넌트 쓰기 가드 — body.tenantId 차단과 집계 일관성

PATCH body에 끼워 넣은 다른 tenantId가 통과해 옆 고객사 회원이 옮겨 쓰였다. NestJS Guard + DTO에서 tenantId 제거 + whitelist:true 3중 차단으로 쓰기 가드를 만들고, count/sum/groupBy는 where 변수 추출 + $transaction으로 묶었다. 시간 슬라이스는 KST 자정 고정, 멱등성은 Redis EX 60 + 충돌 검사 + audit, 정책 위반은 bypassPolicy + reason + audit. ts-morph 정적 스캔까지 1일 트러블슈팅.

NestJSRefine멀티테넌트
📚 NestJS + Refine 풀스택 트러블슈팅

Prisma 그래프 스키마 — 선형 레벨을 DAG로 옮긴 4가지 결정

단일 정수 sortOrder로 줄세운 선형 레벨을 노드/엣지 분리 DAG로 옮겼다. 셀프 참조 1:N vs 별도 엣지 테이블, PostgreSQL recursive CTE로 진행도 계산, 엣지 INSERT 시점 사이클 검출, 선형 i→i+1 자동 마이그레이션 4가지 결정과 zod invariants e2e로 회귀를 차단한 트러블슈팅.

PrismaPostgreSQLDAG
📚 NestJS + Refine 풀스택 트러블슈팅

두 번째 점검은 합류 지점이었다 — Admin Portal 2차에서 한 사이클에 잡힌 FE-BE 연동 버그 11건

1차 점검(SC-A01~A17)이 *FE 단독·BE 단독*의 단위 검수였다면, 2차 점검은 *FE-BE를 처음 같이 돌려 보는 자리*였어요. 그날 자정부터 새벽까지 한 사이클에 11건이 터졌습니다. CORS PATCH·DTO interface→class·운영자 상태 변경 400·콘텐츠 FK 제약·dbVersion 동적 조회 다섯 자리(BE)에 모니터링 useCustom·진단평가 문제 추가 버튼 결정·이메일 인라인 에러·SUPER_ADMIN 활성화 가드·배치고사 상태 엔드포인트 분리·콘텐츠 목록 null 크래시 여섯 자리(FE)까지. 코드 변경은 한 줄짜리 자리가 많았는데, *어떤 자리가 깨질 수 있는지*를 미리 보지 못한 게 11건이 한꺼번에 몰린 이유였어요. 합류 지점이라는 디버깅 환경의 본질을 11개의 자리로 짚은 글입니다.

NestJSRefineCORS
📚 NestJS + Refine 풀스택 트러블슈팅

CORS는 됐다 — PATCH만 빼고. allowedHeaders 한 줄과 Vite 프록시의 소문자 메서드

DTO를 class로 바꾼 다음 날 새벽, 같은 PATCH 흐름에서 이번엔 CORS가 빨갛게 물들었어요. 'Method patch is not allowed'. 메서드 이름이 소문자였습니다. 한쪽은 NestJS의 `allowedHeaders` 한 줄이 비어 있어서, 다른 한쪽은 React Admin의 dataProvider가 `method`를 소문자로 그대로 넘기고 있어서 — 그리고 그걸 Vite 6 프록시가 정규화 없이 그대로 흘려보내서. 두 자리를 동시에 잡고, `.env.local`을 절대 URL에서 `/api` 프록시 경유로 바꾸고, OPTIONS 응답 헤더를 검수 체크리스트로 박은 자정 디버깅 6시간을 다시 짚었습니다.

NestJSCORSVite
📚 NestJS + Refine 풀스택 트러블슈팅

Mock에선 되던 게 REST에선 안 됐다 — 응답 포맷 한 칸 차이가 만든 하루

VITE_USE_MOCK_API=false로 토글한 순간 useTable이 멈췄다. BE는 TransformInterceptor로 모든 응답을 `{ success, data, meta }`로 표준화했고, Refine은 `{ data, total }`을 기대했다. dataProvider 어댑터 한 줄로 메우면 끝나는 줄 알았는데 — 경로가 `/api/v1/api/v1/...`로 중복되고, FE가 `order`로 보낸 정렬 키를 BE는 `sortOrder`로 받았으며, 중첩 리소스 `/contents/:id/problems`는 dataProvider 기본 구현이 못 그렸다. 결국 어댑터 한 줄이 아니라 경로 정규화·필드 매핑·중첩 리소스 라우터·401 인터셉터까지 네 자리를 박아야 토글이 진짜 한 줄이 됐다.

RefineNestJSDataProvider
📚 NestJS + Refine 풀스택 트러블슈팅

1인 다역으로 5일 만에 90% — Admin Portal MVP를 끌어올린 토글 한 줄

SC-A01부터 SC-A20까지 20개 시나리오를 5일 만에 75%에서 90%까지 끌어올린 Admin Portal MVP 사이클. 혼자 PM·BE·FE 세 역할을 돌리면서 만든 병렬화의 환상은 사실 코드 한 줄 — `VITE_USE_MOCK_API=true` 환경변수 토글과 그 뒤에 붙은 Mock/REST DataProvider 두 구현체에서 시작됐다. Refine + Vite 위에서 14개 page 모듈을 어떤 순서로 박았는지, [FE → PM] 태그로 셀프 보고하던 협업 프로토콜이 왜 효과가 있었는지, Mock에서 REST로 갈아끼울 때 실제로 바뀐 건 한 줄이었는지 — 다섯 H2로 정리한다.

RefineViteNestJS
📚 NestJS + Refine 풀스택 트러블슈팅

갈아엎고 80일 — v2.0 마이그레이션 8편 메타 회고

devlog-13부터 devlog-20까지, v2.0 갈아엎기 5편과 v2.1로 끌어올리기 2편, v3.0 한 단계 더 1편을 한 발 떨어져서 다시 읽는다. Block에서 Bundle로의 전환, 5-Phase로 쪼갠 마이그레이션, 같은 날 v2.1로 SSoT를 끌어올린 결정, 1,682줄을 한 커밋에 박은 도메인 레이어, 그리고 그 위에 얇은 막을 입힌 Application Service까지. Before/After가 정말로 달라진 다섯 축(코드 책임, 문서 트랙, 멘탈, 도메인 명확성, 테스트 가능성)과 80일이 지나도 안 달라진 한 축(혼자 결정하고 혼자 박는 운영 모드)을 코드 위에서 정리한다.

DDD마이그레이션NestJS
📚 NestJS + Refine 풀스택 트러블슈팅

v3.0 Application Layer 재작성 — 도메인 서비스 위에 얇은 막을 한 Phase에 박은 날

도메인 서비스를 박은 다음 그 위에 Application Service 4종 + Controller 4종 + DTO 4종을 한 번에 박은 결정 이야기. trackState, secondLevel, track1/2Completed, curriculumProgress 같은 v3.0 필드가 Application 경계에서 어떻게 흡수되는지, 그리고 그 결과로 터진 빌드 에러 51개를 다섯 카테고리로 잡아간 새벽의 디버깅 흐름까지. 도메인이 비즈니스 규칙을 가지고, Application은 그것을 호출하는 얇은 오케스트레이션 막이 된다는 결합 규약을 코드 위에서 다시 한 번 확인한 한 Phase의 기록.

DDDApplication LayerNestJS
📚 NestJS + Refine 풀스택 트러블슈팅

v2.1 Domain Layer — 도메인 서비스 1,682줄을 한 커밋에 박은 날의 설계 철학

전날 4,658줄짜리 DDD 문서를 박은 다음 날 저녁, 그 문서를 입력으로 받아 도메인 레이어 코드를 다시 박았다. 한 커밋에 1,682줄 추가. MetricRank TOP1~5와 V21_THRESHOLDS를 도메인 타입으로 박은 결정, ContentCandidateService의 후보 폴백 설계, 90% 이상도 복습 필수로 바꾼 ReviewModuleService 리팩토링, BundleCompleted 이벤트로 Aggregate 간 결합을 끊은 결정 — 다섯 개의 도메인 서비스가 같은 커밋에 들어간 이유와 각각의 설계 철학.

DDDDomain LayerNestJS
📚 NestJS + Refine 풀스택 트러블슈팅

코드를 박은 다음 날 — 4,658줄 DDD 문서를 24분 사이에 다시 쓴 하루

v2.0 코드 마이그레이션이 끝난 직후, 같은 날 밤 24분 사이에 두 개의 docs 커밋이 들어갔다. v2.0 DDD 문서들은 _archived/v2.0/으로 묻혔고, 마스터 문서가 v2.1로 진화하면서 1,354줄이 갈아 끼워졌고, 그 위에 새 DDD 문서 4,658줄이 새로 적혔다. 코드와 문서를 다른 트랙으로 두지 않기 위해 무엇을 묶었고 무엇을 일부러 묻었는지의 기록.

DDDSSoT문서화
📚 NestJS + Refine 풀스택 트러블슈팅

Phase 3-3·3-4·3-5 — Application부터 Module까지, v2.0 마이그레이션 닫는 날

Phase 3-1·3-2가 만든 Repository와 Domain Service 위에 Application(953줄), Controller+DTO(763줄), Module(39줄)을 차례로 얹어 v2.0 번들 기반 학습 시스템을 닫는 단계. UC-06~10과 UC-14~17을 어떻게 코드로 옮겼는지, 인메모리 챌린지 스토어를 왜 일부러 남겼는지, 39줄짜리 모듈 한 장이 왜 끝의 끝인지를 기록한다.

NestJSApplication ServiceController
📚 NestJS + Refine 풀스택 트러블슈팅

Phase 3-1·3-2 — Repository와 Domain 서비스로 36개 빌드 에러 잡기

Phase 2가 남긴 36개 빌드 에러를 봉합하는 단계. BundleRepository 인터페이스 204줄과 Prisma 구현체 294줄, BundleGenerationService 417줄을 어떻게 분리해 작성했는지, 5콘텐츠 고정 구조와 4단계 폴백 전략을 코드로 어떻게 옮겼는지의 기록. 인터페이스 분리가 멘탈에 어떤 보호막을 쳐줬는지 포함.

NestJSPrismaDDD
📚 NestJS + Refine 풀스택 트러블슈팅

Phase 2 스키마 마이그레이션 — 데이터 안 날리고 구조 바꾸기

v2.0 Phase 2는 self-reference를 배열로 바꾸고, enum 두 개를 추가하고, NOT NULL을 nullable로 푸는 스키마 대수술이었다. Prisma migrate가 자동 생성한 SQL의 'data will be lost' 경고 4개를 어떻게 무력화했는지, 그리고 마이그레이션 직후 36개 빌드 에러가 났는데도 왜 멘탈이 멀쩡했는지의 기록.

NestJSPrismaPostgreSQL
📚 NestJS 실전 트러블슈팅

prisma generate 누락 — 빌드는 되는데 런타임 에러가 나는 이유

NestJS + Prisma 프로젝트에서 schema.prisma에 새 필드를 추가한 뒤 prisma generate를 빠뜨리면, TypeScript 빌드는 as any 캐스팅 덕에 통과하지만 런타임에서 Prisma Client가 새 필드를 모른다. pnpm build와 prisma generate가 별개 명령인 구조적 함정, prebuild 훅으로 자동화하는 해결법, Docker와 CI에서 놓치지 않는 예방 전략을 실전 코드와 함께 정리한다.

NestJSPrismaprisma generate
📚 React 프론트엔드 삽질기

Refine useCustom config.query가 정수를 보장하지 않는 함정 — 타입은 number인데 왜 400이야?

Refine의 useCustom hook에서 config.query 객체에 number 타입 값을 전달해도, URL 쿼리 파라미터로 직렬화되면서 문자열이 된다. NestJS @Type(() => Number) 검증과 조합하면 targetClassId must be an integer number 400 에러가 터진다. URL 직접 삽입 패턴으로 해결한 실전 사례를 정리한다.

ReactRefineuseCustom
📚 NestJS 실전 트러블슈팅

Soft Delete 필터가 빠진 곳 찾기 — 삭제한 데이터가 되살아나는 미스터리

NestJS + Prisma 프로젝트에서 Soft Delete 필터를 Application Service에만 적용하고 Domain Repository를 누락하면, 삭제된 데이터가 배치 프로세스와 조회 API에서 좀비처럼 되살아난다. PM 코드 리뷰에서 11곳 추가 발견된 실전 사례를 통해, 레이어별 필터 점검 체크리스트와 grep 기반 검증법을 정리한다.

NestJSPrismaSoft Delete