PAILot App Store Readiness Checklist
Date: 2026-03-25
Source: Security & Code Quality Review
CRITICAL (Must fix before submission)
- [x] C1: Remove NSAllowsArbitraryLoads — ATS bypass, Apple will reject. Use NSAllowsLocalNetworking only (fixed 2026-03-25)
- [x] C2: Add TLS to MQTT — All conversations and auth token travel in plaintext. Set
client.secure = true, configure TLS on AIBroker broker (fixed 2026-03-25 — self-signed cert auto-generated at ~/.aibroker/tls/, onBadCertificate accepts it; TODO: pin cert fingerprint)
- [x] C3: Remove debug log files in production —
mqtt_debug.log and _chatLog write truncated message content to Documents. Wrap in kDebugMode or remove entirely (fixed 2026-03-25)
HIGH (Should fix before submission)
- [x] H1: Unbounded image cache —
_imageCache in message_bubble.dart grows without limit. Add LRU eviction (cap at 50) (fixed 2026-03-25)
- [x] H2: Audio temp files never cleaned —
_base64ToFile creates .m4a files never deleted. Clean up after playback completes (fixed 2026-03-25)
- [x] H3: TextEditingController leak — Rename dialog in session_drawer.dart creates controller but never disposes it (fixed 2026-03-25)
- [x] H4: Input validation on settings — No validation on host IPs, port range, MAC format. Add regex validators (fixed 2026-03-25)
- [x] H5: LifecycleObserver never removed — AudioService.init() adds observer but dispose() doesn't remove it (fixed 2026-03-25)
- [ ] H6: MQTT token in memory — Acceptable for personal use, document as known limitation
MEDIUM (Improve before submission)
- [ ] M1: Subnet scan hammers 254 hosts — Could trigger IDS. Detect subnet mask or cap range
- [ ] M2: No loadMore debounce — Scroll pagination fires repeatedly on iOS bounce. Add isLoading guard
- [ ] M3: NavigateNotifier global singleton — Mutable static, stale reference risk. Move to Riverpod provider
- [ ] M4: Unbounded _seenSeqs set — O(n log n) eviction. Use FIFO deque instead
- [ ] M5: Screenshots bloat iCloud backup — Store images as files, not base64 in JSON. Or exclude from backup
- [ ] M6: Unused import —
server_config.dart import in chat_screen.dart suppressed with ignore comment
- [ ] M7: Silent error swallowing — ServerConfig _load() catches all exceptions silently. Add debugPrint
LOW (Nice-to-haves)
- [ ] L1: PrivacyInfo.xcprivacy — Required since 2024 for UserDefaults and FileTimestamp APIs
- [ ] L2: Privacy policy URL — Required for microphone/camera access apps
- [ ] L3: Unused dependencies — Remove
web_socket_channel and wakelock_plus from pubspec.yaml
- [x] L4: Unnecessary _http._tcp — Removed from NSBonjourServices (fixed 2026-03-25)
- [ ] L5: Typing indicator timeout — Can get stuck if typing_end missed during background. Auto-clear after 10s
- [ ] L6: Version number — Default 1.0.0+1, set correctly before submission
- [ ] L7: App icon — Verify meets Apple guidelines (no alpha channel, correct sizes)
App Store Requirements
| Requirement | Status | Action |
|------------|--------|--------|
| NSMicrophoneUsageDescription | PASS | - |
| NSCameraUsageDescription | PASS | - |
| NSPhotoLibraryUsageDescription | PASS | - |
| NSLocalNetworkUsageDescription | PASS | - |
| NSBonjourServices | PASS | Fixed - removed http.tcp |
| NSAppTransportSecurity | PASS | Fixed - removed NSAllowsArbitraryLoads |
| UIBackgroundModes: audio | PASS | - |
| Privacy Policy | FAIL | Fix L2 |
| PrivacyInfo.xcprivacy | FAIL | Fix L1 |
| TLS for network | PASS | Fixed C2 - self-signed cert, onBadCertificate=true |