# Phase 5 — Saved jobs persistence and revalidation **Status:** Implemented **Date:** 2026-10-12 ## Scope - Persist saved Indeed listings with **SwiftData** - Dedupe on save by `indeedJobKey` - Keep unavailable jobs visible with status; Open on Indeed still offered - Background revalidation (24h stale interval) - Settings: clear local saved jobs + JSON export ## Architecture ``` Save toggle (Search / Saved) → SavedJobsStore (SwiftDataSavedJobsStore | MockSavedJobsStore) → SavedJobEntity (unique indeedJobKey + JobListing JSON snapshot) → UI refresh via ViewModel version bumps Launch / Saved Jobs appear → SavedJobsRevalidator.runPass() → JobValidationService (source signal → optional HEAD) → updateListing(availability, lastVerifiedAt) ``` ## What shipped | Component | Path | |-----------|------| | Model container | `Persistence/PersistenceController.swift` | | SwiftData entity | `Persistence/SavedJobEntity.swift` | | Persisted store | `Persistence/SwiftDataSavedJobsStore.swift` | | Revalidator | `Persistence/SavedJobsRevalidator.swift` | | Protocol | `SavedJobsStore` (+ `updateListing`, `clearAll`) | | Live DI | `AppDependencies.live` → SwiftData + HTTP HEAD for saved revalidation | | Preview DI | `AppDependencies.preview` → `MockSavedJobsStore` | | Settings | Clear local data + export JSON | | Tests | `indeed_ai_job_searchTests/SavedJobsPersistenceTests.swift` | ## Policies | Policy | Value | |--------|-------| | Dedupe key | `indeedJobKey` (unique SwiftData attribute) | | Snapshot | Full `JobListing` JSON in entity | | Revalidation interval | **24 hours** (`SavedJobsRevalidator.defaultStaleInterval`) | | Unavailable rows | Kept; muted/strikethrough via existing `JobRowView` | | Search validation | Unchanged — source signals only (no HEAD during search) | | Saved revalidation | Source signal + `HTTPJobValidationService` HEAD when unknown | ## Acceptance checklist - [x] Save/unsave survives relaunch (SwiftData disk store) - [x] Dedupe on save by `indeedJobKey` - [x] Unavailable jobs remain visible with status; Open on Indeed still available - [x] Stale saved jobs revalidated on launch / Saved Jobs navigation - [x] Settings clear local data + export JSON - [x] Unit tests for store + revalidator ## Out of scope (Phase 6+) - Persisted job alerts / notification history - Cloud sync / iCloud