Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013H6bXqGX1ygwib1Dm3n3UG
4.3 KiB
MealMood — Project Context for Claude Code
App
- Name: MealMood: Family Meal Planner
- Bundle ID: com.alexandrevazquez.mealmood
- Platform: iOS/iPadOS (also runs as iOS app on Mac)
- Current version: 2.0.5 (dev, beta-bound; 2.0.4 build 72 in App Store review)
- Main branch:
1.0.1(production), feature branches named after versions
Branch ↔ version convention (IMPORTANT)
The active dev branch is named after the current MARKETING_VERSION, not the one it was created with. Whenever the iOS app version changes, rename the branch to match:
# after bumping MARKETING_VERSION in the Xcode project to e.g. 1.1.6
git branch -m <old-version> 1.1.6 # e.g. git branch -m 1.1.5 1.1.6
Right now: MARKETING_VERSION = 2.0.5 → active branch is 2.0.5. Keep them in sync. (The build number bump within the same version does NOT rename the branch — only a version change does.)
MARKETING_VERSION in the Xcode project does NOT drive the shipped version. Both Info.plists hardcode their values, so bumping the project setting alone builds an IPA with the old version and App Store Connect rejects it (90062: must contain a higher version than that of the previously approved version). A version bump means editing three places, and fastlane's increment_build_number only handles the app's build number:
| What | Where | Bumped by fastlane? |
|---|---|---|
| App version | MealMood/Resources/Info.plist → CFBundleShortVersionString |
❌ by hand |
| App build | MealMood/Resources/Info.plist + pbxproj |
✅ |
| Widget version + build | MealMoodWidget/Info.plist |
❌ by hand |
The widget must match the app or the upload is rejected for a version mismatch. Since fastlane beta increments the build as its first step, set the widget to the next build number before running it:
plutil -replace CFBundleShortVersionString -string "<version>" MealMood/Resources/Info.plist
plutil -replace CFBundleShortVersionString -string "<version>" MealMoodWidget/Info.plist
plutil -replace CFBundleVersion -string "<next build>" MealMoodWidget/Info.plist
Credentials — all managed via pass (GPG-encrypted, syncs to Gitea)
Never hardcode credentials. Always read from pass:
# Apple
pass show apple/mealmood/apple-id # alexandre.vazquez@gmail.com
pass show apple/mealmood/developer-team-id # 2825Q76T7H
pass show apple/mealmood/appstore-connect-team-id # 128443966
pass show apple/mealmood/app-store-app-id # 6759255553
pass show apple/mealmood/app-specific-password-fastlane # for fastlane uploads
# Firebase
pass show firebase/mealmood/api-key
pass show firebase/mealmood/project-id
pass show firebase/mealmood/google-app-id
# AdMob
pass show admob/mealmood/app-id
pass show admob/mealmood/banner-home-unit-id
TestFlight upload
export FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD=$(pass show apple/mealmood/app-specific-password-fastlane)
fastlane beta
Stack
- SwiftUI + SwiftData (iOS 17+)
- Firebase Analytics (
AnalyticsService.swift) - Google AdMob (banner, free tier only, hidden on Mac)
- StoreKit 2 (subscription
com.mealmood.premium.monthly) - iCloud KV sync (
ICloudSyncService.swift) — does NOT syncisPremium - Widget extension (
MealMoodWidget/) — requires App Groupgroup.com.alexandrevazquez.mealmood - Fastlane for CI/CD
Premium logic
PremiumSyncServiceis the source of truth for premium state transitionsisPremiumis determined only by StoreKit — never by iCloud syncTransaction.updateslistener inContentViewcatches purchases in real-time- Tests:
MealMoodTests/PremiumSyncServiceTests.swift
Key files
| File | Purpose |
|---|---|
MealMood/ContentView.swift |
App root, premium sync, Transaction.updates listener |
MealMood/Services/PremiumSyncService.swift |
Premium state machine (testable) |
MealMood/Services/StoreManager.swift |
StoreKit 2 purchase/restore |
MealMood/Services/ICloudSyncService.swift |
Cross-device sync (dishes, tags, plans — NOT isPremium) |
MealMood/Views/Home/WeekPlanShareView.swift |
Export styles (default, school, vertical A4) |
MealMoodWidget/MealMoodWidget.swift |
Home screen widget |
fastlane/Fastfile |
beta and release lanes |
fastlane/metadata/ |
App Store metadata in 6 languages |