> ## Documentation Index
> Fetch the complete documentation index at: https://docs.swiftaiboilerplate.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Upgrading from v1.9 to v2.0

> The full migration path for Swift 6, iOS 26 Liquid Glass, and the v2.0 architecture refactor.

v2.0 is the Swift 6 and iOS 26 Liquid Glass release. It changes the toolchain floor, ships a new Liquid Glass primitive, and splits oversized files into ≤ 400-line extension siblings. Most downstream apps upgrade in under an hour.

<Info>
  **Canonical release notes:** [`RELEASE_NOTES.md`](https://github.com/SwiftAIBoilerplatePro/SwiftAIBoilerplatePro-Distribution/blob/main/RELEASE_NOTES.md) in the boilerplate repo. This guide is the step-by-step version.
</Info>

## 1. Toolchain

v2.0 uses iOS 26 SDK symbols (`Glass`, `glassEffect`, `GlassEffectContainer`) that older toolchains cannot compile, regardless of `#available` checks.

**Required:**

* macOS 15+
* Xcode 26.2+ (Swift 6.0)
* iOS 17+ runtime (unchanged)

**The repo pins `26.3` via `.xcode-version`.** If you use `xcodes` or `asdf-xcode`, run `xcodes install` (or `asdf install xcode`) inside the repo to match.

<Warning>
  **Stuck on older Xcode?** Pin your build to [`v1.9.0`](https://github.com/SwiftAIBoilerplatePro/SwiftAIBoilerplatePro-Distribution/releases/tag/v1.9.0) until you can upgrade. There is no forward-compatible fallback; the iOS 26 SDK is required to compile.
</Warning>

## 2. Apply the Supabase migration

v2.0 ships a new SQL migration that fixes an authorization (IDOR) gap in the `get_conversation_with_stats` function — it was `SECURITY DEFINER` with no `auth.uid()` ownership check, so any authenticated user could read any conversation by UUID.

```bash theme={null}
# From the repo root
supabase migration up
```

Or run the file directly:

```bash theme={null}
psql "$SUPABASE_DB_URL" \
  -f supabase/migrations/20260408000000_fix_conversation_stats_auth.sql
```

## 3. Redeploy the `ai` edge function

The Edge Function was updated alongside the migration. Redeploy it so the new version picks up the fix:

```bash theme={null}
supabase functions deploy ai
```

## 4. Install the secrets pre-commit hook

v2.0 ships a pre-commit hook that blocks accidental secret commits (the hook lives in `.githooks/`). Enable it once per clone:

```bash theme={null}
git config core.hooksPath .githooks
```

This is a one-time, per-clone setting. It is not picked up automatically.

## 5. Reapply downstream customisations

A lot of oversized files were split into extension siblings to stay under the new ≤ 400-line rule. Public entry points are unchanged, but if you customised any of these files, your edits may now belong in a subview or sibling file.

| Touched in v1.9         | Where the content lives now                                                       |
| ----------------------- | --------------------------------------------------------------------------------- |
| `ProfileView.swift`     | `AppShell/Profile/*.swift` (composition root + section files)                     |
| `SettingsView.swift`    | `FeatureSettings/Views/Settings/*.swift` (≤ 125-line root + one file per section) |
| `EmailSignUpView.swift` | `AppShell/Auth/EmailSignUp*.swift`                                                |
| `SessionManager.swift`  | `+SignIn`, `+Refresh`, `+Persistence` extensions                                  |
| `L10n.swift`            | `L10n+<Namespace>.swift` per nested enum                                          |
| `ChatViewModel.swift`   | `ChatViewModel+Memory.swift` for history/memory                                   |

Strategy: `git log` the file, find the function you edited, `grep` for it in the new tree, port the change.

## 6. Fighting-glass cleanup

This is the biggest source of visual regressions when upgrading. On iOS 26, SwiftUI handles sheet and container materials for you. If your downstream code piles manual backgrounds on top, you block the Material SwiftUI already provides and you fight Liquid Glass on iOS 26.

**Remove these patterns from your own views:**

* `.background(DSColors.background)` on SwiftUI containers (`NavigationStack`, `Form`, `List`, sheets, `TabView`).
* `DSColors.background.ignoresSafeArea()` stacked under sheets or full-screen covers.
* `.background(.black)` or `.background(Color.clear)` under `.presentationBackground` on sheets.
* `.scrollContentBackground(.hidden)` on forms that already use `.formStyle(.grouped)`. `.grouped` already does the right thing on iOS 26.
* Explicit `.safeAreaInset(edge: .bottom)` gutters under a `TabView`. The tab bar's own inset is already respected.

**Use instead:**

* `.saiGlass(.regular)` when you need glass on a custom view.
* `SAIGlassContainer { ... }` when multiple glass surfaces sit near each other.
* `.saiScrollEdgeGlass(_:)` for scroll-edge treatment under nav and input chrome.
* `.saiTabBarMinimize(.onScrollDown)` if you want iOS 26 tab bar minimisation (it is a no-op on iOS 17–25).

## 7. Paywall CTA theming

Paywall CTAs in v2.0 use the standard system styles:

```swift theme={null}
Button("Upgrade") { ... }
    .buttonStyle(.borderedProminent)

Button("Maybe later") { ... }
    .buttonStyle(.bordered)
```

If you were theming these buttons via `.background()`, **switch to `.tint()`**:

```swift theme={null}
// Before (v1.9)
Button("Upgrade") { ... }
    .background(BrandConfig.accentColor)

// After (v2.0)
Button("Upgrade") { ... }
    .buttonStyle(.borderedProminent)
    .tint(BrandConfig.accentColor)
```

`.tint()` lets the standard button style render the glass-aware surface correctly on iOS 26, and still picks up the correct Material on iOS 17–25.

## Quick verification checklist

After the upgrade, run through this list before shipping:

* [ ] App builds under Xcode 26.2+ with zero Swift 6 warnings.
* [ ] Supabase migration ran cleanly (`supabase migration list` shows `20260408000000_fix_conversation_stats_auth`).
* [ ] The `ai` Edge Function returns a streaming response end-to-end.
* [ ] `git config core.hooksPath` returns `.githooks`.
* [ ] Sheets, paywall, settings, and chat all look right on **iOS 26** (Liquid Glass) and **iOS 17–18** (Material fallback).
* [ ] No remaining `.onReceive(...)` on `ToastCenter` or `DeepLinkBus` in downstream code; migrate to `.onChange(of:)`.
* [ ] No remaining `.background(DSColors.background.ignoresSafeArea())` under containers.

## Related

<CardGroup cols={2}>
  <Card title="Changelog" icon="list" href="/pages/reference/changelog">
    Full v2.0.0 release entry
  </Card>

  <Card title="Liquid Glass API" icon="gem" href="/pages/modules/design-system#liquid-glass">
    `SAIGlass`, modifiers, container
  </Card>

  <Card title="Architecture" icon="diagram-project" href="/pages/architecture">
    Swift 6 concurrency model + ≤ 400-line rule
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/pages/quickstart#troubleshooting">
    Common upgrade errors and fixes
  </Card>
</CardGroup>
