feat(ios): add share ID tracking for share target (Phase 1A)

Generate a UUID per incoming share in the Share Extension, persist it
as sharedPhotoShareId in App Group metadata, and add [ShareTarget] logs
for receive/store/retrieve events without changing retrieval or deletion.
This commit is contained in:
Jose Olarte III
2026-06-23 19:13:44 +08:00
parent 08a55202f5
commit 35a6a6bfb3
3 changed files with 79 additions and 9 deletions

View File

@@ -12,6 +12,7 @@ The iOS share target uses a **Share Extension** (`TimeSafariShareExtension`) tha
|-----|---------|------------|---------|
| `sharedPhotoFilePath` | UserDefaults (suite) | Share Extension | Relative filename of image file in container |
| `sharedPhotoFileName` | UserDefaults (suite) | Share Extension | Display/original filename |
| `sharedPhotoShareId` | UserDefaults (suite) | Share Extension | Unique UUID per incoming share (Phase 1A) |
| `sharedPhotoReady` | UserDefaults (suite) | Share Extension | Boolean signal that a new share is available |
| `sharedPhotoBase64` | UserDefaults (suite) | *(legacy, not written)* | Removed on write for cleanup |
| Image file | App Group filesystem | Share Extension | Raw image bytes at `{container}/{sharedPhotoFilePath}` |
@@ -267,6 +268,62 @@ After native read, image data lives in SQLite `temp` table under key `shared-pho
---
## Share ID Tracking
**Implemented:** 2026-06-23 (Phase 1A)
Phase 1A adds a unique share identifier to the iOS share flow for observability and future reliability work. Existing retrieval and deletion behavior is unchanged.
### Identifier
| Property | Value |
|----------|-------|
| UserDefaults key | `sharedPhotoShareId` |
| Format | `UUID().uuidString` (e.g. `A1B2C3D4-E5F6-7890-ABCD-EF1234567890`) |
| Generated in | `ShareViewController.processSharedImage` when the first image attachment is found |
| Persisted in | `ShareViewController.storeImageData` alongside `sharedPhotoFilePath` and `sharedPhotoFileName` |
### Logging
All log lines use the prefix `[ShareTarget]` and include `shareId=<id>`:
| Event | File | Method | When |
|-------|------|--------|------|
| share received | `ShareViewController.swift` | `processSharedImage` | UUID generated before `loadItem` |
| file stored | `ShareViewController.swift` | `storeImageData` | After successful `imageData.write(to:)` |
| metadata stored | `ShareViewController.swift` | `storeImageData` | After UserDefaults `synchronize()` |
| share retrieved | `SharedImageUtility.swift` | `getSharedImageData` | After successful file read (only if `sharedPhotoShareId` is present) |
Example log sequence for a single share:
```
[ShareTarget] share received shareId=A1B2C3D4-E5F6-7890-ABCD-EF1234567890
[ShareTarget] file stored shareId=A1B2C3D4-E5F6-7890-ABCD-EF1234567890
[ShareTarget] metadata stored shareId=A1B2C3D4-E5F6-7890-ABCD-EF1234567890
[ShareTarget] share retrieved shareId=A1B2C3D4-E5F6-7890-ABCD-EF1234567890
```
### Phase 1A Scope (Intentionally Unchanged)
- `getSharedImageData()` still returns only `base64` and `fileName` to JavaScript
- `sharedPhotoShareId` is **not** deleted on retrieve (deletion deferred to a later phase)
- `hasSharedImage()`, `isSharedPhotoReady()`, and JS consumption paths are unchanged
- Android code is unchanged
### Write Inventory Addition
| File | Method | Key Written |
|------|--------|-------------|
| `ShareViewController.swift` | `storeImageData(_:fileName:shareId:)` | `sharedPhotoShareId` |
### Read Inventory Addition
| File | Method | Key Read |
|------|--------|----------|
| `SharedImageUtility.swift` | `getSharedImageData()` | `sharedPhotoShareId` (logging only) |
---
## Configuration References
| Resource | Value |