버그와의 전쟁 — JOIN 중복부터 외래키까지
2025년 11월 1일 ~ 2일 · v1.3 → v1.4
이틀 연속으로 버그와 싸웠다. 첫째 날은 에셋 중복 표시 버그에 하루 종일 매달렸고, 둘째 날은 텍스트 블록 500 에러를 잡았다. 짧지만 강렬한 이틀이었다.
에셋 중복 버그 — 5번의 시도, 1번의 승리
프로젝트 에디터에서 에셋 목록을 불러오면, ID 86번이 두 번 표시되고 ID 82번은 빠져 있었다. DB에는 10개인데 API가 11개를 반환하는 상황. 원인은 project_assets와 character_assets를 INNER JOIN으로 엮는 복잡한 쿼리에서 1:N 관계로 행이 뻥튀기되고 있었다.
- 1차 — PHP
in_array중복 제거 → 실패 - 2차 —
isset키 기반 제거 → 실패 - 3차 — SQL
DISTINCT→ 실패 - 4차 — 서브쿼리 분리 → 실패
- 5차 — API 전면 재작성 → 성공!
복잡한 INNER JOIN을 버리고, 두 개의 단순한 SELECT 쿼리 + PHP 배열 매핑 방식으로 완전히 다시 썼다. 결과는 완벽. 중복 없이 정확히 10개의 에셋이 반환됐다.
"DB에는 문제가 없다는 거 너도 알지? 그러면 네가 제어할 수 있는 코드에서 모든 문제가 생긴거야."
텍스트 블록 500 에러 — 외래키의 교훈
다음 날, 텍스트 블록을 저장하면 500 Internal Server Error가 발생했다. 이미지 블록은 잘 되는데 텍스트만 에러. 원인은 의외로 간단했다.
portfolio_blocks.block_type이 block_types.type_name을 외래키로 참조하는데, block_types 테이블에 'text' 타입이 등록되어 있지 않았다.
INSERT INTO block_types (type_name, type_label, description, is_active)
VALUES ('text', '텍스트', '리치 텍스트 에디터 블록', 1);
한 줄로 해결됐다. 500 에러의 원인이 코드가 아니라 데이터 누락이었다는 점이 이 이틀의 반전.
교훈: 같은 방법을 반복하지 말고, 세 번 이상 실패하면 접근 방식 자체를 전환할 것. 새로운 블록 타입을 추가할 때는 코드를 짜기 전에 반드시 DB의 block_types 테이블에 먼저 등록할 것.