When API congestion persists after 3 retries + fallback:
- Mark exception with [CONGESTION] tag
- camera_screen catches it and calls DraftService.saveDraft()
- Shows orange snackbar (same UX as offline) instead of red error
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Retry up to 3 times with exponential backoff on 503/UNAVAILABLE
- Fall back to gemini-2.0-flash on final attempt
- Replace raw JSON error with user-friendly Japanese message
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- sake_detail_screen: hide SakeMbtiStampSection when isProVersion=false
(consumer APK no longer shows Pro版限定 placeholder at card bottom)
- sake_grid_item / sake_list_item: apply Pressable to actual tap targets
(grid/list cards now animate on press instead of non-interactive LevelTitleCard)
- soul_screen / sommelier_screen: ambient glow alpha 0.07→0.12 for visibility
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A-1 Micro-animation: Pressable wrapper widget (AnimatedScale 0.97 on tap)
applied to LevelTitleCard
A-2 Bold Typography: LevelTitleCard title font 28→36px, 現在の称号 label
demoted to bodySmall for stronger visual contrast
A-3 Ambient Glow: RadialGradient circle behind My Page (top-left, brandPrimary)
and Sommelier screen (top-right, brandAccent) via Stack + IgnorePointer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
My Page:
- LevelTitleCard: show nickname above title when set
- Add section header 成長記録 above gamification widgets
- Split profile card: basic info (nickname/gender) and sake character
(MBTI/sake persona) are now separate named sections
Sommelier:
- Add section headers テイストプロフィール / MBTI風診断 / さけのわ おすすめ
- Widen share button to full width with rounded rect shape
- Remove Dividers between sections, use SizedBox(32) spacing instead
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- soul_screen.dart: pass showBusinessMode: isBusinessApp to OtherSettingsSection
so the toggle is hidden when built with IS_BUSINESS_APP=false
- build_4_apks.sh: rewrite for current strategy (consumer/business x maita/eiji)
Pro variants removed; set_lite_app_id() restores gradle before each build
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
releases.json に pro キーがないとき apks.pro.url 参照でJSエラーが発生し
hideUserSelect() が実行されず画面が切り替わらないバグを修正。
pro が存在しない場合はカードを非表示にする。
Maita 表記を Mai に変更。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove Phase X / Phase D labels from inline comments and imports
- Remove debugPrint calls from CustomPainter.paint() (called every frame)
- Remove commented-out locale entries (fr, de) from main.dart and language_selector
- Remove version header comments (v1.5 etc.) not needed in source
No logic changes. flutter analyze: No issues found.
Change default behavior from Proxy mode to Direct API mode:
- useProxy defaultValue: true -> false
- General distribution: Users provide their own Gemini API key
- Development with Proxy: Use --dart-define=USE_PROXY=true
Rationale:
- Proxy mode requires Tailscale connection (not suitable for public distribution)
- Direct API mode works anywhere with internet connection
- Each user manages their own API quota
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Infrastructure Improvements:
- Add Redis container to tools/proxy/docker-compose.yml with AOF persistence
- Migrate rate limiting from in-memory to Redis-based storage
- Add TTL-based daily quota reset (expires at midnight)
- Implement health checks for Redis and Proxy containers
Proxy Server Changes (tools/proxy/server.js):
- Add redis client with async connection handling
- Replace usageStore object with Redis GET/INCR/EXPIRE operations
- Add responseMimeType: 'application/json' to Gemini client config
(fixes Markdown response bug)
- Add comprehensive debug logging for JSON parsing issues
Flutter App Configuration:
- Change Secrets.useProxy defaultValue from false to true
- Development builds now use local Synology proxy by default
- Release builds can override with --dart-define=USE_PROXY=false
Documentation:
- Add REDIS_MIGRATION_GUIDE.md with step-by-step migration instructions
- Add tools/proxy/README.md with architecture overview
- Create .env.example template for secrets configuration
- Update PROJECT_TODO.md to mark H3 (Proxy永続化) as in progress
Dependencies:
- Add redis@^4.7.0 to package.json
This resolves the critical tech debt where rate limits reset on container restart.
Redis AOF persistence ensures quota tracking survives server reboots.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add --obfuscate and --split-debug-info options to the release build
command. These options harden the APK against reverse engineering by
obfuscating class/function names and separating debug symbols from
the APK binary. Also add a plain build option for quick verification.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
rootProject.file("app/key.properties") was wrong - rootProject points to
android/ so the actual path would be android/app/key.properties, conflicting
with .gitignore and DISTRIBUTION_API_KEY_SETUP.md which both specify
android/key.properties.
Fix: rootProject.file("key.properties") -> resolves to android/key.properties,
consistent with .gitignore and the setup guide.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Deleted test/widget_test.dart (Flutter Counter template)
- File was unrelated to Ponshu Room Lite functionality
- Actual tests will be added in v1.0.16
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
## Bug Fix
- Badge "初めての一歩" was not unlocking when adding first sake item
- Root cause: GamificationService.checkAndUnlockBadges() was never called in camera_screen.dart
## Changes
- Import gamification_service.dart
- Call checkAndUnlockBadges(ref) after adding sake item to Hive
- Display newly unlocked badges in success SnackBar
- Extend SnackBar duration when badges are unlocked (4s -> 6s)
## User Impact
- Users will now see badge unlock notifications: "バッジ獲得: 初めての一歩 🍶"
- All badge unlock conditions (first_step, regional, collector, flavor) now work correctly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>