# Leftovers Full Mac Handoff - 2026-05-27

## Bottom Line

Leftovers is ready for Mac-side native iOS shell work and TestFlight preparation. It is not ready for public App Store launch until durable paid entitlements, hosted privacy/terms URLs, App Store screenshots, and final legal/privacy review are complete.

Source repo:

```text
https://github.com/throttleshare/leftovers-fridge-to-dinner.git
```

Branch:

```text
leftovers-launch-redesign-mac-asc-handoff-2026-05-27
```

Current verified commit:

```text
fe95717 Gate Leftovers AI scan endpoints
```

Windows verification passed:

```bash
npm run check
```

Result: `node --check app.js && node --check server.mjs` passed.

## Current Product State

The web prototype includes the launch positioning, AI endpoint contract, fallback mode, GLP-safe copy direction, privacy/safety drafts, App Store description draft, and Mac/ASC handoff notes.

Ready artifacts:

- `docs/APP_STORE_DESCRIPTION.md`
- `docs/AI_BACKEND_AND_IMAGE_CONFIRM.md`
- `docs/AI_RATE_ENTITLEMENT_GATE_2026-05-27.md`
- `docs/COMPLIANCE_CHECKLIST.md`
- `docs/DISCLAIMER_SAFETY.md`
- `docs/PRIVACY_POLICY_DRAFT.md`
- `docs/TERMS_DRAFT.md`
- `docs/PRIVACY_SAFETY.md`
- `docs/MAC_ASC_LAUNCH_HANDOFF_2026-05-27.md`
- `docs/LAUNCH_BLOCKERS.md`

Still missing:

- Native Xcode project.
- SwiftUI app shell.
- StoreKit 2 products wired to App Store Connect.
- Durable server-side entitlement checks.
- App Store screenshots.
- Public privacy and terms URLs.
- TestFlight build.
- Attorney-approved public legal copy.

## Mac Setup

On the Mac:

```bash
git clone https://github.com/throttleshare/leftovers-fridge-to-dinner.git
cd leftovers-fridge-to-dinner
git checkout leftovers-launch-redesign-mac-asc-handoff-2026-05-27
npm install
npm run check
```

Run the web prototype locally when comparing copy and flows:

```bash
npm start
```

Required backend secret for AI testing:

```text
OPENAI_API_KEY=...
```

Optional model override:

```text
OPENAI_MODEL=gpt-4.1-mini
```

Do not commit `.env.local`.

## Native iOS Build Target

Create a new Xcode SwiftUI iPhone app:

```text
Product name: Leftovers
Display name: Leftovers
Suggested bundle id: com.<company>.leftovers
Minimum iOS: iOS 17 if possible; iOS 16 only if there is a business reason
Orientation: Portrait first
Storage: local-first for fridge text/history
Networking: hosted Leftovers API contract from docs/AI_BACKEND_AND_IMAGE_CONFIRM.md
Payments: StoreKit 2
```

Recommended app structure:

```text
LeftoversApp.swift
AppView.swift
Models/
  LeftoversAnalysis.swift
  Meal.swift
  FridgeItem.swift
Services/
  LeftoversAPIClient.swift
  EntitlementService.swift
  LocalFallbackPlanner.swift
  PhotoPreparationService.swift
  PrivacyLinks.swift
Features/
  FridgeInput/
  PhotoConfirm/
  MealPlan/
  Reheat/
  GLPProteinMode/
  Settings/
```

Use SwiftUI `TabView` plus one `NavigationStack` per main tab. Keep app-level services in `@Environment`; keep feature state local with `@State` and `@Binding`.

## Required Screens

Build these first:

1. Fridge input
2. Photo confirmation
3. Tonight meal plan
4. Use-first reminders
5. Reheat guidance
6. GLP Protein Mode
7. Settings and subscription
8. Privacy, terms, and safety links

The first screen should have:

- Text input for fridge items.
- Voice input if available.
- Photo picker/camera entry.
- Mode toggles for GLP Protein, Air Fryer, Budget Saver, and Picky Kid.
- Visible fallback state when AI is unavailable.

## API Contract

Use the existing backend contract first.

Health:

```http
GET /health
```

Text/fridge analysis:

```http
POST /api/analyze-fridge
```

Request:

```json
{
  "text": "I have rice, chicken, pizza, broccoli, and eggs.",
  "items": ["rice", "chicken"],
  "modes": {
    "glpProtein": true,
    "airFryer": true,
    "budgetSaver": false,
    "pickyKid": false
  }
}
```

Photo analysis:

```http
POST /api/analyze-photo
```

Request:

```json
{
  "imageDataUrl": "data:image/jpeg;base64,...",
  "items": [],
  "modes": {}
}
```

Expected result shape:

```swift
struct LeftoversAnalysis: Decodable {
    let items: [String]
    let photoGuesses: [String]
    let meals: [Meal]
    let useFirst: [UseFirstItem]
    let glpNotes: [String]
    let safetyNotes: [String]
}
```

Important behavior:

- Text/voice ingredients can be added directly after user submission.
- Photo guesses must be shown as confirmable chips.
- Photo guesses must not become ingredients until the user taps to confirm.
- If AI fails or is unavailable, show local fallback suggestions instead of a dead end.

## Durable Entitlements

The current AI gate is only a stopgap:

- `LEFTOVERS_AI_PUBLIC_ENABLED=true` opens AI endpoints in production.
- `LEFTOVERS_AI_LIMIT_PER_HOUR` controls an in-memory per-IP hourly cap.
- Default is 10 AI scans per hour.
- This resets on process restart and is not tied to a paying user.

Before public launch, replace this with durable entitlement enforcement:

- App creates or restores a stable customer identity.
- StoreKit 2 validates subscription status on device.
- Backend verifies entitlement before paid AI/photo calls.
- Backend stores metering by user/customer/device, not just IP.
- Scan counts and subscription grants survive server restarts.
- Photo AI and text AI share the same paid entitlement policy.
- Failed AI calls should not burn a paid scan.
- Receipt/server notifications are handled for renewal, cancellation, refund, grace period, and billing retry.

Suggested products:

```text
leftovers_plus_monthly
leftovers_plus_annual
```

Do not ship a public paid app with only client-side counters or the current per-IP memory gate.

## StoreKit 2 Acceptance Criteria

The Mac build is not ready for paid public launch until:

- Purchase flow works in StoreKit testing.
- Restore purchase works.
- Expired subscription removes paid AI/photo access.
- Refund/revocation removes entitlement.
- Offline state is graceful and does not unlock unlimited server AI.
- Settings screen shows current plan state.
- Privacy/terms/subscription terms are visible before purchase.
- Backend rejects paid AI calls without a durable entitlement.

## App Store Connect Metadata

Use this as the starting point.

Name:

```text
Leftovers: Fridge to Dinner
```

Subtitle:

```text
Tell us what you have. Get dinner.
```

Short description:

```text
Leftovers turns the food already in your fridge into dinner ideas, reheat steps, air fryer saves, and use-first reminders.
```

Keywords:

```text
leftovers, leftover recipes, fridge, dinner ideas, air fryer leftovers, reheat leftovers, food waste, cook what I have, pantry recipes, fridge cleanout, GLP protein, high protein meals
```

App Review notes:

```text
Leftovers provides general food organization, reheating, and meal suggestion tools. It does not diagnose food safety from photos and does not provide medical nutrition advice.
```

Use the full description from `docs/APP_STORE_DESCRIPTION.md`, then review for final legal/compliance tone.

## Claim Rules

Use:

- Meal ideas
- Protein-forward
- Confirm-first photo suggestions
- Conservative reminders
- General wellness
- Not medical advice
- Food-safety reminders

Avoid:

- Safe to eat
- GLP-approved
- Medical nutrition
- Diet therapy
- Weight loss treatment
- Allergen detection
- Food safety inspection
- Detects spoiled food

GLP Protein Mode must stay framed as small, protein-forward meal ideas. It must not sound like treatment guidance, medication guidance, or a clinician replacement.

## Screenshot Plan

Generate App Store screenshots from the native shell after the SwiftUI build exists.

Required device classes:

- 6.7-inch iPhone
- 6.5-inch iPhone if ASC asks for it
- 5.5-inch iPhone if supporting older screenshot requirements

Recommended screenshot set:

1. Fridge input with text and mode toggles.
2. Photo confirmation with confirmable chips.
3. Tonight meal plan with one cheap unlock ingredient.
4. Reheat guidance and use-first reminders.
5. GLP Protein Mode with conservative, non-medical copy.
6. Settings/subscription/privacy screen.

Screenshot copy must avoid health and food-safety overclaims. Keep it plain:

- "Turn what you have into dinner"
- "Confirm photo guesses before they count"
- "Protein-forward small plate ideas"
- "Reheat and use-first reminders"
- "Fallback ideas when AI is unavailable"

## Test Matrix

Run these on Mac before TestFlight.

Fridge text flow:

- Submit common leftovers: rice, chicken, eggs, broccoli.
- Submit messy text with duplicates.
- Submit empty text and verify no crash.
- Confirm local fallback appears when AI is off.
- Confirm one cheap unlock ingredient appears when appropriate.

Photo flow:

- Pick a fridge photo.
- Verify guesses appear as chips.
- Confirm some chips and reject others.
- Verify rejected guesses do not become ingredients.
- Deny photo permission and verify recovery copy.
- Test large image compression before upload.

GLP-safe copy:

- Enable GLP Protein Mode.
- Verify copy says protein-forward, small plates, gentle reheats.
- Verify copy does not say safe for GLP, treatment, diet prescription, dosage, weight loss, or medical advice.

Fallback mode:

- Run without `OPENAI_API_KEY`.
- Run with AI disabled.
- Simulate quota/rate limit.
- Verify app still returns local rule-based meal ideas.
- Verify UI tells the truth without creating panic.

Privacy and terms:

- Confirm privacy link opens.
- Confirm terms link opens.
- Confirm photo/AI processing disclosure is visible.
- Confirm data deletion/contact path is visible.
- Confirm subscription terms and cancellation language are visible before purchase.

Entitlements:

- Fresh install free state.
- Purchase Plus.
- Restore Plus.
- Expire Plus.
- Refund/revoke Plus.
- Confirm backend blocks paid AI when entitlement is absent.

## Privacy And Food Safety Requirements

Keep these visible in app and store copy:

- Photos and text may be processed to generate suggestions.
- Users must confirm photo guesses.
- Leftovers does not inspect whether food is safe to eat.
- When uncertain, discard food.
- Food inventory should stay local by default where possible.
- Do not sell household food data.

Food-safety reminder baseline:

- Unknown age is cautionary.
- Cooked refrigerated leftovers generally use conservative 3-4 day guidance.
- Remind users to freeze leftovers they will not eat soon.

## TestFlight Go Criteria

Go for internal TestFlight when:

- Native shell builds cleanly.
- Text flow works.
- Photo confirm flow works.
- Fallback mode works.
- GLP-safe copy passes review.
- Privacy/terms links are reachable.
- StoreKit sandbox purchase/restore works or is clearly disabled for internal unpaid TestFlight.
- No medical, allergen, or food-safety inspection claims are present.

No-go for public App Store launch until:

- Durable entitlements are implemented and tested.
- ASC metadata is filled.
- Screenshots are generated from native app.
- Public privacy and terms URLs are live.
- Legal/privacy review is complete.
- AI cost controls are production-grade.

## Ownership

Mac/Xcode owner:

- Create native project.
- Build SwiftUI shell.
- Wire API client and photo confirm flow.
- Add StoreKit 2.
- Generate screenshots.
- Upload TestFlight build.

Backend owner:

- Replace in-memory rate gate with durable entitlements.
- Add account/customer/device metering.
- Verify paid AI calls server-side.
- Keep fallback responses reliable.

Business/legal owner:

- Final privacy policy.
- Final terms.
- Subscription terms.
- Food safety and GLP claim review.
- ASC privacy nutrition labels.

## Final Launch Boundary

Leftovers can move to native build and TestFlight now. It should not move to public paid launch until the entitlement system is durable and the store/legal surface is final.
