summaryrefslogtreecommitdiff
path: root/DomainDig/DomainViewModel.swift
Commit message (Collapse)AuthorAgeFilesLines
* refactor: extract history query surface into DomainViewModel+History (v5 ↵Christian Cleberg11 days1-136/+0
| | | | | | | | | | | | | | | | | | | | | | | step 4, 5/n) Fifth slice of the DomainViewModel decomposition. - Moves the history query/compare surface into DomainViewModel+History.swift: per-domain snapshot reads (historyEntries/historyEntry/previousHistoryEntry), timeline grouping (timelineEntries/timelineSections), the two-snapshot selection model (toggle/clear/selectedSnapshots), diff generation and navigation (generateDiff*/moveTo*DiffChange/currentDiffTargetSectionID), and the resolver-mismatch notes. Pure move. - The inspection *pipeline* that produces history — performLookup, applySnapshot, saveHistoryEntry, persistHistory, snapshot-metadata bookkeeping — stays on the main type with the inspection code. This slice needs zero visibility changes: every dependency (the history array, diff state, latestSnapshot) was already internal. The main-file diff is pure deletion. DomainViewModel.swift: 4306 -> 4171 lines (4864 at the start of step 4; -693 total). App builds clean; unit suite 58/58. No project.pbxproj change.
* refactor: extract workflow surface into DomainViewModel+Workflows (v5 step ↵Christian Cleberg11 days1-134/+7
| | | | | | | | | | | | | | | | | | | | | | | 4, 4/n) Fourth slice of the DomainViewModel decomposition (off main; the audit/ monitoring/export stack has merged). - Moves the workflow surface into DomainViewModel+Workflows.swift: workflow lookup (workflow(withID:)/workflowsContaining), the DomainWorkflow collaboration checks, the CRUD mutators (create/update/delete/add/remove/move), runWorkflow/rerunCurrentDomain, and refreshWorkflowList. Pure move. The TrackedDomain overloads of canEdit/canDelete/collaborationLabel stay on the main type (they're watchlist collaboration, not workflow). - Promotes the shared helpers the moved methods reach to internal, all staying on the main type: persistWorkflows (also called by clearWorkflows), startBatchLookup (the batch primitive shared with manual/watchlist runs), normalizedDomain/normalizedDomains, loadWorkflows, and the activeWorkflowRunID/ Name state. The extension carries its own fileprivate String.nilIfEmpty, matching the per-file pattern already used across the codebase. DomainViewModel.swift: 4433 -> 4306 lines (4864 at the start of step 4). App builds clean; unit suite 58/58. No project.pbxproj change.
* refactor: extract export/portability into DomainViewModel+Export (v5 step 4, ↵Christian Cleberg11 days1-171/+4
| | | | | | | | | | | | | | | | | | | | | | 3/n) Third slice of the DomainViewModel decomposition, stacked on the monitoring split. - Moves the export/data-portability surface into DomainViewModel+Export.swift: the single-report/batch/tracked-domain/timeline/workflow exporters, the full-backup and portable-slice exporters, prepareDataImport/applyDataImport, and persistCurrentAppSettings. The export-only WorkflowExportPayload struct moves with them. Pure move, no logic changes. - The four report-projection helpers the exporters call (currentBatchReports, reports(for:), timelineReports, workflowReports) are promoted private -> internal and stay on the main type: they build DomainReports through the shared report layer (report(for:)/reportBuilder), so they belong with inspection, not export. Those four visibility drops are the only non-deletion edits to DomainViewModel. DomainViewModel.swift: 4601 -> 4434 lines. App builds clean; unit suite 58/58. No project.pbxproj change (DomainDig/ is a synchronized group).
* refactor: extract monitoring surface into DomainViewModel+Monitoring (v5 ↵Christian Cleberg11 days1-163/+2
| | | | | | | | | | | | | | | | | | | step 4, 2/n) Second slice of the DomainViewModel decomposition, stacked on the audit split. - Moves the monitoring configuration surface — notification authorization, the settings mutators (enabled/scope/interval/adaptive/sensitivity/quiet-hours/ alert filter/alerts/selection), toggleMonitoring, runMonitoringNow, the manual run, and the per-domain interval/status labels — plus the private intervalLabel helper into DomainViewModel+Monitoring.swift. Pure move. - persistMonitoringSettings(...) and sanitizeMonitoringSelection() are promoted private -> internal: the tracked-domain lifecycle (add/delete/clear) on the main type calls them too, so they stay put and are now reachable cross-file. The two visibility drops are the only non-deletion edits to DomainViewModel. DomainViewModel.swift: 4761 -> 4601 lines. App builds clean; unit suite 58/58. No project.pbxproj change (DomainDig/ is a synchronized group).
* refactor: extract audit surface into DomainViewModel+Audit (v5 step 4, 1/n)Christian Cleberg11 days1-104/+1
| | | | | | | | | | | | | | | | | | | | | First slice of the v5.0.0 god-file decomposition. DomainViewModel.swift is a single ~4.9k-line class body; this begins splitting it into focused `DomainViewModel+<Concern>.swift` extensions, one cohesive concern at a time, with each move behavior-preserving and verified by build + the test net. - Moves the audit read/CRUD/export surface (audits/auditSession/auditTimeline, updateAuditStatus/Notes, toggleAuditChecklistItem, add/update/remove AuditFinding, exportAuditData) into DomainViewModel+Audit.swift as an extension. Pure move — no logic changes. - `startAudit(for:)` intentionally stays on the main type: it drives a live inspection to seed the session, so it belongs with the inspection pipeline until that is extracted. `persistAuditSessions()` is promoted from private to internal so both files can call it (its only cross-file dependency). No project.pbxproj change is needed — DomainDig/ is a file-system-synchronized group, so the new file is picked up automatically. DomainViewModel.swift: 4864 -> 4761 lines. App builds clean; unit suite 58/58.
* feat(a11y): seeded audit fixtures; fix dense-row reflow they exposed (#21)Christian Cleberg13 days1-0/+27
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The dense rows and portfolio sections never rendered in the audit — the test simulator has no tracked domains or batch results — so five phases of row treatment shipped unmeasured. Driving the add-domain UI was tried earlier and rejected (keyboard contamination, persistent state), so this adds DOMAIN_DIG_SEED_FIXTURES: DEBUG-only launch argument, same pattern as DOMAIN_DIG_FORCE_PRO_PLUS, seeding four tracked domains and four batch results chosen to exercise every badge path, including a failed lookup and a stress-length domain name. Fixtures are strictly in-memory. persistTrackedDomains, refreshWidgetData (App Group file), refreshPersistedData, and refreshMonitoringState are all guarded while fixtures are active — the last one mattered: it runs right after seeding in the app task and was reloading the empty disk over the fixtures, which initially made the seeded watchlist audit pass by silently auditing the empty state. Four new audit tests cover the seeded Dashboard, Tracked Domains, and batch results at default and AccessibilityXXXL. What they found was real. At XXXL the watchlist row rendered the domain as "hea lt…" while the Registered badge wrapped one character per line into a screen-height capsule. Fixes, verified by before/after screenshots and the XXXL audits dropping to 7-8 findings per screen: - AppStatusBadgeView gets .fixedSize() — a capsule badge must never letter-wrap; taking natural width instead forces the row layout to its stacked alternative. - WatchlistRowView, BatchResultRowView, and PortfolioExpiryRow headers use ViewThatFits: domain-beside-badge while it genuinely fits, badge below the domain at accessibility sizes. Domain titles get fixedSize(horizontal: false, vertical: true) so they wrap rather than report a single-line ideal width to ViewThatFits and truncate. - The watchlist monitoring metadata strip (three texts abreast) stacks vertically when it no longer fits instead of wrapping mid-word. Known and deliberate: the seeded default-size audits still report a contrast/dynamicType wave attributed to "unknown element". Bisecting the row and badge accessibility modifiers showed most of it is an audit artifact on children-ignored content (the same rows measure 6-7:1 and render correctly); the artifact classes get characterised suppressions when enforcement lands, not blanket ones.
* feat(a11y): VoiceOver labels, dense-row rotor content, announcements (#21 ↵Christian Cleberg14 days1-3/+19
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | phase 4) The audit count is unchanged at 11 dark, and that is the expected result: performAccessibilityAudit validates descriptions, traits, contrast, hit regions, and clipping, but exercises none of VoiceOver's speech, the More Content rotor, custom-content ordering, or announcements — which is the entire substance of this phase. It is verified by construction and stays green with no regressions; the manual VoiceOver pass is Phase 6. Icon-only controls (~14) get accessibilityLabel, obeying label-in-name: where a control has visible text the label keeps it, so Voice Control still works. The pin and bookmark toggles gain accessibilityValue and .isSelected; the audit and workflow checkboxes gain .isSelected and a hint. Decorative icons split out of Labels are hidden. AppStatusBadgeView now reads as one word ("Critical"), not "icon, Critical", via children: .ignore + label. SectionTitleView and CollapsibleSectionView headers get the .isHeader trait for rotor navigation; the collapsible header also exposes expanded/collapsed as a value with a hint. The header deliberately does NOT use children: .combine — its trailing() closure can hold Track/Pin controls, and combining would swallow them. Dense rows use combine-for-summary, custom-content-for-detail. BatchResultRowView (8 elements) and WatchlistRowView (up to 9) become a single element — domain as label, status as value — with risk, IP, timestamp, source, certificate, and monitoring on the More Content rotor, risk and certificate at .high importance. Reading all of it inline would make a long sweep unnavigable. The custom-content chains live in ViewModifiers because inlining six of them plus the layout broke the type-checker. The shorter 3-4 element portfolio rows are left to NavigationLink's automatic combine, per WWDC21-10121. Technical strings get a speechStyle field on InfoRowViewData: .technical applies speechAlwaysIncludesPunctuation and accessibilityTextContentType(.sourceCode), set on DNS record values and cipher suites so load-bearing punctuation is not swallowed. Completion announcements: the sweep posts from the view model; the single lookup posts from an onChange in the view, since resultsLoaded is derived from many loading flags and has no single view-model moment. Widget: each domain row was a silent 8pt status dot plus a bare "12d" countdown. Rows now read as one phrase ("example.com, critical, certificate expires in 12 days"); the count pills are labelled. Not verifiable by the suite: the dense rows and the widget never render in the audit (no tracked domains or batch results in the test simulator), same limit as the deferred Phase 3 row reflow. Documented in Docs/ACCESSIBILITY.md.
* fix: extract nested ternary in batch quickStatusChristian Cleberg2026-07-201-1/+5
| | | | | | Closes the last swift:S3358 in the new-code period. The hasChanges branch nested a severity check inside the impactClassification ternary; split into if/else. No behavior change.
* v4.8.3: Clear SonarCloud new-code issuesChristian Cleberg2026-07-201-81/+17
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | Fixes the 4 reported bugs and ~97 code smells flagged in the new-code period. No behavior changes. Bugs (swift:S3923) — DomainInspectionService's confidenceFor* helpers each returned `error == nil ? .low : .low`, an inert conditional. Simplified to `return .low` and dropped the now-unused `error` parameter. Smells: - Merged 14 identical `.empty`/`.error` switch branches in DomainViewModel - Consolidated duplicate implementations (clearPresentedResults/reset, String.nonEmpty/nilIfEmpty, ExportFormat.id/fileExtension) - Extracted nested ternaries into TLSGrade.tone, EmailSecurityGrade.tone, and ChangeImpactClassification.color; removed ContentView.impactColor and the duplicate mapping in BatchResultsView - Documented empty closures and singleton inits - Marked unused protocol-conformance parameters `_` - Renamed CloudSyncTrigger.`import` to `imported` (raw value preserved) and SSLSessionDelegate's _serverTrust/_tlsMetadata - Merged nested ifs in the DER parser; flattened closure nesting in PortScanService and IntegrationService - Replaced two-case switches with if/else Left open: S107 (init parameter counts), S115 (constants mirroring DoH and ipapi JSON keys), S1075 (false positives on https:// literals), and two S117 hits on SwiftUI $binding shorthand. These want a Won't Fix resolution in SonarCloud, not a code change.
* v4.8.0: Add markdown and PDF export formatsChristian Cleberg2026-07-201-36/+34
| | | | | | | | | | | | | | | | | - 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: Add watchlist tags and saved filter viewsChristian Cleberg2026-07-171-0/+69
| | | | | | | | | | | - 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-171-0/+51
| | | | | | | | | | | | | | | | | | | - 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.
* Implement v4.6.0: sweep Live Activity, share extension, iPad split view, ↵Christian Cleberg2026-07-171-0/+16
| | | | | | | | | | | | | | | | 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.
* Complete v4.5.0: Run Sweep intent, detail deep link, and portfolio widgetChristian Cleberg2026-07-171-0/+1
| | | | | | | | | | | | | | | | | 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.
* DomainDig v4.4.1: Consolidate Audit Mode and remove the CLI targetv4.4.1Christian Cleberg2026-07-161-0/+193
| | | | | | | | | | | - 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
* DomainDig v3.5.0: Expand the Pro+ Data+ intelligence layer with deeper local ↵Christian Cleberg2026-04-261-3/+53
| | | | | | | | | | | | | | | | | | | | | | | | 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.1.0: Add a full local data reset flow in Data ManagementChristian Cleberg2026-04-251-0/+40
| | | | | | | | | | | | | | | | | | | | - 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 v3.9.0 — Portfolio DashboardChristian Cleberg2026-04-251-0/+474
| | | | | | | | | | | * 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-241-55/+83
| | | | | | | | | * 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-241-26/+295
| | | | | | | | | | - 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-231-11/+91
| | | | | | | | | | | | | | | | - 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-231-73/+222
| | | | | | | | | | | • 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-221-2/+336
| | | | | | | | | | - 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-221-4/+19
| | | | | | | | | • 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-221-6/+42
| | | | | | | | | | | * 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
* feat(v2.9.0): add risk scoring and deterministic insight engineChristian Cleberg2026-04-221-22/+94
| | | | | | | | | * introduce domain risk assessment with transparent factors * add insight engine for actionable observations * implement cross-domain insights for workflows * improve DNS, subdomain, email, and TLS interpretation * classify change impact severity * include insights and risk in export
* feat(v2.8.0): add workflows and repeatable inspection automationChristian Cleberg2026-04-221-5/+202
| | | | | | | | | | * introduce DomainWorkflow model and persistence * add WorkflowsView and execution flow * support batch inspection via workflows * add workflow-based export (TXT/CSV/JSON) * enable bulk add from history/watchlist * add quick actions for common operations * integrate workflows with tracking and history
* feat(v2.7.0): add provenance, confidence, and reproducibility metadataChristian Cleberg2026-04-221-18/+169
| | | | | | | | | | * add result provenance across major sections * introduce confidence levels for ambiguous outputs * distinguish observed facts from inferred summaries * expand snapshot metadata for reproducibility * improve error classification and partial snapshot handling * include provenance and confidence in export * add local notes for tracked domains and history
* feat(v2​.6​.0): refine ​UI, density, and usabilityChristian Cleberg2026-04-221-0/+6
| | | | | | | | | • add compact/comfortable density modes • implement collapsible sections and sticky summary header • improve visual status indicators and copy actions • refine watchlist and history UX with swipe actions • reorganize settings and improve empty states • add subtle animations and accessibility improvements
* feat(v2.5.0): add caching, request deduplication, and performance improvementsChristian Cleberg2026-04-211-50/+217
|
* feat(v2.4.0): add JSON output, CLI foundation, and shared report layerChristian Cleberg2026-04-211-361/+69
| | | | | | | | | * introduce DomainReport as canonical output model * add JSON export for single and batch results * create DomainReportBuilder for reusable report construction * add CLI target using shared inspection pipeline * refactor services for UI-independent usage * ensure consistency across TXT, CSV, and JSON outputs
* feat(v2.3.0): add ownership intelligence and subdomain discoveryChristian Cleberg2026-04-211-2/+212
| | | | | | | | | * implement RDAP-based ownership section * add ownership diffing and change classification * add passive subdomain discovery via certificate transparency * highlight interesting subdomains * introduce Data+ scaffolding for future features * include ownership and subdomains in export and history
* feat(v2.2.0): add foreground monitoring, notifications, and smarter diffsChristian Cleberg2026-04-211-120/+538
| | | | | | | | | | | - implement “Check All” sweep for tracked domains - add local notifications for changes and certificate expiration - introduce change severity filtering (low/medium/high) - enhance change summaries and diff readability - add certificate expiration tracking and alerts - improve watchlist indicators for changes - add sweep summary screen - optimize performance for larger watchlists
* feat(v2.1.0): add bulk workflows, CSV export, and filteringChristian Cleberg2026-04-201-35/+506
|
* feat(v2.0.0): introduce tracked domains, diffing, and monitoring foundationsv2.0.0Christian Cleberg2026-04-201-41/+340
| | | | | | | | | | | | | | | | | | - replace basic watchlist with structured TrackedDomain model - add manual refresh flow for tracked domains - implement snapshot diffing (DNS, IP, TLS, HTTP, redirect, email, availability) - add change summaries (changed/unchanged + affected sections) - link tracked domains to history snapshots - enhance HistoryEntry with normalized summary fields - persist availability + suggestions in history and export - add WatchlistView with pinning, notes, and status display - introduce premium capability scaffolding (no StoreKit) - enforce free-tier tracked domain limit (local only) - refactor view model to support tracking, diffing, and refresh flows notes: - no background monitoring, notifications, or paid APIs yet - all features remain local-first and manual
* feat(v1.9.0): add domain availability lookup and watchlist foundationChristian Cleberg2026-04-201-3/+170
| | | | | | | | | - implement availability detection (available/registered/unknown) - integrate availability into domain results - add lightweight domain suggestions - introduce local watchlist with persistence - add WatchlistView and toolbar access - include availability in export
* feat(v1.8): improve result structure, history, and consistencyChristian Cleberg2026-04-201-476/+965
| | | | | | | | - normalize sections and add summary card - fix resolver usage in reverse DNS - include custom port scans in history/export - standardize error handling - decompose ContentView into smaller views
* add custom port scans and improve DNS/email/security diagnosticsv1.7.0Christian Cleberg2026-04-031-2/+66
|
* Add HTTP header grading and protocol metadatav1.6.0Christian Cleberg2026-04-031-2/+47
|
* Add BIMI and MTA-STS checks to email securityv1.5.0Christian Cleberg2026-04-031-1/+17
|
* Release 1.4.0v1.4.0Christian Cleberg2026-04-031-2/+35
| | | | | | | Add richer SSL/TLS inspection details including negotiated TLS version, cipher suite, full certificate chain display, crt.sh lookup, and HSTS preload status. Persist HSTS preload in history/export and run the preload check in parallel with the SSL lookup.
* realigning commitsChristian Cleberg2026-03-181-10/+418
|
* initial commitChristian Cleberg2026-03-111-0/+157