summaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAgeFilesLines
...
* add all SonarCloud badges to READMEChristian Cleberg2026-07-201-0/+3
|
* v4.8.2: Bump version and mark shipped in roadmapv4.8.2Christian Cleberg2026-07-203-18/+43
| | | | | | | | Bump AppVersion/marketing version to 4.8.2 and build number to 42 across the app, widget, and share extension targets. Mark v4.8.2 (delivery visibility for disabled integrations, forced queue retries, unreachable-domain reporting, Swift 6 concurrency warnings, synced StoreKit configuration) shipped in RELEASE_ROADMAP.md and record the UAT follow-ups as resolved.
* fix: report unreachable domains instead of 'No meaningful changes'Christian Cleberg2026-07-202-3/+48
| | | | | | | | | | | | | | | | | Closes #10. resolvedSnapshotAfterFallback replaces a failed lookup's snapshot with the previous one, so alertDescriptor compared the old snapshot against itself, found matching hashes, and the run reported 'No meaningful changes' for a domain that was never actually reached. Nothing in the UI or the monitoring log distinguished that from a genuine no-change. MonitoringDomainResult now carries unreachableReason, set when the fallback fires. It is Optional so already-persisted monitoring logs still decode. The run summary reads 'Could not check — kept the previous result' with the underlying error, and monitoringEvents emits a warning- severity monitoringFailure so configured integrations hear about it rather than seeing silence.
* fix: make disabled targets and forced queue processing visibleChristian Cleberg2026-07-201-6/+52
| | | | | | | | | | | | | | | | | | | | | Closes #8, closes #9. enqueue(events:) filtered to enabled targets before writing any DeliveryRecord, so events routed to a disabled integration disappeared with nothing in the Delivery Log. Disabled targets now record a .skipped entry with a reason, matching how filter mismatches are already surfaced. sendTest bypassed the isEnabled check entirely, so a test event delivered against a target that silently dropped every real event — exactly the wrong signal when someone is verifying their setup. It now skips with the same reason. processQueueNow only restarted the processing task; it never moved nextAttemptAt, so an item in retry backoff stayed undue and the fresh task went straight back to sleep. Backoff reaches an hour, so the button appeared inert for the one case it exists to handle. It now pulls every queued item forward, and reports when the queue is empty instead of returning silently.
* chore: rename StoreKit configuration to SyncedProducts.storekitChristian Cleberg2026-07-203-3/+3
| | | | | | | | | | | DomainDig.storekit sat beside the DomainDig/ source folder, and Xcode treated the two as conflicting when creating the synced configuration — the resulting confirmation dialog offered to replace the folder. Naming the file SyncedProducts.storekit removes the collision entirely and matches the convention Xcode uses for synced configurations elsewhere. Updates the project file reference and the scheme's StoreKitConfigurationFileReference to match.
* chore: adopt synced StoreKit configurationChristian Cleberg2026-07-202-47/+115
| | | | | | | | | | | | | Xcode synced DomainDig.storekit against App Store Connect, replacing the hand-authored placeholders with real values: the app's internal ID (6760368004), the real subscription group ID (22051301), a synchronized timestamp, and group localizations. Also registers the file in the project so Xcode can find and re-sync it, but without target membership. Xcode's default added it to the Resources build phase of all three targets, which would ship the test configuration inside the app, widget, and share extension bundles. The scheme references it by path for the Run action; it does not need bundling.
* fix: correct StoreKit configuration file formatChristian Cleberg2026-07-201-5/+21
| | | | | | | | | | | | | | | | | Compared against a known-good Xcode-generated configuration (hutch/SyncedProducts.storekit) and corrected the hand-authored file: - version bumped 4.0 -> 5.0, the format Xcode 26 writes - added the appPolicies block Xcode always emits - added the missing settings keys (_askToBuyEnabled, _billingGracePeriodEnabled, _billingIssuesEnabled, _disableDialogs, _renewalBillingIssuesEnabled, _timeRate) - _developerTeamID set to ZCNAX3VL9D, matching DEVELOPMENT_TEAM in the project rather than being left empty - _applicationInternalID cleared. It previously held 6763610682, which is the Apple ID of the Pro+ (Annually) subscription, not the app's internal ID. That value is now on the subscription's internalID where it belongs; the app ID is left empty rather than wrong.
* fix: StoreKit config path and Swift 6 concurrency warningsChristian Cleberg2026-07-203-9/+14
| | | | | | | | | | | | | | | | | | The StoreKitConfigurationFileReference added in #11 used one '../' too many, resolving outside the repository. Xcode resolves it relative to the .xcodeproj's xcshareddata directory, so two levels reaches the repo root. SweepActivityAttributes is now explicitly nonisolated. The app target sets SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor while the widget target does not, so a type shared by both inferred a main-actor-isolated ActivityAttributes conformance that ActivityKit cannot use from its concurrent contexts. LocalAPIService's logger closures captured self strongly while their inner Tasks declared [weak self]. The weak capture is now on the outer closure and bound before the Task, so the concurrently-executing closure references an immutable strong local rather than the weak capture.
* docs: record the IAP fixes in the v4.8.1 roadmap sectionv4.8.1Christian Cleberg2026-07-201-0/+9
| | | | | | | PR #11 merged after the v4.8.1 version bump, so the roadmap's v4.8.1 section omitted the product ID correction and the StoreKit configuration file. Both are in the 4.8.1 tree; document them alongside the other fixes.
* test: add StoreKit configuration for local IAP testingChristian Cleberg2026-07-202-1/+139
| | | | | | | | | | | | | | Adds DomainDig.storekit mirroring the App Store Connect setup: one subscription group with Pro+ at level 1 and Pro at level 2, using the corrected product IDs. Wires it into the Run action so purchases resolve locally against StoreKit instead of the App Store, and disables the DOMAIN_DIG_FORCE_PRO_PLUS launch argument, which bypasses StoreKit entirely and would mask whether the purchase path works. Prices in the configuration are local-testing placeholders and do not need to match App Store Connect.
* fix: match IAP product IDs to App Store ConnectChristian Cleberg2026-07-201-4/+4
| | | | | | | | | | | | | | The four product ID constants did not match the auto-renewable subscriptions configured in App Store Connect, so Product.products(for:) returned an empty array and tier(for:) resolved every purchase to .free. Product IDs are permanent in App Store Connect, so the code is corrected to match the configured values rather than the reverse: domaindig.pro.monthly -> domaindig.pro.month domaindig.pro.yearly -> domaindig.pro.annually domaindig.dataplus.monthly -> domaindig.proplus.monthly domaindig.dataplus.yearly -> domaindig.proplus.annually
* v4.8.1: Bump version and mark shipped in roadmapChristian Cleberg2026-07-203-14/+38
| | | | | | | | Bump AppVersion/marketing version to 4.8.1 and build number to 41 across the app, widget, and share extension targets. Mark v4.8.1 (scheduled report tap target, completed Pro gate, markdown underline rendering, DNS record dedup, inspect tab keyboard behavior) shipped in RELEASE_ROADMAP.md, and note the three follow-ups filed during UAT.
* fix: markdown report underlines and duplicate DNS record valuesChristian Cleberg2026-07-201-2/+29
| | | | | | | | | | | | | | | | | | | | The plain-text-to-Markdown transform only recognized '-' underlines, but batchText writes '=' — under the document title and as a 48-character separator between reports. Both leaked through as literal bullets, so a generated report opened with: # Scheduled Watchlist Report - ========================== Title underlines are now consumed alongside the title, '=' underlines promote to H2 the same as '-', and standalone divider runs render as a Markdown horizontal rule. Separately, the DNS section concatenated apex and wildcard records without dedup. On a domain with wildcard DNS resolving to the same addresses as the apex, every value was listed twice. Now deduped while preserving order, so a wildcard value that genuinely differs is still shown.
* fix: Generate Now tap target, remove keyboard dismiss button and launch focusChristian Cleberg2026-07-203-60/+49
| | | | | | | | | | | | | | | | Scheduled Reports: the entire Overview section was wrapped in a single VStack inside one List row, so SwiftUI collapsed every control into one tap target and the menu-style Cadence Picker captured taps intended for the Generate Now button. Unwraps the VStack so each control is its own row, matching the pattern used in IntegrationsView and elsewhere. Also extends the .automatedMonitoring gate to the two Pickers and the Generate Now button. Previously only the Toggle was disabled, leaving a button that appeared active on Free but silently no-opped against the guard in ScheduledReportService. Inspect tab: removes the keyboard toolbar's Dismiss Keyboard button and the onAppear that focused the single-domain field at launch.
* misc. cleanupChristian Cleberg2026-07-203-421/+2
|
* fix: reject non-HTTPS webhook URLs at save timeChristian Cleberg2026-07-201-1/+18
| | | | | | | | | Validating only at send time meant an http:// URL saved fine and then failed silently on delivery. Validate in upsert so the integration editor surfaces it, and give the failure its own error case rather than reusing the generic invalid-URL message. The send-time guard stays as defense in depth for URLs saved before this.
* fix: harden webhook transport and gate debug loggingChristian Cleberg2026-07-202-1/+5
| | | | | | | | | | Require HTTPS for outbound integration webhooks. Webhook URLs are themselves secrets (Slack in particular), so an http:// endpoint leaked both the URL and the alert payload in cleartext. Disable DomainDebugLog in release builds. Every message used privacy: .public, which opted out of OSLog redaction and wrote looked-up domains to the unified log in shipped builds.
* v4.8.0: Bump version and mark shipped in roadmapChristian Cleberg2026-07-203-18/+38
| | | | | | | Bump AppVersion/marketing version to 4.8.0 and build number to 40 across the app, widget, and share extension targets. Mark v4.8.0 (markdown/PDF export, scheduled reports, stronger share affordances, verified local API consistency) shipped in RELEASE_ROADMAP.md.
* v4.8.0: Add scheduled report generationChristian Cleberg2026-07-207-1/+406
| | | | | | | | | | | | | | | | | | | | | - ScheduledReportService (@MainActor, headless/storage-backed like DomainMonitoringService): builds the latest report for every tracked domain from persisted history, exports it via DomainReportExporter in the configured format (markdown/PDF/JSON), writes it to a local Documents subdirectory, logs the run, and fires a "Scheduled Report Ready" local notification. - ScheduledReportScheduler mirrors DomainMonitoringScheduler's BGTaskScheduler approach with its own task identifier (net.cleberg.DomainDig.report.schedule, added to Info.plist) and a daily/weekly cadence. - ScheduledReportsView (Settings → Scheduled Reports): enable toggle, cadence and format pickers, "Generate Now", and a log of past reports each shareable via the existing ExportPresenter share sheet. - Gated behind the existing .automatedMonitoring capability (Pro), consistent with monitoring being the other background-automation feature. - Settings/logs persist via UserDefaults (DomainExportFormat is now Codable), not DomainDataPortabilityService backup/restore — this is local automation configuration, not user-authored content, same reasoning as v4.7.0's watchlist saved views.
* v4.8.0: Wire markdown/PDF export buttons into share menusChristian Cleberg2026-07-203-0/+52
| | | | | | | | | Adds "Export Markdown"/"Export PDF" (and batch/workflow equivalents) to the single-result, batch, watchlist, and workflow export menus, gated behind .advancedExports like the existing CSV/JSON options. Matches the existing menu structure and Pro-gate wording per file rather than introducing a new shared component, consistent with how CSV/JSON were already duplicated across these five menus before this change.
* v4.8.0: Add markdown and PDF export formatsChristian Cleberg2026-07-205-100/+147
| | | | | | | | | | | | | | | | | - DomainExportFormat gains .markdown and .pdf (CaseIterable, Identifiable, titled), alongside the existing text/csv/json. - Markdown reuses the existing text-export content verbatim via a line-based transform (section "Title\n----" underlines become "## Title", the leading title becomes an H1, other lines become bullets), so the two formats can never drift apart. - PDF renders that Markdown as a simple monospaced multi-page document via UIGraphicsPDFRenderer (mirrors AuditExporter's existing PDF approach; degrades to raw Markdown bytes on non-UIKit platforms). - Replaced the single/batch/tracked-domains/workflow share call sites' hand- written per-format switches with format-agnostic functions (exportSingleReportData, exportBatchReportData, exportTrackedDomainsData, exportWorkflowData) that delegate straight to DomainReportExporter, removing the now-orphaned per-format helper functions those switches used to call.
* v4.7.0: Bump version and mark shipped in roadmapv4.7.0Christian Cleberg2026-07-173-23/+34
| | | | | | | Bump AppVersion/marketing version to 4.7.0 and build number to 39 across the app, widget, and share extension targets. Mark v4.7.0 (comparison, reputation, tags/saved views) shipped in RELEASE_ROADMAP.md and escalate the overdue XCTest-target gap ahead of v5.0.0.
* v4.7.0: Add watchlist tags and saved filter viewsChristian Cleberg2026-07-174-3/+261
| | | | | | | | | | | - TrackedDomain.tags: [String] (backward-compatible custom decode), with updateTags(_:for:) and a normalized/deduplicated write path. - Tag editing in TrackedDomainDetailView (comma-separated field, chip display). - Tag filter chips in WatchlistView (TagFilterChipRowView), integrated into filteredTrackedDomains alongside the existing filter/search. - Saved views: name + snapshot the current tag/filter/sort as a WatchlistSavedView preset (UserDefaults-backed, not part of backup/restore), with a management sheet to apply or delete presets.
* v4.7.0: Add domain reputation/blocklist data sourceChristian Cleberg2026-07-1711-5/+192
| | | | | | | | | | | | | | | | | | | - New DomainReputationResult model (status: clean/listed/unknown, listed sources, checked-at) and a `reputation(domain:)` method on ExternalDataService, mirroring the existing pluggable-URL enrichment pattern (ownership history, DNS history, extended subdomains, pricing). With no endpoint configured (the default; DomainDig ships no bundled third-party reputation dependency) it resolves to unavailable rather than "clean". - New .reputation FeatureCapability/DataCapability, gated Pro+ like domainPricing. - Threaded reputation/reputationError through LookupSnapshot and HistoryEntry (backward-compatible decode) so results persist with history entries. - Auto-fetched in performLookup alongside pricing; surfaced as a "Reputation" info row, folded into DomainInsightEngine's risk score/factors and top-level insights (a listed domain raises risk score and adds a factor/insight), and exported in text, CSV, and JSON report output. - Reputation-driven risk changes ride the existing change-severity pipeline, so a listed status flip is visible to monitoring the same way any other risk delta is, without bespoke monitoring wiring.
* v4.7.0: Add domain-vs-domain comparisonChristian Cleberg2026-07-173-0/+139
| | | | | | | | | | - DiffService.compare(domainA:domainB:) reuses the existing section-diff builders to compare two distinct domains' latest reports, returning a new DomainComparisonResult (parallel to the time-based DomainDiff). - DomainCompareView: pick two tracked domains and render the comparison with the existing DomainDiffView section renderer. - Entry point: "Compare Domains" in the Watchlist toolbar menu, shown once at least two domains are tracked.
* Xcode: backfill extension display-name build settingsv4.6.0Christian Cleberg2026-07-171-0/+4
|
* docs: mark v4.6.0 shipped in roadmap and READMEChristian Cleberg2026-07-172-11/+17
|
* Implement v4.6.0: sweep Live Activity, share extension, iPad split view, ↵Christian Cleberg2026-07-1716-69/+677
| | | | | | | | | | | | | | | | actionable notifications - Sweep Live Activity: SweepActivityAttributes (Shared/), lock-screen + Dynamic Island UI in the widget extension, driven by SweepActivityController wired into the batch pipeline (begin/update/end); NSSupportsLiveActivities in Info.plist. - Share extension (DomainDigShareExtension): accepts a web URL from the share sheet, extracts the host, and hands it to the app via the App Group inbox (DomainDigShareInbox); the app consumes it on activation and inspects it. - iPad layout: RootTabView uses NavigationSplitView in the regular size class and the tab bar in compact. - Actionable notifications: per-domain threadIdentifier grouping, a Re-inspect action, and tap routing into the domain detail via the intent router. - Bump version to 4.6.0 (build 38) across app, widget, and share targets.
* docs: mark v4.4.1/v4.5.0 shipped in roadmap and READMEv4.5.0Christian Cleberg2026-07-172-24/+23
| | | | | | Update RELEASE_ROADMAP.md to show v4.4.1 and v4.5.0 as shipped (with the actual delivered scope), set the current version to v4.5.0, and note the deferred Lock Screen widget families. Refresh the README release target to v4.5.0.
* Complete v4.5.0: Run Sweep intent, detail deep link, and portfolio widgetChristian Cleberg2026-07-1714-51/+681
| | | | | | | | | | | | | | | | | Finishes the v4.5.0 "Home Screen & Shortcuts reach" scope that the tag shipped partially: - Add RunSweepIntent (opens the app and runs refreshAllTrackedDomains via the in-process router) and expose it in DomainDigShortcuts. - Extend the domaindig:// scheme with `sweep` and `domain` (detail) actions; route .detail to present TrackedDomainDetailView and .sweep to refresh the watchlist. Move DomainDigDeepLink into Shared/ so the widget can build links. - Add a WidgetKit extension (DomainDigWidgetExtension) with small/medium/large Portfolio widgets showing health counts, per-domain status, and certificate countdowns; tapping a domain deep-links into its detail. - Share portfolio state via an App Group (group.net.cleberg.DomainDig): the app writes a DomainDigWidgetData snapshot on launch/foreground and on watchlist changes and reloads timelines; the widget reads the same store.
* Merge pull request #3 from zerolabsco/fix/inspect-intent-actor-isolationChristian Cleberg2026-07-171-0/+1
|\ | | | | Fix Swift 6 actor-isolation warning in InspectDomainIntent
| * Fix Swift 6 actor-isolation warning in InspectDomainIntentChristian Cleberg2026-07-171-0/+1
| | | | | | | | | | | | | | | | The app target sets SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor, so DomainReportBuilder and DomainInspectionService are MainActor-isolated. The unmarked perform() ran nonisolated, so calling build(from:) triggered an "expression is 'async' but is not marked with 'await'" warning (an error in the Swift 6 language mode). Mark perform() @MainActor to match AddToWatchlistIntent.
* | Merge pull request #2 from zerolabsco/ccleberg-patch-1Christian Cleberg2026-07-171-0/+11
|\ \ | |/ |/| Set package ecosystem to 'swift' in dependabot config
| * Set package ecosystem to 'swift' in dependabot configChristian Cleberg2026-07-171-0/+11
|/
* Add GitHub Actions build workflowChristian Cleberg2026-07-161-0/+78
| | | | | | | Compile gate on macos-26 for the GitHub mirror (builds.sr.ht has no macOS images). Runs `xcodebuild build` on pull_request and manual dispatch, with docs-only paths ignored. Mirrors the CI setup in the sibling hutch repo, adapted to `build` because there is no test target yet (planned for v5.0.0).
* DomainDig v4.5.0: Add App Intents, Shortcuts, and a domaindig:// deep linkChristian Cleberg2026-07-165-5/+257
| | | | | | | | | | | - Add InspectDomainIntent that runs the headless inspection pipeline and returns a summary for Shortcuts, Spotlight, the Action button, and Siri - Add AddToWatchlistIntent that opens the app and tracks a domain through the existing premium-checked path via an in-process router - Register the domaindig:// URL scheme with inspect/watch deep links routed in RootTabView (onOpenURL) - Expose both intents through DomainDigShortcuts (AppShortcutsProvider) - Bump AppVersion/marketing version to 4.5.0 and build number to 37
* DomainDig v4.4.1: Consolidate Audit Mode and remove the CLI targetv4.4.1Christian Cleberg2026-07-1615-703/+1559
| | | | | | | | | | | - Make DomainDig/DomainDig/Audit* the single active Audit Mode implementation (models, views, exporter) with an Audit tab and session/export UI - Include audit sessions in backup/restore lifecycle counts, summaries, and merge behavior via DomainDataPortabilityService - Remove the DomainDigCLI target, source file, scheme, and all project references; keep the shared inspection/report pipeline for the app - Align AppVersion.current to 4.4.1 and refresh README/architecture docs - Add RELEASE_ROADMAP.md
* Add v4.4 audit mode sessions and export workflowChristian Cleberg2026-05-133-0/+345
|
* DomainDig v3.5.0: Expand the Pro+ Data+ intelligence layer with deeper local ↵Christian Cleberg2026-04-2613-41/+1061
| | | | | | | | | | | | | | | | | | | | | | | | historical context and inferred enrichment. - add derived intelligence fields for provider fingerprinting, classification, ownership transitions, hosting transitions, subdomain history, risk signals, and inferred timeline events - expand DNS history beyond A/NS snapshots to retain A, AAAA, MX, NS, TXT, and CNAME change state - persist enriched intelligence in snapshots and history entries so analysis is local-first and incremental - add a dedicated Data+ Intelligence panel to current and historical domain detail views - surface intelligence events in timeline rows and include Data+ changes in diff output - preserve non-blocking inspection behavior by keeping enrichment additive to the main lookup path This makes Pro+ materially deeper for investigative workflows by improving historical ownership visibility, infrastructure context, hosting change detection, subdomain intelligence, and explainable risk signals.
* DomainDig v4.2.0: Add a local-only HTTP API layer for DomainDigChristian Cleberg2026-04-266-5/+1217
| | | | | | | | | | | | | | | | | | | | Expose DomainDig as a programmable local domain intelligence engine over localhost with explicit user opt-in and token-based authentication. Highlights: - add a localhost-only API server with safe start/stop lifecycle - require a local token for every request and store it in Keychain - add read endpoints for portfolio, domains, history, events, and monitoring - add inspection endpoints that reuse the existing inspection engine - add monitoring enable/disable control endpoints - add structured JSON response envelopes with API versioning - add lightweight capped request logging with clear/reset support - add a Settings UI for Local API enablement, token management, status, and logs - start the server on launch only when enabled - include Local API secrets in local data reset cleanup This is the first programmability release for DomainDig and establishes the foundation for Shortcuts, scripts, and other local automation workflows.
* DomainDig v4.1.0: Add a full local data reset flow in Data ManagementChristian Cleberg2026-04-2510-5/+677
| | | | | | | | | | | | | | | | | | | | - add a destructive Delete All Data action with confirmation, progress, success, and failure handling - centralize wipe behavior in DataResetService instead of scattering delete logic in views - clear local persistence, temp/export files, integration secrets, notifications, caches, and in-memory app state - reset sync, purchase, and integration services after wipe so the app returns to a clean first-launch state Polish batch and empty-state UX - present the batch sweep summary after manual bulk searches complete, not only from Watchlist - align the Workflows empty state styling with other empty states by removing the extra background card treatment Bump the project version from 4.0.0 to 4.1.0
* DomainDig v4.0.0 — IntegrationsChristian Cleberg2026-04-257-4/+1815
| | | | | | | | | | | | * Outbound webhook delivery * Native Slack webhook integration * SMTP-based email alerts * Per-integration event filtering * Reliable local delivery queue * Delivery logs and retry visibility * Integration management UI * Normalized event severity model * Canonical structured event payloads
* DomainDig v3.9.0 — Portfolio DashboardChristian Cleberg2026-04-258-24/+1025
| | | | | | | | | | | * Portfolio summary cards * Recent activity feed across tracked domains * Attention-required queue prioritized by severity * Certificate expiry visibility and expiring-soon section * Quick portfolio filters for triage * Deterministic per-domain health scoring * Local portfolio search * Apex-domain grouping for tracked assets
* DomainDig v3.8.0 — Smart MonitoringChristian Cleberg2026-04-2421-498/+1647
| | | | | | | | | * Stable domain intervals * Frequent changes decrease intervals * Duplicate states do not trigger alerts * Quiet hours suppress alerts * Quiet hours across midnight work correctly * Sensitivity levels alter behavior as expected
* feat(v3.7.0): add timeline and advanced diffing systemChristian Cleberg2026-04-2421-694/+1701
| | | | | | | | | | - introduce TimelineView for historical snapshots - allow comparison between any two snapshots - implement DiffService for structured domain diffs - improve diff visualization with clear change indicators - add navigation across changes - optimize history loading for performance - extend CLI and export to support timeline data
* feat(v3.6.0): add iCloud sharing for workflows and tracked domainsChristian Cleberg2026-04-2316-48/+2048
| | | | | | | | | | | | | | | | - implement CloudKit sharing (CKShare) for TrackedDomain and DomainWorkflow - support read-only and editable permissions - add Share actions and shared state indicators in UI - handle shared record ownership and participant roles - implement deterministic conflict resolution to prevent duplication - ensure compatibility with existing iCloud sync layer - maintain local-first behavior with graceful offline handling - remove debug logging for domain availability/rdap messages notes: - no custom backend or accounts introduced - sharing is Apple ecosystem only (iCloud-based) - large history data remains local-only
* feat(v3.4.0): add backup, restore, and data portabilityChristian Cleberg2026-04-2317-92/+3326
| | | | | | | | | | | • introduce versioned DomainDig backup format • add full backup export/import with merge and replace modes • implement data validation and conflict handling • add partial exports for tracked domains, workflows, and history • add Data Portability settings section • support Files/iCloud Drive import and export • harden migrations for evolving local models • extend CLI with backup export and validation
* feat(v3.2.0): add Data+ tier and external data integrationsChristian Cleberg2026-04-2218-97/+1935
| | | | | | | | | | - introduce Data+ tier for advanced data features - add ownership history and DNS history - expand subdomain discovery with external sources - add domain pricing insights - implement local usage/credit system - integrate external data service layer with rate limiting - extend export and CLI for Data+ features
* feat(v3​.1​.0): add ​Store​Kit integration and ​Pro tierChristian Cleberg2026-04-2210-103/+586
| | | | | | | | | • implement Purchase​Service using StoreKit 2 • activate feature tiers based on entitlement • add minimal paywall and restore flow • enforce free-tier limits with upgrade paths • integrate Pro status into settings • ensure clean and non-intrusive monetization flow
* feat(v3.0.0): unify platform architecture and introduce feature tiersChristian Cleberg2026-04-2213-177/+654
| | | | | | | | | | | * consolidate DomainReport as canonical data model * add feature tier system (free/pro/data+ scaffolding) * apply clean feature gating across workflows and tracking * refactor app structure for maintainability * standardize navigation and settings * add data lifecycle controls * ensure consistency across UI, export, and CLI * stabilize internal inspection API