krz/domain-dig

an ios app for DNS & SSL analysis

clone: git clone https://gitbay.org/krz/domain-dig.git

6e9dea95d015c0f2d335d9b89b8ee843b4c2b05e

unsigned

author: Christian Cleberg <hello@cleberg.net> · 2026-07-17T16:20:50Z

v4.8.0: Bump version and mark shipped in roadmap

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.
 DomainDig.xcodeproj/project.pbxproj | 24 ++++++++++++------------
 DomainDig/AppVersion.swift          |  2 +-
 RELEASE_ROADMAP.md                  | 30 +++++++++++++++++++++++++-----
 3 files changed, 38 insertions(+), 18 deletions(-)

diff --git a/DomainDig.xcodeproj/project.pbxproj b/DomainDig.xcodeproj/project.pbxproj
index e51e7f8..69a283a 100644
--- a/DomainDig.xcodeproj/project.pbxproj
+++ b/DomainDig.xcodeproj/project.pbxproj
@@ -495,7 +495,7 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CODE_SIGN_ENTITLEMENTS = DomainDig/DomainDig.entitlements;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 39;
+				CURRENT_PROJECT_VERSION = 40;
 				DEVELOPMENT_TEAM = ZCNAX3VL9D;
 				ENABLE_PREVIEWS = YES;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -512,7 +512,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 4.7.0;
+				MARKETING_VERSION = 4.8.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.DomainDig;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -532,7 +532,7 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CODE_SIGN_ENTITLEMENTS = DomainDig/DomainDig.entitlements;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 39;
+				CURRENT_PROJECT_VERSION = 40;
 				DEVELOPMENT_TEAM = ZCNAX3VL9D;
 				ENABLE_PREVIEWS = YES;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -549,7 +549,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 4.7.0;
+				MARKETING_VERSION = 4.8.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.DomainDig;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -568,7 +568,7 @@
 				APPLICATION_EXTENSION_API_ONLY = YES;
 				CODE_SIGN_ENTITLEMENTS = DomainDigWidget/DomainDigWidget.entitlements;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 39;
+				CURRENT_PROJECT_VERSION = 40;
 				DEVELOPMENT_TEAM = ZCNAX3VL9D;
 				GENERATE_INFOPLIST_FILE = NO;
 				INFOPLIST_FILE = DomainDigWidget/Info.plist;
@@ -579,7 +579,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 4.7.0;
+				MARKETING_VERSION = 4.8.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.DomainDig.DomainDigWidget;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
@@ -597,7 +597,7 @@
 				APPLICATION_EXTENSION_API_ONLY = YES;
 				CODE_SIGN_ENTITLEMENTS = DomainDigWidget/DomainDigWidget.entitlements;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 39;
+				CURRENT_PROJECT_VERSION = 40;
 				DEVELOPMENT_TEAM = ZCNAX3VL9D;
 				GENERATE_INFOPLIST_FILE = NO;
 				INFOPLIST_FILE = DomainDigWidget/Info.plist;
@@ -608,7 +608,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 4.7.0;
+				MARKETING_VERSION = 4.8.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.DomainDig.DomainDigWidget;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
@@ -626,7 +626,7 @@
 				APPLICATION_EXTENSION_API_ONLY = YES;
 				CODE_SIGN_ENTITLEMENTS = DomainDigShareExtension/DomainDigShareExtension.entitlements;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 39;
+				CURRENT_PROJECT_VERSION = 40;
 				DEVELOPMENT_TEAM = ZCNAX3VL9D;
 				GENERATE_INFOPLIST_FILE = NO;
 				INFOPLIST_FILE = DomainDigShareExtension/Info.plist;
@@ -637,7 +637,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 4.7.0;
+				MARKETING_VERSION = 4.8.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.DomainDig.DomainDigShareExtension;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
@@ -655,7 +655,7 @@
 				APPLICATION_EXTENSION_API_ONLY = YES;
 				CODE_SIGN_ENTITLEMENTS = DomainDigShareExtension/DomainDigShareExtension.entitlements;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 39;
+				CURRENT_PROJECT_VERSION = 40;
 				DEVELOPMENT_TEAM = ZCNAX3VL9D;
 				GENERATE_INFOPLIST_FILE = NO;
 				INFOPLIST_FILE = DomainDigShareExtension/Info.plist;
@@ -666,7 +666,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 4.7.0;
+				MARKETING_VERSION = 4.8.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.DomainDig.DomainDigShareExtension;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
diff --git a/DomainDig/AppVersion.swift b/DomainDig/AppVersion.swift
index 9865f5b..137fde9 100644
--- a/DomainDig/AppVersion.swift
+++ b/DomainDig/AppVersion.swift
@@ -2,6 +2,6 @@ import Foundation
 
 enum AppVersion {
     nonisolated static var current: String {
-        "4.7.0"
+        "4.8.0"
     }
 }
diff --git a/RELEASE_ROADMAP.md b/RELEASE_ROADMAP.md
index dd07fa9..3bb7966 100644
--- a/RELEASE_ROADMAP.md
+++ b/RELEASE_ROADMAP.md
@@ -6,7 +6,7 @@ ports, geolocation, subdomains, availability). The next several releases invest
 in *reach and surfacing* — getting that data onto more iOS surfaces and into more
 workflows — rather than adding raw protocol checks.
 
-Current version: `v4.7.0`.
+Current version: `v4.8.0`.
 
 ## v4.4.1 Patch: Release Readiness — ✅ shipped
 
@@ -68,13 +68,33 @@ Goal: help users interpret and organize, not just collect.
   domain, tag filter chips, and named saved filter/sort/tag presets
   (UserDefaults-backed; not yet part of backup/restore).
 
-## v4.8.0 Minor: Reporting & Sharing
+## v4.8.0 Minor: Reporting & Sharing — ✅ shipped
 
 Goal: turn point-in-time snapshots into shareable, scheduled deliverables.
 
-- Scheduled report generation (markdown/json/pdf) for tracked domains.
-- Stronger share affordances for reports and audit evidence.
-- Export polish and consistency across app and local API output.
+- **Markdown and PDF export formats** — `DomainExportFormat` gains `.markdown`
+  and `.pdf` alongside text/csv/json. Markdown reuses the existing text-export
+  content via a line-based transform (never drifts from the text export); PDF
+  renders that Markdown via `UIGraphicsPDFRenderer`, mirroring the approach
+  `AuditExporter` already used for audit sessions.
+- **Scheduled report generation** — `ScheduledReportService` /
+  `ScheduledReportScheduler` (Settings → Scheduled Reports): a BGTaskScheduler-
+  driven daily/weekly job that builds a markdown/PDF/JSON report bundle for all
+  tracked domains, writes it locally, logs the run, and notifies when ready.
+  Mirrors `DomainMonitoringService`'s headless, storage-backed design; gated
+  behind the same Pro `.automatedMonitoring` capability.
+- **Stronger share affordances** — "Export Markdown"/"Export PDF" added to the
+  single-result, batch, watchlist, and workflow export menus; generated
+  scheduled reports are individually shareable from their log.
+- **Export consistency verified** — the local API already serves the canonical
+  `DomainReport` directly (no field allowlist), so `reputation`, `domainPricing`,
+  and every other field added since v4.7.0 already flow through automatically.
+  No code change was needed there.
+
+Deferred/scoped out: scheduled-report settings and logs are UserDefaults-only
+(not part of `DomainDataPortabilityService` backup/restore), same reasoning as
+v4.7.0's watchlist saved views — this is local automation config, not
+user-authored content.
 
 ## v5.0.0 Major: Contract Stabilization & Engineering Health