Oracle3
Open-source trading engine and MCP server for prediction markets. Fee-aware no-arbitrage trading across related contracts, live on Kalshi, Polymarket and Solana or on paper.
우리가 정한 방식대로, 함께
Translation pending
FinanceHTML · TypeScriptGitHub @SHY-wantedOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
가족·부부·커플·룸메이트 등 원하는 단위로 그룹을 만들어 지출을 함께 관리하는 공유 가계부 — 영수증을 사진 한 장으로 기록하고, 아낀 만큼 저금통 펫이 자라는 앱. • 타깃 사용자: 대학생, 부부, 커플 • 겪는 문제 1. 지출 출처를 알 수 없는 지출이 나온다 (예: 토스로 결제하면 "토스페이 지출"로만 뜸) 2. 카카오톡·메시지로 오는 전자 영수증을 캡쳐해서 등록하는 것이 번거롭다 3. 내 돈이 어느 순간 사라진 것처럼 느낀다 4. 그룹원끼리 쓴 내역을 직접 다 더해서 정산해야 한다 5. 그룹원끼리 각자 다른 방식(수기·단톡방·개별 앱)으로 기록해 한곳에서 보기 어렵다 6. 그룹 성격이 "가족"으로 고정돼 있어 커플·룸메이트 등 다른 관계에는 맞지 않는다 • 우리의 해결: 그룹의 성격을 앱이 정해주지 않고 사용자가 만들 때 직접 고르게 하고(가족/부부/커플/친구/모임·동아리/기타), 영수증은 촬영 한 번으로 OCR 자동 입력, 기록은 그룹 피드 한곳에 모은다. 목적은 세 가지 — 투명성 · 신뢰성 · 정산 편의.Read the full README ↗
가족·부부·커플·룸메이트 등 원하는 단위로 그룹을 만들어 지출을 함께 관리하는 공유 가계부 — 영수증을 사진 한 장으로 기록하고, 아낀 만큼 저금통 펫이 자라는 앱.
| 항목 | 내용 |
|---|---|
| 팀명 | ShooT |
| 팀원 | 이종민(형상관리자), 황하윤(리서쳐), 신아림(PM) |
| 기간 | 2026.08.26 ~ 2026.09.22 |
| 배포 링크 | https://module1-two.vercel.app/ |
| 피그마 | 사용하지 않음 (디자인은 Claude Design으로 대체) |
| Claude Design | https://claude.ai/design/p/d96d3213-5f1e-437d-aeee-2a78011034a2?file=ShooT+%ED%95%98%EC%9C%A4.dc.html&via=share |
| 저장소 | https://github.com/SHY-wanted/module1 |
팀이 직접 확인한 유사 서비스: 카카오페이·토스·뱅크샐러드 — 셋 다 자동 기록은 되지만 실물 영수증 촬영 등록과 "가족 외 그룹" 단위 공유가 없다는 점을 차별점으로 잡았다.
| 우선순위 | 기능 | 상태 |
|---|---|---|
| 최상 | F1~F3 그룹 생성·초대코드 발급·참여 | 완료 |
| 최상 | F5·F6 지출 기록·목록 조회 | 완료 |
| 최상 | F8·F10·F11 영수증 촬영 OCR 자동 입력 + 인식 실패 항목 후수정 | 완료 |
| 최상 | F12·F13 그룹 공유 토글 · 그룹 피드 | 완료 |
| 최상 | F14 본인 지출만 수정·삭제(권한 제약) | 완료 |
| 상 | F7 메모 · F19·F20 저금 등록 · F21 캘린더 | 완료 |
| 중 | F18 그룹장 위임 | 완료 (v2 범위였으나 구현) |
| — | F22 그룹 반려 캐릭터 · F23 피드 이모지 반응 (v2 통합) | 완료 |
| — | 저금통 펫(P1·P2·P3·P5·P8), 월별 목표(P7'·P4), 출석체크, 개인 랭킹, 카카오 로그인, 회원 탈퇴 | 완료 |
| 하 | F17 월별 리포트 | 일부 (월별 목표 리포트로 대체) |
MVP를 끝낸 뒤 더 붙인 것 (9/199/22, PR #17#23과 main 직접 커밋)
| 기능 | 무엇인가 |
|---|---|
| 정기 지출 | 매달 같은 날 자동으로 기록되는 템플릿(월세·구독료 등). 화면을 열 때 이번 달 것을 만든다 — 별도 배치 서버 없음 |
| 그룹 예산 | 그룹장이 카테고리별 이번 달 예산을 정하고, 그룹 상세에서 쓴 만큼 비교해 보여준다 |
| 그룹원 지출 비교표 | 정산 자동계산 대신 "누가 이번 달 얼마나 썼는지"만 나란히 보여준다 |
| 지출 페이스 경고 · 저녁 리마인더 · 메모 검색 | 이 속도면 목표를 넘는다는 경고, 오후 8시까지 기록이 없으면 알림, 메모로 지출 찾기 |
| 온보딩 투어 · 카테고리 도넛 차트 · 지출 정렬 | 첫 실행 안내, 홈의 카테고리 비중 시각화, 목록 정렬 옵션 |
| 펫 경제 개편 | 단계별 필요 XP 증가, 밥값 5코인, 지출 기록 코인(하루 한 번), 그룹원이 각자 하루 한 번 그룹 펫 먹이기(XP는 인원수로 나눠 형평성 유지) |
| 그룹 펫 꾸미기 | 그룹 펫도 색을 바꿀 수 있다. 그룹원 누구나 바꾸고 모두에게 같이 보인다 |
| 실시간 동기화 | 그룹원이 무엇을 하든(참여·탈퇴·지출·저금·이모지·펫 꾸미기·예산 변경·닉네임 변경) 새로고침 없이 내 화면에 반영된다 |
| 보안 강화 | REST/RPC를 직접 호출해 코인·XP를 무한정 채우거나 아무 그룹의 그룹장을 자가 임명할 수 있던 구멍을 막았다. 보상 계산을 클라이언트에서 서버 RPC로 옮기고, pets의 경제 컬럼은 컬럼 단위 권한으로 잠갔다 |
| 회원가입 비밀번호 검증 | 입력칸에 "8자 이상"이라고 써 있는데 실제로 검사하는 코드가 없어 7자로도 가입됐다 — 이메일 형식과 같은 인라인 오류로 막았다 |
| 상황 | 사용자에게 보이는 것 | 다음 행동 | 구현 여부 |
|---|---|---|---|
| 필수 입력이 비어 있음 (P1) | "이메일과 비밀번호를 입력해주세요" / "그룹 이름을 입력해주세요" | 입력 후 재시도 | ✅ |
| 데이터가 하나도 없음(빈 상태) | "아직 지출 내역이 없어요" · "아직 속한 그룹이 없어요" · "이번 달 설정한 목표가 아직 없어요" + 첫 행동 유도 버튼 | 추가하기 | ✅ |
| OCR 인식 실패 (P7·F11) | 저장은 항상 성공하고 category="확인 필요" 배지로 표시 | 항목을 눌러 수정(F10) | ✅ |
| 본인 지출이 아닌 것을 수정 시도 (P6) | "본인 지출만 수정할 수 있어요" (RLS가 서버에서도 차단) | 조회만 가능 | ✅ |
| 그룹 멤버가 아닌 그룹 피드 조회 (P5) | "그룹 멤버만 볼 수 있어요" | 초대 코드로 참여 | ✅ |
| 이미 참여한 그룹에 다시 참여 (P3) | "이미 참여한 그룹입니다" | 그룹 목록으로 | ✅ |
| 그룹장이 위임 없이 나가기 (P10) | "새 그룹장을 먼저 지정해주세요" (혼자면 그룹·지출 함께 삭제) | 10a-1에서 위임 | ✅ |
| 그룹에 속하지 않아 공유 대상이 없음 (P8) | 공유 select가 아예 표시되지 않음 (오류 아님) | 개인 지출로 저장 | ✅ |
| 저장·불러오기 실패(네트워크·권한) | "지출을 저장하지 못했어요" 등 원인별 한국어 문구 | 다시 시도 | ✅ |
| 카메라를 쓸 수 없음 | "카메라를 사용할 수 없어요. 갤러리에서 사진을 선택해주세요" | 갤러리 선택 | ✅ |
문서는 문제에서 화면까지 한 줄로 이어지도록 번호 순으로 썼다. 앞 문서의 결론이 뒷 문서의 입력이 되고, 각 항목에 ID(R·F·P·E)를 붙여 서로를 참조한다 — 예를 들어 "본인 지출만 수정" 규칙은 요구 R14 → 기능 F14 → 정책 P6 → 데이터 E4 → 화면 7로 추적된다.
01 문제 정의 → 02 업무 분석 → 03 요구사항(R) → 04 기능(F) → 05 정책(P) → 06 데이터(E) → 07 화면
↘ PRD (전부 요약한 종합본)
| 문서 | 무엇이 들어 있나 | 분량 |
|---|---|---|
| 01. 문제 정의 | 팀이 이 주제를 고른 기록, 목적 3가지(투명성·신뢰성·정산 편의), 문제/대상/현재해법/불편 4요소 표, 팀이 모은 불편 6개, 유사 서비스 3개(카카오페이·토스·뱅크샐러드) 직접 접속 조사와 차별점 | 71줄 |
| 02. 업무 분석 | 행위자 4명(그룹원·그룹장·신규 초대 멤버·정산 상대)과 각자 지금 쓰는 도구, 지출 기록의 As-Is → To-Be 단계표(그룹 생성 → 지출 발생 → 출처 확인 → OCR 등록 → 인식 실패 수정 → 공유 → 정산), 단계별 감정·불편 | 62줄 |
| 03. 요구사항 | R1~R21. 각 요구의 우선순위(최상/상/중/하)와 그 근거, 어느 목적과 연결되는지. 목적에 연결되지 않은 요구는 지우지 않고 "연결 안 됨"으로 표시만 해 남겼다 | 87줄 |
| 04. 기능 | F1~F23. R을 기능으로 옮긴 것으로, 기능마다 어느 R에서 나왔는지 출처를 달았다. 중요도 × 난이도 2축으로 우선순위를 다시 매겼고, 에이전트가 던진 발산 질문의 채택·거절 결과와 MVP 이후 추가된 기능도 여기 있다 | 114줄 |
| 05. 정책 | P1~P17. "누가 / 언제 / 무엇을 할 수 없다 / 위반하면 화면에 뭐가 보이는가" 네 칸으로 쓴 규칙표. 상태값 2개(그룹장 위임, 지출 인식 상태)와 서비스 정책 SP1~SP4(범위 밖 명시). 이 표가 그대로 Supabase RLS 정책이 됐다 | 69줄 |
| 06. 데이터 | 엔티티 16개(E1 | 305줄 |
| 07. 화면 | (디자인 초안 23개 + 나중에 추가된 비밀번호 찾기·정기 지출 관리 등)의 ID·이름·관련 R·F·진입 경로·다음 화면, 화면별 상세, (탭은 120ms 크로스페이드, 스택은 280ms 세로 슬라이드). 마지막에 목록을 따로 남겼다 |
계획과 실제가 갈라진 곳도 지우지 않고 남겼다. PRD 7절 기술 스택은 오래
React + Vite로 적혀 있었지만 실제로는 Next.js로 만들었다 — 셋업에서 바꾸고 문서에 반영하지 않았던 것을 2026-09-21에 현행화하면서, 값을 덮어쓰는 대신 "계획 / 실제" 2열 표로 바꿔 무엇이 언제 갈라졌는지 보이게 했다. 펫 명세(08)도 같은 방식으로 맨 뒤에 「이 문서와 실제 구현이 달라진 곳」 절을 뒀다 — 주간 예산·주간 정산 배치처럼 제안됐다가 폐기된 것이 왜 사라졌는지 추적된다.
문서 공통 표기 규약 — 이 프로젝트 기획 문서의 핵심 장치다.
| 표기 | 뜻 |
|---|---|
[?] | 팀이 아직 모르는 것. 짐작해서 채우지 않고 물음표로 남긴다 |
[제안] | 에이전트가 보탠 후보. 근거 한 줄을 함께 적고, 팀이 채택하면 태그를 지운다 |
| 「검토했으나 제외」 | 각 문서 끝에 두는 표. 거절한 후보를 이유와 함께 남겨 같은 논의를 두 번 하지 않는다 |
즉 문서 어느 줄을 봐도 그게 팀이 정한 것인지, 에이전트가 제안한 것인지, 아직 모르는 것인지 구분된다.
| 도구 | 어느 단계에 썼나 | 원본 여부 |
|---|---|---|
| 피그마 | 사용하지 않음 | — |
| Claude Design | 색·타이포·컴포넌트 정의부터 화면 생성까지 (ShooT 하윤.dc.html). 초안 23종으로 시작해 최종본 36종 — 구현하면서 추가된 화면(펫·배지·월별 목표·그룹장 위임·정기 지출 관리 등)을 디자인에 역으로 반영했다 | 원본 |
app/globals.css | Claude Design의 값을 CSS 변수(디자인 토큰)로 옮겨 코드의 단일 기준으로 삼음 | 구현 기준 |
| 구분 | 정의 | 피그마 | Claude Design |
|---|---|---|---|
| 색상(라이트) | Accent #6a5ecf, Background #f6f5fc, Surface #ffffff, Surface-alt #f0eeff, Border #e8e4f4, Text #2d2a3e, Muted #6b6980 | ✗ | ✅ |
| 색상(다크) | Accent #9b8cff, Background #15131f, Surface #201d2e, Text #f1eefa | ✗ | ✅ |
| 타이포 | 본문·제목 모두 Geist Sans (next/font), 코드 Geist Mono · 강조는 크기(11~30px)와 두께(600/700/800)로만 구분 | ✗ | ✅ |
| 아이콘 | Lucide (stroke 2px, round cap/join, 24×24 viewBox) — components/icons.tsx에 직접 이식해 외부 의존성 0 | ✗ | ✅ |
색은 전부
var(--shoot-*)토큰으로만 쓴다. 다크모드는.shoot-app-root[data-dark="true"]에서 토큰 값만 바꾸면 앱 전체가 따라 바뀌도록 설계했다.
cursor: 71efault) / Kakao(브랜드 고정색 #FEE500)borderRadius: 20, 1px solid var(--shoot-border), 항목 간 간격 10·16px 두 단계borderRadius: 14, 2px 테두리(오류 시 #E8B4B4, 포커스 시 accent)피그마를 쓰지 않았으므로 Claude Design 원본 ↔ 실제 배포 화면 2단 비교다.
Claude Design (ShooT 하윤.dc.html) | 실제 배포 화면 |
|---|---|
로그인 화면 — 아이콘 타일·제목·입력칸 radius·"로그인 상태 유지" 토글·카카오로 계속하기까지 그대로다. 남은 차이는 하나 — 실제 화면은 비밀번호 칸 아래에 비밀번호를 잊으셨나요? 링크를 인라인으로 뒀는데, 디자인은 이를 별도 화면(2a-1 비밀번호 재설정)으로 그렸다.
홈 화면 — 출석체크 배너, 수입 카드, 보라색 지출 카드(전월 대비 + 도넛 차트), 이번 달 목표 설정하기, 점선 "그룹 만들기", 최근 지출까지 순서와 구성이 같다. 남은 차이는 원본 맨 아래의 월 캘린더 — 실제 앱은 이를 홈에서 빼고 별도 화면으로 옮겼다.
실제 화면 더 보기(로그인 후):
flowchart LR
T["팀 3인"] -->|"인터뷰 답변"| PP["planning-partner<br/>기획 파트너"]
PP -->|"docs/ 기획 문서 초안"| PC["product-planner<br/>기획 코치"]
PC -->|"빠진 것·모호한 문장 질문"| T
T -->|"확정된 PRD + Claude Design"| PB["product-builder<br/>구현 에이전트"]
PB -->|화면 구현| T
T -->|CLAUDE.md + 스킬 문서| PB
| Agent | 역할 | 입력 | 출력 | 제약 |
|---|---|---|---|---|
| planning-partner | 기획 인터뷰를 한 번에 한 질문씩 진행하고 답을 문서 양식에 받아 적음. 발산 질문으로 후보를 [제안]으로 보탬 | 팀의 구두 답변, 앞 문서(01→05) | docs/0N-*.md 초안·종합 문서 | 팀 대신 결정하지 않음 · 모르면 [?] · docs/ 아래만 수정 (Read/Write/Edit) |
| product-planner | 기획 문서를 읽고 빈칸과 모호한 문장을 질문으로 되돌려줌. F↔R↔P ID 참조 검사(고아 ID 탐지) | docs/ 기획 문서 | 질문 목록·참조 검사 결과 | 문서를 대신 쓰지 않음 · 답을 정해주지 않음 (Read 전용) |
| product-builder | PRD와 Claude Design 화면을 입력으로 실제 화면 구현 | docs/PRD.md, 디자인 파일 | 화면 코드 | 첨부에 없는 화면을 지어내지 않음 · 서버/새 폴더가 필요하면 만들지 말고 되물음 |
| 스킬 문서 5종 | UI / CHARACTER / ANIMATION / ASSET_PIPELINE / DESIGN_SYSTEM — 작업 종류별로 반드시 먼저 읽는 규칙집 | — | — | CLAUDE.md가 "작업 시작 전 확인 필수"로 지정 |
[planning-partner]
팀이 말한 것은 그대로 적는다. 말을 매끄럽게 고치지 않는다. 팀의 단어를 쓴다.
네가 보탠 것에는 반드시 [제안]을 붙인다. [제안]마다 근거 한 줄.
대신 정하지 않는다. "이걸로 하자"고 쓰지 않는다.
모르면 [?]. 짐작해서 채우지 않는다.
질문은 한 번에 하나만 한다.
[product-planner]
기획 문서를 대신 써 주지 않는다. 빈칸을 찾아 질문으로 돌려준다.
"편리하다·좋다·귀찮다"처럼 확인할 수 없는 문장은 원문을 인용하고 왜 확인할 수 없는지 적는다.
기능 문장의 주어가 앱이거나, 정책에 기술 단어(DB·API)가 들어 있으면 지적한다.
[제안] 태그와 [?] 규칙을 넣어 출처가 팀인지 에이전트인지 항상 구분되게 바꿨다.product-planner 를 따로 만들어 질문만 하게 분리했다.CLAUDE.md에 Golden Asset 보호 · 최소 변경 · 원인 확인 전 수정 금지 조항을 넣고, 작업 종류별 스킬 문서 5종을 추가했다.CLAUDE.md는 44개 조항의 최상위 작업 규칙이다. 특히 중요한 것:
app/(라우트·API) · components/screens/(화면 컴포넌트 43개) · lib/(store·selectors·순수 로직) · docs/(기획) · supabase/(SQL 32개) · scripts/(마스크 생성·검증) · .claude/agents/(에이전트·스킬 문서)public/stage_*.png 원본 캐릭터 이미지는 덮어쓰기·재생성·크롭 금지. 색 변경은 런타임 마스크 합성으로만| 이름 | 하는 일 | 사용 |
|---|---|---|
DESIGN_SYSTEM.md | 임의 색·폰트·radius·그림자 추가 금지, 화면마다 새 버튼 스타일 금지 | UI 작업 전 상시 |
UI.md | 화면 구조·간격·상태 표시 규칙 | UI 작업 전 상시 |
CHARACTER.md | 부위 마스크·고정 색(코인 금색, 입) 보호 규칙 | 캐릭터 작업 12회+ |
ASSET_PIPELINE.md | 마스크 생성·검증 스크립트 규약 | 마스크 재생성 시 |
ANIMATION.md | 둥둥 뜨기·깜빡임·그림자 등 모션 원칙 | 애니메이션 작업 시 |
planning-partner / product-planner / product-builder | 위 3절 참고 | 기획 전 구간 |
매 변경마다 아래 3단계를 순서대로 통과시킨다.
| 명령 | 무엇을 잡나 |
|---|---|
npx tsc --noEmit | 타입이 안 맞는 실수. --noEmit은 "파일은 만들지 말고 검사만 해라"는 뜻 — 숫자 자리에 문자를 넣었거나 없는 값을 참조한 경우를 여기서 잡는다 |
npx eslint <변경 파일> | 코드 스타일과 흔한 버그 패턴. 안 쓰는 변수, React 의존성 빠뜨림 등. 실제로 고친 파일 경로를 넣는다 |
npx next build --webpack | 진짜 배포 가능한지. 앞 둘을 통과해도 빌드가 깨지는 경우가 있다(서버 전용 코드를 클라이언트에 섞는 등) |
캐릭터·마스크 작업은 node scripts/verify-character-masks.js로 13개 항목 자동 검증 + 실제 렌더 이미지를 눈으로 확인한다.
화면 동작은 로컬 HTTPS 서버(npm run 62ev:https)를 띄우고 실제 계정으로 로그인해 확인한다. 서버 로그([account], [receipt-ocr] 등)에 원인 진단용 로그를 남겨 실패 지점을 특정한다. 또는 vercel의 각각 브랜치 도메인 링크를 통해서 직접 확인.
잘못되면 덧붙여 고치지 않고 git status / git log로 마지막 정상 커밋을 확인해 되돌린다 (CLAUDE.md 29조).
실제 사례 1 — 캐릭터 부위 경계의 보라색 윤곽선 에이전트가 마스크를 "색 범위(밝기·색조 임계값)"로 나눴더니, 부위 경계마다 어느 마스크에도 속하지 않는 픽셀이 남아 색을 바꿀 때 보라색 테두리로 드러났다. 200% 확대 QA에서 발견 → 판정 기준을 "실제 오브젝트 경계(연결된 덩어리)"로 전면 재작성하고, 검증 스크립트로 "임자 없는 픽셀 0개"를 자동 확인하게 했다.
실제 사례 2 — 출석체크 연속일수가 매번 1일차
"어제 날짜"를 new Date(...).setDate(-1) 후 toISOString()으로 구했는데, 한국(UTC+9)에서는 이 변환이 날짜를 하루 더 밀어 어제 기록을 못 찾았다. 사용자 제보 → 로그로 재현 → 타임존 안전한 shiftDateKST()로 교체하고 순수 함수 단위로 검증했다.
실제 사례 3 — 그림자 마스크가 다리를 타고 올라감 알파 페이드를 그림자로 판정하다 보니 다리 실루엣을 따라 3~4px 흔적이 남았다. 사용자가 다크 배경 스크린샷으로 제보 → 형태학적 opening(침식→팽창)으로 얇은 돌기만 제거하도록 고쳤다.
gitGraph
commit id: "기획 문서"
branch yaru
commit id: "기획 초안 01~03"
checkout main
merge yaru tag: "PR #1"
branch petbranch
commit id: "저금통 펫"
checkout main
merge petbranch tag: "PR #8"
branch shooTbranch
commit id: "월별 목표"
checkout main
merge shooTbranch tag: "PR #10"
branch feature-income-account
commit id: "수입·회원탈퇴"
checkout main
merge feature-income-account tag: "PR #12"
branch shooTbranch2
commit id: "정기지출·그룹예산"
checkout main
merge shooTbranch2 tag: "PR #17"
branch feature-group-compare
commit id: "비교표·도넛차트"
checkout main
merge feature-group-compare tag: "PR #18"
commit id: "실시간 동기화" type: HIGHLIGHT
다이어그램의 브랜치 이름은
/를 뺀 축약형이고,shooTbranch2는 같은 브랜치를 두 번째로 쓴 것을 구분한 표기다(실제로는 같은shooTbranch). 실제 이름 예:feature/income-avatar-account-deletion,feature/group-compare-onboarding-donut-sort. 맨 끝실시간 동기화는 PR 없이 main에 직접 병합한 구간이다.
main(배포용) / 개인 작업 브랜치(mg, hybran~hybran7, hybranch, petbranch, shooTbranch, yaru, teamshy) / 기능·수정 브랜치(feature/<기능명>, fix/<버그>, docs/<문서>, draft/<문서>)mg, hybranch)으로 쓰다가, 후반에 작업 내용 기반(feature/income-avatar-account-deletion, draft/hy-ledger-planning-01-03)으로 옮겨갔다.main을 먼저 merge해 충돌을 자기 브랜치에서 해소 → PR 생성 → main 병합별도 이슈를 하나도 만들지 않았다. GitHub Issues 탭에 뜨는 숫자는 전부 열려 있는 PR이고 순수 이슈는 0건이다. 이슈 템플릿·PR 템플릿(.github/)도 쓰지 않았다. 작업 단위는 브랜치명과 커밋 메시지로 나눴고, 결정 사항은 docs/ 문서에 날짜와 함께 남기는 방식으로 대체했다. → 이 선택의 대가는 7. 회고에 적었다.
총 PR 23개 (병합 19 · 열린 PR 없음). 계정명은 Lezo-Jong=이종민, hhy0123=황하윤, arim0317-dot=신아림.
| PR | 내용 | 브랜치 | 상태 |
|---|---|---|---|
| #1 | 기획 초안 01-problem·02-workflow·03-requirements | yaru | 병합 |
| #2 · #3 | 팀/개인 기획 문서 저장 | teamshy, draft/hy-... | 열림 |
| #4 · #6 | 캐릭터 에셋·마스크 파이프라인 1차 | mg | 병합 |
| #5 | 반려 캐릭터(다마고치)·이모지 반응 | hybranch | 열림 |
| #7 · #10 | 월별 목표 설정/삭제, 홈 카테고리 % 실제 계산 | shooTbranch | 병합 |
| #8 | 성년기 코인 재작업, 눈 흰자·가방 끈 번짐 근본 수정 | petbranch | 병합 |
| #9 | 출석체크 — 7일 연속 시 코인 2배 | hybran | 병합 |
| #11 | 로그인 빈 칸 한국어 안내, 목표 금액 입력칸 강조 | hybran2 | 병합 |
| #12 | 수입 DB 연동, 프로필 사진 저장, 회원 탈퇴 | feature/income-avatar-account-deletion | 병합 |
| #13 | 지출 페이스 경고 · 저녁 리마인더 · 메모 검색 | feature/pace-warning-... | 병합 |
| #14 | 날짜/시간대 버그 3건 수정 | fix/date-timezone-bugs | 병합 |
| #15 · #20 · #21 | 펫 경제 개편, 밥 관련 버그, 시무룩 그림 재조정 | hybran3, hybran4, hybran5 | 병합 |
| #16 | README 스크린샷·기록 정정 | docs/readme-images | 열림 |
| #17 | 정기 지출 · 그룹 예산 · 영수증 원본 재확인 | shooTbranch | 병합 |
| #18 | 그룹 지출 비교표 · 온보딩 투어 · 도넛 차트 · 정렬 | feature/group-compare-... | 병합 |
| #19 | 개인 펫 밥주기 하루 1회 제한 복원 | fix/pet-feed-daily-limit | 병합 |
| #22 | 정기 지출 빈 목록 아이콘 수정 | hybran7 | 병합 |
| #23 | 개인 펫 코인·XP 지급을 원자적 RPC로 통일, 목표 정산 버그 수정 | hybran9 | 병합 |
| 팀원 | 담당 영역 | 주요 작업 | 커밋 |
|---|---|---|---|
| 이종민 (형상관리자) | 캐릭터 에셋 파이프라인 · 외부 연동 · 하네스 규칙 · 실시간 | 마스크 생성/검증 스크립트, PNG+마스크 렌더러, 네이버 CLOVA OCR 영수증 인식, 카카오 로그인, 개인 랭킹, 그룹 펫 꾸미기, 13개 테이블 실시간 동기화, CLAUDE.md·스킬 문서 5종 | 85 |
| 신아림 (PM) | 기획 종합 · 목표(퀘스트) · 그룹 예산 | 01~03 기획 초안, 월별 목표 설정/삭제, 홈 캘린더 날짜 선택 바, 비밀번호 찾기, 정기 지출, 그룹 예산, 그룹장 배지, 기획 문서 현행화 | 23 |
| 황하윤 (리서쳐) | 리서치 · 디자인 원본 · 참여 유도 · 펫 경제 | ShooT 하윤.dc.html 디자인 원본, 출석체크(7일 연속 보너스), 반려 캐릭터·이모지 반응, 수입 DB 연동, 회원 탈퇴, 펫 경제 개편, 그룹 지출 비교표·온보딩 투어·도넛 차트 | 23 |
components/screens/*.tsx)을 맡아 서로 다른 파일을 건드리게 해서 충돌 면적을 줄였다.lib/store.tsx)은 함수 단위로 나눠서 추가만 하고 기존 함수는 건드리지 않는 규칙을 뒀다.009_ ~ 020_, 총 20개)만 추가하는 방식으로 서로의 스키마 작업이 겹치지 않게 했다. 프로젝트 내내 스키마 충돌이 한 번도 없었다.main 병합 시 같은 줄이 충돌 → 나중 PR(#11)에서 한쪽을 되돌리고 하나로 합치는 커밋("목표 금액 입력칸 테두리 강조 되돌리기")을 따로 만들어 정리했다.mg·hybranch·shooTbranch가 각자 다른 펫 스펙(성장 5단계 vs 4단계, 종 선택 vs 색상 커스텀, 주간 예산 vs 월별 목표)을 구현해 충돌했다. 코드로 먼저 합치지 않고 충돌 지점 4개를 사용자에게 직접 질문해 결정한 뒤 합쳤고, 결정 내용을 docs/07-screens.md·PRD.md에 날짜와 함께 기록했다.실행 방법
npm install
npm run 87ev # http://localhost:3000
npm run 114ev:https # https://localhost:3000 (카메라 기능 테스트용 — getUserMedia는 HTTPS 필수)
.env.local): NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY, SUPABASE_SERVICE_ROLE_KEY, CLOVA_OCR_INVOKE_URL, CLOVA_OCR_SECRET_KEY, KAKAO_ADMIN_KEYsupabase/schema.sql → 002 ~ 032 순서대로 SQL Editor에서 실행 (fix_group_members_recursion.sql은 schema.sql만 실행해 둔 기존 프로젝트를 고치는 용도라 새로 세팅할 땐 건너뛴다. 033은 시연 전용이라 아래 별도 설명 참고)
019·020을 빠뜨리면 앱은 정상 동작하지만 실시간 반영만 꺼진다 — 조용히 아무 일도 안 일어나서 알아채기 어렵다. 확인 방법:select tablename from pg_publication_tables where pubname = 'supabase_realtime' and schemaname = 'public';결과가 13줄이어야 한다.
025~031은 보안 강화(REST/RPC 직접 호출로 코인·XP·그룹 권한을 조작할 수 있던 구멍 차단),032는 그 과정에서 생긴 출석체크 버그 수정이다 —032를 빠뜨리면 "출석하기"를 눌러도 코인이 들어오지 않는다.
시연에 쓰는 실제 계정과 분리된 테스트 계정이다. 비밀번호는 셋 다 공통 test123.
이 앱은 이메일로 로그인한다(별도 아이디 체계가 없다). 그래서 요청하신 아이디
test123·test1234·test12345를 그대로 쓰되 뒤에@test.com을 붙인 형태다 — 로그인 화면에는 아래 이메일을 그대로 입력하면 된다.
| 계정 | 이메일 | 권한 | 이 계정으로 확인할 수 있는 것 |
|---|---|---|---|
| 팀장(그룹장) | [email protected] | 그룹장(OWNER) | 그룹 예산 설정·수정, 그룹 이름 변경, 그룹장 위임 |
| 팀원(그룹원) | [email protected] | 그룹원(MEMBER) | 그룹 피드 조회, 본인 지출만 수정·삭제. 그룹 예산은 읽기 전용 |
| 일반 사용자 | [email protected] | 그룹 미소속 | 그룹이 없을 때의 화면 — 공유 select가 아예 안 보임(P8) |
세 계정 모두 로그인 후 바로 볼 내용이 있도록 데이터를 넣어 뒀다 — 그룹장·그룹원 계정은 강사 평가용 그룹(초대 코드 TEST01)에 함께 속해 있고 공유 지출 3건과 그룹 예산 2건이 있다.
관리자 계정은 없습니다. 이 앱의 권한은
member_roleenum의 OWNER / MEMBER 두 가지, 즉 "그룹 안에서의 역할"만 존재합니다(06-data.md E3). 앱 전체를 관리하는 관리자 개념은 기획 단계부터 범위에 없었습니다. 위 세 계정이 이 앱에서 구분 가능한 권한의 전부입니다.
권한이 서버에서 실제로 막히는지 확인한 결과 — 화면에서 숨기는 것이 아니라 Supabase RLS가 차단합니다.
| 그룹원 계정으로 시도 | 결과 |
|---|---|
| 남이 쓴 지출 수정 (P6) | 차단 |
| 본인 지출 수정 | 허용 |
| 그룹 예산 생성 (P14) | 차단 (42501) |
| 그룹 이름 변경 (P2) | 차단 |
계정 관리 스크립트 — scripts/seed-instructor-accounts.mjs. .env.local의 서비스 롤 키를 쓰므로 그 파일이 있는 PC에서만 동작한다.
| 명령 | 하는 일 |
|---|---|
node scripts/seed-instructor-accounts.mjs | 계정·그룹·샘플 데이터 생성. 여러 번 실행해도 안전하고, 이미 있으면 비밀번호만 다시 맞춘다 |
… --demo-reset | 리허설을 다시 돌릴 때. 오늘의 출석체크·밥주기 기록을 지우고 코인을 100개로 채우고 온보딩 투어가 다시 뜨게 한다. 계정·그룹·지출은 건드리지 않는다 |
… --delete | 계정·그룹·지출 전부 삭제(평가 종료 후 정리) |
돌린 뒤에는 브라우저를 새로고침해야 한다. 앱이 이 값들을 로그인·페이지 로드 시점에 읽기 때문에, 열려 있는 화면에는 바로 반영되지 않는다.
시연용 예외 — 팀장 계정만 밥주기 무제한
밥주기는 서버에서 하루 1회로 막혀 있다(pet_feedings의 (pet_id, user_id, fed_date) 유니크 제약). 그런데 발표에서 성장 4단계(알 → 유년기 → 청소년기 → 성체)를 그 자리에서 보여주려면 연속으로 먹여야 한다. 그래서 팀장 계정 하나에만 예외를 두는 SQL을 따로 준비했다.
| 파일 | 언제 실행 |
|---|---|
033_demo_unlimited_feed.sql | 발표 전 — 예외 열기 |
033_revert_demo_unlimited_feed.sql | 발표 후 — 원상복구 |
feed_pet() 안에서 그 계정(uuid 하나)일 때만 오늘 기록을 지우고 다시 넣는다.025~031 보안 강화가 막아둔 경제 조작에 예외를 일부러 하나 여는 것이다. 그래서 되돌리는 파일을 함께 뒀고, 평가가 끝나면 닫는 것을 전제로 한다.시연 순서
[?](팀이 모름)와 [제안](에이전트가 보탬)을 구분해 적었더니, 나중에 "이거 누가 정한 거였지?"로 되돌아가는 일이 없었다. 거절한 후보도 「검토했으나 제외」 표에 이유와 함께 남겨서 같은 논의를 두 번 하지 않았다.docs/06-data.md·07-screens.md·PRD.md에 날짜와 함께 남았다.| 무엇이 실패했나 | 왜 | 어떻게 고쳤나 |
|---|---|---|
| 캐릭터 색 변경 시 부위 경계에 보라색 선이 남음 | 마스크를 색 범위로 나눠 경계 픽셀이 어느 마스크에도 안 들어감 | 판정 기준을 실제 오브젝트 경계로 재작성 + "임자 없는 픽셀 0개" 자동 검증 |
| Vercel 배포가 계속 실패 | .env.local은 git에 안 올라가는데 Vercel에 환경변수를 등록하지 않음 | 4개 변수를 Production/Preview/Development 전부 체크해 등록 후 재배포(기존 배포엔 소급 적용 안 됨) |
카카오 로그인 후 localhost로 튕김 | Supabase의 Site URL이 http://localhost:3000이라, 배포 주소에서 로그인해도 거기로 돌려보냄 | Site URL을 배포 주소로 바꾸고 Redirect URLs에 https://module1-*.vercel.app/** 와일드카드 추가 |
| 월별 목표 삭제 버튼이 눌러도 안 됨 | category_goals 테이블에 DELETE RLS 정책만 빠져 있었음(RLS는 정책 없으면 기본 차단) | 010_category_goals_delete_policy.sql 추가 |
| 영수증 OCR이 자꾸 인식 실패 | 무료 커스텀 템플릿 방식은 좌표로 판정해서, 영수증이 조금만 기울거나 잘려도 매칭 실패 | 안정적인 종이 영수증만 지원 범위로 좁히고, 간편결제 캡쳐는 범위에서 제외. 인식 실패 시 수동 수정 경로를 보장 |
| 회원 탈퇴 후 카카오로 다시 로그인하면 동의 화면이 안 뜸 | 우리 DB의 계정만 지우고 카카오 쪽 연결은 안 끊었음 | 탈퇴 시 카카오 unlink API도 함께 호출(실패해도 탈퇴 자체는 진행) |
| 화면에는 규칙이 써 있는데 검사하는 코드가 없었다 — 회원가입 비밀번호 칸에 "8자 이상"이라고 적혀 있었지만 7자로도 가입됐다 | 화면 문구를 먼저 만들고 검증은 나중에 붙이려다 잊었다. 서버(Supabase) 기본 최소 길이가 6자라 서버도 안 막았고, 화면 문구만 보고 "되는 줄" 알았다 | 이메일 형식 검사와 같은 인라인 오류로 막았다. 07-screens.md에 [?]로 남아 있던 자리를 그제서야 채운 셈이다 |
| 보안 수정이 멀쩡하던 기능을 조용히 깨뜨렸다 — 출석체크를 눌러도 코인이 안 들어왔다 | 보상 계산을 서버 RPC로 옮기면서 함수 반환 컬럼 이름(checkin_date)이 테이블 컬럼과 겹쳤다. 마이그레이션 실행은 성공하고 호출할 때만 실패해서, 적용 직후엔 아무도 몰랐다 | 테이블 참조에 별칭을 붙여 고쳤다(032). 이후 임시 계정으로 주요 기능 15개를 실제로 호출해 다른 곳은 멀쩡한지 확인했다 |
| 같은 입력칸을 세 명이 같은 시각에 고침 — 9/18 14:08에 세 사람이 각자 "목표 금액 입력칸"을 수정한 커밋을 올렸다 | 브랜치는 나눴지만 화면 담당자를 정하지 않았다. "금액 입력칸이 눈에 안 띈다"는 같은 피드백을 세 명이 각자 받아 각자 고쳤다 | 21분 뒤 한 명이 되돌리는 커밋(14:29)으로 하나로 합쳤다. 이후로는 같은 화면을 한 사람이 맡도록 나눴다 |
| 타임존 버그가 1차 점검을 통과했다 — 출석 연속일수·저녁 리마인더·페이스 경고가 각각 다른 증상으로 어긋났다 | "오늘 날짜"를 모듈을 불러올 때 한 번만 고정하는 패턴이 세 곳에 복사돼 있었다. 증상이 제각각이라 처음엔 서로 다른 버그로 보였다 | 2차 점검을 따로 돌려 3건을 한 번에 찾았고, 날짜를 쓸 때마다 다시 계산하도록 통일했다 |
| 기획이 구현 중에 바뀌었다 — 모임 유형 "룸메이트"→"친구", 성장 5단계→4단계, 주간 예산→월별 목표 | 세 브랜치가 서로 다르다는 게 드러났다. 기획 문서에 적히기 전에 코드가 먼저 나간 부분이 있었다 |
CLAUDE.md나 스킬 문서에 조항으로 넣는다.console.error("[account] ...") 같은 태그 로그를 먼저 심고 재현시키면, 추측 없이 원인을 특정할 수 있다.tsc → eslint → build 통과 결과를 항상 같이 보고하게 했다.mg, hybran, hybran2)는 나중에 어떤 작업인지 추적하기 어려웠다.| 271줄 |
| PRD (종합) | 위 문서를 한 곳에 요약 — 제품 개요, 핵심 사용자 흐름, MVP/v2 기능 범위, 화면·데이터·정책 요약, 기술 스택(계획 / 실제 2열), 7일 마일스톤, 그리고 열린 이슈를 착수 우선순위로 재배열한 목록 | 204줄 |
| 저금통 펫 명세 | 펫 기능만 따로 뗀 화면·기능 명세(2026-09-15 제안 시점). 전체 개념, 펫 선택·상세·먹이주기 팝업·절약 리포트·배지·그룹 랭킹, 백엔드 참고사항, 확인 후 결정된 것과 남은 [?], 그리고 이 문서와 실제 구현이 달라진 곳 정리 | 137줄 |
| 충돌 지점 4개를 코드로 합치기 전에 팀에 물어 결정하고, 정한 내용을 날짜와 함께 기획 문서에 반영한 뒤 병합했다 |
| 공유 가계부인데 새로고침을 해야 서로가 보였다 — 초대를 받아 들어가도 멤버 목록에 자기 혼자였다 | 데이터를 로그인 직후 한 번만 읽는 구조였다. 실시간은 지출 알림 하나에만 걸려 있었고, 그마저 토스트만 띄우고 목록에는 넣지 않았다 | 참여 직후 그룹 멤버 전체를 다시 읽게 고치고, 화면이 읽는 13개 테이블을 전부 Realtime으로 구독하도록 바꿨다(019·020 마이그레이션) |