AI용 분할본 · 지도 6단계(선택 기능 — 결정서에 고른 것만) · 이 페이지 전에 읽을 페이지: PART 0 사용법·AI 시작 지침, PART 4 결정서·마스터 스펙, 부록 A 스펙·코드 받기(A-2) · 코드 파일은 여기 없다 — 코드 자리의 줄을 따른다(폴더에 책 파일이 하나도 없는 처음이면 부록 A-2 의 curl 한 줄부터)
핵심 규칙 — AI 는 어느 페이지에서든 이것을 지킨다
node scripts/get-book-code.mjs 가 책 그대로 만든다(첫 실행은 부록 A-2 의 curl 한 줄). AI용 분할본의 코드 자리는 " 경로" 한 줄이다 — 그 파일을 cat 으로 읽는다. 고쳐도 되는 파일은 PART 0 [AI 시작 지침] 5-b 의 목록뿐이다.node scripts/verify-book-code.mjs 를 실행해 "불일치 0개" 출력을 그대로 보인다.각 레시피는 마스터 스펙으로 만든 앱 위에 얹는 프롬프트입니다.
홈 상단에 "오늘의 운세" 카드를 추가해 주세요. - POST /api/float/reading 사용(lib/api.ts callProxy 경유 — requestId 필수), question은 고정: "오늘 하루의 전반적인 흐름과 조심할 것, 활용하면 좋은 시간대를 짧게 알려 주세요" - 본문에 personaKey 를 넣어 캐릭터 말투로 받는다(readingBody(profile, question, personaKey)). 답변 표시는 components/AssistantMessage.tsx 로(plain text 금지) - 하루 1회만 호출하고 결과를 이 브라우저에 캐시한다(크레딧 절약). 캐시 키에는 회원 id(/api/me)·원국(생년월일시·성별)·한국 날짜를 전부 넣는다 — 날짜만 넣으면 같은 폰에서 다른 회원이 로그인하거나 생년월일을 고쳤을 때 앞 사람·옛 원국의 운세가 보인다. 로그아웃할 때 이 캐시를 지운다 - 카드에 오늘 날짜와 캐릭터 이름 표시 - 완료 기준: 회원 A 로 운세를 본 뒤 같은 브라우저에서 회원 B(다른 생년월일)로 로그인하면 B 의 일간으로 새 운세가 나온다 / 생년월일 수정 후 운세가 새로 나온다
HRUM 궁합 API 한 번이면 사주 궁합(일주·8글자)과 띠 궁합이 함께 옵니다. 점수·6가지 축·두 사람 일주의 합충·오행 보완·서로를 보는 십신까지 계산이 끝난 값이라, 앱은 보기 좋게 그리기만 하면 됩니다. 사주·속궁합 기호표·띠 궁합은 규칙표, 별자리 궁합은 천문 계산이라 같은 두 사람은 언제 봐도 같은 결과가 나옵니다(LLM 미사용 — AI가 지어낸 문장 아님). 1회 20원.
궁합 API 제대로 쓰기 — 이것만 지키면 됩니다
- 메인은 사주 궁합(
saju)입니다. 띠 궁합(tti)만 보여 주면 "쥐 × 호랑이 · 주의" 한 줄짜리 빈약한 화면이 됩니다. 띠 궁합은 맨 아래 덤으로.- 응답에 온 건 다 보여 줍니다. 점수·등급·관계 유형, 6축, 천간·지지 관계, 오행 보완, 십신, 신살 문장, 잘 맞는/조심할 관계. 값이
null·빈 배열인 칸만 숨깁니다.- 해석 문장을 지어내지 않습니다. 화면의 문장은 응답 값(
pattern.description등) 그대로. 관계별 서술 2~3문장은 응답의categoryNarrative.text에 이미 있으니 그대로 씁니다. 그보다 긴 풀이가 필요할 때만 궁합 결과를/reading질문에 넣어 캐릭터 말투로 받습니다(6-2).- 용도(
purpose)를 고르게 합니다. 연애·결혼·우정·사업에 따라 점수와 6축이 달라집니다. 바꿀 때마다 다시 호출(1회 20원).- 겁주지 않습니다. 띠 궁합(
tti)은 등급과 관계 배지만 보여 주고 "재미로 보는 전통 궁합이에요"를 붙입니다.필드 이름과 뜻은 콘솔 API 문서(https://console.hrum.ai/docs.html#compat-api — 분할 모드에서도 열어도 된다) "궁합 API"에 실제 응답 예시와 함께 있습니다. 화면 모양은 자유 — 위 다섯 가지만 지키면 됩니다.
궁합 페이지(/compat)를 추가해 주세요.
- 나(A)는 로그인한 회원의 저장된 원국(GET /api/profile)을 쓰고, 상대방(B)만 생년월일·성별을 입력받는다 — 태어난 시각은 선택(비워 두면 보내지 않음, 필수 입력으로 막지 않는다). 원국이 없으면 먼저 원국 입력으로 보낸다
- 궁합 용도 고르기(칩 4개): 연애 yeonae_attraction(기본) · 결혼 marriage_stability · 우정 friendship · 사업 business_partnership — 용도에 따라 점수와 6축이 달라진다
- POST /api/float/compat (lib/api.ts callProxy 경유 — requestId 필수, 궁합 조회 1회에 UUID 1개)
req: { personABirthDate:"1990-03-15", personABirthTime:"08:30"(선택), personAGender:"male", personBBirthDate, personBBirthTime(선택), personBGender, purpose }
- res.data (필드 이름 그대로 쓴다 — 추측해서 다른 이름을 만들지 않는다):
saju: { ← 메인. null 일 수 있다(그때는 띠 궁합만 보여 준다)
purpose, hourKnown: { a, b }, ← 한쪽이라도 false 면 "태어난 시각을 넣으면 더 정확해요" 한 줄
personA: { ilju }, personB: { ilju }, ← 일주 이름(예 "병인") — 두 사람 카드에 "병인 일주"로
score: { total: 0~100, grade: 쉬운 말 등급("아주 잘 맞아요"·"잘 맞아요"·"무난해요"·"맞춰 가면 좋아요"·"서로 많이 달라요"), breakdown: { ilju, authority, eightChar } (각각 숫자 또는 null — 화면에 굳이 안 보여도 된다) },
axes: { attraction 끌림, stability 안정, growth 성장, communication 소통, passion 열정, longevity 지속 } ← 0~100
pattern: { name: 관계 유형(예 "보완형"·"중독형"), description: 그 유형 설명 한두 문장 } 또는 null,
relation: { summary, stem: { type, detail } 또는 null, branches: [ { type, detail } ] }, ← 천간·지지 관계
elements: { basis: "eight"|"six", aLacks, bProvidesToA, bLacks, aProvidesToB } 또는 null, ← 오행 이름 배열("목"·"화"·…)
tenGods: { aView, bView }, ← 나에게 상대는 "정재", 상대에게 나는 "정관" 같은 식
bestFor: [..], weakFor: [..], ← 잘 맞는/조심할 관계 종류
highlights: [문장, 최대 5개] ← 8글자에서 찾은 특별한 연결(예 천을귀인)
}
tti: { userTti, partnerTti, tier, relation: { type, detail } } ← 띠 궁합(두 띠의 관계와 등급)
categoryNarrative: { category, purpose, lang, text } 또는 null ← 이 관계(purpose)에서 두 사람을 풀어 쓴 2~3문장(미리 써 둔 문장)
classic1995: { symbol, grade, score, conflictFrame } 또는 null ← 일주 속궁합 기호표(참고 문헌 1995)의 기호(●·◎·○·△·×·××)
astroSynastry: { layers[], purposeBodies[], caveatTexts[], score } ← 별자리 궁합(시간을 모르면 상승궁 층이 빠진다)
astroReadings: [ { key, lang, text } ] ← 별자리 접점 풀이 문단(없으면 빈 배열)
headerBreakdown: { average, … } 또는 null ← 종합 점수(INTA 앱 궁합 화면의 큰 숫자)
costPoints
- 결과 화면 순서:
1) 큰 점수(score.total)와 등급(score.grade) + 관계 유형(pattern.name)과 설명(pattern.description) + 관계 서술(categoryNarrative.text, null 이면 숨김)
2) 두 사람 카드: 일주 이름·띠·서로 보는 십신(tenGods)
3) 6축 막대 6개(axes, 라벨은 위 한글) — 막대 길이 = 값%
4) 관계: relation.summary + 천간/지지 관계 배지(branches 의 type), detail 은 있을 때만
5) 오행 보완: "상대가 채워 주는 오행: 화·토"처럼(bProvidesToA / aProvidesToB). 빈 배열이면 그 줄을 숨긴다. basis 가 "six"면 "(시간 제외 6글자 기준)"
6) highlights 목록(없으면 숨김), bestFor·weakFor 칩
7) 띠 궁합 카드: userTti × partnerTti + tier 배지 + tti.relation.type 배지. 띠 궁합 풀이 문장은 응답에 없으니 지어내지 않는다
맨 아래 "재미로 보는 전통 궁합이에요" 한 줄. 점수가 낮거나 tier 가 "흉"이어도 겁주는 문구를 만들지 않는다
- null·빈 배열은 그 부분만 숨기고, 객체를 그대로 화면에 넣지 않는다(React 는 객체를 그리면 화면 전체가 멈춘다)
- 연도는 1900~2100 만 받는다 — 날짜 칸에 연도를 두 자리로 치면 0090 처럼 들어가니 보내기 전에 막고, 400(INVALID_BIRTH_YEAR·COMPAT_UNAVAILABLE·INVALID_PURPOSE)이 오면 "생년월일을 다시 확인해 주세요"처럼 사람 말로 보여 준다
- "결과 공유" 버튼은 점수·등급·관계 유형을 텍스트로 복사하는 것으로 단순하게
- 로그인 필요(비로그인이면 /login 으로). 메인(app/page.tsx)에 /compat 으로 가는 링크(탭·메뉴)를, /compat 에는 돌아가는 링크를 둔다
- 완료 기준: node scripts/smoke-live.mjs https://이름.ridm.ai --compat (배포 전 로컬이면 http://localhost:3000 --quick --compat) 의 궁합 세 항목(호출 200 + data.saju 있음 · 화면이 saju 점수·6축을 씀 · 메인에서 링크) 통과 + 390px 폭에서 가로 넘침 0
성격유형 페이지(/type)를 추가해 주세요.
- POST /api/float/personality-type (lib/api.ts callProxy 경유), req: { tier: "free", answers: [...], requestId } — 제출 1회에 UUID 1개, 재시도 시 동일
- 질문 UI는 한 화면에 하나씩, 진행 바 표시 (무료 티어 질문 24개 세트는 콘솔 문서 https://console.hrum.ai/docs.html 의 성격유형 섹션 참조 — AI에게 "이 문서의 질문 세트를 가져와" 하면 됨)
- res.data: { personalityType, typeLabel, scores } → 유형 카드 + 축별 점수 바 4개
페르소나 블록만 바꾸면 같은 코드가 완전히 다른 앱이 됩니다.
페르소나를 아래로 교체하고(lib/persona-list.ts), 같은 캐릭터 항목의 loadingText(로딩 문구)·chips(추천 질문 칩)도 새 페르소나 말투로 적어 주세요. 앱 이름·컬러 무드는 화면 파일(app/page.tsx·app/layout.tsx·app/globals.css) 안에서만 맞춰 주세요:
{새 페르소나 블록}
만세력 화면에 "인생의 큰 흐름" 섹션을 추가해 주세요. - data.daeun 배열로 가로 타임라인: 각 구간 startAge~endAge, 간지(stemHanja+branchHanja), 십성 - isCurrent 구간은 페르소나 포인트 컬러로 강조 + "지금 여기" 라벨 - 클릭하면 그 대운에 대해 상담 채팅으로 질문이 자동 입력되게: "OO~OO세 대운에 대해 알려 주세요"
채팅형과 정반대 상품입니다. 질문을 주고받는 게 아니라, 버튼 하나 누르면 전체 풀이가 한 방에 좌르륵 나오는 방식 — 국내 사주 앱들이 검증한 히트 공식입니다. 이 책의 앱은 두 상품을 나눠 둘 수 있습니다:
| 대화용 (상담 채팅) | 리포트형 (사주 리포트) | |
|---|---|---|
| 방식 | 주고받는 채팅, 기억 유지 | 버튼 1회 → 전 섹션 리포트 |
| 모델 | /reading/memory (모델 지정 없음 — HRUM 사주 상담 엔진) · 자유채팅을 붙였다면 ridm/gpt-5.6-terra(6-3) | ridm/saju-report (리포트 특화) |
| 과금 감각 | 회당 소액, 반복 사용 | 1회 단품 상품과 궁합 (결제를 붙이면 — 9-4) |
1회 원가는 약 ₩85입니다 (기본 8섹션 약 3,000자 리포트 기준 — 콘솔 요금표 실측). 섹션을 두 배로 늘려도 ₩200 안쪽. 나중에 990원 단품으로 팔면 원가의 약 11배가 남습니다. 그 전까지는 회원별 하루 횟수 제한을 걸고 무료로 둡니다.
[프롬프트 — 사주 리포트 페이지]
/report 페이지를 추가해 주세요. "내 사주 리포트 보기" 버튼 하나로 전체 리포트가 생성되는 방식.
1. 서버 라우트 app/api/report/route.ts (7-2 범용 프록시가 아니라 전용 라우트 — 프록시 allowlist 에 reading/report 를 넣지 않는다):
- getSessionUser(req) 로 로그인 확인(비로그인 401), dedup.allow 로 회원별 하루 3회 같은 제한
- 입력: { requestId, personaKey? } 만 받는다. 생년월일은 서버가 DB birth_profiles 에서 읽는다(브라우저가 보낸 원국을 믿지 않는다)
- FLOAT 호출: lib/float-client.ts 의 callFloat('reading/report', body, requestId, 50_000) 을 dedup.once(`${user.id}:report:${requestId}`, …) 로 감싼다
body: { year, month, day, hour?, minute?, gender, tone, persona } — 사용자가 고른 캐릭터(요청 body 의 personaKey → lib/persona.ts findPersona, 없으면 400)의 tone·persona 를 서버가 붙인다
- 사주 계산·주입은 FLOAT 서버가 알아서 하고, 응답 data.report 에 "## 섹션명" 제목의 마크다운 전문, data.sections 가 목차
2. 기본 8섹션(총평/타고난 기질/재물운/연애·인연/직업·적성/올해와 내년/10년 대운 흐름/마지막 한 줄 처방)이 자동 — 바꾸고 싶으면 서버 body 에 sections: ["원하는", "섹션들"] (최대 12개)
3. UI: 생성 중에는 "풀이 중..." 로딩 연출(리포트는 오래 걸린다. callFloat 에는 네 번째 인자 timeoutMs(기본 15초)가 이미 있으니 이 라우트만 50_000 을 넘긴다 — lib/float-client.ts 는 고치지 않고, 다른 라우트는 15초 그대로), 완성되면 목차(섹션 앵커)가 있는 긴 스크롤 리포트로. 표시는 components/AssistantMessage.tsx 로만(plain text 금지)
4. 다시 보기: 생성된 리포트를 다시 열게 하려면 부록 E-2 의 saju_reports 테이블에 저장한다(같은 회원만 읽기). 저장하지 않으면 새로고침 때 다시 생성돼 크레딧이 또 든다
5. 유료 상품으로 팔 계획이면: 지금은 무료로 두고, 팔 때 PG사와 직접 계약해 붙인다(9-4)
완료 기준: 버튼 1회로 8개 섹션이 전부 채워진 리포트가 나오고, 같은 requestId 로 다시 요청해도 HRUM이 두 번 불리지 않으며(콘솔 사용량), 비로그인 401. 저장을 붙였다면 새로고침해도 다시 생성 없이 보이는지 확인.
AI용 분할본 · 지도 6단계(선택 기능 — 결정서에 고른 것만) · 이 페이지 전에 읽을 페이지: PART 0 사용법·AI 시작 지침, PART 4 결정서·마스터 스펙, 부록 A 스펙·코드 받기(A-2) · 코드 파일은 여기 없다 — 코드 자리의 줄을 따른다(폴더에 책 파일이 하나도 없는 처음이면 부록 A-2 의 curl 한 줄부터)