Today's

길을 나서지 않으면 그 길에서 만날 수 있는 사람을 만날 수 없다

모바일 앱(안드로이드)

자기 성찰 타로 상담 앱 실행 로드맵 (MVP 기준, 업데이트 #1)

Billcorea 2026. 3. 27. 15:39

자기 성찰 타로 상담 앱 실행 로드맵 (MVP 기준)

앱 메인 예시

 

1) 제품 방향

  • 제품 한 줄 정의: 예언이 아니라, 사용자의 감정과 생각을 비추는 자기 성찰형 타로 상담 앱
  • 앱 목표: 카드 해석, 상담형 질문, 저널 기록, 치유 메시지를 통해 감정 탐색과 정서적 안정을 돕는다.
  • 핵심 사용자: 감정 정리가 필요한 사용자, 가벼운 셀프 상담을 원하는 사용자, 타로를 심리적 도구로 쓰고 싶은 사용자
  • 핵심 가치: 자기 성찰, 정서적 안정, 기록 습관, 감정 탐색, 치유 경험

2) MVP 범위 (필수)

  • 랜덤 카드 추출 (공정한 무작위 셔플)
  • 스프레드: 1장 / 3장 우선 구현
  • 해석 엔진: 카드 의미 + 사용자 질문 맥락 기반 상담 메시지 생성
  • 저널링: 상담 내용 저장/조회, 회고 기록
  • 세션 종료 치유 콘텐츠: 긍정 확언(Affirmation), 명상/호흡 메시지

3) 사용자 경험 흐름

  1. 홈에서 오늘의 질문 선택
  2. 스프레드 선택 후 카드 추출
  3. 카드 해석 + 공감형 상담 메시지 확인
  4. 후속 질문에 사용자 응답 입력
  5. 저널 저장
  6. 확언/명상 메시지 확인 후 세션 종료

4) 기능 설계 요약

4-1. 콘텐츠/데이터

  • 카드 정보: 카드명, 키워드, 정/역방향 의미, 확언, 명상 문구
  • 저널 정보: 질문, 선택 카드, 해석 요약, 상담 메시지, 사용자 회고, 감정 태그, 생성 시각

4-2. 해석 엔진 원칙

  • 입력: 사용자 질문 + 선택 카드 + 모드(개인용/상담 모드)
  • 처리: 카드 의미 추출 -> 질문 맥락 분류 -> 조합 해석 -> 상담 메시지 -> 후속 질문 생성
  • 출력: 해석 결과, 후속 질문, 확언 문구
  • 중요 가이드: 미래 예언형 문장 금지, 감정 탐색/자기 이해 중심 어조 유지

4-3. UI/UX

  • 기본 플로우: 카드 뽑기 -> 해석 -> 상담 질문 -> 기록 -> 치유 메시지
  • 화면 후보: Home, DrawCard, Reading, Counseling, Journal, Meditation
  • 디자인 방향: 안정감 있는 색감, 부드러운 애니메이션, 공감형 문구 중심

5) 기술/구조 계획

  • 기술 스택: Kotlin, Jetpack Compose, Coroutines, Navigation
  • 로컬 데이터: Room 기반 카드/저널 저장
  • DI: Hilt 도입 검토(MVP 초기에는 단순 구조 우선, 복잡도 증가 시 적용)
  • 아키텍처: 현재 단순 Compose 구조 유지, 이후 Presentation/Domain/Data 레이어로 점진 분리

6) 비기능 요구사항

  • 오프라인에서도 카드 조회/저널 저장 동작
  • 첫 화면 진입 속도 목표: 2초 내
  • 문구 품질: 비판적 표현 없이 중립적/공감적 톤 유지
  • UX 품질: 불안 조장 표현 지양, 안정감 있는 경험 유지

7) 8주 실행 일정(초안)

  • 1주차: 기획 확정, 와이어프레임, DB 스키마 정의
  • 2주차: Navigation/데이터 계층 기초, Room 세팅
  • 3주차: 카드 셔플/추출 + 1장/3장 스프레드
  • 4주차: 해석 화면 + 해석 엔진 1차 연결
  • 5주차: 상담 질문 흐름 + 사용자 입력 UI
  • 6주차: 저널 저장/조회 + 확언/명상 화면
  • 7주차: 디자인 보정, 문구 튜닝, QA
  • 8주차: MVP 배포 및 베타 피드백 수집

8) 출시 후 확장 백로그

  • 스프레드 확장: 5장, 켈틱 크로스
  • 감정 태그 기반 개인화 리포트
  • AI 기반 맞춤형 상담 강화
  • 커뮤니티 기능(경험 공유)
  • 전문가/상담가 연계 세션

9) 핵심 메시지

"예언이 아닌, 마음을 비추는 거울"

10) 현재 구현 상태 점검 (코드 기준, 2026-03-16)

  • 홈 화면 기본 구성(브랜드/히어로/메뉴/상단 앱바) 구현
  • Home -> ReadingList -> ReadingDetail Navigation 기본 흐름 구현
  • 앱 시작 시 raw/hanbok_prompt.txt 기반 Room 초기 적재 구현
  • raw/tarot_app_cards_ko.json 기반 카드 한글명/키워드/의미 보강 로직 구현
  • 리딩 목록에서 카드 이미지 + 한글 프롬프트 요약 + 상세 이동 구현
  • 리딩 상세에서 한글/영문 프롬프트, 키워드, 의미 전체 스크롤 조회 구현
  • 스프레드 선택(1장/3장) 전용 화면/상태 모델 고정
  • 카드 드로우(중복 없는 랜덤 선택) 세션 플로우 구현
  • 상담 입력(Counseling) 화면 및 후속 질문 플로우 구현
  • Journal Entity/DAO/저장-목록-상세 흐름 구현
  • 세션 종료용 확언/명상(Meditation) 화면 구현

11) Home 이후 실행 체크리스트 (우선순위 + DoD)

P0 (이번 스프린트 필수)

  • 스프레드 선택 흐름 고정 (1장, 3장)
  • 카드 추출(셔플/중복 없는 랜덤 선택) 완료
  • 리딩 결과 화면에서 선택 카드 + 질문 + 해석 요약 표시
  • 홈 -> 스프레드 -> 드로우 -> 리딩 단일 플로우 완성

완료 기준(DoD)

  • 홈에서 시작해 리딩 결과까지 한 번에 이동 가능
  • 시스템 뒤로가기 시 흐름이 깨지지 않음

P1 (P0 직후)

  • 상담 질문 1~2개 입력 화면 연결
  • 세션 결과를 Journal로 저장
  • Journal 목록/상세 조회 연결
  • 상세 화면에서 한글 데이터/카드 이미지/본문 전체 확인 가능

완료 기준(DoD)

  • 리딩 -> 상담 입력 -> 저널 저장 -> 목록/상세 조회까지 끊김 없음

P2 (품질/마무리)

  • 세션 종료용 확언/명상 화면 연결
  • 빈 상태/오류 상태 문구 정리
  • 오탈자/한국어 톤(자연스러운 번역) 최종 점검
  • 릴리즈 전 QA 체크리스트 정리

12) 2주 스프린트 실행안

Week 1: 핵심 플로우 고정

  • Route/인자 규칙 확정 (spreadType, sessionId)
  • Draw + Reading 구현 마무리
  • ViewModel 세션 상태(spreadType, selectedCardIds, userQuestion) 고정
  • 더미 문구 제거 및 실제 데이터 연결

반영 메모 (2026-03-17)

  • Reading 요약이 카드 DB의 keywords / meanings / 사용자 질문을 기반으로 생성되도록 연결
  • Meditation 마무리 문구와 확언이 선택 카드/감정 태그 기반 파생 문구를 사용하도록 전환
  • 최근 기록 카드가 날짜/감정 태그뿐 아니라 실제 질문/요약/선택 카드명을 노출하도록 보강

Week 2: 세션 완결 + QA

  • Counseling 입력 흐름 연결
  • Journal 저장/목록/상세 완성
  • Meditation(확언/명상) 종료 화면 연결
  • 리소스 매핑/오류 처리/빈 상태/문구 톤 최종 점검

13) 오늘 바로 시작할 작업 (1 -> 2 순서)

  1. Route/인자 표 확정
  2. Draw/Reading 상태 모델 고정
  3. 리딩 결과 화면 최소 스펙(카드/요약/다음 액션) 잠금
  4. Journal 저장 스키마 + DAO 쿼리 확정

13-1) Route/인자 표 확정

  • 목표: Navigation 계약을 먼저 고정해 화면 연결 재작업을 줄인다.
  • 세부 작업
    • 라우트 후보 확정: Home, SpreadSelect, Draw, Reading, Counseling, JournalList, JournalDetail, Meditation
    • 인자 분류: 필수/선택/없음 (spreadType, sessionId, journalId)
    • 뒤로가기/딥링크 대응 기준 정리
  • 산출물: Route/인자 표 v1 + TarotNavRoutes 반영 기준
  • 완료 기준(DoD): 모든 화면의 인자 규칙이 문서와 코드에서 동일
  • 예상 소요: 1.5 ~ 2시간
route 인자 타입 필수 예시
home - - - home
draw/{spreadType} spreadType String Y draw/three_card
reading/{sessionId} sessionId Long Y reading/1710572400000
counseling/{sessionId} sessionId Long Y counseling/1710572400000
journal/detail/{journalId} journalId Long Y journal/detail/42
meditation?sessionId={sessionId} sessionId Long N meditation?sessionId=1710572400000

13-2) Draw/Reading 상태 모델 고정

  • 목표: ViewModel 단일 상태원천(SSOT)으로 Draw와 Reading을 일관되게 연결한다.
  • 세부 작업
    • TarotViewModel에 세션 상태 필드 정의
    • 이벤트 목록 확정 (onSpreadSelected, onQuestionChanged, drawCards, clearSession)
    • UI 로컬 상태와 ViewModel 상태 경계 명시
  • 산출물: SessionState 필드 표 v1 + 이벤트 계약
  • 완료 기준(DoD): Draw/Reading이 동일 상태 모델을 참조하고 상태 전달이 끊기지 않음
  • 예상 소요: 2 ~ 3시간
필드명 타입 용도 갱신 시점
sessionId Long? 세션 식별자 스프레드 시작 시 생성
spreadType String one_card/three_card 구분 스프레드 선택 시
userQuestion String 사용자 질문 원문 홈/상담 입력 시
selectedCardIds List 중복 없는 카드 번호 Draw 완료 시
readingSummary String 리딩 요약 Reading 계산 후
nextAction String 다음 CTA 분기 Reading 진입 시
isLoading Boolean 로딩 상태 Draw/저장 중
errorMessage String? 에러 노출 실패 시

13-3) 리딩 결과 화면 최소 스펙 잠금

  • 목표: P0 범위를 고정해 과도한 화면 확장을 방지한다.
  • 세부 작업
    • 필수 UI 3요소 고정: 선택 카드 썸네일, 요약 텍스트(24줄), 다음 액션 버튼(12개)
    • P1 이관 항목 분리: 심화 해석/부가 텍스트
    • 빈 상태/오류 상태 문구 확정
  • 산출물: Reading 최소 스펙 체크리스트
  • 완료 기준(DoD): 리딩 진입 시 필수 3요소가 항상 보이고 다음 화면 이동이 일관됨
  • 예상 소요: 1.5 ~ 2.5시간

13-4) Journal 저장 스키마 + DAO 쿼리 확정

  • 목표: 세션 저장/조회의 DB 계약을 먼저 고정한다.
  • 세부 작업
    • JournalEntity 필드 확정 (질문, 카드목록, 요약, 상담응답, 감정태그, 생성시각)
    • JournalDao 최소 쿼리 확정 (insert, list, detail, recent)
    • TarotDatabase 버전 업 및 마이그레이션 정책 결정
  • 산출물: JournalEntity/JournalDao 설계표 v1
  • 완료 기준(DoD): 저장 1건/목록 조회/상세 조회를 커버하는 쿼리 셋 정의 완료
  • 예상 소요: 2 ~ 3시간

추가 반영 메모 (2026-03-17)

  • TarotRepositoryDataSource 도입으로 TarotViewModel JVM 단위 테스트 가능 구조로 정리
  • MainDispatcherRule, TarotViewModelTest 추가로 리딩 요약 생성 / Journal 저장 회귀 검증 자동화
  • JournalDaoTest 추가로 최신순 목록 / 상세 조회 / DB 재오픈 후 데이터 유지 검증
  • MIGRATION_4_5 명시적 Room 마이그레이션 추가
  • DB 정책: 4 -> 5는 비파괴 마이그레이션 적용, 1~3 구버전은 destructive fallback 유지

14) QA 체크리스트 문서

  • MVP QA 체크리스트 작성: documents/qa_checklist_mvp.md

15) QA/테스트/마이그레이션 진행 상태 (2026-03-17)

  • TarotViewModel 최소 회귀 테스트 추가
  • JournalDao 저장/조회/재오픈 테스트 추가
  • TarotDatabase 4 -> 5 마이그레이션 정책 코드 반영 및 테스트 추가
  • 시스템 뒤로가기 동작을 BackHandler로 세션/저널/프롬프트 화면에 명시적 반영
  • 명상/확언 문구 톤을 차분한 반성형 문장으로 보강하고 테스트 추가
  • 기본 테마를 medium contrast 색상표와 surfaceContainer* 계열 배경으로 조정해 다크/라이트 대비 보강

16) 코드 품질 정리 (2026-03-17)

  • JournalScreens.kt CardDetailBlock: 영문 카드명 중복 표시 버그 수정 → cardNameKo 우선 주 타이틀, 영문명은 부제목으로 분리
  • TarotSummaryScreen.kt: 홈 화면 Journal 직접 이동 버튼 복원 (EditNote 아이콘, 3 Card Spread 아래 배치)
  • TarotSessionFlowScreens.kt: 미사용 SimpleTodoScreen 제거
  • TarotReadingScreens.kt: 미사용 private DetailCard 제거
  • TarotViewModel.kt: 미사용 public observeJournalDetail / clearSessionError 제거
  • TarotViewModel.kt buildReadingSummary: 카드명을 cardNameKo 우선 사용으로 리딩 요약 문구 한국어화

17) AI 도입

AI 카드 리딩

 

  • 기본 전략: 온디바이스 우선(MediaPipe LLM) + 서버 폴백(선택적)
  • 폴백 순서(고정): on-device -> server(optional) -> rule-based
  • 보안 원칙:
    • 평문 API 키를 문서/코드/Git 이력에서 제거
    • 기존 노출 키는 즉시 폐기(revoke) 후 신규 발급
    • 키는 local.properties 또는 CI Secret으로만 주입

17-1) 보안/운영 준비 (즉시)

  • working_plan.md 포함 문서 내 실제 키/토큰 제거
  • 네트워크 폴백을 사용할 경우, 질문 텍스트의 PII 마스킹 규칙 확정
  • 로그 정책 확정: 사용자 질문 원문/응답 원문의 로그 저장 금지

17-2) 구현 전 아키텍처 고정

  • TarotAiService 계약 고정(입력: 질문/카드/키워드, 출력: 해석/확언)
  • 실패 코드 표준화(모델 미로딩/타임아웃/네트워크 실패/안전필터)
  • AiModule에서 전략 스위칭(온디바이스만 / 폴백 허용) 플래그 고정

17-3) 빌드/의존성 준비

  • 온디바이스 추론 자산(모델 파일) 배치 경로와 크기 정책 확정
  • 서버 폴백 사용 시 네트워크 권한/클라이언트 의존성 추가 범위 확정
  • Debug/Release별 AI 설정 분리(성능 로그는 Debug 전용)

17-4) 테스트/QA 준비

  • 폴백 회귀 테스트: on-device 실패 시 server 또는 rule-based로 정상 전환
  • 프롬프트 품질 테스트: 질문-카드 연관성, 확언 톤(비예언/비단정) 검증
  • 저널 저장 연동 테스트: AI 결과 저장/조회/재진입 시 일관성 검증

17-5) 다음 코딩 라운드 최소 마일스톤

  1. 보안 정리(키 폐기 + 비밀 주입 경로 확정)
  2. AI 서비스 계약/DI 고정
  3. 서버 폴백 Mock 연결
  4. ViewModel 연동 + 단위 테스트 보강
  5. QA 체크리스트 반영

17-6) 참고 코드 (키는 환경변수/시크릿에서만 주입)

import os
import requests

GROQ_API_URL = "https://api.groq.com/openai/v1/chat/completions"


def groq_chat(messages, model="llama-3.3-70b-versatile", max_tokens=500, temperature=0.7):
    api_key = os.environ.get("GROQ_API_KEY", "")
    if not api_key:
        raise RuntimeError("GROQ_API_KEY is not set")

    resp = requests.post(
        GROQ_API_URL,
        headers={
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json",
        },
        json={
            "model": model,
            "messages": messages,
            "max_tokens": max_tokens,
            "temperature": temperature,
        },
        timeout=30,
    )
    resp.raise_for_status()
    data = resp.json()
    return data["choices"][0]["message"]["content"]

def example_tarot():    
  respText = groq_chat([
        {
            "role": "system",
            "content": "당신은 한국어 타로 상담 전문가입니다. "
                       "카드의 상징과 의미를 따뜻하게 해석해 주세요. "
                       "5~8문장으로 답변합니다."
        },
        {
            "role": "user",
            "content": "질문: 올해 이직을 해도 괜찮을까요?\n"
                       "뽑은 카드: 태양(The Sun), 운명의 수레바퀴(Wheel of Fortune), 힘(Strength)\n"
                       "타로 해석을 해주세요."
        },
    ])   
  print(respText) 

2026-03-27 작업 현황 및 업데이트 (자동 요약)

이 문서는 현재 저장소 코드와 최근 수정사항을 바탕으로 자동으로 생성한 진행 현황입니다. 아래 내용은 "적용됨", "부분 적용/확인 필요", "미실행/추가 필요"로 구분되어 있습니다.

1) 주요 적용됨

  • GroqClient.groqChat 유틸이 app/src/main/java/.../ai/TarotAiService.kt에 Ktor(OkHttp) 기반으로 구현되어 있음.
  • app/build.gradle.kts에 Ktor, OkHttp, kotlinx-serialization-json, Material Dialogs 등의 의존성이 추가됨.
  • Kotlin Serialization 플러그인(alias)와 런타임 의존성이 버전 카탈로그와 app 모듈에 추가되어 @Serializable 클래스의 직렬화가 가능하도록 설정함.
  • MeditationFinishScreen(구성: TarotSessionFlowScreens.kt)에 Groq 호출을 이용한 AI 명상 가이드/확언 통합 로직이 추가됨(LaunchedEffect에서 Groq 호출, 실패시 로컬 폴백).
  • 시스템 프롬프트에 "앱 기본 언어로 응답" 지시문을 추가함(명상 가이드/확언 프롬프트).
  • Settings 화면(app/src/main/java/.../presentation/SettingsScreen.kt)에 Material Dialog를 이용한 Groq 동의/철회 로직이 구현되어 있으며, SharedPreferences에 동의 상태와 타임스탬프를 저장/삭제함.

2) 부분 적용 / 확인 필요

  • Kotlin Serialization 플러그인과 라이브러리 의존성은 추가되었으나, 실제 직렬화기 생성(빌드 성공)은 로컬 Gradle 빌드를 통해 확인해야 함. 현재 사용자의 환경에서 JAVA_HOME 문제로 빌드가 차단되어 있어 검증 불가.
  • 동적 drawable 조회를 위해 context.resources.getIdentifier(...)을 사용하고 있음 — 유연성에는 유리하나 Lint/IDE 경고가 존재함. 정적 R 매핑으로 대체하거나 자동 매핑을 생성하여 경고를 제거할 수 있음.
  • 앱 전체 다이얼로그를 MaterialDialog로 통일하는 작업은 일부 컴포저블에 반영되었으나, 모든 다이얼로그(예: ExitAppConfirmDialog, MandatoryUpdateDialog 등) 변환 여부는 추가 점검 필요.

3) 미실행 / 추가 필요

  • 온디바이스 AI(MediaPipe LLM) 모델 파일 배치, 추론 런타임 통합 및 용량/권한 정책 정리(완료되지 않음).
  • TarotAiService 전략(온디바이스 우선 -> 서버 폴백) 및 DI(AiModule) 고정, ViewModel 연동과 회귀 테스트 보강 필요.
  • 보안/운영 항목 정리: API 키 폐기/마스킹, PII 마스킹 규칙, 로그 정책(사용자 질문 원문 저장 금지) 적용 필요.
  • BuildConfig.GROQ_API_KEY 주입은 local.properties를 사용하도록 되어 있으나, 실제 키 삽입과 CI secret 설정은 수동 작업이 필요함.

4) 로컬 검증/테스트 권장 순서
a) JDK 경로(JAVA_HOME)를 로컬 세션에 설정한 후 프로젝트 빌드 및 직렬화기 생성 확인:

$env:JAVA_HOME = 'C:\Program Files\Java\jdk-17'  # 실제 설치 경로로 변경
./gradlew.bat :app:assembleDebug --no-daemon

b) 단위 테스트 실행(성공 시 코드 변경의 회귀 방지 확인):

./gradlew.bat :app:testDebugUnitTest --no-daemon

c) Groq API 호출 실험 전에 local.propertiesGROQ_API_KEY 추가(절대 커밋 금지):

# local.properties (로컬 전용)
GROQ_API_KEY=sk_live_xxx

d) 앱 플로우 확인

  • Settings -> Groq 동의 토글 및 동의/철회 다이얼로그 동작
  • Draw -> Reading -> MeditationFinish: Groq 응답으로 명상/확언 생성(실제 API 키 필요)

5) 우선순위가 높은 다음 작업 제안

  • 1순위: 로컬 환경에서 Gradle 빌드를 성공시켜 직렬화 플러그인 적용 및 Groq 통신(직렬화 문제 해결)을 검증하세요.
  • 2순위: TarotAiService 전략 분리(AiModule), 온디바이스 모델 준비 계획 수립.
  • 3순위: 보안 정책 정리(키 관리, 로그 규칙, PII 마스킹) 및 문서화.
  • 4순위: 앱 전역 다이얼로그를 Material Dialog로 통일 및 getIdentifier 경고 제거 전략 적용.

원하시면 제가 다음을 수행하겠습니다:

  • (A) getIdentifier 경고를 제거하는 자동 리소스 매핑 생성 스크립트 및 코드 적용
  • (B) GroqClient가 API 키가 없을 때 안전히 동작하도록 방어 로직 추가(테스트 친화적)
  • (C) 사용자의 로컬 세션에서 Gradle 빌드를 실행해 결과 보고(사용자가 임시로 JAVA_HOME 설정 필요)
반응형