initial commit: Proximity iOS app proposal, full Swift code scaffold, reference backend, testing docs, generated Xcode project
This commit is contained in:
250
proximity_proposal.md
Normal file
250
proximity_proposal.md
Normal file
@@ -0,0 +1,250 @@
|
||||
# "Proximity" — A Near-Field Social Connection App
|
||||
## Product Proposal & iOS Technical Design Specification
|
||||
|
||||
---
|
||||
|
||||
## 1. Executive Summary
|
||||
|
||||
**Proximity** is an iOS application that reimagines social networking around *physical presence* rather than *online profiles*. The core premise: technology has made us hyper-visible to institutions (AirTags, Flock cameras, location tracking) while simultaneously making us invisible to each other. Proximity inverts this — it uses the same proximity-sensing hardware to let strangers in the real world acknowledge each other as human beings.
|
||||
|
||||
The defining constraint, and the product's soul: **you cannot connect with someone unless you are physically near them.** There is no global search, no "add by username," no online-only discovery. The network graph grows only through real-world encounters.
|
||||
|
||||
---
|
||||
|
||||
## 2. Problem Statement
|
||||
|
||||
| The Problem | The Evidence |
|
||||
|---|---|
|
||||
| Urban isolation | People pass thousands of strangers daily without interaction |
|
||||
| Asymmetric surveillance | We're tracked by cameras and tags, but never "seen" by each other |
|
||||
| Parasocial networking | Online platforms connect us to people we never meet, while eroding local community |
|
||||
| Attention economy | Apps optimize for time-on-screen, not real-world connection |
|
||||
|
||||
**The insight:** The *same* hardware stack used to surveil us (UWB, BLE beacons, geolocation) can be repurposed for *mutual, consented, human connection*.
|
||||
|
||||
---
|
||||
|
||||
## 3. Product Vision
|
||||
|
||||
> *"A social network you can only enter by being physically present. Every connection is a real-world encounter. The map is your neighborhood, not the internet."*
|
||||
|
||||
**Core loop:**
|
||||
1. **Opt in** — You signal "I'm open to connection" (a digital handshake-ready state).
|
||||
2. **Encounter** — You pass someone nearby who has also opted in.
|
||||
3. **Handshake** — Devices exchange anonymous tokens via proximity hardware.
|
||||
4. **Grow the network** — The encounter becomes a "possible connection" in your graph.
|
||||
5. **Optional reveal** — Either party can choose to reveal identity and start a conversation.
|
||||
|
||||
---
|
||||
|
||||
## 4. How It Works (Product Behavior)
|
||||
|
||||
### 4.1 Distance Tiers
|
||||
Proximity operates across a spectrum of physical range, each using different technology:
|
||||
|
||||
| Tier | Range | Technology | Use Case |
|
||||
|---|---|---|---|
|
||||
| **Tier 1 — "Right here"** | 0–9 m | UWB (Nearby Interaction) | Precise, directional handshake — "this exact person" |
|
||||
| **Tier 2 — "Nearby"** | 10–100 m | BLE / iBeacon | Room, cafe, street-corner presence |
|
||||
| **Tier 3 — "In the area"** | 100 m–50 mi | Server + opt-in location | Regional community graph, events, neighborhoods |
|
||||
|
||||
### 4.2 The Encounter Flow
|
||||
1. Both users have **"Open to Connect"** toggled on.
|
||||
2. As they approach, devices exchange **ephemeral anonymous tokens** (no names, no photos, no personal data).
|
||||
3. A subtle, non-intrusive notification: *"You passed 3 people who are open to connection."*
|
||||
4. The encounter is stored as a **"Possible Connection"** — a silhouette, not a profile.
|
||||
5. If both parties **mutually** choose to "wave," identities are revealed and a chat opens.
|
||||
|
||||
### 4.3 Anti-Harassment & Consent
|
||||
- **Mutual opt-in required** for any reveal. No unilateral contact.
|
||||
- **Silhouette-only** until mutual consent.
|
||||
- **Block/ignore** removes you from the graph permanently.
|
||||
- **Incognito mode** — be present but invisible.
|
||||
|
||||
---
|
||||
|
||||
## 5. Technical Architecture
|
||||
|
||||
### 5.1 The Honest Constraint (Important)
|
||||
iOS imposes hard limits on background proximity sensing. A naive "always-on background scanner" is **not possible** on iOS. The design must work *with* the platform:
|
||||
|
||||
| Framework | Foreground | Background | Notes |
|
||||
|---|---|---|---|
|
||||
| **Core NFC** | ✅ Read/write NDEF tags | ❌ No background reading; no card emulation | Requires user-initiated tap; short range (~4 cm) |
|
||||
| **Nearby Interaction (UWB)** | ✅ Precise ranging (~9 m) | ❌ Not available in background | Requires U1/U2 chip (iPhone 11+) |
|
||||
| **Core Bluetooth** | ✅ Advertise + scan | ⚠️ Severely restricted; ~1 advertisement | Background scanning unreliable |
|
||||
| **Core Location (iBeacon)** | ✅ | ✅ Region monitoring works in background | The *only* reliable background mechanism |
|
||||
|
||||
**Architectural conclusion:** Use a **hybrid, foreground-first** model where the phone is the active "handshake device," supplemented by **iBeacon region monitoring** for background wake-ups and **push notifications** to prompt re-engagement.
|
||||
|
||||
### 5.2 System Diagram
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ iOS Client (Swift) │
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────┐ │
|
||||
│ │ NearbyInter. │ │ CoreBluetooth│ │ CoreLocation │ │
|
||||
│ │ (UWB) │ │ (BLE) │ │ (iBeacon) │ │
|
||||
│ └──────┬───────┘ └──────┬───────┘ └───────┬───────┘ │
|
||||
│ │ │ │ │
|
||||
│ └────────┬────────┘ │ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌────────────────┐ ┌──────────────────┐ │
|
||||
│ │ Encounter │ │ Region Monitor │ │
|
||||
│ │ Engine │ │ (background) │ │
|
||||
│ └───────┬────────┘ └────────┬─────────┘ │
|
||||
│ ▼ ▼ │
|
||||
│ ┌──────────────────────────────────────────┐ │
|
||||
│ │ Local Graph Store (SQLite) │ │
|
||||
│ └───────────────────┬──────────────────────┘ │
|
||||
└─────────────────────────────┼───────────────────────────┘
|
||||
│ HTTPS (TLS 1.3) / WebSocket
|
||||
▼
|
||||
┌─────────────────────┐
|
||||
│ Backend (Server) │
|
||||
│ - Token relay │
|
||||
│ - Graph database │
|
||||
│ - Push (APNs) │
|
||||
│ - Consent ledger │
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. iOS Technical Design (Swift)
|
||||
|
||||
### 6.1 Target & Minimums
|
||||
- **Minimum iOS:** 15.0 (UWB/NI requires 14+; 15 for broader BLE reliability)
|
||||
- **Recommended:** iOS 17+ for modern concurrency and background improvements
|
||||
- **Hardware:** iPhone 11 or newer (U1/U2 chip for UWB); BLE fallback for older devices
|
||||
- **Language:** Swift 5.9+ with Swift Concurrency (async/await)
|
||||
|
||||
### 6.2 Framework Usage
|
||||
|
||||
**Nearby Interaction (UWB)** — Tier 1 handshake
|
||||
```swift
|
||||
import NearbyInteraction
|
||||
|
||||
final class UWBHandshake: NSObject, NISessionDelegate {
|
||||
private var session = NISession()
|
||||
private var peerToken: NIDiscoveryToken?
|
||||
|
||||
func beginHandshake(peerToken: NIDiscoveryToken) {
|
||||
session.delegate = self
|
||||
session.delegateQueue = .main
|
||||
let config = NINearbyPeerConfiguration(peerToken: peerToken)
|
||||
session.run(config)
|
||||
}
|
||||
|
||||
func session(_ session: NISession,
|
||||
didUpdate nearbyObjects: [NINearbyObject]) {
|
||||
guard let object = nearbyObjects.first else { return }
|
||||
// object.distance (meters), object.direction (vector)
|
||||
if let distance = object.distance, distance < 2.0 {
|
||||
triggerEncounter() // within ~2m → mutual handshake
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Core Bluetooth (BLE)** — Tier 2 presence
|
||||
```swift
|
||||
import CoreBluetooth
|
||||
|
||||
// Advertise an ephemeral, rotating service UUID (privacy)
|
||||
let serviceUUID = CBUUID(string: "A1B2...") // rotates per session
|
||||
peripheralManager.startAdvertising([
|
||||
CBAdvertisementDataServiceUUIDsKey: [serviceUUID],
|
||||
CBAdvertisementDataLocalNameKey: "" // empty = anonymous
|
||||
])
|
||||
```
|
||||
|
||||
**Core Location (iBeacon)** — Tier 2 background wake-up
|
||||
```swift
|
||||
let region = CLBeaconRegion(
|
||||
uuid: UUID(uuidString: "...")!,
|
||||
identifier: "proximity.region"
|
||||
)
|
||||
locationManager.startMonitoring(for: region) // works in background
|
||||
```
|
||||
|
||||
**Core NFC** — Tier 1b, physical tap (optional "meet at the door" mode)
|
||||
```swift
|
||||
import CoreNFC
|
||||
// NFCNDEFReaderSession — foreground, user-initiated tap
|
||||
// Used for "tap phones to connect" at events/doors
|
||||
```
|
||||
|
||||
### 6.3 Data Model (Local SQLite via SwiftData/Core Data)
|
||||
|
||||
```
|
||||
User (local identity)
|
||||
├── PublicKey (for E2E handshake)
|
||||
├── Preferences (open-to-connect, radius, incognito)
|
||||
└──
|
||||
Encounter
|
||||
├── EncounterID (UUID)
|
||||
├── AnonToken (ephemeral, rotating)
|
||||
├── Timestamp
|
||||
├── GeoHash (coarse, optional)
|
||||
├── DistanceTier (1/2/3)
|
||||
└── Status (.silhouette, .mutual, .blocked)
|
||||
|
||||
Connection
|
||||
├── UserA, UserB
|
||||
├── MutualConsent (bool)
|
||||
├── RevealedAt
|
||||
└── ChatThreadID
|
||||
```
|
||||
|
||||
### 6.4 Privacy & Security Architecture
|
||||
- **Ephemeral rotating tokens** — no persistent identifiers broadcast.
|
||||
- **End-to-end encryption** for revealed conversations (Signal-style, via libsodium or CryptoKit).
|
||||
- **Zero-knowledge graph** — server sees tokens, not identities.
|
||||
- **On-device consent ledger** — the user controls all data.
|
||||
- **Right to be forgotten** — delete account purges graph + tokens.
|
||||
- **No location history stored server-side** by default.
|
||||
|
||||
---
|
||||
|
||||
## 7. MVP Scope (v1.0)
|
||||
|
||||
| Feature | Priority | Framework |
|
||||
|---|---|---|
|
||||
| Opt-in "Open to Connect" toggle | P0 | — |
|
||||
| Foreground UWB handshake (Tier 1) | P0 | NearbyInteraction |
|
||||
| Silhouette encounter list | P0 | SwiftData |
|
||||
| Mutual "wave" → reveal + chat | P0 | WebSocket + CryptoKit |
|
||||
| BLE presence (Tier 2) | P1 | CoreBluetooth |
|
||||
| iBeacon background wake-up | P1 | CoreLocation |
|
||||
| Regional graph (Tier 3, 50 mi) | P2 | Backend |
|
||||
| NFC tap-to-connect | P2 | CoreNFC |
|
||||
| Block/incognito/privacy controls | P0 | — |
|
||||
|
||||
---
|
||||
|
||||
## 8. Key Risks & Mitigations
|
||||
|
||||
| Risk | Mitigation |
|
||||
|---|---|
|
||||
| iOS background sensing limits | Foreground-first UX; iBeacon + push for background; set expectations |
|
||||
| Battery drain (UWB/BLE) | Duty-cycling, session timeouts, user-controlled scanning windows |
|
||||
| Harassment / stalking | Mutual consent, silhouettes, blocking, no persistent IDs |
|
||||
| Cold start (network effect) | Event mode, "meet at the door" NFC, regional Tier 3 seeding |
|
||||
| App Store privacy review | Transparent privacy nutrition labels; clear consent flows |
|
||||
|
||||
---
|
||||
|
||||
## 9. Roadmap
|
||||
|
||||
- **Phase 0 (4–6 wks):** Tech spike — UWB handshake + BLE presence proof-of-concept.
|
||||
- **Phase 1 (8–12 wks):** MVP — Tier 1 handshake, silhouettes, mutual reveal, chat.
|
||||
- **Phase 2:** Tier 2/3, background monitoring, regional graph.
|
||||
- **Phase 3:** Android interoperability (via BLE + server relay), events, communities.
|
||||
|
||||
---
|
||||
|
||||
## 10. Summary
|
||||
|
||||
**Proximity** is a deliberate counterpoint to both the surveillance state *and* the attention economy. It uses the same proximity hardware that tracks us — UWB, BLE, geolocation — to restore what that tracking erases: **mutual, consensual, real-world human connection.** The technical design is feasible on iOS today using a hybrid of Nearby Interaction, Core Bluetooth, Core Location, and Core NFC, with a privacy-first architecture where the network graph grows only through physical presence.
|
||||
Reference in New Issue
Block a user