Day 29 휴식 의식 + Day 30~35 두 탭 UI
사용자가 처음 화면에서 줍줍을 만지는 자리 — E5 [2] 톤 분리 본격
📑 이 챕터에서 다룰 내용
- 서문 — 권1·권2에서 권3으로
- 0-1. Day 29 — 휴식 의식 적용
- 0-2. 권3 구조 안내 (Day 30~73, 45일)
- 0-3. 권3 5확장 진화 예고
- 0-4. 권3에서 가장 가치 있는 두 자리
- 제1장 — 사용자 첫 만남의 자리
- 1-1. Day 30 — 두 탭 메인 (Agent Teams)
- 1-2. Day 31 — 카테고리 필터·정렬
- 1-3. Day 32 — 상세 페이지
- 1-4. Day 33 — 단계적 기여: 체크박스
- 1-5. Day 34 — 단계적 기여: 결과 3택
- 1-6. Day 35 — 자유 후기 폼 + 닉네임 노출
- 1-7. Day 30~35 (5주차) 진행 점검
- 📌 제0·1장 정리
권1 (Phase 0) 21h + 권2 (Phase 1.0 절반) 63h = 누적 84h. 5파일+ 체계 가동 + 5확장 5/5 운영 사이클 완성. 1탄 v2 메타 원칙 6개 모두 데이터 입증.
이제 권3 — 사용자가 직접 줍줍을 보고 만지는 자리. Day 29~73 (45일).
| 권 | 본질 | 핵심 사건 |
|---|---|---|
| 권1 (Phase 0) | 5파일+ 사이클 | E1·E3·E4 등장 |
| 권2 (Phase 1.0 절반) | DB·인증·E5 [3] | R4 자동 회복 + G2 통과 |
| 권3 (Phase 1.0 후반·1.1·출시) | UI·외부 노출·심사 | E5 [2] [5] + E1 4자리 + G3·G4·G5 |
권3 끝 = 앱스토어 심사 통과 + 1순위 커뮤니티 게시 + 첫 100 사용자 + Phase 2 예고.
권2 끝에서 ★ G2 PASSED + git tag v0.1-G2-passed. 누적 84h. Day 28 "Day 29 1일 휴식 의무" 결정.
이 챕터는 휴식 의식 적용 + 권3 45일 구조 안내 + 5확장의 권3 진화 예고입니다.
| 사전 지식 체크 | 이 장의 목적 | 완료 후 결과물 |
|---|---|---|
| 권1·권2 누적 / G2 PASSED / Day 29 휴식 결정 | Day 29 휴식 적용 + 권3 구조 + 권3에서 등장할 5확장 진화 + Day 30 작업 시작 준비 | 충분한 휴식 + 권3 구조 인지 + 페이스 정상 복귀 (4h/일) |
## Phase 1.0 Day 29 — ★ G2 통과 후 휴식 의무 ★ [계획] - 작업 X (의식적 휴식) [실행] - 작업 X - 가족·자유 시간 - 가벼운 활동만 (산책·읽기) - BUILD.md·CLAUDE.md 노출 X (강제 단절) [E2 페이스 회복 효과] - 권1+권2 누적 84h → Day 29 휴식 → 다음 4주 새 시작 - "G2 통과 → 1일 휴식" 의식 (1탄 v2 부록 H-2 본문 일치) - 다음 4주 평균 R4 60h/4주 트리거 안전 영역 재진입 [6개월 후 동업자 시나리오] "왜 Day 29에 작업 안 했나?" 펼치면 본 트레이스에 답: "G2 게이트 통과 의식 = 1일 휴식 의무. 1탄 v2 부록 H-2 R4 본문 그대로. 운영자 보호 = R1~R12 모두 의미 있게 만드는 자리." [누적] 84h (Day 29 변동 없음)
휴식 후 Day 30 작업 정상 4h/일 복귀 준비.
┌──────────────────────────────────────────────────────────────┐ │ 5주차 (Day 30~35) + Day 36 휴식 — G3 첫 주 │ │ Day 30: 두 탭 메인 (Agent Teams 위임 — 소상공인·시민) │ │ Day 31: 카테고리 필터·정렬 (★ E5 [2] 톤 분리) │ │ Day 32: 상세 페이지 (지원금 정보 카드) │ │ Day 33: 단계적 기여 — 체크박스 (부담 0) │ │ Day 34: 단계적 기여 — 결과 3택 (부담 낮음) │ │ Day 35: 자유 후기 폼 + 닉네임 노출 (E5 [3] 적용) │ │ Day 36: 일요일 회고 │ ├──────────────────────────────────────────────────────────────┤ │ 6주차 (Day 37~42) — G3 통과 │ │ Day 37: 후기 신고 UI (사용자 측, C-4 연결) │ │ Day 38: ⚖️ E1 일관 노출 텍스트 (콘텐츠 면책 1차) │ │ Day 39: 매칭 알고리즘 (사용자 필터 ↔ benefits) │ │ Day 40: 통합 시뮬 (사용자 1명 줍줍 완료) │ │ Day 41: G3 점검 │ │ Day 42: ★ G3 PASSED 의식 + 6주 회고 │ ├──────────────────────────────────────────────────────────────┤ │ 7주차 (Day 43~49) — 통계 시각화 + Sentry │ │ Day 43: 마이페이지 (내가 줍줍한 총액 — DB 집계) │ │ Day 44: 통계 차트 (성공률·평균 일수) │ │ Day 45: Phase 1 KPI 측정 (E1 [측정 메트릭]) │ │ Day 46~47: Sentry 통합 (Day 56 게이트 조건) │ │ Day 48: 첫 7일 무장애 관측 시작 │ │ Day 49: 일요일 회고 │ ├──────────────────────────────────────────────────────────────┤ │ 8주차 (Day 50~56) — G4: FCM 알림 + 공유 카드 │ │ Day 50: FCM 마감 D-7 알림 cron │ │ Day 51: FCM 신규 매칭 즉시 알림 │ │ Day 52: 공유 카드 (Satori OG 이미지) │ │ Day 53: 1순위 커뮤니티 측정 폼 (어드민) │ │ Day 54~55: G4 통합 + 7일 무장애 관측 완료 │ │ Day 56: ★ G4 PASSED 의식 + 8주 회고 │ ├──────────────────────────────────────────────────────────────┤ │ 9주차 (Day 57~63) — 약관·개인정보·QA │ │ Day 57~58: ⚖️ E1 외부 노출 4자리 │ │ (About + 약관 + 개인정보처리방침 + Footer) │ │ Day 59: Apple Privacy Manifest 자동 검증 (G-7) │ │ Day 60: 어드민 마무리 (검수·신고·매칭·통계) │ │ Day 61: QA 1차 (전체 시나리오) │ │ Day 62: QA 2차 (Edge case) │ │ Day 63: 일요일 회고 │ ├──────────────────────────────────────────────────────────────┤ │ 10주차 (Day 64~73) — ★ G5 FINAL: 심사 + 커뮤니티 │ │ Day 64: EAS Build (iOS·Android) │ │ Day 65: 앱스토어 심사 제출 (iOS) │ │ Day 66: 플레이스토어 심사 제출 (Android) │ │ Day 67~68: 1순위 커뮤니티 게시 준비 + 게시 │ │ Day 69~71: 심사 결과 대응 (필요 시 재제출) │ │ Day 72: 1순위 커뮤니티 반응 수집 │ │ Day 73: ★ G5 PASSED + Phase 1 종합 회고 + Phase 2 예고 │ └──────────────────────────────────────────────────────────────┘
| 확장 | 권1·권2 진화 | 권3 진화 |
|---|---|---|
| E1 회색지대 | SPEC § 두 결정 + CLAUDE.md §3 | 외부 노출 4자리 (Day 57~) |
| E2 1인 페이스 | R4 자동 회복 1회 | 휴식 의식 4번 (G3·G4·G5·Phase 1 종합) |
| E3 두 검토자 | G-1·G-3·G-4·G-5·G-6 | G-7 (Apple Privacy Manifest 자동) |
| E4 LogOnTable | 39 트레이스 | +50 트레이스 → 누적 ~90 |
| E5 콘텐츠 SSOT | [1] [3] [4] [6] [7] | [2] 톤 분리 + [5] E1 외부 노출 4자리 일관 |
1. E5 [2] 톤 분리 (Day 30~35)
권1·권2에서 [3] 닉네임 페르소나 풀로 부분 등장. 권3에서 UI 카피 전체 톤 분리입니다.
[소상공인 탭 — 사장님 톤] - 메인 제목: "사장님, 오늘 받을 수 있는 지원금" - 카테고리: "신청 자격 + 매출 영향" - 줍줍 버튼: "사업장에 도움 → 줍줍" [개인 복지 탭 — 시민 톤] - 메인 제목: "당신에게 맞는 복지 혜택" - 카테고리: "생애주기 + 가구 상황" - 줍줍 버튼: "내 상황에 맞아 → 줍줍"
같은 "줍줍 버튼"인데 두 탭에서 다른 카피. 사실은 같지만 표현은 다름 — E5 콘텐츠 SSOT 시스템의 핵심입니다.
2. E1 외부 노출 4자리 (Day 57~58)
권1 제3장에서 SPEC § 회색지대 결정 두 결정 박힘. 권3에서 About + 약관 + 개인정보처리방침 + Footer 4자리에 같은 메시지 박힙니다.
[About 페이지] "줍줍은 정부 지원금 정보를 정리하고, 사용자 후기를 공유하는 미디어입니다. ✓ 약속하는 것: 공식 정보 정리 / 마감·요건 알림 / 후기 공유 / 자유 공간 ✗ 약속하지 않는 것: 무조건 받게 X / 신청 대행 X / 요건 우회 X / 정부 공식 X" [약관 §3 서비스 범위] "본 서비스는 신청 대행 X, 신청 결과 보장 X, 정부 공식 X." [개인정보처리방침 §1] "수집: 카카오 ID, 닉네임 자동, 자발적 필터, jupjups 행위 수집 안 함: IDFA·디바이스 식별자·위치 제3자 제공: X (Phase 3 익명 집계만)" [Footer 모든 페이지] "본 서비스는 정보 제공 목적, 결과 보장 X | About | 약관 | 개인정보"
핵심 한 줄: 권3 = 45일 (Day 29~73). G3·G4·G5 + E1 4자리 + E5 [2] [5] 본격. ★ G5 FINAL 앱스토어 심사 + 1순위 커뮤니티.
- Day 29 휴식 의식: 권1+권2 누적 84h → Day 29 작업 X → Day 30 정상 복귀
- 5~6주차: G3 두 탭 UI + 단계적 기여
- 7주차: 통계 + Sentry
- 8주차: G4 알림·공유
- 9주차: 약관·개인정보·QA
- 10주차: ★ G5 심사 + 커뮤니티
권2까지 "DB + 인증 + 백엔드". 권3 제1장부터 사용자가 직접 보고 만지는 화면. 5확장 E5 [2] (톤 분리) 본격 등장 자리입니다.
| 사전 지식 체크 | 이 장의 목적 | 완료 후 결과물 |
|---|---|---|
| 권1·권2 + Day 29 휴식 / CLAUDE.md §5 [2] / G3 통과 조건 | Day 30~35 두 탭 UI + 단계적 기여 시스템 + E5 [2] 본격 | 두 탭 메인·필터·상세 페이지 + 단계적 기여 3 단계 + 첫 사용자 줍줍 시뮬 |
작업 (4h — 페이스 정상 복귀)
CLAUDE.md §6 폴더 구조 그대로 두 에이전트에 병렬 위임합니다.
[Claude Code, Sonnet + medium]
"두 탭 메인 페이지 동시 (Agent Teams):
/delegate
에이전트 A (담당: src/app/(tabs)/business/index.tsx):
- 메인 제목: '사장님, 오늘 받을 수 있는 지원금' (E5 [2] 사장님 톤)
- benefits 목록 (target_business_type 필터)
- 카드 컴포넌트: 사업단계 + 지원 금액 + 마감 D-N + 줍줍 수
- 줍줍 버튼 카피: '사업장에 도움 → 줍줍'
에이전트 B (담당: src/app/(tabs)/individual/index.tsx):
- 메인 제목: '당신에게 맞는 복지 혜택' (E5 [2] 시민 톤)
- benefits 목록 (target_age·target_household 필터)
- 카드 컴포넌트: 생애주기 + 지원 금액 + 마감 D-N + 줍줍 수
- 줍줍 버튼 카피: '내 상황에 맞아 → 줍줍'
CLAUDE.md §5 [2] Two-Tab 톤 분리 절대 준수.
공통 BenefitCard.tsx 는 components/에 (직접 수정, 톤 prop으로 분기).
E5 [1] SSOT 준수 — 같은 benefit_id 두 탭 노출 시 사실 일치 자동 검증."
## Phase 1.0 Day 30
[계획]
- 두 탭 메인 페이지 Agent Teams 위임
[실행]
- /delegate 에이전트 A·B 병렬 (4h 합계, 순차 8h 대비 -50%)
- src/app/(tabs)/business/index.tsx (160줄)
- src/app/(tabs)/individual/index.tsx (155줄)
- src/components/BenefitCard.tsx (110줄, tone prop으로 분기)
- 일관성 테스트 5/5 통과 (E5 [6])
[LogOnTable 트레이스 — BenefitCard tone prop 결정]
> 결정: BenefitCard 단일 컴포넌트 + tone='business'|'individual' prop
> 근거: SSOT 시스템 [1] — 사실 단일 출처 + 톤 분리 [2]. 두 컴포넌트
복사 X = DRY + E5 [1] 자연 보장.
> 대안: BusinessCard / IndividualCard 분리 — 코드 중복 + 일관성 검증 어려움
> 부작용: tone prop 전환 시 카피만 변경. 다음 톤 추가 시 enum 확장 가능
[E5 [2] 본격 등장]
- 같은 BenefitCard 컴포넌트, tone prop 'business' / 'individual'
- 사실은 같지만 표현은 다름 (SSOT 시스템 깊이)
[누적] 84h + Day 30 (4h) = 88h
[Claude Code]
"카테고리 필터·정렬 컴포넌트 — 두 탭 톤 분리:
에이전트 A (담당: src/app/(tabs)/business/filters.tsx):
- 필터 카테고리 (사장님 톤):
· '내 사업단계는?' (창업준비/1년미만/3년미만/3년이상/폐업재기)
· '지원 유형' (자금/공간/컨설팅)
· '신청 자격' (강조)
- 정렬:
· '마감 임박순' / '많이 줍줍한 순' / '내가 받을 가능성 높은 순'
에이전트 B (담당: src/app/(tabs)/individual/filters.tsx):
- 필터 카테고리 (시민 톤):
· '내 가구는?' (1인/부부/한부모/다자녀/노인/장애인)
· '내 상황' (생애주기)
· '소득 분위' (선택)
- 정렬: 동일 3개 (단, 카피 시민 톤)
E5 [1] [2] 절대 준수."
결정: 같은 기능 (필터 6 + 정렬 3 = 9개) × 두 탭 = 카피 18개 톤 분기
근거: E5 [2] "같은 사실 다른 톤"의 깊이. UI 카피 1개씩 분기.
대안: 같은 카피 사용 — 톤 분리 본질 손상 (사장님이 시민 카피 읽으면 "내 앱이 아닌 듯" 느낌)
부작용: 카피 18개 i18n 매핑 (Phase 1.1 다국어 시 본격), 현재는 static.
누적: 88h + Day 31 (4h) = 92h
에이전트 A (src/app/(tabs)/business/[benefit_id].tsx):
- 헤더: benefit name + 지원 금액 + 마감 D-N
- 사장님 톤 섹션:
· '신청 자격' / '지원 내용' / '꼭 필요한 서류' / '담당 기관'
- 후기 영역 (Day 33~35 단계적 기여 컴포넌트 placeholder)
- 줍줍 버튼: '사업장에 도움 → 줍줍'
에이전트 B (src/app/(tabs)/individual/[benefit_id].tsx):
- 헤더 동일 (사실 동일 — E5 [1])
- 시민 톤 섹션:
· '신청 자격' / '받는 방법' / '필요한 것' / '문의처'
- 후기 영역 placeholder
- 줍줍 버튼: '내 상황에 맞아 → 줍줍'
결정: 사장님 톤 = '담당 기관' / 시민 톤 = '문의처'
근거: 사장님 = "공식 절차 인식 강함" → 기관명 정확히 / 시민 = "친근한 안내" → 문의처 표현 자연
누적: 92h + Day 32 (4h) = 96h
// components/JupjupCheckbox.tsx
import { useState } from 'react';
import { Alert } from 'react-native';
import { jupjupCreate } from '@/lib/jupjups';
interface Props {
benefitId: string;
tone: 'business' | 'individual';
onSuccess?: () => void; // Day 34 부담 낮음 노출 트리거
}
const COPIES = {
business: {
label: '사업장에 도움 → 줍줍',
success: '줍줍! 다음 단계 어땠나요?',
duplicate: '이미 줍줍한 지원금입니다',
rateLimit: '잠시 후 재시도해주세요',
},
individual: {
label: '내 상황에 맞아 → 줍줍',
success: '줍줍! 다음 단계 어땠나요?',
duplicate: '이미 줍줍한 지원금입니다',
rateLimit: '잠시 후 재시도해주세요',
},
};
export function JupjupCheckbox({ benefitId, tone, onSuccess }: Props) {
const [pending, setPending] = useState(false);
const [done, setDone] = useState(false);
const copy = COPIES[tone];
const handleClick = async () => {
if (done || pending) return;
setPending(true);
try {
const result = await jupjupCreate(benefitId);
if (result.error === 'DUPLICATE') {
Alert.alert(copy.duplicate);
} else if (result.error === 'RATE_LIMIT') {
Alert.alert(copy.rateLimit);
} else if (result.success) {
setDone(true);
onSuccess?.(); // Day 34 부담 낮음 노출
}
} finally {
setPending(false);
}
};
return (
<Pressable onPress={handleClick} disabled={pending || done}>
<Text>{done ? copy.success : copy.label}</Text>
{/* ⚖️ E1 하단 면책 */}
<Text className="text-xs text-gray-500 mt-1">
본 서비스는 정보 제공 목적, 신청 결과 보장 X
</Text>
</Pressable>
);
}
결정: 체크박스 컴포넌트 안에 E1 면책 1줄 명시
근거: 권1 제3장 E1 결정 ① + 권3 Day 38 외부 노출 4자리 예정이지만 사용자 행위 시점 (체크박스 누르는 자리) = 가장 강한 자리. "신청 결과 보장 X" 즉시 인지.
누적: 96h + Day 33 (4h) = 100h
요구사항: 1. components/JupjupResultPicker.tsx — 체크박스 후 1초 안에 노출 2. 3택: SUCCESS (받았어요) / FAILED (떨어졌어요) / IN_PROGRESS (진행중) 3. UPDATE jupjups SET result = ? 4. 트리거 자동: benefits.total_jupjups·total_success 갱신 5. E5 [2] 카피 두 탭 분리: - business 톤: '받았어요 (대박!) / 떨어졌어요 (다음을 위해) / 진행중' - individual 톤: '받았어요! / 떨어졌어요... / 진행중이에요'
결정: 'SUCCESS / FAILED / IN_PROGRESS' enum + 두 톤 6 카피
근거: enum 동일 (DB 일관) + UI 카피 분리 (E5 [2] 톤 분리 깊이). 사장님 톤 "대박!" vs 시민 톤 "받았어요!" 감정 표현 차이. 분리가 자연스럽습니다.
누적: 100h + Day 34 (4h) = 104h
1. components/JupjupReviewForm.tsx - 결과 입력 후 1초 안에 노출 (선택, "건너뛰기" 버튼) - 200자 제한 + 자동 카운트 - UPDATE jupjups SET review_text, days_taken 2. 자유 후기 노출 시 닉네임 표시: - components/UserNicknameBadge.tsx - E5 [3] 닉네임 + 신뢰 표시 (총 줍줍 N개·후기 M개) 3. 후기 노출 페이지 (상세 페이지 안): - components/ReviewList.tsx - 닉네임 + 결과 + 후기 텍스트 + N일 전 - 신고 버튼 (C-4 연결, Day 37)
결정: 닉네임 + 신뢰 (총 줍줍·후기 수) 강조 (실명 X)
근거: E1 결정 ② "익명성 유지" + 사용자 신뢰 = 줍줍·후기 수 (실명보다 행위 데이터)
누적: 104h + Day 35 (4h) = 108h
[권1·권2 누적] 84h [권3 5주차 (Day 30~35)] 24h [합계 누적] 108h [5주차 평균] 24h/6일 = 4h/일 (페이스 정상) [R4 4주 누적 (2~5주차)] 14+14+21+24 = 73h ⚠️ R4 60h 트리거 초과
4주 누적 73h로 R4 트리거 (60h/4주) 초과. 자동 결정이 발동합니다.
- Day 36 일요일 추가 휴식 (회고만)
- 6주차 (Day 37~42) 페이스 25% 축소 (4h/일 → 3h/일)
- "피곤하다" 신호 부재 — 단, 트리거 초과만으로 자동 보호
📌 권3 제0·1장 정리
- Day 29 휴식 의식: 권1+권2 누적 84h → 작업 X → Day 30 정상 복귀
- 5주차 산출물: 두 탭 메인 (315줄) + 필터·정렬 (265줄, 18 카피) + 상세 (290줄) + 단계적 기여 3단계 (340줄) + 닉네임·후기 (150줄) = ~1,360줄
- E5 [2] 본격 등장: BenefitCard tone prop 분기 + 18 카피 톤 분기. "사실은 같지만 표현은 다름"
- 단계적 기여 3단계: 부담 0 (체크박스) → 부담 낮음 (3택) → 부담 선택 (200자 후기)
- 누적: 108h / 4주 누적 73h (R4 트리거 초과 → 6주차 페이스 축소 자동 결정)
- 다음 장: 권3 제2장 — Day 36~42 (G3 두 탭 마무리 + 단계적 기여 완성 + ★ G3 PASSED)