Found during the first real device session, and it cost about twenty minutes of confusion.
Open the app fresh and the Status tab reads "Not enrolled yet" — with no button that obviously does anything about it. Nothing enrols on launch: EnrollmentService.validToken() is called lazily, only by sync, lookup, or report. StatusScreen.onAppear just reads local state.
So the actual way to enrol is to tap Sync now, which a first-time user has no reason to guess. The card even says "Enrollment happens automatically the first time you sync or report" — accurate, but it is describing a side effect rather than offering an action.
What to do
Options, roughly in order of preference — worth discussing on the issue before building:
- Give the enrolment card its own primary action ("Set up this device") that triggers enrolment directly.
- Enrol on first launch, in the background, with the card reflecting progress.
- Keep it lazy but make the copy imperative rather than explanatory.
Option 2 is the nicest but has a wrinkle worth thinking about: it makes a network call before the user has asked for anything, which sits slightly awkwardly with a product whose pitch is that it does nothing behind your back. Worth an explicit decision rather than a default.
Where to look
ios/SpamFilter/Screens/StatusScreen.swift — the enrolment card
ios/SpamFilter/ViewModels/SyncStatusViewModel.swift — refresh() / syncNow()
ios/SpamFilter/AppEnvironment.swift — where the lazy validToken() calls are wired
Good first issue: contained to the iOS app, no backend change, and the existing view-model tests give you a place to start.
Found during the first real device session, and it cost about twenty minutes of confusion.
Open the app fresh and the Status tab reads "Not enrolled yet" — with no button that obviously does anything about it. Nothing enrols on launch:
EnrollmentService.validToken()is called lazily, only by sync, lookup, or report.StatusScreen.onAppearjust reads local state.So the actual way to enrol is to tap Sync now, which a first-time user has no reason to guess. The card even says "Enrollment happens automatically the first time you sync or report" — accurate, but it is describing a side effect rather than offering an action.
What to do
Options, roughly in order of preference — worth discussing on the issue before building:
Option 2 is the nicest but has a wrinkle worth thinking about: it makes a network call before the user has asked for anything, which sits slightly awkwardly with a product whose pitch is that it does nothing behind your back. Worth an explicit decision rather than a default.
Where to look
ios/SpamFilter/Screens/StatusScreen.swift— the enrolment cardios/SpamFilter/ViewModels/SyncStatusViewModel.swift—refresh()/syncNow()ios/SpamFilter/AppEnvironment.swift— where the lazyvalidToken()calls are wiredGood first issue: contained to the iOS app, no backend change, and the existing view-model tests give you a place to start.