Skip to content

Release v1.3.2#570

Merged
dydals3440 merged 15 commits into
mainfrom
develop
May 17, 2026
Merged

Release v1.3.2#570
dydals3440 merged 15 commits into
mainfrom
develop

Conversation

@dydals3440

Copy link
Copy Markdown
Member

Release v1.3.2

v1.3.1 → v1.3.2 | develop → main

⚙️ Chores

Expo SDK 55 패치 정렬 + 안전 라이브러리 업데이트 (#569)

  • SDK 55 patch level 정렬expo ~55.0.5 → ~55.0.24, react-native 0.83.2 → 0.83.6, react-native-worklets 0.7.2 → 0.7.4, jest-expo ~55.0.13 → ~55.0.17, @expo/dom-webview 55.0.6/@expo/metro-runtime 55.0.11 명시 추가, @shopify/react-native-skia를 SDK 55 bundle ^2.4.18로 정렬
  • Monorepo entry 정리apps/mobile/index.js 신규(import 'expo-router/entry';), package.json#main"index.js"로 전환, metro.config.js에 워크스페이스 루트 진입점 요청을 Uniwind 리졸버보다 먼저 처리하는 resolveRequest 추가
  • 루트 pnpm.packageExtensions 보강uniwind@*metro@0.83.7, metro-cache@0.83.7 peer 보강
  • Group A 안전 minor/patch 업데이트 (코드 변경 없음)heroui-native 1.0.1 → 1.0.3, tailwindcss ^4.2.1 → ^4.3.0, tailwind-merge ^3.5.0 → ^3.6.0, uniwind ^1.5.0 → ^1.6.5, @tanstack/react-query ^5.90.21 → ^5.100.10, react-hook-form ^7.71.2 → ^7.76.0, @react-navigation/native ^7.1.28 → ^7.1.33, @react-navigation/bottom-tabs 7.10.1 → ^7.15.5, es-toolkit ^1.45.1 → ^1.46.1, react-native-svg-transformer ^1.5.2 → ^1.5.3

⚠️ 본 PR 제외(별도 PR 예정): ky 1→2, react-native-mmkv 3→4(Nitro), react-native-purchases 9→10, @react-native-firebase/* 23→24, react-native-intersection-observer 0.2→0.3


📝 Docs

문서 메타데이터 표준화 및 CLAUDE.md 구조 개선

  • 모든 .md 문서(33개)에 Version / Last Updated / Owner 메타 블록 추가
  • 루트·apps CLAUDE.md를 2026-04 권장 포맷(얇은 인덱스 + .claude/*.md 위임)으로 재작성
  • apps/mobile/CLAUDE.md 420 → 123줄로 축약 (세부 내용은 apps/mobile/.claude/architecture.md로 위임)
  • 불일치 정정: pnpm 9.15 → 10.29, Node 22+ → 20+, Swagger 경로 /api-docs 통일, .env.docker.development.env.docker.dev, 깨진 PUSH_NOTIFICATION_GUIDE 링크 제거

⚠️ 런타임 회귀 가능성 (UI 픽셀 단위 확인 권장)

정적 검사(typecheck/단위 테스트)는 통과했으나 다음 항목은 시각적 확인 권장:

  • heroui-native 1.0.2/1.0.3 픽스: field 패딩, input primary border 색상, scroll-shadow inverted, select trigger, tabs RTL
  • uniwind 1.6.5: themed variable resolution 픽스 — 다크/라이트 토글 시 미세 변화 가능
  • tailwindcss 4.2 → 4.3: CSS 출력 미세 차이

🧪 테스트

  • pnpm install 정합 ✅
  • pnpm lint 통과
  • pnpm typecheck 통과
  • pnpm -F @aido/mobile test610 / 610 ✅
  • npx expo-doctor18 / 18 ✅

📦 버전

  • @aido/mobile: 1.3.1 → 1.3.2
  • @aido/api: 변경 없음 (서버 코드 변경 없음, 문서 메타데이터만 수정)

dydals3440 and others added 14 commits April 14, 2026 03:38
* refactor(mobile): 알림 코드 아키텍처 가이드 준수 리팩토링 (#552)

- notification-item: 핸들러 훅(useNotificationPress) 추출, return 전 9줄→2줄
- unread-notification-header: useCallback 핸들러 → 인라인화
- notification-provider: cold start router.replace → router.navigate (뒤로가기 복원)
- use-notification-handler: replace 옵션 제거, NotificationResponseOptions 삭제
- 전체 알림 코드 한줄 if문 → 중괄호 3줄 통일

* fix(mobile): unused import/variable 린트 에러 수정

- _layout.tsx: 미사용 DocsIconSvg import 제거
- memo/create.tsx: 미사용 navigation 변수 및 useNavigation import 제거
* feat(mobile): 로봇 아이콘 추가 (outline + pixel 2종)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(mobile): AI 메모 파싱 리뷰 화면 구현

- AI 파싱 결과를 TodoCard 리스트로 표시, 편집 후 할 일로 변환
- TodoCard를 Context 기반으로 리팩토링 — props는 index만, 데이터는 자체 접근
- 메모 상세 화면 삭제 다이얼로그를 useOverlay로 통일
- [id].tsx → [id]/index.tsx + [id]/ai-review.tsx 분리

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(mobile): 메모 화면 공통 헤더 레이아웃으로 통합

- (tabs)/memo 하위 중복 화면 삭제, memo 그룹으로 일원화
- memo/_layout.tsx에 공통 헤더 (back, 타이틀, 폰트 스케일) 적용
- [id]/index, ai-review에서 커스텀 헤더 제거 후 Stack.Screen options 활용

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(mobile): 메모 생성 화면 키보드 두 번 올라오는 버그 수정

- transitionEnd 리스너로 화면 열릴 때만 포커스 실행
- useNavigation 제네릭으로 타입 안전하게 처리

* feat(mobile): AI 사용 횟수 초과 시 구독 유도 UI 및 쿼리 캐시 키 개선

- AI_1303 에러 시 구독 페이지로 이동하는 전용 Result 화면 추가
- parseMemo 쿼리 키에 content 포함하여 내용 변경 시 재요청되도록 수정

* fix(mobile): AI 리뷰 화면 picker onExit race condition 수정

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(mobile): AI 파싱 전 확인 다이얼로그 추가

- AiParseConfirmDialog 컴포넌트 분리 (남은 횟수 + 경고 표시)
- AiUsagePolicy.getRemainingCount() 도메인 규칙 추가
- AI 버튼 로딩 중 스피너 표시

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(mobile): 리베이스 충돌 해결 시 누락된 useNavigation 복원

* fix(mobile): AI 파싱 다이얼로그 문구 개선

* feat(mobile): AI 파싱 일일 한도 소진 시 구독 유도로 개선

* feat(mobile): AI 파싱 일일 한도 소진 시 구독 유도로 개선

- 다이얼로그 타이틀을 액션 중심으로 변경 (AI로 메모를 할 일로 만들게요)
- 횟수 소진 시 구독 유도 분기 추가 (구독하기 버튼 → 구독 화면 이동)
- 프리미엄 유저는 횟수 표시 없이 경고만 노출
- ai-review 에러: AI_1303 발생 시 구독 화면으로 이동
- 문구 토스 보이스톤으로 통일 (해요체, 닫기 버튼)

* fix(mobile): 메모 빈 상태 DocsIcon SVG 복원

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(mobile): AI 메모 파싱 — mutation 기반으로 전환 및 중복 차감 방지

- parseMemo를 query → mutation으로 전환, onSuccess에서 setQueryData로 캐싱
- AiParseConfirmDialog에서 직접 parseMutation 실행 및 navigate
- 캐시 있으면 mutation 없이 ai-review로 바로 이동 (중복 차감 방지)
- 메모 수정 저장 시 parseMemo 캐시 제거
- use-parse-memo-query-options.ts 삭제

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(api,mobile): AI 파싱 프롬프트 품질 개선 및 카테고리 자동 유추

- 프롬프트 system/user 메시지 분리 (parse-memo, parse-todo)
- 공유 시간 규칙 모듈 추출 (time-rules.ts)
- Few-shot 예시 3개 추가 및 분리 규칙 강화
- Sanitization 버그 수정: ~ 제거로 범위 표현 훼손 방지
- 메모/줄바꿈 구조 보존 (newline → semicolon)
- AI 카테고리 자동 유추: 유저 카테고리 목록을 프롬프트에 포함
- 클라이언트 전달 categoryId 우선, AI 유추값 fallback
- AI 리뷰 화면 X 버튼을 HeroUI CloseButton으로 교체 및 우상단 배치

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(api): AI 제안 프롬프트 품질 개선 — 구체적 행동 중심으로 전환

- system/user 메시지 분리 (기존 단일 prompt → system 규칙 + user 데이터)
- title 작성 규칙 강화: "오후 집중 업무 시간" 같은 추상적 이름 금지
- 바로 실행 가능한 구체적 행동 강제 ("아침 스트레칭 10분", "달리기 3km")
- reason 규칙 강화: 숫자 근거 필수, 동기부여형 톤
- 모든 유형에 구체적 title 예시 추가 (밸런스, 습관 회복 등)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Matthew Kim <dydals3440@gmail.com>
API 로깅 정리:
- Controller 로깅 제거 (가이드: Controller는 로깅 불필요)
- AI Service: userId 포함, 에러 로그 중복 제거, warn 레벨 추가
- AI Suggestion Service: 프리미엄 차단 시 warn 추가
- Memo Controller: 불필요한 debug 로깅 제거

모바일 analytics 추가:
- 메모 AI 파싱 성공/실패 이벤트 (ai_parse_used)
- 사용량 초과 프리미엄 게이트 이벤트 (premium_gate_shown)
- AI 리뷰 할일 생성 확정 이벤트 (memo_converted_to_todos)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(api,mobile): AI 파싱 월 5회 전환 + AI 전반 품질 개선 (#555)

* refactor(api): remove Anthropic + fix E2E + strengthen AI quality (#555)

Gemini Code Review + CI 실패 + Live QA 결과 피드백 반영

## Anthropic 전체 제거
- anthropic.provider.ts 삭제, @ai-sdk/anthropic 의존성 제거
- AiRouterProvider 단일 Gemini pass-through 로 단순화 (향후 확장성은 유지)
- AI_PROVIDER_ANTHROPIC DI/심볼 제거
- modelHint 타입에서 "report" 제거
- report-generator 의 modelHint 호출 제거
- 환경변수 예시/주석에서 ANTHROPIC_API_KEY, Claude 언급 제거
- ai-router.provider.spec.ts 재작성 (pass-through 검증)

## E2E 2건 수정 (응답 구조 이중 중첩)
- ai.e2e-spec.ts 349/350/365: usageResponse.body.data → .data.data

## parse-todo 인젝션 방어 강화 (Live QA A4 실패 대응)
- PROMPT_SECURITY_GUARD 에 예시 추가 ("HACKED" 케이스 명시적 금지)
- parse-todo 프롬프트에 "특수 입력 처리" 섹션 추가 (영문 명령/JSON 입력 시 "입력 확인 필요" 로 고정)

## Suggestion 품질 개선
- 중복 필터: 제목 앞 2어절 + daysOfWeek 동일하면 최고 confidence 만 남김
  (Live QA 에서 "오전 자기계발 30분"/"오전 자기계발 1시간" 중복 관찰)
- cap + 정렬: confidence 내림차순으로 MAX_SUGGESTIONS_PER_USER 상한 적용 (Gemini review medium)
- categoryId 정합성: 제안 제목 단어가 사용자 카테고리명과 일치하면 우선 할당
  (Live QA 에서 "운동 30분" 제안이 자기계발 카테고리로 할당되던 문제 개선)

## 검증
- API 단위 2190 pass, mobile 597 pass, typecheck + lint + build 통과
- ai.e2e-spec 단독 35/35 통과 (이전 실패 2건 해소)
- 기존 앱 크래시 위험 0: suggestedCategoryId 스키마 nullable 유지, 모바일 3단계 null fallback

Closes #555
$executeRaw + GREATEST 대신 Prisma updateMany 를 사용해 동일한 음수 방지
효과를 얻으면서 타입 안전성과 프로젝트 컨벤션을 유지한다.

- where: { aiUsageCount: { gt: 0 } } 조건으로 count=0 일 때 no-op
- Prisma 타입 체크 + 쿼리 로깅 일관성 회복
- 다른 모든 repository 와 동일한 Prisma 스타일 유지

검증:
- SQL 레벨 실측: count=0 → UPDATE 0 rows, count=3 → 2 로 감소
- ai.service.spec / user.repository.spec 59 passed
- lint / typecheck / build / test / ai.e2e-spec 35 passed
…recoverableError (#559) (#560)

* refactor(api): enforce SRP + centralize log masking + adopt BullMQ UnrecoverableError (#559)

* refactor(api): address Gemini review on PR #560

- mask.util: split('@') → lastIndexOf('@') for RFC 5321 compliance
  (quoted local-part can contain @, preserves domain accuracy)
- category-resolver: O(N*M) → O(N) via Set lookup for matchedTitles
- mask.util.spec: add quoted local-part + empty domain cases
- useRepeatSetting에 toggleWeekdays/toggleWeekends 액션 추가
- DayOfWeekSelector 칩 배치를 매일/주중/주말/요일 순으로 재배치
- DayOfWeekSelector props를 repeatSetting 객체 하나로 단순화
* feat(mobile): SwipePager 공통 컴포넌트 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(mobile): 캘린더 스와이프 페이저 적용

- CalendarMonthView/WeekView 삭제, CalendarPager로 통합
- CalendarDateCell 월 외 날짜 opacity 처리

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test(mobile): getMonthWeeks 단위 테스트 추가

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(mobile): 캘린더 관련 date 유틸 추가

- addWeeks, addMonths: n주/n달 이동
- isSameWeek: 같은 주 판정
- withDayOfWeek, withDayOfMonth: 같은 주/달 내 요일·날짜 이동 (월말 clamp)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(mobile): 캘린더 페이저/viewMode 구조 재설계

- CalendarPager: controlled 패턴 (data/value/onChange) + day 보존 동작
- WeekPager/MonthPager 분리, Row/Grid 역할 명확화
- viewMode 상태를 CalendarProvider에 단일 소유로 통합 (sync 버그 제거)
- CalendarNavigation 순수 UI 전환, Toggle/DateCell context 직접 구독
- SwipePager 공용 컴포넌트 제거 (Calendar 내부로 흡수)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(mobile): 피드 날씨 뱃지가 selectedDate 대신 오늘 기준으로 조회

- 캘린더 스와이프 시 날씨 쿼리가 매번 재호출되어 깜빡이던 문제 해결
- Memo 탭과 동일하게 useToday() 기준으로 통일

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(mobile): 캘린더 페이저 고정 윈도우 101페이지로 확장

- CalendarPager data를 Date 배열 → 페이지 번호 배열로 전환 (lazy Date 생성)
- 9 → 101 페이지로 범위 확장 (±50주/월, PR 리뷰 대응)
- weekAtPage/pageOfWeek 등 도메인 네이밍 적용
- shared/utils/date.ts 에 diffWeeks/diffMonths 추가 + 단위 테스트

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(mobile): 캘린더 페이저 범위를 ±5년으로 확장

주간 뷰 ±1년 boundary 가 실사용에서 도달 가능해
"조용한 멈춤" UX 문제가 있었음. 101 → 521페이지로 넓혀
실질 도달 불가화 (주 ±5년 / 월 ±21년).
메모리 3KB 증가, virtualization 덕에 렌더 비용 동일.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v1.3.0 squash merge 커밋을 develop에 흡수. 충돌은 develop 우선으로 해결.
- 모든 .md(33개)에 Version/Last Updated/Owner 메타 블록 추가
- 루트·apps CLAUDE.md를 2026-04 권장 포맷(얇은 인덱스)으로 재작성
- apps/mobile/CLAUDE.md 409 → 123줄로 축약 (세부 내용은 .claude/architecture.md에 위임)
- 불일치 정정: pnpm 9.15→10.29, Node 22+→20+, Swagger 경로 /api-docs 통일,
  .env.docker.development→.env.docker.dev, PUSH_NOTIFICATION_GUIDE 깨진 링크 제거
* chore(mobile): SDK 55 패치 정렬 및 안전 라이브러리 업데이트 (#568)

SDK 55 패치 정렬:
- expo ~55.0.5 → ~55.0.24, expo-* 패치 일괄
- react-native 0.83.2 → 0.83.6
- react-native-worklets 0.7.2 → 0.7.4
- jest-expo ~55.0.13 → ~55.0.17
- @expo/dom-webview 55.0.6, @expo/metro-runtime 55.0.11 명시
- @shopify/react-native-skia를 SDK bundle ^2.4.18로 정렬

Monorepo entry 정리:
- apps/mobile/index.js 신규 (expo-router/entry import)
- package.json#main을 "index.js"로 전환
- metro.config.js에 워크스페이스 루트 resolveRequest 추가

루트 pnpm.packageExtensions:
- uniwind@*에 metro/metro-cache 0.83.7 peer 보강

Group A 안전 라이브러리 minor/patch:
- heroui-native 1.0.1 → 1.0.3 (beta exact pin)
- tailwindcss ^4.2.1 → ^4.3.0
- tailwind-merge ^3.5.0 → ^3.6.0
- uniwind ^1.5.0 → ^1.6.5
- @tanstack/react-query ^5.90.21 → ^5.100.10
- react-hook-form ^7.71.2 → ^7.76.0
- @react-navigation/native ^7.1.28 → ^7.1.33 (SDK 권장)
- @react-navigation/bottom-tabs 7.10.1 → ^7.15.5 (SDK 권장 + 캐럿)
- es-toolkit ^1.45.1 → ^1.46.1
- react-native-svg-transformer ^1.5.2 → ^1.5.3 (dev)

* chore(mobile): bump version to 1.3.2
@dydals3440 dydals3440 added the release 🚀 릴리즈 - develop → main 배포 PR label May 17, 2026
@dydals3440 dydals3440 self-assigned this May 17, 2026
@dydals3440 dydals3440 requested a review from hijjoy May 17, 2026 10:12
# Conflicts:
#	apps/mobile/app.config.ts
#	apps/mobile/package.json
#	pnpm-lock.yaml
@dydals3440 dydals3440 merged commit a1f275c into main May 17, 2026
3 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request transitions AI usage tracking from a daily to a monthly limit across the API and mobile applications, while also standardizing AI prompts for security and consistency. It introduces PII masking for logs and refactors the mobile calendar to a pager-based system. Feedback focuses on improving category matching logic to support multi-word names, fixing a regression in the weather badge date selection, and refining the calendar pager implementation to avoid UI flickering by using virtualization instead of dynamic re-centering.

I am having trouble creating individual review comments. Click here to see my feedback.

apps/api/src/modules/ai-suggestion/utils/category-resolver.util.ts (53-58)

medium

현재 구현된 matchTitleToCategory는 제목을 단어 단위로 쪼개어 카테고리명과 일치하는지 확인합니다. 이 방식은 '유산소 운동'과 같이 공백이 포함된 다중 단어 카테고리명을 처리하지 못하는 한계가 있습니다. 또한 긴 카테고리명을 우선적으로 매칭(예: '운동'보다 '유산소 운동'을 먼저 확인)하도록 개선하는 것이 정확도를 높이는 데 도움이 됩니다.

	const sortedNames = Array.from(categoryByName.keys()).sort((a, b) => b.length - a.length);
	for (const name of sortedNames) {
		if (new RegExp("(^|\\s)" + name + "(\\s|$)").test(title)) {
			return categoryByName.get(name)!;
		}
	}

apps/mobile/app/(app)/(tabs)/feed/_layout.tsx (42-43)

medium

날씨 배지(WeatherForecastBadge)가 현재 선택된 날짜(selectedDate)가 아닌 오늘(today)의 날씨만 표시하도록 변경되었습니다. 피드 탭에서 사용자가 캘린더를 통해 다른 날짜를 조회할 때 해당 날짜의 날씨 정보가 함께 업데이트되지 않는 기능적 회귀가 발생합니다. 의도된 변경이 아니라면 기존처럼 useFeedDate를 사용하여 선택된 날짜의 날씨를 보여주도록 수정이 필요합니다. (상단의 useToday 임포트도 useFeedDate로 복구해야 합니다.)

  const [selectedDate] = useFeedDate();
  return <WeatherForecastBadge date={formatDate(selectedDate)} />;

apps/mobile/src/features/todo/presentations/components/Calendar/Calendar.tsx (302)

medium

현재 initialScrollIndexvalue로 설정하여 깜빡임을 해결하려는 방식은, 안드로이드 등에서 데이터 윈도우를 동적으로 재설정할 때 발생하는 UI 깜빡임 문제를 야기할 수 있습니다. 저장소 규칙(Rule 13)에 따라, 페이저 컴포넌트 구현 시 동적 재중심화 대신 가상화(virtualization)와 함께 매우 큰 정적 데이터 범위를 사용하여 경계 문제와 깜빡임을 방지하는 구조로 개선해 주세요.

References
  1. For pagers or carousels, instead of dynamically re-centering the data window, which can cause UI flickering on Android, consider using a very large, practically infinite static data range combined with virtualization to avoid boundary issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release 🚀 릴리즈 - develop → main 배포 PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants