Files
linkding-ios/openwiki/operations/development-and-testing.md
Krishna Kumar 4d875e12d6
All checks were successful
CI / build-and-deploy (push) Successful in 17s
add openwiki docs
2026-07-02 00:33:49 -05:00

7.2 KiB

Development and Testing

This page covers local setup, generated project guidance, runtime configuration/storage, and verification strategy for changes.

Local setup

Requirements from /README.md and /project.yml:

  • macOS with Xcode capable of building the declared iOS 26 / Swift 6 project.
  • XcodeGen.
  • A linkding server with API access for real sync testing.
  • Access to the Marks backend for AI, semantic search, smart collections, analytics, and podcast generation flows.

Setup:

brew install xcodegen
xcodegen generate
open Marks.xcodeproj

Build and run the Marks scheme in Xcode. /project.yml declares schemes for Marks, MarksWidget, and ShareExtension; the Marks scheme builds the app, share extension, and widget extension and runs MarksTests in the test action.

Project generation rules

Use /project.yml as the source of truth for targets, source membership, entitlements, and dependencies. Regenerate the Xcode project after changing target membership:

xcodegen generate

Common target-membership traps:

  • The main app includes /MarksWidget/WidgetDataStore.swift directly so it can write widget JSON.
  • The share extension includes selected shared files from /Marks/Models and /Marks/Services; if the extension needs new model/service code, add it in /project.yml.
  • The app, widget, and share extension all depend on matching app-group entitlements.

Testing

Current automated test coverage is concentrated in /MarksTests/AppIntentsTests.swift.

Covered today:

  • BookmarkEntity mapping from Bookmark, fallback title behavior, and round-trip fields.
  • EntityIdentifier encoding.
  • IntentRouter open/search setters.
  • Direct no-network perform() tests for Search and Open intents.
  • App Shortcuts registration count.

Not currently covered by repository tests:

  • BookmarksViewModel load/cache/pagination/mutation flows.
  • Linkding networking with mocks.
  • AI enrichment, semantic search, smart collections, or podcast backend calls.
  • Share extension save/update/tag suggestion flows.
  • Widget timeline rendering/deep links.
  • Browser reading progress/reader mode.
  • Podcast generation, playback, queue, played/unplayed, and background audio behavior.

Suggested test command:

xcodebuild test -scheme Marks -destination 'platform=iOS Simulator,name=iPhone 16'

Use an installed simulator name if iPhone 16 is unavailable.

Manual verification checklist by area

Bookmark sync/list changes:

  • Launch with valid linkding config.
  • Confirm cached bookmarks render quickly, then network refresh updates the list.
  • Test pull-to-refresh, pagination, unread filter, add, edit, archive, delete.
  • Confirm widget bookmark JSON updates and Spotlight indexing still happens.

Search/tag changes:

  • Test linkding search and semantic search separately.
  • Verify unread filter interactions.
  • Confirm Tags tab counts include expected linkding and AI tags.

AI changes:

  • Test enrichment on add, background enrichment, Enrich All, semantic search, Smart Collections, and Summarize intent if affected.
  • Test Ask on a device/simulator environment where Apple on-device model availability can be observed; handle unavailable states.
  • Preserve backend privacy expectations: URLs/titles/tags/summaries may be sent to the Marks backend for backend AI paths.

Share extension changes:

  • Share a new URL and an already-saved URL.
  • Verify duplicate-aware update behavior.
  • Test linkding auto-tags, AI suggestion chips, tag parsing, notes, read-later, and Create Podcast.
  • Confirm the extension works when shared config is missing; current UI shows an "Open Marks first" style failure.

Podcast changes:

  • Generate from bookmark row and Browser view.
  • Start generation while another podcast is playing; confirm background generation does not interrupt playback.
  • Test queue playback, played/unplayed state, delete, sleep timer, saved speed, background audio, remote controls, now-playing metadata, relaunch restore, and widget recent podcasts.
  • Share a URL with Create Podcast and confirm the main app drains and starts the queued request.

Widget/deep-link changes:

  • Confirm widget_bookmarks.json and widget_podcasts.json are refreshed by main-app writes.
  • Test Recent Bookmarks, Random Bookmark, and Recent Podcasts widgets.
  • Tap bookmark and podcast widget entries and verify marks://bookmark and marks://podcast routing in MainContainer.

App Intents changes:

  • Run MarksTests.
  • Test Shortcuts/Siri flows for Add Bookmark, Search, Show Unread, Summarize, and Open Bookmark.
  • Verify entity queries still fetch/resolve bookmarks correctly with a configured linkding server.

Configuration and persistence map

Do not read or document live secret values.

Main app / standard defaults:

  • serverConfig — linkding config saved by ServerConfig.save().
  • marksDeviceId, marksJWT, marksJWTExpiry — Marks backend auth state from MarksAuth.
  • aiData — AI summaries/tags by bookmark ID.
  • aiSummaryByURL — summary mirror used outside the main bookmark array.
  • podcastProgress, podcastPlaybackSpeed, podcastSession — podcast playback state.
  • readingProgress — in-browser reading progress.

App-group defaults/files (group.com.magicive.marks):

  • serverConfig — shared linkding config for extensions.
  • pendingPodcastRequests — share extension to main app podcast queue.
  • podcastAutoTags — tags that auto-enable podcast creation in the share extension.
  • widget_bookmarks.json — recent bookmark widget cache.
  • widget_podcasts.json — recent podcast widget cache.

Application Support files:

  • bookmarks_cache.json or bookmarks_{host}.json — cached bookmarks.
  • podcasts/{hash}.mp3 — generated podcast audio.
  • podcasts/index.json — podcast metadata and played state.

Known caveats and stale-doc risks

  • /Marks/MarksApp.swift contains a built-in default linkding configuration with a token-like value. Treat it as sensitive and consider replacing it with a safer onboarding/configuration flow before distribution.
  • OnboardingView exists but is not the active first-launch path in MarksApp as currently written.
  • Disconnect behavior currently resets via the default config callback path instead of clearly deleting config and returning to onboarding.
  • README AI provider text appears older than source: current backend AI/podcast features go through MarksAuth + ClaudeService, while Ask uses Apple's on-device FoundationModels.
  • MarksAuth stores backend JWT/device state in UserDefaults, not Keychain.
  • App-group ID strings are duplicated in code and entitlements; update all occurrences together if changing it.
  • Share-extension podcast queue draining clears requests before generation success, so crash/retry semantics deserve care.
  • Recent git history shows podcast and on-device AI features were added across many files; avoid narrow changes that ignore cross-target data flow.

Existing design guidance

/docs/design-wwdc26.md is a useful source for UI direction. It emphasizes native iOS 26 UI/Liquid Glass behavior, editorial bookmark rows as the brand canvas, Dynamic Type-safe row layout, bottom/reachable search patterns, WidgetKit app-group data, and standard platform affordances. Link to it rather than duplicating the full design brief.