MindLog

AI 기반 감정 케어 다이어리

당신의 일기를 분석하여 감정 상태를 파악하고,
따뜻한 위로의 메시지와 맞춤형 행동 지침을 제공합니다.

주요 기능

📝

일기 작성 및 저장

로컬 데이터베이스(SQLite)에 안전하게 저장되며, 날짜별로 일기를 관리하고 조회할 수 있습니다.

🤖

AI 감정 분석

Groq API (Llama 3.3)를 활용하여 실시간에 가까운 감정 분석을 제공합니다. 캐릭터 선택에 따라 공감 톤이 달라집니다.

📊

감정 통계 대시보드

감정 추이 차트, 감정 정원(🌱→🌻), 키워드 태그 클라우드로 나의 감정 패턴을 시각화합니다.

💬

맞춤형 추천

AI가 분석한 감정 상태에 기반하여 공감 메시지와 맞춤형 행동 지침을 제안합니다.

🔒

프라이버시 보호

모든 일기 데이터는 로컬 기기에만 저장되어 개인 정보가 안전하게 보호됩니다.

📱

반응형 UI

320dp~600dp+ 다양한 화면 크기에 최적화된 반응형 디자인으로 모든 기기에서 편안하게 사용할 수 있습니다.

🔐

비밀일기

4자리 PIN + SHA-256 암호화로 민감한 일기를 안전하게 보호합니다. 인증된 세션에서만 접근 가능하며 통계에서 완전히 제외됩니다.

최근 개선

v1.4.54까지의 개선 사항을 소개합니다. 3-way LLM 합의(Claude × Gemini × Codex)로 도출한 P0/P1 성능 최적화 묶음 — Firebase Performance 측정 인프라 도입, Groq 응답 SQLite 캐싱(SHA-256 해시·LRU 1000건), 알림 큐 diff 알고리즘으로 platform channel 호출 0-call 최적화, JSON 파싱 isolate 오프로드, Cheer Me 7일 큐 재구축 — 등이 포함됩니다.

Performance

Groq 응답 SQLite 캐싱 — DB v8 + SHA-256 + LRU (v1.4.54)

3-way LLM 합의 기반 P0 작업으로, 동일 일기 재분석 비용을 0에 가깝게 만들었습니다. groq_analysis_cache 테이블을 신설하고 (model, content, character, userName, imageHashes, promptVersion)을 SHA-256 해시 키로 사용합니다. content는 공백 압축으로 정규화하며, 1000건 임계 시 last_used_at 기반 LRU eviction이 작동합니다. 위기 감지(is_emergency=true) 응답은 캐시 제외로 매번 재평가하여 안전성을 보장하며, PromptConstants.version 변경으로 일괄 무효화 가능한 설계입니다.

Performance

알림 큐 diff 알고리즘 — Platform Channel 0-call 최적화 (v1.4.54)

매 호출마다 7일치 Cheer Me 큐를 통째로 cancel + reschedule 하던 비용을 제거했습니다. 신규 notification_diff_planner.dartgetPendingNotifications()로 추출한 현재 상태와 새 plan을 결정적 ID 기준으로 비교하여 변경된 알림만 cancel/reschedule 합니다. 동일 plan 재적용 시 platform channel 호출 0건을 보장하며, 캐시 적중은 reminder_unchanged analytics 이벤트로 모니터링됩니다.

Performance

측정 인프라 — Firebase Performance + TimelineTask 통합 래퍼 (v1.4.54)

최적화 작업의 객관적 검증을 위해 측정 인프라부터 구축했습니다. firebase_performance ^0.10.0+11를 도입하고, PerformanceTraces.measure() 헬퍼로 TimelineTask(local DevTools)와 Firebase Trace(prod 텔레메트리)를 동시에 래핑합니다. db.getAllDiaries, groq.analyze, notification.applySettings, first.diaryList.paint 4개 핵심 trace 정의. prod에서만 collection enable로 debug 빌드 노이즈를 차단합니다.

Performance

JSON 파싱 Isolate 오프로드 — Vision 응답 jank 방지 (v1.4.54)

Vision 응답(약 1500토큰, 4KB+)의 메인 isolate 파싱이 일으키던 프레임 드롭을 해결했습니다. AnalysisResponseParser의 진입점을 top-level 함수로 추출하고 compute() API로 isolate에 오프로드했습니다. 4KB 미만 작은 응답은 isolate 생성 비용을 피해 메인에서 처리하며, isolate 실행 실패 시 메인 fallback으로 안정성을 보장합니다.

Architecture

Cheer Me 7일 알림 큐 재구축 — 멱등 reschedule (v1.4.54)

단일 시점 reminder를 7일치 일별 큐로 재설계했습니다(+1176/-322 lines). 자가응원 메시지 변경, 사용자 이름 변경, 시간 변경 등 다양한 트리거에서 큐 전체를 멱등적으로 재생성하며, 새로운 requiresCheerMeQueueRebuild() 게이트로 불필요한 재생성을 차단합니다. getRandomMindcareBody() 폴백 로직 정비로 빈 메시지 알림 발생 가능성도 제거했습니다.

UX

일기 목록 낙관적 갱신 — 분석 후 풀스캔 0건 (v1.4.54)

분석 직후 provider.invalidate()로 SQLite 풀스캔이 발생하여 발생하던 새로고침 깜빡임을 제거했습니다. DiaryListController.addOrUpdateDiary()를 신설해 메모리 상태를 직접 갱신하며, DiaryAnalysisController는 invalidate 대신 이 메서드를 호출하도록 변경되었습니다. 결과적으로 일기 분석 완료 → 목록 화면 표시까지 SQLite I/O가 0회 발생합니다.

Reliability

Groq Retry 복원력 회복 — 일시 장애 내성 (v1.4.54)

이전 리팩토링 과정에서 누락된 retry 로직을 복원했습니다. 5xx 응답과 타임아웃에 대한 지수 백오프 재시도가 다시 활성화되어, Groq API 일시 장애 시에도 분석이 안정적으로 완료됩니다. 테스트 472줄을 전면 재구성하여 retry 시나리오(횟수, 백오프, 최종 실패 등)를 명시적으로 검증합니다.

Testing

TDD 사이클 + 1696 그린 — 신규 테스트 +41 (v1.4.54)

모든 P0/P1 작업을 RED-GREEN-REFACTOR로 진행했습니다. notification_diff_planner_test.dart 8건(동일 plan 0-call 검증), groq_cache_key_test.dart 9건(해시 결정성·정규화), groq_analysis_cache_test.dart 7건(CRUD + LRU + emergency 제외), diary_repository_impl_test.dart +254줄 등 신규 41건을 포함해 1696/1696 통과를 유지하며 flutter analyze 클린입니다.

Feature

시간대별 맞춤 응원 메시지 — timeAware 모드 완성 (v1.4.53)

Self-Encouragement 시스템에 시간대 기반 메시지 필터링을 구현했습니다. MessageRotationMode.timeAware 선택 시 morning(5-11h)/afternoon(12-17h)/evening(18-4h)로 분류하여 시간대에 맞는 메시지를 우선 전달합니다. 매칭 메시지 없을 시 전체 풀 폴백을 포함한 안전장치도 설계했습니다. 설정 UI에 '시간대 맞춤 선택' RadioListTile을 추가하고, 메시지 입력 다이얼로그에 ChoiceChip 4종(전체/아침/오후/저녁) 시간대 태깅 UI를 구현했습니다.

Code Quality

Dead Code 제거 + 단일 책임 통일 (v1.4.53)

메시지 선택 로직이 UseCase와 Service 두 곳에 중복되어 있던 구조적 문제를 해결했습니다. GetNextSelfEncouragementMessageUseCase + 테스트 총 485줄을 삭제하고, NotificationSettingsService를 유일한 메시지 선택 경로로 통일했습니다. 이로써 emotionAware/timeAware 로직 변경 시 단일 수정 지점만 관리하면 되는 구조가 확립됐습니다.

Testing

테스트 커버리지 확대 — selectMessage + Widget 37건 (v1.4.53)

selectMessage() 단위 테스트 6케이스(시간대 필터링 경계값, emotionAware 가중치 검증)와 MessageInputDialog 위젯 테스트 17건(timeCategory 선택/해제, 수정 모드 프리로드, record 반환값 검증)을 추가했습니다. 전체 테스트 1,633건 통과, flutter analyze 0 errors를 유지합니다.

UX

공감 메시지 truncation 제거 — StatefulWidget → StatelessWidget (v1.4.52)

EmpathyMessage가 항상 SingleChildScrollView 안에 렌더링됨에도 maxLines: 4 + AnimatedCrossFade + TextPainter 측정으로 내부에서 truncation을 유발했습니다. 렌더링 컨텍스트를 분석해 불필요한 상태 관리를 전면 제거하고 StatelessWidget으로 전환했습니다. 코드 90줄 → 62줄, HapticFeedback·AppDurations import 삭제.

Bug Fix

Cheer Me 알림 개인화 복합 버그 수정 (v1.4.50)

4개 독립 원인이 동시에 작용한 복합 버그를 체계적으로 분석하고 수정했습니다. (D) 정규식 [,의은을이]?(?:[,의은을이]|에게|께)? alternation. (C) getRandomReminderTitle() userName 인자 전파 누락. (B) valueOrNull AsyncLoading → await .future. (A) hasPlaceholder 검사로 bake-in 리터럴 강제 재스케줄.

스크린샷

MindLog 온보딩 화면

온보딩

MindLog 일기 목록 화면

일기 목록

MindLog 일기 작성 화면

일기 작성

MindLog 마음 달력 화면

마음 달력

MindLog 감정 추이 차트

감정 추이

MindLog 키워드 분석 화면

키워드 분석

MindLog AI 캐릭터 선택 화면

AI 캐릭터

MindLog 설정 화면

설정

기술 스택

Framework Flutter
Language Dart
State Management Riverpod
Local DB SQLite
AI API Groq (Llama 3.3 + Vision)
Charts fl_chart
Architecture Clean Architecture

지금 시작해보세요

MindLog와 함께 나의 감정을 기록하고 이해해보세요.