experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

○ feat(mobile): add CLI scripts for iOS device and simulator builds │ ~ Add package.json scripts for building and deploying iOS app via command line:

Simulator:
- mobile:ios:xcodebuild:release:full - full release build pipeline
- mobile:ios:sim:run - boot, build, install, and launch in one command
- mobile:ios:sim:boot/open/launch - individual simulator controls

Device:
- mobile:ios:xcodebuild:device:full - full release build + install on USB device
- mobile:ios:device:launch - launch app on connected device
- mobile:ios:device:list - list connected iOS devices

Fixes:
- Use lowercase config names (release/debug) to match Xcode project
- Fix build output paths for proper library linking

Also updates docs/mobile.md with CLI build script reference.

+99 -4
+23
docs/mobile.md
··· 278 278 | `xcode` | Copy libraries and open Xcode (no build) | 279 279 | `dev:ios` | Full dev setup with server (for sync testing) | 280 280 281 + ### CLI Build Scripts (from repo root) 282 + 283 + **Simulator builds:** 284 + | Script | Description | 285 + |--------|-------------| 286 + | `mobile:ios:xcodebuild:full` | Full debug build + install on simulator | 287 + | `mobile:ios:xcodebuild:release:full` | Full release build + install on simulator | 288 + | `mobile:ios:sim:run` | Boot simulator + build + install + launch | 289 + | `mobile:ios:sim:boot` | Boot iPhone 17 Pro simulator | 290 + | `mobile:ios:sim:launch` | Launch app on booted simulator | 291 + 292 + **Device builds:** 293 + | Script | Description | 294 + |--------|-------------| 295 + | `mobile:ios:xcodebuild:device:full` | Full release build + install on USB device | 296 + | `mobile:ios:device:launch` | Launch app on connected device | 297 + | `mobile:ios:device:list` | List connected iOS devices | 298 + 299 + **One-liner for device deployment:** 300 + ```bash 301 + yarn mobile:ios:xcodebuild:device:full && yarn mobile:ios:device:launch 302 + ``` 303 + 281 304 **Important Notes:** 282 305 - Debug uses `Externals/arm64/Debug/libapp.a` and target `aarch64-apple-ios-sim` 283 306 - Release uses `Externals/arm64/Release/libapp.a` and target `aarch64-apple-ios`
+63 -1
notes/ios-storage-architecture.md
··· 361 361 362 362 --- 363 363 364 - ## 7. References 364 + ## 7. Case Study: INTEGER→TEXT Tag Migration (January 2026) 365 + 366 + This section documents the practical impact of the dual-codebase architecture during a real schema migration. 367 + 368 + ### The Problem 369 + 370 + Mobile tags used `INTEGER PRIMARY KEY AUTOINCREMENT` for `tags.id` while server/desktop used `TEXT` UUIDs. This broke tag sync completely—tags created on mobile couldn't sync because their IDs were incompatible. 371 + 372 + ### Migration Scope 373 + 374 + | Task | Rust (lib.rs) | Swift (ShareViewController.swift) | 375 + |------|---------------|-----------------------------------| 376 + | Schema version bump | 1 location | 1 location | 377 + | ID generator function | New function | New function | 378 + | Migration function | ~60 lines | ~50 lines | 379 + | Type declaration changes | ~15 locations | ~8 locations | 380 + | Query updates | ~10 locations | ~4 locations | 381 + | Test updates | ~5 locations | N/A | 382 + 383 + **Total: ~40 code changes across 2 files in 2 languages** 384 + 385 + ### What Would Have Been Different with UniFFI 386 + 387 + With a unified Rust core linked to both main app and Share Extension: 388 + 389 + | Task | Unified Rust Core | 390 + |------|-------------------| 391 + | Schema version bump | 1 location | 392 + | ID generator function | 1 function | 393 + | Migration function | ~60 lines (once) | 394 + | Type declaration changes | ~15 locations (once) | 395 + | Query updates | ~10 locations (once) | 396 + | Swift changes | **0** (auto-generated bindings) | 397 + 398 + **Total: ~20 code changes in 1 file, 1 language** 399 + 400 + ### Risk Comparison 401 + 402 + | Risk | Dual Codebase | UniFFI | 403 + |------|---------------|--------| 404 + | Type mismatch between codepaths | High (manual sync) | None (single source) | 405 + | Migration logic divergence | High | None | 406 + | ID format inconsistency | Medium (copy-paste errors) | None | 407 + | First-writer-wins race condition | Must implement twice | Implement once | 408 + | Testing coverage | Test both paths | Test once | 409 + 410 + ### Conclusion 411 + 412 + The migration succeeded, but required: 413 + - Implementing identical logic twice (Rust + Swift) 414 + - Coordinating transaction safety in two different SQLite libraries 415 + - Ensuring ID format strings match exactly 416 + - Updating schema fidelity tests to track the fix 417 + 418 + **With UniFFI, this would have been a single-codebase change with auto-generated Swift bindings.** The upfront investment in UniFFI (~1-2 weeks) would pay off in reduced migration risk and maintenance burden for any future schema changes. 419 + 420 + ### Recommendation Update 421 + 422 + Based on this experience, **Option A (UniFFI)** should be prioritized higher than originally assessed. The complexity cost of dual codepaths compounds with each schema change, and the tag migration demonstrated concrete examples of divergence risk. 423 + 424 + --- 425 + 426 + ## 8. References 365 427 366 428 - [Apple TN2408: Accessing Shared Data](https://developer.apple.com/library/archive/technotes/tn2408/_index.html) 367 429 - [iOS App Extensions Data Sharing](https://dmtopolog.com/ios-app-extensions-data-sharing/)
+13 -3
package.json
··· 58 58 "mobile:ios:xcode": "open backend/tauri-mobile/src-tauri/gen/apple/peek-save.xcodeproj", 59 59 "mobile:ios:xcodebuild:list": "xcodebuild -project backend/tauri-mobile/src-tauri/gen/apple/peek-save.xcodeproj -list", 60 60 "mobile:ios:xcodebuild": "cd backend/tauri-mobile/src-tauri/gen/apple && xcodebuild -scheme peek-save_iOS -configuration Debug -sdk iphonesimulator -derivedDataPath /tmp/peek-xcodebuild -destination 'platform=iOS Simulator,name=iPhone 17 Pro' build", 61 - "mobile:ios:xcodebuild:release": "rm -rf /tmp/peek-xcodebuild && mkdir -p backend/tauri-mobile/src-tauri/gen/apple/Externals/arm64/Release && ln -sf ../Debug/libapp.a backend/tauri-mobile/src-tauri/gen/apple/Externals/arm64/Release/libapp.a && cd backend/tauri-mobile/src-tauri/gen/apple && xcodebuild -scheme peek-save_iOS -configuration Release -sdk iphonesimulator -derivedDataPath /tmp/peek-xcodebuild -destination 'platform=iOS Simulator,name=iPhone 17 Pro' CONFIGURATION=Release build", 62 - "mobile:ios:xcodebuild:install": "xcrun simctl install booted '/tmp/peek-xcodebuild/Build/Products/Debug-iphonesimulator/Peek Save.app'", 63 - "mobile:ios:xcodebuild:install:release": "xcrun simctl install booted '/tmp/peek-xcodebuild/Build/Products/Release-iphonesimulator/Peek Save.app'", 61 + "mobile:ios:xcodebuild:release": "rm -rf /tmp/peek-xcodebuild && mkdir -p backend/tauri-mobile/src-tauri/gen/apple/Externals/arm64/release && ln -sf ../Debug/libapp.a backend/tauri-mobile/src-tauri/gen/apple/Externals/arm64/release/libapp.a && cd backend/tauri-mobile/src-tauri/gen/apple && xcodebuild -scheme peek-save_iOS -configuration release -sdk iphonesimulator -derivedDataPath /tmp/peek-xcodebuild -destination 'platform=iOS Simulator,name=iPhone 17 Pro' clean build", 62 + "mobile:ios:xcodebuild:install": "xcrun simctl install booted '/tmp/peek-xcodebuild/Build/Products/debug-iphonesimulator/Peek Save.app'", 63 + "mobile:ios:xcodebuild:install:release": "xcrun simctl install booted '/tmp/peek-xcodebuild/Build/Products/release-iphonesimulator/Peek Save.app'", 64 64 "mobile:ios:xcodebuild:full": "yarn mobile:ios:build && yarn mobile:ios:xcodebuild && yarn mobile:ios:xcodebuild:install", 65 + "mobile:ios:xcodebuild:release:full": "yarn mobile:ios:build && yarn mobile:ios:xcodebuild:release && yarn mobile:ios:xcodebuild:install:release", 66 + "mobile:ios:xcodebuild:device": "rm -rf /tmp/peek-xcodebuild && cd backend/tauri-mobile/src-tauri/gen/apple && xcodebuild -scheme peek-save_iOS -configuration release -sdk iphoneos -derivedDataPath /tmp/peek-xcodebuild -destination 'generic/platform=iOS' ONLY_ACTIVE_ARCH=NO clean build", 67 + "mobile:ios:device:list": "xcrun devicectl list devices", 68 + "mobile:ios:xcodebuild:device:install": "DEVICE_ID=$(xcrun devicectl list devices 2>/dev/null | grep 'iPhone' | awk '{for(i=1;i<=NF;i++)if($i~/^[0-9A-F-]{36}$/)print $i}' | head -1) && echo \"Installing to device: $DEVICE_ID\" && xcrun devicectl device install app --device \"$DEVICE_ID\" '/tmp/peek-xcodebuild/Build/Products/release-iphoneos/Peek Save.app'", 69 + "mobile:ios:xcodebuild:device:full": "yarn mobile:ios:build:release && yarn mobile:ios:xcodebuild:device && yarn mobile:ios:xcodebuild:device:install", 70 + "mobile:ios:device:launch": "DEVICE_ID=$(xcrun devicectl list devices 2>/dev/null | grep 'iPhone' | awk '{for(i=1;i<=NF;i++)if($i~/^[0-9A-F-]{36}$/)print $i}' | head -1) && xcrun devicectl device process launch --device \"$DEVICE_ID\" com.dietrich.peek-mobile", 71 + "mobile:ios:sim:boot": "xcrun simctl boot 'iPhone 17 Pro' 2>/dev/null || echo 'Simulator already booted or not found'", 72 + "mobile:ios:sim:open": "open -a Simulator", 73 + "mobile:ios:sim:launch": "xcrun simctl launch booted com.dietrich.peek-mobile", 74 + "mobile:ios:sim:run": "yarn mobile:ios:sim:boot && yarn mobile:ios:sim:open && yarn mobile:ios:xcodebuild:release:full && yarn mobile:ios:sim:launch", 65 75 "mobile:ios:test": "cd backend/tauri-mobile && ./dev-setup.sh", 66 76 "mobile:android:init": "cd backend/tauri-mobile/src-tauri && cargo tauri android init", 67 77 "mobile:android:dev": "cd backend/tauri-mobile/src-tauri && cargo tauri android dev",