← 목록으로

크루 100명 전면 재설계 — 작업 보고

2026-08-26 새벽 · 커밋 16건 · → 크루 100명 프로필 보기


한 줄

크루 211명을 100명으로 다시 짜고, 이름 체계·관계 축·성격·사진을 전부 새로 만들었다.
기존에 쌓아 둔 지식 자산은 버리지 않고 1,266행을 새 크루에게 넘겼다.


왜 갈아엎었나 — 실측으로 드러난 것

이미지를 뽑기 전에 크루 구성부터 보자는 대표 지시로 DB를 전수 조사했다. 상태가 이랬다.

무엇 실측
닉네임 유니크 55종 / 211명156명이 남의 이름을 썼다
"망하기 일보직전" 하나를 헤드헌터·커피전문가·업무효율화·HR인사이더 등 15명이 공유
본명·호칭 0명. 부를 수 있는 이름을 가진 크루가 하나도 없었다
카테고리 연애 크루 13명이 "커리어" 로 분류 (첫데이트 코치·짝사랑 상담·프렌드존 탈출…)
성별 값 male 70 / 여성 51 / 남성 46 / female 44 — 네 값이 섞임
hook_messages 211명 전부 빈값
스키마 문서 CLAUDE.md 의 knowledge_text·skill_ids 칼럼이 실제 테이블에 없음

닉네임 중복은 증상이지 원인이 아니었다. nickname 은 처음부터 이름이 아니라
캐치프레이즈였다 — "망하기 일보직전아"라고 부를 수 없다. 진짜 결손은 본명·호칭이 0명인 것.


1. 명부 — 211명 → 100명

기획 에이전트 4명(사용빈도·신규유입·정보구조·참신성)이 각각 푼 뒤 종합했다.

동행 34 · 몸마음 12 · 일 11 · 돈 9 · 배움 9 · 살림 8 · 각계각층 6 · 만들기 6 · 연애 5

대표가 못 박은 조건이 전부 반영됐다.

기계 검증 전항목 통과: 총원 100 / slug 중복 0 / 성비 여60:남40(목표 정확히 일치) /
이성친구 8명 여4:남4 / 미성년 4명 전원 친구 / 나이 앵커 외 값 0 /
인용한 기존 slug 178개 전부 실재(허수 0)


2. 이름은 네 겹이다

만나기 전에는 간판, 만난 뒤에는 호칭.

칼럼 쓰는 자리
L1 본명 person_name 박서진 자기소개·프롬프트
L2 호칭 call_name + call_style 박 차장 / 은주 선배 / 상철 형 대화에서 부를 때
L3 간판 handle 연봉부스터 목록·알림·결제
L4 한 줄 tagline "올려 달라고 말하지 마세요" 카드·상세

call_style직함 24 · 이름 48 · 관계 28. 대표가 말한 "박 차장", "영이 엄마"가 그대로 축이 됐다.

나이는 UI에서 뺀다. Flutter Crew 모델에 age 필드가 애초에 없어 이미 노출되지 않고 있었다.
DB에는 남겨 말투 생성에만 쓴다. 동행 크루만 또래대(peer_band)를 노출한다.


3. 관계 축 — "영어 선생을 이성친구로 쓰지 않는다"

카테고리(무엇을 해주는가)와 별개로 relations(어떤 사이인가)를 뒀다.

전문가 54 · 멘토 20 · 친구 10 · 이성친구 8 · 가족같은 5 · 말벗 3

동행 34명 — 이 축이 유일하게 재방문을 만든다

전문가는 문제가 풀리면 안 온다. 친구는 이유 없이 온다.

또래 친구   초등·중고등·20대·30-40대·50대+ × 남녀   10명
이성친구    20대·30대·40대·50대+ × 남녀            8명 (남4:여4)
말벗·가족   할머니·삼촌·언니·형                     8명
멘토형 친구                                        8명

"영입"이 아니라 "사귀기"다. 문턱(거절·승낙)은 두지 않는다 — 만나는 건 즉시고,
관계가 대화로 자란다. 처음엔 존댓말과 거리, 쌓이면 말이 편해지고, 가까워지면 부르는 말이 바뀐다.
user_crews.closeness(0~3)와 turn_count 로 저장한다. 동행은 정액(access='subscription').


4. 성격 100개 — 전부 직접 썼다

대표: "네가 직접 써야지 왜 오픈AI 키를 이용해서 쓰냐, 너도 LLM인데."

맞는 지적이었다(게다가 OPENAI_API_KEY 는 401로 죽어 있었다). 서브에이전트 4명이 25명씩 썼다.

구조[나는 누구인가][말투][내가 아는 것][내가 모르는 것][답변 규칙]

검증: 100개 / 721~1076자(평균 891) / 이모지 0 / 자기 간판 호명 0 / 실명 0 /
5개 섹션 전원 존재 / 동행 34명 전원 친밀도 3줄

[내가 모르는 것]을 필수로 넣은 이유는 하나다 — 여기서 선을 긋지 않으면 크루가 아무거나 아는 척한다.


5. 기존 자산은 버리지 않았다

대표: "많은 시간을 투여해서 작업했던 거고 중고차 딜러도 그렇고… 버리기보다 가져다 쓰라고."

1,266행을 승계했다.

물려준 쪽 받은 쪽 행수
stock-aga-house stock-101 주린이탈출 416
heyenka car-guide 중고차형님 318
start-with-10k saving-starter 종잣돈반 171
yummy-zero-cal diet-realist 다이어트현실 143
money-talk money-talk 세상물정 76
ano-sensei japanese-sensei 일본어센세 58
brand-young design-basic 브랜드디자이너 35
toss-interview-king interview-coach 면접왕 30
knee-slap-master youtube-coach 유튜브수익화 19

동양 고전·부의 사고방식 199행은 대응 주제가 없어 지우지 않고 _parked_classics보관했다.
나중에 그 크루가 생기면 slug만 바꿔 붙는다.

그리고 성격을 쓸 때 이 자료를 읽고 "무엇을 아는 사람인지"만 가져왔다. 문장은 베끼지 않았다.

실명 세탁 — 453행

crew_knowledge 에 실존 인물 이름이 남아 있었다(이광수 415건·노희영 34건 등).
지식 방침대로 "누가 말했나"가 아니라 "그 사람으로 오인되는가" 에 선을 긋고 역할 표현으로 바꿨다.

검증: title·content 전수 재조회 결과 실명 잔존 0건.

source_url 1,465건이 전부 로컬 파일 경로여서 원 출처 역추적·삭제 요청 대응이 불가능했다.
로컬 경로는 지웠다(남은 0건). 앞으로 적재할 때는 원 URL을 넣는다.


6. 사진 — 한 장만 만들고 얼굴은 잘라낸다

대표: "작은 원 안의 얼굴도 이미 있는 이미지를 갖는 거지? 얼굴 하나만 갖고 쓰는 게 맞느냐?"

맞다. 한 장이면 된다. 실제로 돌려서 확인했다.

  1. creagen(nano-banana-2, 3:4 1K)로 원본 1장 생성 — fal.ai 는 키가 죽어 있다
  2. macOS Vision 으로 얼굴 정사각 크롭 (tool/faceavatar) — 100/100 검출 성공
  3. Supabase Storage 업로드 → full_body_image_url / avatar_url 연결

고정 크롭으로는 안 된다 — 얼굴 중심 Y가 0.198 ~ 0.281 로 흩어져 크루마다 눈높이가 어긋난다.
자르는 규칙은 정사각 변 = 얼굴 높이 × 2.35, 중심은 얼굴 중심에서 위로 10%.

작은 원은 44px이 맞다 — 22·26은 색점으로 읽히고, 34부터 사람이 보이고, 44에서 누구인지 안다.
무대 아바타(26)·캐스트(22)·대화 카드(34)를 44로 올릴 것을 제안한다.

세 번 뽑았다 — 두 번은 내 실수다

1차 카테고리별로 옷·배경을 하나로 고정해서 100명이 다 비슷해 보였다.
어제 "톤이 제각각이라 스톡 사진 같다"를 고치려다 반대로 복제처럼 됐다.
→ 옷 12종·배경 12종·머리 6종·얼굴 인상 6종·안경 여부를 slug 해시로 크루마다 갈리게 했다.

2차 다양성은 살았는데 전부 가로 사진이었다. aspect_ratio 로 넘겼는데
그 라이브러리는 aspectRatio 를 받는다. 이름이 안 맞아 조용히 무시되고 기본값 16:9 가 걸렸다.

이게 중요하다 — 에러가 안 났다. 파일 해시 100개 유니크, 얼굴 검출 100/100,
업로드 100/100, 외부 200까지 전부 통과했는데도 못 잡았다.
이미지를 직접 열어 보고서야 알았다. 숫자로만 검증하면 이런 게 빠져나간다.

3차 896×1200 세로로 나오는 것을 한 장으로 먼저 확인하고 전량 재생성했다.
최종: 100장 전부 896×1200, 서로 다른 파일 100개, 얼굴 검출 100/100.


7. 코드에서 고친 것

정규식 @멘션 주입 폐기 (93줄)post-processor.ts 가 크루 이름과 역할 키워드를
정규식으로 훑어 @닉네임 을 문장에 꽂아 넣고 있었다. 프로젝트 룰 정면 위반이고,
새 호칭이 "박 차장"처럼 짧아지면 오탐이 터진다. 팀 명부를 프롬프트에 실어
LLM이 스스로 부르게 하고 라우팅은 crew_id 로 한다.

클라이언트 8곳 호명 통일 — 서버는 고쳐졌는데 클라이언트가 아직 nickname ?? name 이라
말풍선과 팀 슬롯에 "16년째 연습중" 같은 캐치프레이즈가 사람 이름 자리에 떴다.

191명 내리기 전 조회 코드 2곳 선제 수정 — 딥링크로 대화를 열 때와 영입 크루 목록이
is_active 만 가져오고 있었다. 그대로 뒀으면 939개 대화방과 영입 55건이 깨졌다.
"고르는 자리"(마켓·추천·검색)에만 is_active 를 걸고, "여는 자리"에는 걸지 않는다.


8. 남은 것 — 대표 확인 필요

🔴 키 두 개가 죽어 있다

오늘 밤 작업엔 지장이 없었다(이미지는 creagen, 성격은 직접 작성).
다만 앱 런타임이 OpenAI를 쓴다면 크루 대화 자체가 안 된다. 크루를 100명으로 새로 깔았으니
이것부터 확인해야 한다.

🟡 KNOWLEDGE_SEARCH_ENABLED

코드 기본값은 false라 안 켰으면 실사용자에게 안 나간다. 다만 Supabase 시크릿 조회가 403이라
실제 값을 확인하지 못했다. 대시보드에서 값만 봐 주면 된다.

🟡 폐기 191명

is_active=false 로 내렸다. 지우지 않았고 되돌릴 SQL 194줄이 백업에 있다.

🟢 다음 작업


검증 요약

항목 결과
명부 100명 / slug 중복 0 / 성비 여60:남40
성격 100개 / 이모지 0 / 간판 호명 0 / 실명 0
활성 크루 100명 (임시 프롬프트 0건)
지식 승계 1,266행 / 보관 199행 / 실명 잔존 0
사진 생성 100 / 얼굴 검출 100 / 업로드 100 / 외부 200 확인
코드 flutter analyze 새 경고 0 / build web 성공 / 배포 완료

백업은 전부 claudedocs/migration/backup/ 에 있다 —
gender 원본 211행 + 롤백 SQL, 폐기 191명 롤백 SQL, crew_knowledge 세탁 전 1,465행.