# Biz Connect — iOS App Store setup (Codemagic, no Mac needed)

The iOS app is a Capacitor shell that loads the live Connect web UI (`https://remote.bizgaze.com`).
Building/signing/uploading happens on **Codemagic's macOS cloud** — you never need a Mac.

Bundle id: **`com.bizgaze.connect`** · CI config: [`codemagic.yaml`](../codemagic.yaml) (repo root).

---

## Step 0 — Register the App ID (Identifiers → + → App IDs → App)
On the **Register an App ID** page, only three fields matter — leave everything else default:
- **Platform**: leave as-is (the default `iOS, iPadOS, macOS…` combined App ID is fine).
- **Description**: `Biz Connect` (label only; no `@ & * "`).
- **Bundle ID**: keep **Explicit** → `com.bizgaze.connect`.
- **Capabilities**: tick **Push Notifications** only. Leave all others unchecked. (Camera/mic are NOT
  here — they're Info.plist runtime strings, added by the build pipeline.)
- Continue → Register.  *(The App ID Prefix shown is your Team ID — note it for Step 5's APNs.)*

## Step 1 — App Store Connect: create the app record
1. [appstoreconnect.apple.com](https://appstoreconnect.apple.com) → **Apps → +** → **New App**.
2. Platform **iOS**, Name **Biz Connect**, primary language, **Bundle ID** = `com.bizgaze.connect`
   (the App ID you registered in Step 0 now appears in the dropdown).
3. SKU: anything unique (e.g. `bizconnect-ios`). Create.

## Step 2 — App Store Connect API key (for Codemagic to sign + upload)
1. App Store Connect → **Users and Access → Integrations → App Store Connect API** → **+**.
2. Access **App Manager**. Generate. Note the **Issuer ID** (top of the page) and the key's **Key ID**,
   and **download the `.p8`** (you can only download it once).

## Step 3 — Codemagic: connect + add the key
1. [codemagic.io](https://codemagic.io) → sign in with the git provider → add this repository.
2. **Teams → Integrations → App Store Connect → Connect**, upload the `.p8`, paste the **Issuer ID** and
   **Key ID**. **Name it exactly `BizGaze App Store Connect`** (the `codemagic.yaml` references that name).
3. Codemagic detects `codemagic.yaml`. That's all the signing setup — automatic signing creates the
   distribution certificate + provisioning profile from this key on the first build.

## Step 4 — Run the build
- Codemagic → the app → **Start new build** → workflow **"Biz Connect iOS → TestFlight"**.
- ~10–15 min. On success the build appears in **App Store Connect → TestFlight**.
- Add yourself under **TestFlight → Internal Testing** to install via the TestFlight app on your iPhone.

## Step 5 — Push notifications (APNs) — do this once, then tell me
So the app gets **calls/messages while it's closed**. Two independent pieces must BOTH be in place:

> **A. App ID capability (client side).** The App ID `com.bizgaze.connect` must have **Push Notifications**
> enabled (Step 0 ticks it). The build now injects the `aps-environment` entitlement automatically
> (`ios-patch.sh`), so the app can obtain an APNs token — but if the App ID lacks the Push capability, the
> archive fails code-signing on `aps-environment`. If a build errors on that after you enable the
> capability, delete the app's provisioning profile in App Store Connect so the next Codemagic run
> regenerates one that includes push.
>
> **B. APNs key (server side).** Do the two steps below so the server can actually SEND to that token.

1. developer.apple.com → **Keys → +** → enable **Apple Push Notifications service (APNs)** → download the
   **`.p8`**. Note its **Key ID** and your **Team ID** (top-right of the developer portal).
2. **Send me**: the `.p8` contents, the **Key ID**, and the **Team ID**. I set these in the server `.env`
   (server-side only, like the LiveKit/Giphy keys):
   ```
   APNS_KEY=<contents of the .p8>
   APNS_KEY_ID=<key id>
   APNS_TEAM_ID=<team id>
   APNS_BUNDLE_ID=com.bizgaze.connect
   APNS_PRODUCTION=1
   ```
   The APNs sender is already built into the server — it's a no-op until these are set.

## Step 6 — Public App Store submission (when you're ready to leave TestFlight)
In App Store Connect, fill the listing: **screenshots** (6.7" + 6.1" iPhone), description, keywords,
support URL, and a **Privacy Policy URL** (required). Complete the **App Privacy** questionnaire (we
collect account info + usage for chat/calls). Then submit for review (or flip `submit_to_app_store` in
`codemagic.yaml`).

---

### App Review note (Guideline 4.2 — "Minimum Functionality")
Apple scrutinises apps that look like "just a website". Ours passes because it ships **real native
capabilities** — push notifications, camera/microphone for calls, photo sharing. Make sure push (Step 5)
is live before the **public** submission, and in the reviewer notes mention the **native video/voice
calling + push notifications**. Do **not** advertise "share your screen" as an iOS feature in the store
listing yet — see the follow-up below (you can still *view* a screen someone else shares).

---

## Known iOS limitations & follow-ups (phase 2 — after TestFlight)

### 1. Sharing YOUR iOS screen into a meeting → needs a ReplayKit Broadcast Upload Extension
- **Why:** the app's screen share uses the web `getDisplayMedia` API, which **iOS WebViews and Safari do
  not support**. Apple only allows capturing the *device* screen via **ReplayKit**.
- **What works today on iOS:** *viewing* a screen another participant shares (it's just incoming video),
  chat, voice/video calls, camera, photo sharing.
- **What's needed to broadcast the iOS screen:** a native **Broadcast Upload Extension** target that
  captures frames via ReplayKit and feeds them into the LiveKit/WebRTC session, plus the **App Groups**
  capability (to pass data between the app and the extension). This is native Swift work — NOT part of
  the Capacitor wrapper — so it's tracked as a separate task, done after the app is on TestFlight.
- **Store impact:** don't claim iOS screen-sharing in the listing until this ships, or a reviewer may
  test it and it will fail.

### 2. Native mobile audio routing (speaker / earpiece / Bluetooth) — needs a Capacitor audio plugin
- Mobile **web** can't switch the audio output route (`setSinkId` is unimplemented on iOS/Android), so the
  in-meeting speaker/earpiece/Bluetooth control is web-only where it works and hidden where it doesn't.
- True routing on iOS needs a small native plugin driving `AVAudioSession`. Phase-2 native task.

---

## Share Extension ("Biz Connect" in the iOS share sheet) — one-time Apple portal setup

The app now has a **Share Extension** target (`com.bizgaze.connect.share`) so users can share a photo /
video / file FROM the Photos or Files app INTO a Biz Connect conversation. The Codemagic build injects the
target and fetches a profile for it automatically, but two things can ONLY be done once, by hand, in the
Apple Developer portal — CI cannot toggle App capabilities:

1. **Create the App Group** (developer.apple.com → Identifiers → App Groups → +):
   identifier **`group.com.bizgaze.connect`**.
2. **Enable the App Groups capability on BOTH App IDs** and assign them to that group:
   - `com.bizgaze.connect` (the app)
   - `com.bizgaze.connect.share` (the extension — create this App ID if the first build hasn't yet;
     `fetch-signing-files --create` will register it, then edit it to add App Groups)
   After enabling the capability, the provisioning profiles must be regenerated — the next Codemagic build
   does that via `fetch-signing-files`, so just re-run it once the capability is on.

If the App Group isn't set up, the app and the extension can't see each other's files: sharing will appear
to do nothing (the extension stages the file, but the app finds an empty inbox). Everything else — download
to the Files folder, the Photos "Connect" album, Manage storage — works without it.

Also enabled by this change (main app Info.plist, done automatically by `ios-patch.sh`):
- `UIFileSharingEnabled` + `LSSupportsOpeningDocumentsInPlace` → the **Biz Connect** folder in Files.
- `CFBundleURLTypes` scheme **`bizconnect`** → lets the extension bounce back into the app after staging.
