#PostgreSQL (9)

📚 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 풀스택 트러블슈팅

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

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

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

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

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

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

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

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

NestJSPrismaPostgreSQL