initial commit: Proximity iOS app proposal, full Swift code scaffold, reference backend, testing docs, generated Xcode project

This commit is contained in:
2026-08-12 00:22:01 +00:00
commit 9d1b0f8dd9
52 changed files with 6271 additions and 0 deletions

149
docs/TESTING.md Normal file
View File

@@ -0,0 +1,149 @@
# Testing Proximity Without an iPhone
This document explains **how to run and test the entire app using only the
iOS Simulator** — no physical iPhone required for the core interaction loop.
## The strategy in one sentence
> **The interaction logic is fully testable in the simulator. Only the physical
> sensors (UWB, NFC) need real hardware.**
We achieved this by abstracting all hardware behind protocols
(`ProximityAdapterProtocols`) and injecting a `SimulatedAdapter` in DEBUG
builds. `PresenceEngine` talks to the protocols, never to hardware directly,
so it behaves identically whether it's sensing real UWB or receiving simulated
encounters.
## What you can test without any device
| Capability | Simulator | Real iPhone |
|---|---|---|
| SwiftUI UI, navigation, chat | ✅ | ✅ |
| Auth (Apple / Google) | ✅ (Apple needs bundle config) | ✅ |
| Backend + WebSocket live loop | ✅ | ✅ |
| Full reveal flow (wave → mutual → chat) | ✅ | ✅ |
| Simulated encounters / crowd | ✅ | ✅ |
| Core Location / iBeacon | ⚠️ simulated location | ✅ |
| BLE broadcast/discovery | ⚠️ limited | ✅ |
| **UWB (Nearby Interaction)** | ❌ | ✅ |
| **NFC tap** | ❌ | ✅ |
---
## Quick start (simulator)
### 1. Run the reference backend
The Swift client in DEBUG mode points at a local server. Start it:
```bash
cd server
npm install
npm run dev # runs on http://localhost:8080
```
### 2. Run the app in the Simulator
1. Open `Proximity.xcodeproj` in Xcode.
2. Select an iPhone simulator (any model).
3. Build & run (⌘R).
In DEBUG builds, `AppState` automatically:
- Points `APIClient` at `http://localhost:8080`
- Injects `SimulatedAdapter` into the `PresenceEngine`
### 3. Exercise the interaction loop
1. **Sign in** (Apple or Google — the reference server accepts any token).
2. Tap the big **"I'm Here"** toggle to go present.
3. Open the **debug menu** (hammer icon, top-left).
4. Tap **"Simulate someone walking by"** — a silhouette appears in the feed.
5. Tap **Wave** on the silhouette.
6. To complete the reveal, simulate the *other* side waving back — in real
life the server pushes this over the socket. For a fully local test, you
can drive the mutual wave via the debug tools or a second client.
### 4. Test the reveal moment
When both sides wave, `RevealView` presents full-screen — two avatars
converging. Tap **"Say hello"** to open the E2E chat.
---
## Driving the simulation
The debug menu (`DebugMenu`) provides:
- **Simulate someone walking by** — one UWB encounter.
- **Simulate a crowd (20 people)** — a burst of silhouettes.
- **Auto-broadcast nearby users** — emits encounters on a timer (a "busy
street" simulator).
`SimulatedAdapter` also exposes programmatic methods if you want to write
UITests:
```swift
simulatedAdapter.simulateEncounter(remoteToken: "any-token", distance: 1.0)
simulatedAdapter.simulateCrowd(count: 20)
```
---
## Two-simulator / two-client testing
To test the **mutual** flow (both sides), run **two simulator instances**:
1. Boot two simulators (e.g. iPhone 15 + iPhone 15 Pro).
2. Run the app on both against the same local backend.
3. In each, go present and simulate an encounter (the debug menu gives each a
distinct token).
4. Wave from one — the server derives each sender's own token from its
session, records the directional edge, and when both directions exist it
pushes `mutual` to **both** sockets. The reveal triggers on both devices
in real time.
The reference server now implements the full session→token mapping, so the
mutual reveal and E2E key exchange work end-to-end across two clients.
## Running the UI tests
The `ProximityUITests` target drives the happy path automatically:
```bash
xcodebuild test \
-project Proximity.xcodeproj \
-scheme Proximity \
-destination 'platform=iOS Simulator,name=iPhone 15' \
-only-testing:ProximityUITests/ProximityFlowUITests
```
Start the reference server first (`cd server && npm run dev`).
---
## Testing on real hardware (the sensors)
When you're ready to test UWB / BLE / NFC for real:
1. **Disable the simulated adapter.** Either build a non-DEBUG configuration,
or set `AppState.isSimulated = false`.
2. Use two physical iPhones (iPhone 11+ for UWB).
3. The real `UWBAdapter`, `BLEAdapter`, `BeaconAdapter` take over.
The rest of the app (auth, chat, reveal, backend) works identically — that's
the point of the abstraction.
---
## What the simulator can't do (and why it's OK)
- **UWB**: no support in the simulator. But UWB is only the *"this exact
person"* distance sensor — the interaction logic (handshake → reveal) is
fully testable via simulation.
- **NFC**: no support. NFC is a niche "tap to connect" feature, not core.
- **BLE**: very limited in simulator. The presence *logic* is testable; the
radio isn't.
Since the make-or-break mechanic — **the physical interaction moment** — is
driven by logic + UI, not by the radio, you can validate the entire product
experience in the simulator before ever touching real devices.