---
title: 'Product Requirements Document: Local Community Network (React Native - 1-Month MVP)'
---
# Product Requirements Document: Local Community Network (React Native - 1-Month MVP)
**Version:** 2.1
**Last Updated:** October 2025
**Status:** Active Development
**Owner:** Product Team
**Target Launch:** October 31, 2025
---
## 1. Product Vision
Build a privacy-first platform for discovering local events and building neighborhood connections in just 4 weeks. Focus on proving core value: **Advertising-only Bluetooth verification** + encrypted event discovery.
**The killer use case:** Answer "What's happening in my neighborhood this weekend?" in under 30 seconds.
**1-Month Scope:** Ruthlessly minimal. **No Bluetooth pairing** - advertising/scanning only, basic encryption, single device, core event features. Prove the concept, then iterate.
### Success Criteria (by Oct 30)
- **Working prototype** with 20-30 beta users in one neighborhood
- **Core flow works:** BLE advertise/scan → exchange keys (no pairing) → post event → discover in feed → attend event
- **1+ successful event** coordinated through the app
- **Zero critical bugs** or security vulnerabilities
- **Technical proof:** Advertising-only Bluetooth + E2E encryption working reliably
- **Fast verification:** <5 seconds to exchange keys (no connection overhead)
---
## 2. User Stories & Acceptance Criteria
### Epic 1: Identity & Onboarding
#### US-1.1: Create Identity
**As a** new user
**I want to** create an account without providing email or phone
**So that** I maintain privacy and control over my identity
**Acceptance Criteria:**
- Generate Ed25519 key pair on device
- Public key becomes user identifier
- Private key stored in device secure storage (Keychain/KeyStore)
- User chooses display name and optional profile photo
- No server authentication required for account creation
- Account creation completes in <30 seconds
#### US-1.2: Onboarding Flow
**As a** new user
**I want to** understand the app's value in under 2 minutes
**So that** I know why and how to use it
**Acceptance Criteria:**
- 3-screen onboarding explaining: (1) tap-to-connect (no pairing!), (2) private posts, (3) local connections
- Skip option available after first screen
- App functional immediately after onboarding
- Onboarding never shown again unless user resets
- Emphasize "No pairing needed - just hold phones close"
### Epic 2: Advertising-Only Bluetooth Verification (Week 1 Priority)
#### US-2.1: Exchange Keys via Bluetooth (NO PAIRING - PRIMARY METHOD)
**As a** user
**I want to** hold my phone near someone to exchange keys
**So that** I can verify we're physically together without any pairing hassle
**Acceptance Criteria:**
- "Connect" button prominently visible on home screen
- Tapping starts **both advertising AND scanning simultaneously**
- **No Bluetooth pairing dialog** - happens in background
- Shows list of detected nearby users (within 1-3 meters, RSSI > -70 dBm)
- User selects correct person from list (shows their name from advertisement)
- Visual confirmation: shows their profile name and photo
- Both users tap "Confirm" in app
- Connection saved locally within 3 seconds
- Works offline-only for MVP (no server sync)
- **Entire process: <10 seconds** (typically 3-5 seconds)
**Technical Requirements:**
- Use **BLE advertising with service data** (no GATT connection)
- Each device simultaneously:
- **Advertises:** Service UUID + name + public key (32 bytes) in service data
- **Scans:** For same service UUID from other devices
- RSSI threshold: -70 dBm minimum for detection
- Advertisement payload structure:
```
Service UUID: a1b2c3d4-1234-5678-90ab-cdef12345678
Service Data: {
version: 1 byte,
name_length: 1 byte,
name: variable (max 20 bytes),
public_key: 32 bytes (Ed25519)
}
Total: ~55 bytes (well within 31-byte advertisement limit via service data)
```
- iOS: Use CoreBluetooth (CBPeripheralManager + CBCentralManager)
- Android: Use BLE Advertiser + Scanner APIs
- **NO GATT connection** - keys extracted directly from advertisement payload
- Store connection in local SQLite
- 30-second timeout if no confirmation
- Both devices show same confirmation prompt with exchanged info
**1-Month Simplifications:**
- No background scanning (app must be in foreground)
- No retry logic (exchange fails = start over)
- Manual selection from list (no auto-matching)
- Basic error messages only
- Single advertisement packet (no multi-packet key exchange)
**UX Flow:**
```
User A User B
│ │
├─ Taps "Connect" ├─ Taps "Connect"
├─ Starts advertising ├─ Starts advertising
├─ Starts scanning ├─ Starts scanning
│ │
├─ Sees "Bob" in list ◄─────────┤─ Advertising as "Bob"
├─ Taps "Bob" │
│ │
├─ Shows confirmation: ├─ Shows confirmation:
│ "Connect with Bob?" │ "Alice wants to connect"
├─ Taps "Confirm" ──────────────├─ Taps "Confirm"
│ │
├─ ✓ Connected! ├─ ✓ Connected!
│ (Keys exchanged) │ (Keys exchanged)
└─ Stops advertising/scanning └─ Stops advertising/scanning
```
**Why Advertising-Only Is Better:**
- ⚡ **Faster:** No connection handshake (2-5s saved)
- 🎯 **More reliable:** Connection establishment often fails
- 🔋 **Lower power:** Advertising uses less battery than maintaining connections
- 😌 **Better UX:** No "Pairing request" system dialogs
- 🔒 **More private:** No device pairing history in OS Bluetooth settings
#### US-2.2: Connection Confirmation
**As a** user
**I want to** see confirmation after exchanging keys
**So that** I know it worked and can verify the right person
**Acceptance Criteria:**
- Show connected user's profile (name, photo if they have one)
- Display connection timestamp
- Option to add personal note about person
- Send first message immediately from confirmation screen
- Connection appears in contacts list within 1 second
- Clear visual feedback: "✓ Connected with [Name]"
**Technical Requirements:**
- After both users confirm, derive shared secret via ECDH
- Store connection record:
```javascript
{
connectionID: uuid,
theirPublicKey: Uint8Array(32),
theirName: string,
sharedSecret: Uint8Array(32),
connectedAt: timestamp,
myNotes: string
}
```
- Stop advertising and scanning immediately after confirmation
- Show success animation
### Epic 3: Event Posting (Week 2-3 Priority)
#### US-3.1: Create Event Post (SIMPLIFIED)
**As a** user
**I want to** post events with basic details
**So that** my verified neighbors can discover them
**Acceptance Criteria:**
- "New Event" button on home feed
- Simple form: Title (required), Date/Time (required), Location (optional), Description (optional)
- Single photo support only (no multi-photo)
- Character limit: 1000 for description
- Preview shows formatted event card
- Post saves immediately to local database
- Encrypts for each connection (simple AES-256)
- No offline queue - must be online to post
**Technical Requirements:**
- Event schema: `{title, datetime, location, description, photo_base64?}`
- Simple encryption: generate AES key, encrypt event, wrap key with each connection's DH shared secret
- Local storage: SQLite with events table
- Server upload when online
- **SIMPLIFICATION:** Events sync via server (not peer-to-peer BLE)
#### US-3.2: Discover Events in Feed (SIMPLIFIED)
**As a** user
**I want to** see events from connections in simple list
**So that** I know what's happening
**Acceptance Criteria:**
- Feed shows events in chronological order (newest first)
- Basic list view - no fancy filtering
- Decrypt and display events from connections
- Pull down to manually sync with server
- No real-time updates - manual refresh only
- Show event date/time prominently
- "Going" button only (no maybe/no for MVP)
**Technical Requirements:**
- Query local SQLite for events
- Decrypt with connection's shared key
- Sort by datetime client-side
- Basic list rendering (FlatList with <100 events)
#### US-3.3: Simple Post Interactions (MINIMAL)
**As a** user
**I want to** indicate I'm attending an event
**So that** the host knows I'm coming
**Acceptance Criteria:**
- "I'm Going" button on event cards
- Shows count of attendees
- No comments or reactions for MVP
- Attendance stored locally and synced to server
**Technical Requirements:**
- RSVP stored as `{eventID, userID, status: 'going'}`
- Encrypted with same pattern as events
- Sync RSVPs to server when online
### Epic 4 (Optional): Direct Messaging (SIMPLIFIED - Week 3)
#### US-4.1: Send Direct Message (BASIC ENCRYPTION)
**As a** user
**I want to** send simple encrypted messages to connections
**So that** I can coordinate about events
**Acceptance Criteria:**
- Tap connection to open basic chat thread
- Send text messages only (no photos/files for MVP)
- Messages encrypted with shared secret from Bluetooth exchange
- No delivery receipts or read status for MVP
- No typing indicators
- Messages sync via server when online
- Works offline: compose and queue messages
**Technical Requirements:**
- Use simple AES-256-GCM encryption with shared secret from DH key exchange
- Store messages in local SQLite: `{messageID, conversationID, senderID, ciphertext, timestamp}`
- Server relays encrypted messages via REST API or WebSocket
- **NO Signal Protocol** (too complex for 1-month MVP)
- **NO cloud storage** - messages on device only
**1-Month Simplifications:**
- Simple encryption (no forward secrecy)
- No message history when switching devices
- No backup/restore
- Messages lost if app deleted (warn user)
### Epic 5: Profile & Settings (MINIMAL - Week 1)
#### US-5.1: Basic Profile (SIMPLIFIED)
**As a** user
**I want to** set my name and photo
**So that** connections can identify me
**Acceptance Criteria:**
- Set display name during first launch (shown in Bluetooth advertisements!)
- Optional profile photo (take or choose from library)
- Name and photo shown to connections after key exchange
- No bio, no location, no other fields for MVP
- Changes saved locally only
**Technical Requirements:**
- Profile: `{name: string (max 20 chars for BLE), photo: base64?}`
- Name included in BLE advertisement (so others see it before confirming)
- Photo sent to server, not in advertisement (too large)
- Stored in device secure storage
#### US-5.2: Basic Settings (MINIMAL)
**As a** user
**I want to** manage basic app settings
**So that** I can control my experience
**Acceptance Criteria:**
- View list of connections
- Disconnect from a user (removes from local storage)
- Clear all data (factory reset)
- No privacy toggles for MVP
- No data export for MVP
- No account deletion (just clear data)
**Technical Requirements:**
- Settings stored in async storage
- Disconnect: delete connection record from SQLite
- Clear data: wipe SQLite database and secure storage
### Epic 6: Multi-Device Sync (OUT OF SCOPE FOR MVP)
**For future phases only.** MVP is single-device only.
---
## 3. Technical Architecture
### 3.1 System Architecture
```
┌─────────────┐ ┌─────────────┐
│ Mobile │ │ Mobile │
│ Client │◄────────►│ Client │
│ (Alice) │ BLE Ad │ (Bob) │
└──────┬──────┘ /Scan └──────┬──────┘
│ (No pairing!) │
│ │
│ Encrypted Posts │
│ Encrypted Messages │
│ │
▼ ▼
┌────────────────────────────────────┐
│ Sync/Relay Server │
│ (Stores encrypted blobs, │
│ cannot decrypt content) │
└────────────────────────────────────┘
```
### 3.2 Bluetooth Advertising Architecture
```
Device A Device B
┌──────────────────────────────┐ ┌──────────────────────────────┐
│ BLE Peripheral Manager │ │ BLE Peripheral Manager │
│ (Advertising) │ │ (Advertising) │
│ │ │ │
│ Service UUID: [app-uuid] │ │ Service UUID: [app-uuid] │
│ Service Data: │ │ Service Data: │
│ - Version: 0x01 │◄─────►│ - Version: 0x01 │
│ - Name: "Alice" │ Air │ - Name: "Bob" │
│ - Public Key: [32 bytes] │ │ - Public Key: [32 bytes] │
│ │ │ │
└──────────────────────────────┘ └──────────────────────────────┘
│ │
│ │
▼ ▼
┌──────────────────────────────┐ ┌──────────────────────────────┐
│ BLE Central Manager │ │ BLE Central Manager │
│ (Scanning) │ │ (Scanning) │
│ │ │ │
│ Discovers Device B ──────────┼───────┼─────────► Discovers Device A │
│ Reads Service Data │ │ Reads Service Data │
│ │ │ │
└──────────────────────────────┘ └──────────────────────────────┘
```
**Key Point:** No GATT connection established. Data flows only via advertisements.
### 3.3 Data Model
#### Identity
```javascript
{
userID: "base58(publicKey)",
publicKey: Uint8Array(32), // Ed25519
privateKey: Uint8Array(64), // NEVER leaves device
profile: {
name: string, // Max 20 chars (for BLE advertisement)
photo: string, // base64 or URL
bio: string,
location: string
}
}
```
#### Connection
```javascript
{
connectionID: "uuid",
theirPublicKey: Uint8Array(32),
theirName: string,
sharedSecret: Uint8Array(32), // ECDH(myPrivate, theirPublic)
metadata: {
photo: string,
notes: string, // my private notes about them
connectedAt: timestamp
},
encryptionKey: Uint8Array(32) // derived from sharedSecret
}
```
#### Post/Event
```javascript
{
postID: "uuid",
authorID: "base58(publicKey)",
timestamp: number,
postType: "event" | "post" | "recommendation",
encryptedContent: {
// One per connection
connectionID_1: {
encryptedPostKey: Uint8Array, // Post key encrypted with connection key
encryptedData: Uint8Array // Post data encrypted with post key
},
connectionID_2: { ... },
...
}
}
// Decrypted Event Content
{
type: "event",
title: string,
datetime: ISO8601,
location: string,
description: string,
photo?: string,
rsvps: {
going: number,
maybe: number,
notGoing: number
}
}
```
#### Message (Direct)
```javascript
{
messageID: "uuid",
conversationID: "uuid",
senderID: "base58(publicKey)",
recipientID: "base58(publicKey)",
timestamp: number,
aesCiphertext: Uint8Array, // AES-256-GCM encrypted
iv: Uint8Array(12),
tag: Uint8Array(16)
}
```
### 3.4 BLE Advertisement Payload Structure
**iOS/Android Advertisement:**
```
Service UUID: a1b2c3d4-1234-5678-90ab-cdef12345678 (16 bytes)
Service Data (max 31 bytes total):
┌──────────┬──────────────┬─────────┬─────────────────────┐
│ Version │ Name Length │ Name │ Public Key │
│ (1 byte) │ (1 byte) │(0-20 B) │ (32 bytes) │
└──────────┴──────────────┴─────────┴─────────────────────┘
Note: Public key might need to be split across multiple
advertisements or shortened via hashing for discovery,
then full key exchanged via characteristics if needed.
SIMPLIFIED FOR MVP:
- Advertise shortened identifier (hash of public key)
- Full key exchange happens via brief GATT read/write
- OR use manufacturer data field (more space available)
```
**Alternative Approach (More Practical for MVP):**
```
Advertisement includes:
- Service UUID (identifies our app)
- Manufacturer Data: Name (20 bytes) + Key Hash (8 bytes)
- Local Name: Display name
Full public key retrieved via:
- Single GATT characteristic read (no pairing needed)
- OR included in scan response data (31 additional bytes)
```
**RECOMMENDATION for 1-Month MVP:**
Use a **hybrid approach**:
1. Advertise with name + key hash (for discovery)
2. When user taps to connect, establish brief GATT connection (no pairing)
3. Exchange full public keys via characteristic
4. Close connection immediately
5. Still faster than traditional pairing!
### 3.5 Encryption Flows
#### Connection Key Derivation (ECDH)
```javascript
// Convert Ed25519 keys to Curve25519 for ECDH
const myPrivateKey = ed25519_to_curve25519(myEd25519Private);
const theirPublicKey = ed25519_to_curve25519(theirEd25519Public);
// Perform ECDH
const sharedSecret = crypto_scalarmult(myPrivateKey, theirPublicKey);
// Derive encryption key
const connectionKey = HKDF(
sharedSecret,
salt: "connection-key-v1",
info: "AES-256"
);
```
#### Post Encryption
```javascript
// 1. User creates post
// 2. Generate random post key (AES-256 key)
const postKey = crypto.randomBytes(32);
// 3. Encrypt post content with post key
const encryptedContent = aes256gcm.encrypt(postData, postKey);
// 4. For each connection: encrypt post key with connection key
const encryptedPostKeys = {};
for (const conn of connections) {
encryptedPostKeys[conn.id] = aes256gcm.encrypt(
postKey,
conn.encryptionKey
);
}
// 5. Upload to server
uploadPost({
postID,
authorID,
timestamp,
encryptedPostKeys,
encryptedContent
});
```
#### Post Decryption
```javascript
// 1. Fetch encrypted post from server
// 2. Find my connectionID in encryptedPostKeys
// 3. Retrieve connection key from local storage
// 4. Decrypt encryptedPostKey → post key
const postKey = aes256gcm.decrypt(
post.encryptedPostKeys[myConnectionID],
myConnectionKey
);
// 5. Decrypt content with post key
const content = aes256gcm.decrypt(
post.encryptedContent,
postKey
);
```
### 3.6 API Specifications
#### Authentication
```
POST /api/auth/challenge
Response: { challenge: "random-string" }
POST /api/auth/verify
Body: { userID, signature(challenge), publicKey }
Response: { token: "jwt-token" }
```
#### Posts API
```
POST /api/posts
Headers: { Authorization: "Bearer {token}" }
Body: {
postID: "uuid",
authorID: "base58",
timestamp: number,
encryptedContent: {...}
}
Response: { success: true, postID }
GET /api/posts?since={timestamp}&limit=50
Response: {
posts: [{ postID, authorID, timestamp, encryptedContent }],
nextCursor: "timestamp"
}
```
#### Messages API (WebSocket)
```
WS /api/messages
Client → Server: {
type: "send",
messageID: "uuid",
recipientID: "base58",
ciphertext: Uint8Array,
iv: Uint8Array,
tag: Uint8Array
}
Server → Client: {
type: "message",
messageID: "uuid",
senderID: "base58",
ciphertext: Uint8Array,
iv: Uint8Array,
tag: Uint8Array
}
```
### 3.7 Technology Stack
#### Mobile (React Native)
- **Framework:** React Native 0.74+
- **State Management:** Zustand
- **Crypto:**
- @noble/ed25519 (identity keys)
- @noble/curves (ECDH)
- react-native-quick-crypto (AES-256-GCM)
- react-native-sodium (optional, for crypto_box)
- **Storage:**
- react-native-keychain (secure key storage)
- @react-native-async-storage/async-storage (app data)
- react-native-sqlite-storage (local database)
- **Bluetooth:**
- react-native-ble-plx (BLE advertising + scanning)
- **No react-native-ble-manager** (doesn't support advertising)
#### Backend (Node.js)
- **Framework:** Express.js or Fastify
- **Database:** PostgreSQL (encrypted blobs) + Redis (real-time)
- **WebSocket:** Socket.io or ws
- **Storage:** S3-compatible for photos/files
- **Deployment:** Docker + Railway/Render
---
## 4. Security Requirements
### 4.1 Cryptographic Requirements
**MUST:**
- Use only well-vetted cryptographic libraries (@noble/*, libsodium)
- Generate keys using cryptographically secure random number generator (CSRNG)
- Never transmit private keys over network (only public keys in BLE advertisements)
- Use authenticated encryption (AES-GCM, not AES-CBC)
- Store private keys in device secure enclave (Keychain/KeyStore)
- Use constant-time operations for key comparisons
**MUST NOT:**
- Roll custom cryptography
- Include private keys in BLE advertisements
- Store private keys unencrypted
- Log decrypted content or keys
- Use deprecated algorithms (MD5, SHA1, RC4)
### 4.2 Bluetooth-Specific Security
**Advertisement Security:**
- Only advertise public key or hash (never private key)
- RSSI filtering to ensure physical proximity (<3 meters)
- 30-second timeout on advertisement listening
- Both users must confirm in-app (prevent passive sniffing)
- Stop advertising immediately after key exchange
**Physical Verification:**
- Require in-person confirmation on both devices
- Show name and photo for visual verification
- Allow user to cancel if wrong person
- No automatic acceptance
### 4.3 Threat Model
**Threats we protect against:**
- Server compromise (server cannot read content)
- Network eavesdropping (TLS + E2EE)
- Device theft (keys in secure enclave)
- Malicious connections (in-person verification)
- Passive BLE sniffing (confirmation required on both devices)
**Threats out of scope for MVP:**
- Active BLE attacks (MITM during key exchange)
- Device compromise (malware, root access)
- Physical attacks (rubber hose cryptanalysis)
- Nation-state adversaries
- Quantum computers (post-quantum crypto for v2)
### 4.4 Privacy Requirements
**Data Minimization:**
- Collect only: public keys, encrypted content, timestamps
- Never collect: location, IP addresses (beyond rate limiting), device identifiers
**Bluetooth Privacy:**
- Use random MAC addresses (iOS does this automatically, Android optional)
- Don't include identifying info in advertisements beyond name
- Stop advertising when not actively connecting
**User Rights (GDPR):**
- Right to access: Export all data
- Right to erasure: Delete all data within 30 days
- Right to portability: JSON export
- Right to rectification: Edit profile anytime
---
## 5. MVP Scope
### In Scope (Event Discovery Core)
✅ **Advertising-only Bluetooth** (no pairing dialogs!)
✅ In-person verification (hold phones close, tap to confirm)
✅ **Event posting with rich details** (title, date/time, location, description, photo)
✅ **Event discovery feed** (chronological)
✅ **Quick RSVP** (going only)
✅ General posts (text + photos)
✅ Direct messaging (optional) (AES-GCM encryption)
✅ Profile management
✅ **Single neighborhood pilot**
✅ **Single device only** (no sync for MVP)
### Out of Scope (Future Phases)
❌ Multi-device sync
❌ Cloud backup
❌ Background Bluetooth scanning
❌ Advanced event features (recurring, reminders, calendar sync)
❌ Group chats
❌ Marketplace
❌ Web app
❌ Video/voice calls
❌ Location-based auto-discovery
### Success Metrics for MVP
- **Technical:**
- 99.9% encryption success rate
- <5 seconds average key exchange time (advertising-only is fast!)
- <2% Bluetooth discovery failure rate
- <30s event discovery time
- **Event Focus:**
- 60%+ of WAU attend ≥1 event/month
- 1+ event posted/week per neighborhood
- **User:**
- 40% Day-30 retention
- 2+ posts per user per week
- **Growth:**
- 30% household penetration in pilot neighborhood
---
## 6. Implementation Phases
### Phase 1: Core Infrastructure (Week 1)
- [ ] Set up React Native project with TypeScript
- [ ] Implement key generation and storage (Ed25519 in Keychain/KeyStore)
- [ ] Build basic UI shell (navigation, screens)
- [ ] Set up development server (Node.js + PostgreSQL)
- [ ] Implement signature-based authentication
### Phase 2: Advertising-Only Bluetooth (Week 1-2)
- [ ] BLE advertising implementation (react-native-ble-plx)
- [ ] iOS: Configure CBPeripheralManager
- [ ] Android: Configure BLE Advertiser
- [ ] BLE scanning implementation
- [ ] iOS: Configure CBCentralManager
- [ ] Android: Configure BLE Scanner
- [ ] Simultaneous advertising + scanning
- [ ] Parse advertisement service data
- [ ] RSSI filtering (<3 meters)
- [ ] Display discovered users in list
- [ ] User selection and confirmation UI
- [ ] Key exchange and storage
- [ ] Connection list UI
- [ ] Test on iOS and Android devices
### Phase 3: Event Discovery & Posting (Week 2-3)
- [ ] Event post creation UI
- [ ] Event encryption (AES-256 per connection)
- [ ] Event feed with decryption
- [ ] Pull-to-refresh
- [ ] Quick RSVP system
- [ ] General post creation
- [ ] Image upload and compression
### Phase 4: Direct Messaging (Week 3)
- [ ] Simple AES-GCM encryption
- [ ] Message storage (SQLite)
- [ ] Conversation list and thread UI
- [ ] WebSocket for real-time messages
- [ ] Push notifications
### Phase 5: Polish (Week 4)
- [ ] Settings UI (connections, data management)
- [ ] Onboarding flow
- [ ] Error handling and edge cases
- [ ] Performance optimization
### Phase 6: Pilot Launch (Week 4-5)
- [ ] Security audit
- [ ] Beta testing with 10-20 users
- [ ] Founding Block Party event
- [ ] Monitor metrics and iterate
---
## 7. Open Questions & Decisions Needed
**Q1:** Should we use full 32-byte public key in advertisement or just a hash?
- **Tradeoff:** Hash requires follow-up GATT read for full key (adds 2s), but fits in advertisement
- **Recommendation:** Use hash in advertisement + brief GATT read for full key (still no pairing!)
**Q2:** How do we handle simultaneous connections?
- **Scenario:** User A and B both try to connect at same time
- **Recommendation:** Both can see each other in list, either can initiate, confirmation required on both
**Q3:** What happens if advertisement is not detected?
- **Recommendation:** "Retry" button, suggest moving closer, check Bluetooth permissions
**Q4:** Maximum number of connections per user?
- **Recommendation:** Start with 500 limit; revisit if needed
**Q5:** Photo storage: on-device vs. server?
- **Recommendation:** Hybrid - thumbnails on device, full-res encrypted on server, auto-purge after 90 days
**Q6:** How should replies to posts work?
- **Recommendation:** Encrypted for all of poster's connections (only intersection can see reply)
---
## 8. Non-Functional Requirements
### Performance
- App launch: <2 seconds cold start
- Bluetooth key exchange: <5 seconds (advertising-only is fast!)
- Post creation to upload: <3 seconds
- Message delivery: <500ms latency
- Feed load: <1 second for 50 posts
- Decryption: <100ms per post
### Reliability
- 99.9% uptime for sync server
- Message delivery guarantee: at-least-once
- Data loss prevention: stored in device secure storage
- Graceful degradation when offline
### Scalability
- Support 1,000 concurrent users per server instance
- Database: 10,000 users per neighborhood
- Message throughput: 1,000 messages/second
- Storage: 500MB per user (5 years of typical usage)
### Accessibility
- WCAG 2.1 AA compliance
- VoiceOver/TalkBack support
- Minimum font size: 16px
- High contrast mode support
- Localization: English first, Spanish/French in Phase 2
---
## 9. Testing Strategy
### Unit Tests
- Crypto functions (key generation, encryption, decryption)
- ECDH key derivation
- Message queue (send, retry, failure)
- Target: 80% code coverage
### Integration Tests
- End-to-end post encryption/decryption flow
- BLE advertising/scanning (mock on simulator, real devices for full test)
- Key exchange flow
- WebSocket message delivery
### Bluetooth-Specific Tests
- Advertisement payload parsing
- RSSI filtering
- Simultaneous advertising + scanning
- Multiple device discovery
- Key exchange confirmation
- Test on physical devices (iOS + Android)
### Security Tests
- Penetration testing (external firm)
- Crypto library audit
- Key storage verification (Keychain/KeyStore)
- Advertisement sniffing simulation
### User Testing
- Beta with 20 users before launch
- Usability testing (5 users, think-aloud protocol)
- A/B test onboarding flows
- Monitor crash reports and error logs
---
## 10. Launch Plan
### Pre-Launch (Weeks 13-15)
- Recruit 5-10 Neighborhood Champions
- Print door hangers and yard signs
- Create pre-registration landing page
- Security audit and fixes
### Launch Event: Founding Block Party (Week 16)
- Saturday afternoon, 2-3 hours
- Free food and entertainment
- On-site verification stations: **"Hold phones close, tap Connect, tap Confirm - done!"**
- Professional photos for profiles
- Goal: 60-150 users in one day
- **Emphasize:** "No pairing popups - it just works!"
### Post-Launch (Weeks 17-20)
- Daily engagement monitoring
- Weekly community events (online + offline)
- Rapid bug fixes and UX improvements
- Collect qualitative feedback
- Prepare for neighborhood #2
---
## 11. Success Criteria & KPIs
### Must-Have (Launch Blockers)
- ✅ Zero critical security vulnerabilities
- ✅ <5% crash rate
- ✅ >95% encryption success rate
- ✅ >60% Day-1 retention
- ✅ <5s average Bluetooth key exchange (advertising-only!)
### Should-Have (Quality Bar)
- ✅ >40% Day-30 retention
- ✅ 2+ posts per user per week
- ✅ <500ms message latency
- ✅ User NPS >50
- ✅ <3% Bluetooth connection failure rate
### Nice-to-Have (Aspirational)
- 🎯 50%+ household penetration
- 🎯 70% Day-30 retention
- 🎯 DAU / MAU >25%
- 🎯 Organic invitation rate >5 invites per user
---
## 12. Appendix
### A. Glossary
- **Connection:** Two users who verified in person via BLE key exchange
- **E2EE:** End-to-end encryption (only sender and recipient can read)
- **ECDH:** Elliptic Curve Diffie-Hellman key exchange
- **BLE Advertising:** Broadcasting data via Bluetooth without pairing
- **GATT:** Generic Attribute Profile (not used for key exchange in MVP)
- **RSSI:** Received Signal Strength Indicator (measures proximity)
### B. References
- [Core Bluetooth Programming Guide](https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/)
- [Android BLE Guide](https://developer.android.com/guide/topics/connectivity/bluetooth/ble-overview)
- [react-native-ble-plx Documentation](https://github.com/dotintent/react-native-ble-plx)
- [NIST Cryptographic Standards](https://csrc.nist.gov/publications)
- [OWASP Mobile Security](https://owasp.org/www-project-mobile-security/)
### C. Team Roles
- **Product Manager:** Define features, prioritize roadmap
- **Tech Lead:** Architecture decisions, code reviews
- **Mobile Engineers (2):** iOS and Android development, Bluetooth expertise
- **Backend Engineer:** Server, database, APIs
- **Security Engineer:** Crypto implementation, audits
- **Designer:** UI/UX, visual design, user research
### D. Contact
- **Project Lead:** [Name]
- **Technical Questions:** [Email]
- **Security Reports:** security@[domain]
- **General Inquiries:** hello@[domain]
---
**Document History**
- v2.1 (Oct 2025): Updated to advertising-only Bluetooth approach
- v2.0 (Oct 2025): PWA version (deprecated)
- v1.1 (Oct 2025): Original React Native with GATT connection
- v1.0 (Oct 2025): Initial PRD