[GH-ISSUE #3] Implement initial configuration and local identity persistence #2

Closed
opened 2026-10-23 18:09:13 +02:00 by jayanezj · 9 comments
Owner

Originally created by @jayanezj on GitHub (Oct 23, 2026).
Original GitHub issue: https://github.com/jayanezj/traccar-client-macos/issues/3

Originally assigned to: @jayanezj on GitHub.

Goal

Let users configure a receiver and either reuse an existing device identifier or generate a stable local identifier.

Scope

  • Reuse Settings for first-run configuration, with Connection, Tracking, General and Diagnostics sections.
  • Default receiver: http://demo.traccar.org:5055. Accept HTTP/HTTPS URLs with IP addresses or domains, optional ports and paths; validate locally without contacting the receiver.
  • Preserve a supplied device identifier. If the field is blank when saving, generate and display an eight-digit random identifier, following the official client reference. Persist it; do not regenerate at launch or per position, derive it from hardware or claim global uniqueness.
  • Store non-sensitive settings in UserDefaults and sensitive material in Keychain. Treat the device identifier as sensitive. Do not register devices through server APIs or request account credentials.
  • Defaults: medium accuracy, 300 seconds, 75 metres, angle and heartbeat disabled, buffering and stationary detection enabled. Login startup and restoration of tracking state are initially disabled.

Acceptance criteria

  • Save preserves settings and identity across relaunch without starting tracking or sending test requests.
  • Existing identifiers are not replaced, numerically coerced or stripped of significant leading zeros.
  • A generated identifier remains visible and reusable; Keychain failures are reported without silent regeneration or plaintext fallback.
  • Invalid receiver URLs cannot be saved as valid configuration; the demo destination is clearly identified.
  • A shared configuration boundary allows pending-position checks before later destination/identity changes.

Validation

Exercise first save, blank/generated and supplied identifiers, restart, malformed URLs and storage failure. Use synthetic identifiers and isolated test preferences/Keychain entries.

Add or extend this feature's meaningful deterministic tests in the CI workflow from PROTO-002 as part of the same implementation, without waiting for the final milestone. Keep physical-Mac checks explicitly manual.

References

Pinned official source references for implementation comparison; mobile APIs are not assumed available on macOS.

Dependencies

Originally created by @jayanezj on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/jayanezj/traccar-client-macos/issues/3 Originally assigned to: @jayanezj on GitHub. ## Goal Let users configure a receiver and either reuse an existing device identifier or generate a stable local identifier. ## Scope - Reuse Settings for first-run configuration, with Connection, Tracking, General and Diagnostics sections. - Default receiver: `http://demo.traccar.org:5055`. Accept HTTP/HTTPS URLs with IP addresses or domains, optional ports and paths; validate locally without contacting the receiver. - Preserve a supplied device identifier. If the field is blank when saving, generate and display an eight-digit random identifier, following the official client reference. Persist it; do not regenerate at launch or per position, derive it from hardware or claim global uniqueness. - Store non-sensitive settings in UserDefaults and sensitive material in Keychain. Treat the device identifier as sensitive. Do not register devices through server APIs or request account credentials. - Defaults: medium accuracy, 300 seconds, 75 metres, angle and heartbeat disabled, buffering and stationary detection enabled. Login startup and restoration of tracking state are initially disabled. ## Acceptance criteria - [x] Save preserves settings and identity across relaunch without starting tracking or sending test requests. - [x] Existing identifiers are not replaced, numerically coerced or stripped of significant leading zeros. - [x] A generated identifier remains visible and reusable; Keychain failures are reported without silent regeneration or plaintext fallback. - [x] Invalid receiver URLs cannot be saved as valid configuration; the demo destination is clearly identified. - [x] A shared configuration boundary allows pending-position checks before later destination/identity changes. ## Validation Exercise first save, blank/generated and supplied identifiers, restart, malformed URLs and storage failure. Use synthetic identifiers and isolated test preferences/Keychain entries. Add or extend this feature's meaningful deterministic tests in the CI workflow from [PROTO-002](https://github.com/jayanezj/traccar-client-macos/issues/2) as part of the same implementation, without waiting for the final milestone. Keep physical-Mac checks explicitly manual. ## References Pinned official source references for implementation comparison; mobile APIs are not assumed available on macOS. - [Official source 1](https://github.com/traccar/traccar-client/blob/c189d52f0bf464d18bebaff48b0fac15fc8cd1e2/lib/preferences.dart) ## Dependencies - [PROTO-001](https://github.com/jayanezj/traccar-client-macos/issues/1) - [PROTO-002](https://github.com/jayanezj/traccar-client-macos/issues/2) <!-- planning-id: PROTO-003 -->
jayanezj added this to the M1 - Foundation and CI milestone 2026-10-23 18:09:13 +02:00
jayanezj added the type:featurearea:storagepriority:high labels 2026-10-23 18:09:13 +02:00
jayanezj added type:feature and removed type:feature labels 2026-10-23 23:01:07 +02:00
Author
Owner

@jayanezj commented on GitHub (Oct 23, 2026):

Implement configuration and local identity persistence on feature/3-configuration-persistence, starting from main after #22. Settings will save a validated HTTP/HTTPS receiver and tracking preferences in UserDefaults, with the device identifier in Keychain. Blank identifiers generate eight random digits only on save; supplied identifiers retain their exact text. Loading or saving will not start tracking, request location or contact the receiver.

Introduce a shared save boundary for future pending-position checks, explicit storage-error handling, and deterministic tests using isolated preferences and synthetic identity storage. Wire the test suite into both CI toolchains and the local validation command. Real Keychain and Settings behaviour remain separate manual/integration checks.

<!-- gh-comment-id:6372567646 --> @jayanezj commented on GitHub (Oct 23, 2026): Implement configuration and local identity persistence on `feature/3-configuration-persistence`, starting from main after #22. Settings will save a validated HTTP/HTTPS receiver and tracking preferences in UserDefaults, with the device identifier in Keychain. Blank identifiers generate eight random digits only on save; supplied identifiers retain their exact text. Loading or saving will not start tracking, request location or contact the receiver. Introduce a shared save boundary for future pending-position checks, explicit storage-error handling, and deterministic tests using isolated preferences and synthetic identity storage. Wire the test suite into both CI toolchains and the local validation command. Real Keychain and Settings behaviour remain separate manual/integration checks.
Author
Owner

@jayanezj commented on GitHub (Oct 23, 2026):

Implemented local configuration in Settings with the agreed receiver, identity and tracking defaults. HTTP/HTTPS validation accepts IP addresses, domains, ports, paths and query parameters without contacting the receiver. Supplied identifiers retain their exact text; blank identifiers generate eight random digits on save and remain visible for reuse.

The receiver URL and identifier share one Keychain item, refining the initial storage split to protect sensitive URL query parameters and keep destination and identity together. Tracking preferences use a versioned UserDefaults record. Storage errors are visible, with no plaintext fallback or silent identity replacement. A shared pre-save guard can reject destination or identity changes before persistence; pending-position coordination will be connected when the queue exists.

Added a hostless Swift Testing target and the shared scripts/test.sh command. Both CI build jobs and scripts/check-local.sh now run configuration tests. The suite uses isolated preferences and synthetic Keychain operations, without launching the app or accessing the login Keychain.

Local validation passed on Xcode 27.1 / macOS 27: strict SwiftLint, Debug and Release builds, 13 tests including parameterized URL cases, arm64/deployment-target checks and ad hoc signature verification. An isolated copy with an intentionally wrong assertion failed with exit 65; the correct suite subsequently passed. Shell syntax, shared scheme and workflow parsing also passed.

Hosted execution on both runners and manual Settings/real-Keychain verification across application relaunch remain pending. README includes the configuration smoke check. Tracking, location permissions and receiver requests remain inactive.

<!-- gh-comment-id:6372854757 --> @jayanezj commented on GitHub (Oct 23, 2026): Implemented local configuration in Settings with the agreed receiver, identity and tracking defaults. HTTP/HTTPS validation accepts IP addresses, domains, ports, paths and query parameters without contacting the receiver. Supplied identifiers retain their exact text; blank identifiers generate eight random digits on save and remain visible for reuse. The receiver URL and identifier share one Keychain item, refining the initial storage split to protect sensitive URL query parameters and keep destination and identity together. Tracking preferences use a versioned UserDefaults record. Storage errors are visible, with no plaintext fallback or silent identity replacement. A shared pre-save guard can reject destination or identity changes before persistence; pending-position coordination will be connected when the queue exists. Added a hostless Swift Testing target and the shared `scripts/test.sh` command. Both CI build jobs and `scripts/check-local.sh` now run configuration tests. The suite uses isolated preferences and synthetic Keychain operations, without launching the app or accessing the login Keychain. Local validation passed on Xcode 27.1 / macOS 27: strict SwiftLint, Debug and Release builds, 13 tests including parameterized URL cases, arm64/deployment-target checks and ad hoc signature verification. An isolated copy with an intentionally wrong assertion failed with exit 65; the correct suite subsequently passed. Shell syntax, shared scheme and workflow parsing also passed. Hosted execution on both runners and manual Settings/real-Keychain verification across application relaunch remain pending. README includes the configuration smoke check. Tracking, location permissions and receiver requests remain inactive.
Author
Owner

@jayanezj commented on GitHub (Oct 23, 2026):

Manually verified configuration saving and persistence in the real Keychain across Quit and relaunch, generated and supplied identifiers (including leading zeros), receiver validation, the demo notice and Settings reopening. The first four acceptance criteria are now supported by the manual checks together with the deterministic storage-failure tests. The fifth is supported by tests showing that the shared connection guard rejects destination/identity changes before writing and skips tracking-only changes.

Keep this issue open while refining window access and Settings presentation: show Dock/Command-Tab presence whenever application windows are open, return to menu-bar-only operation after the last window closes, label the server section “Traccar Server”, make editable fields explicit, add information icons, and dismiss informational status messages after ten seconds. Hosted CI execution remains pending.

<!-- gh-comment-id:6373115755 --> @jayanezj commented on GitHub (Oct 23, 2026): Manually verified configuration saving and persistence in the real Keychain across Quit and relaunch, generated and supplied identifiers (including leading zeros), receiver validation, the demo notice and Settings reopening. The first four acceptance criteria are now supported by the manual checks together with the deterministic storage-failure tests. The fifth is supported by tests showing that the shared connection guard rejects destination/identity changes before writing and skips tracking-only changes. Keep this issue open while refining window access and Settings presentation: show Dock/Command-Tab presence whenever application windows are open, return to menu-bar-only operation after the last window closes, label the server section “Traccar Server”, make editable fields explicit, add information icons, and dismiss informational status messages after ten seconds. Hosted CI execution remains pending.
Author
Owner

@jayanezj commented on GitHub (Oct 23, 2026):

Implemented the Settings refinements: “Traccar Server” heading, explicit labels above bordered connection fields, bordered numeric fields, information/warning icons, and ten-second expiry for loaded/saved status messages. New messages cancel the previous timer; errors remain visible. Three additional deterministic tests cover expiry, timer replacement and error preservation.

Window lifecycle handling now switches between regular application presence while Settings/About windows are open and menu-bar-only operation after the last closes. Open windows remain tracked when minimized or the application is hidden; Dock reopening restores a window. Menu-bar popups do not count as application windows.

Local validation passed: strict SwiftLint, Debug/Release builds, all 16 tests, binary architecture/deployment target and ad hoc signatures. Visual verification of the updated fields, multi-window Dock/Command-Tab behaviour and the status timeout remains pending, along with hosted CI. The existing five acceptance criteria retain their original wording and confirmed evidence.

<!-- gh-comment-id:6373189751 --> @jayanezj commented on GitHub (Oct 23, 2026): Implemented the Settings refinements: “Traccar Server” heading, explicit labels above bordered connection fields, bordered numeric fields, information/warning icons, and ten-second expiry for loaded/saved status messages. New messages cancel the previous timer; errors remain visible. Three additional deterministic tests cover expiry, timer replacement and error preservation. Window lifecycle handling now switches between regular application presence while Settings/About windows are open and menu-bar-only operation after the last closes. Open windows remain tracked when minimized or the application is hidden; Dock reopening restores a window. Menu-bar popups do not count as application windows. Local validation passed: strict SwiftLint, Debug/Release builds, all 16 tests, binary architecture/deployment target and ad hoc signatures. Visual verification of the updated fields, multi-window Dock/Command-Tab behaviour and the status timeout remains pending, along with hosted CI. The existing five acceptance criteria retain their original wording and confirmed evidence.
Author
Owner

@jayanezj commented on GitHub (Oct 23, 2026):

Settings now presents a Keychain explanation before configuration is loaded. Access occurs only after choosing Access Keychain, with explicit Retry loading after failure; reopening Settings does not automatically retry a denied request. Once loaded, configuration remains available during the app session.

errSecUserCanceled (-128) now reports that access was cancelled and stored configuration is unchanged, rather than presenting a failed-save message during loading. No password is collected by the app, no authorization is granted automatically, and there is no fallback or identity replacement. Added tests for deferred initial access, cancelled reads followed by successful retry, and cancelled writes preserving the saved connection and preferences.

Local validation passed: strict SwiftLint, Debug/Release, all 18 tests, arm64/minimum deployment target and ad hoc signature checks. The revised explanation/cancellation flow still needs a manual UI check. Hosted CI remains pending; signing and Keychain access policies are unchanged.

<!-- gh-comment-id:6373393130 --> @jayanezj commented on GitHub (Oct 23, 2026): Settings now presents a Keychain explanation before configuration is loaded. Access occurs only after choosing Access Keychain, with explicit Retry loading after failure; reopening Settings does not automatically retry a denied request. Once loaded, configuration remains available during the app session. errSecUserCanceled (-128) now reports that access was cancelled and stored configuration is unchanged, rather than presenting a failed-save message during loading. No password is collected by the app, no authorization is granted automatically, and there is no fallback or identity replacement. Added tests for deferred initial access, cancelled reads followed by successful retry, and cancelled writes preserving the saved connection and preferences. Local validation passed: strict SwiftLint, Debug/Release, all 18 tests, arm64/minimum deployment target and ad hoc signature checks. The revised explanation/cancellation flow still needs a manual UI check. Hosted CI remains pending; signing and Keychain access policies are unchanged.
Author
Owner

@jayanezj commented on GitHub (Oct 23, 2026):

Settings now attempts a noninteractive load first. Accessible Keychain items and fresh configurations open directly; the authorization explanation appears only when access needs interaction. A denied request is not retried automatically when Settings reopens. The file-based Keychain adapter scopes the legacy interaction setting around a synchronous read and restores the previous value immediately; all application Keychain operations remain serialized on MainActor.

The message footer now reserves a fixed 64-point area and the window has sufficient additional height. Showing or dismissing status therefore does not shrink the form. Visual confirmation of the reported scrollbar case remains pending.

Local validation passed: strict SwiftLint, Debug/Release, all 21 tests, binary architecture/deployment target and ad hoc signature checks. An isolated self-signed development build 101 is prepared and running with a separate bundle identifier and storage service. Its signature verifies and its designated requirement binds the certificate and identifier. First-save and cross-build Keychain continuity are still pending manual verification; production signing and hosted CI are unchanged.

<!-- gh-comment-id:6373744642 --> @jayanezj commented on GitHub (Oct 23, 2026): Settings now attempts a noninteractive load first. Accessible Keychain items and fresh configurations open directly; the authorization explanation appears only when access needs interaction. A denied request is not retried automatically when Settings reopens. The file-based Keychain adapter scopes the legacy interaction setting around a synchronous read and restores the previous value immediately; all application Keychain operations remain serialized on MainActor. The message footer now reserves a fixed 64-point area and the window has sufficient additional height. Showing or dismissing status therefore does not shrink the form. Visual confirmation of the reported scrollbar case remains pending. Local validation passed: strict SwiftLint, Debug/Release, all 21 tests, binary architecture/deployment target and ad hoc signature checks. An isolated self-signed development build 101 is prepared and running with a separate bundle identifier and storage service. Its signature verifies and its designated requirement binds the certificate and identifier. First-save and cross-build Keychain continuity are still pending manual verification; production signing and hosted CI are unchanged.
Author
Owner

@jayanezj commented on GitHub (Oct 23, 2026):

Manually verified isolated build 101: Settings loads directly, configuration saves correctly, and transient messages do not introduce scrolling.

Build 102 is compiled and running at the same application path, signed with the same isolated self-signed certificate and designated requirement. Its CDHash differs from 101, and signature verification plus verification against the 101 requirement both pass. Saved data was not reset. Runtime Keychain continuity without an authorization prompt remains the next manual check.

Launch at login remains disabled and unimplemented; lifecycle/login registration belongs to #11.

<!-- gh-comment-id:6373834926 --> @jayanezj commented on GitHub (Oct 23, 2026): Manually verified isolated build 101: Settings loads directly, configuration saves correctly, and transient messages do not introduce scrolling. Build 102 is compiled and running at the same application path, signed with the same isolated self-signed certificate and designated requirement. Its CDHash differs from 101, and signature verification plus verification against the 101 requirement both pass. Saved data was not reset. Runtime Keychain continuity without an authorization prompt remains the next manual check. Launch at login remains disabled and unimplemented; lifecycle/login registration belongs to #11.
Author
Owner

@jayanezj commented on GitHub (Oct 23, 2026):

The manual 101 → 102 test failed to preserve authorization: Settings correctly detected that interaction was needed, and the system requested the Keychain password. Cancellation produced the expected message, but Settings lost foreground focus.

Read-only inspection of the isolated test item's ACL explains the authorization failure: its partition list contains the 101 CDHash and excludes 102, with no teamid partition. The certificate and designated requirement match and signature checks pass, but those facts do not satisfy this additional Keychain policy. Self-signing alone therefore does not meet the no-prompt update objective on this Mac. No ACLs, trust settings or stored values were changed.

Settings now restores the initiating window after explicit load/save operations return from SecurityAgent, including cancellation. Restoration is deferred until the modal call unwinds, uses a weak window reference, and skips closed/minimized windows. Automatic loading does not activate windows. Strict lint, Debug/Release, all 21 tests and binary/signature checks pass; visual focus verification remains pending. The existing running 102 does not contain this new fix.

<!-- gh-comment-id:6373982417 --> @jayanezj commented on GitHub (Oct 23, 2026): The manual 101 → 102 test failed to preserve authorization: Settings correctly detected that interaction was needed, and the system requested the Keychain password. Cancellation produced the expected message, but Settings lost foreground focus. Read-only inspection of the isolated test item's ACL explains the authorization failure: its partition list contains the 101 CDHash and excludes 102, with no teamid partition. The certificate and designated requirement match and signature checks pass, but those facts do not satisfy this additional Keychain policy. Self-signing alone therefore does not meet the no-prompt update objective on this Mac. No ACLs, trust settings or stored values were changed. Settings now restores the initiating window after explicit load/save operations return from SecurityAgent, including cancellation. Restoration is deferred until the modal call unwinds, uses a weak window reference, and skips closed/minimized windows. Automatic loading does not activate windows. Strict lint, Debug/Release, all 21 tests and binary/signature checks pass; visual focus verification remains pending. The existing running 102 does not contain this new fix.
jayanezj added priority:high and removed priority:high labels 2026-10-25 11:00:17 +01:00
Author
Owner

@jayanezj commented on GitHub (Oct 25, 2026):

Final implementation decisions and validation for #3:

  • Settings saves a locally validated HTTP/HTTPS receiver and an exact supplied device identifier, or generates eight random digits on save when blank. The receiver URL and identifier share one Keychain item; tracking preferences use a versioned UserDefaults record. Loading and saving never start tracking, request location or contact a receiver.
  • Accessible or empty storage loads directly. The authorization explanation appears only when Keychain requires interaction. Cancellation preserves stored data and requires an explicit retry, with no plaintext fallback or silent identity replacement.
  • Settings uses explicit bordered fields, the “Traccar Server” heading and information/warning icons. Informational messages expire after ten seconds in a fixed footer; errors remain visible. Dock and Command-Tab presence follow open application windows. Focus returns to the initiating Settings window after explicit Keychain operations.
  • Free Apple Development signing is adopted for local app builds and future distribution candidates, with the Personal Team/certificate selected in an ignored local configuration file. Ordinary CI explicitly uses ad hoc signing for compilation and deterministic tests, including fork PRs; no Apple account or private signing key is exposed to those jobs. Protected release signing and downloaded-DMG/Gatekeeper validation remain in #17 and #16.
  • Keychain continuity across builds signed with the same Apple Development certificate is manually verified. Continuity after certificate renewal remains an assumption, not a verified guarantee.
  • A shared pre-save boundary supports future pending-position checks before changing destination or identity; queue integration remains outside this issue.

Local validation passed: strict SwiftLint, Debug/Release, 26 tests, arm64/macOS 15.0 deployment-target checks and Apple Development signatures. A separate working copy without local signing configuration also passed Debug/Release, all 26 tests and explicit ad hoc verification. Opposite signature modes are rejected.

Manually verified configuration/identity persistence across relaunch, Keychain cancellation and retry, focus retention after two denials, and the complete Settings/Dock/Command-Tab/About/status-message regression. The five existing acceptance criteria retain their wording and confirmed evidence. Hosted CI on both toolchains remains the integration gate; physical macOS 15 distribution coverage is separate.

<!-- gh-comment-id:6396087703 --> @jayanezj commented on GitHub (Oct 25, 2026): Final implementation decisions and validation for #3: - Settings saves a locally validated HTTP/HTTPS receiver and an exact supplied device identifier, or generates eight random digits on save when blank. The receiver URL and identifier share one Keychain item; tracking preferences use a versioned UserDefaults record. Loading and saving never start tracking, request location or contact a receiver. - Accessible or empty storage loads directly. The authorization explanation appears only when Keychain requires interaction. Cancellation preserves stored data and requires an explicit retry, with no plaintext fallback or silent identity replacement. - Settings uses explicit bordered fields, the “Traccar Server” heading and information/warning icons. Informational messages expire after ten seconds in a fixed footer; errors remain visible. Dock and Command-Tab presence follow open application windows. Focus returns to the initiating Settings window after explicit Keychain operations. - Free Apple Development signing is adopted for local app builds and future distribution candidates, with the Personal Team/certificate selected in an ignored local configuration file. Ordinary CI explicitly uses ad hoc signing for compilation and deterministic tests, including fork PRs; no Apple account or private signing key is exposed to those jobs. Protected release signing and downloaded-DMG/Gatekeeper validation remain in #17 and #16. - Keychain continuity across builds signed with the same Apple Development certificate is manually verified. Continuity after certificate renewal remains an assumption, not a verified guarantee. - A shared pre-save boundary supports future pending-position checks before changing destination or identity; queue integration remains outside this issue. Local validation passed: strict SwiftLint, Debug/Release, 26 tests, arm64/macOS 15.0 deployment-target checks and Apple Development signatures. A separate working copy without local signing configuration also passed Debug/Release, all 26 tests and explicit ad hoc verification. Opposite signature modes are rejected. Manually verified configuration/identity persistence across relaunch, Keychain cancellation and retry, focus retention after two denials, and the complete Settings/Dock/Command-Tab/About/status-message regression. The five existing acceptance criteria retain their wording and confirmed evidence. Hosted CI on both toolchains remains the integration gate; physical macOS 15 distribution coverage is separate.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jayanezj/traccar-client-macos#2