Skip to content

Ask people to agree to the terms when they sign in and again when the terms change - #82

Merged
simonhamp merged 8 commits into
mainfrom
feat/accept-terms
Nov 3, 2026
Merged

simonhamp merged 8 commits into
mainfrom
feat/accept-terms

Conversation

@shanerbaner82

@shanerbaner82 shanerbaner82 commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

What

The sign-in screen has a checkbox, "I agree to the terms of service and privacy policy. There's no tolerance for objectionable content or abusive users.", with links to both pages (dev-null.sh/terms and /privacy, in the app's browser). Sign in with GitHub and Sign in with Apple stay disabled until it's ticked. This is what App Review's guideline 1.2 asks of an app with user-generated content.

The phone sends terms_accepted: true with the sign-in call for both ways in. A sign-in can't start without the tick, so it doesn't read the tick again when the sign-in finishes. devnull records the time, which says which version was in force. The phone no longer carries a version, because a built app can't keep up when the server raises it.

People already signed in now get asked too. When GET /me says terms_accepted: false, the app opens a new screen, like the web's terms dialog: "We updated our terms" (or "Accept our terms" for someone who never accepted any), links to both pages, and Accept the terms, Sign out or Delete account. The app opens on it at launch if the last /me said the terms are owed, and any /me answer that says so sends you there from whatever screen you're on. Accepting sends PUT /me/terms with the version /me named. If the terms changed again while the screen was open, devnull answers 422 and the screen asks /me for the new version.

Account settings has a Terms and privacy section just before Delete account. It links to both pages in the in-app browser and says in one sentence which terms you accepted and when: "You accepted the terms of Nov 1, 2026 on Nov 3, 2026." Each version of the terms goes by the day it took effect. devnull only stores when you accepted, so if that was before the current terms, the sentence says you accepted an earlier version on that day. You'd only see that for a moment, because the new terms screen takes over as soon as /me answers.

Sign out and Delete account moved into a LeavesDevnull concern so the new screen shares them with Settings, and the two page links into OpensLegalPages.

Depends on

dev-null-sh/dev-null.sh#1385, which makes the server take terms_accepted at sign-in. It's merged. Until it's deployed the server ignores the field, so someone who just signed in lands on the new terms screen once and accepts there. Nothing breaks, it's just an extra step.

Verified

Pest passes after merging main (1791, with main's 36 Skia tests skipped). The checkbox was checked in iOS and Android builds earlier. The new screen and the Settings sentence were checked in an iOS 26.2 simulator and an Android 15 emulator against a local devnull with #1385. On both, the screen appears as soon as /me says the terms are owed, and Accept records the time on the server and goes back to the log. On iOS the screen also comes up on a cold launch, and Terms of service opens in the in-app browser. Sign out and Delete account on the new screen were only exercised by the tests, not on a device.

Screenshots

accept-terms

iOS light iOS dark Android light Android dark
After

onboarding

iOS light iOS dark Android light Android dark
Before
After

onboarding-ticked

iOS light iOS dark Android light Android dark
After

settings

iOS light iOS dark Android light Android dark
Before
After

The Sign in with Apple button doesn't show in these builds, so it isn't pictured. It uses the same disabled condition as the other button. The remote row in Settings shows because these builds talk to a local devnull.

🤖 Generated with Claude Code

Neither Sign in with GitHub nor Sign in with Apple works until the box is ticked, and links open the terms and privacy policy in the app's browser. The phone tells devnull which version it showed as it signs in (terms_version), which devnull records.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@simonhamp

Copy link
Copy Markdown
Member

Nice. Just waiting on the API PR to get merged first

@RaphaelFakhri RaphaelFakhri left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GitHub sign-in drops terms_version whenever onboarding is the root screen. In that case AuthCallback replaces /onboarding with a fresh Onboarding, so $acceptedTerms is back to false when finishSignIn() runs from mount(), and redeemSignIn() posts {"code":"c","code_verifier":"..."} with no version. The pop-back path (onResume() on the same instance) does send "terms_version":"2026-10-23", so you only see the bug when the callback arrives as a replace. The existing test "follows the deep link back, redeems the code with the verifier and signs in" also locks this in: it still expects a body without terms_version. Since signIn() and signInWithApple() already refuse to start without the tick, you can send Client::TermsVersion unconditionally in finishSignIn() and useAppleToken(), or carry it on the SignInAttempt.

The branch also conflicts with main in resources/views/native/onboarding.blade.php after #92, and vendor/bin/pint --test flags the double blank lines this PR adds to tests/Pest.php and OnboardingTest.php. CONTRIBUTING.md asks for before and after screenshots on iOS and Android in light and dark mode for this screen.

tests/Feature/Screens/OnboardingTest.php line 209: This asserts the GitHub redeem body without terms_version, which contradicts "sends terms_version with the sign-in call for both ways in". Add 'terms_version' => Client::TermsVersion here once the replace path sends it.

Comment thread app/NativeComponents/Onboarding.php Resolved
simonhamp and others added 4 commits November 2, 2026 13:23
The phone sent a hard-coded terms version and the server refuses anything but the one in force, so the 1 November terms update would have made sign-in fail with a 422, and every later update would do the same to builds already installed. The server now takes a yes (dev-null-sh/dev-null.sh#1385) and works out the version from when it hears.

Both Client methods always send it. A sign-in can't start without the tick, and reading the tick when the sign-in finishes lost it whenever the browser's answer landed on a new onboarding screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	tests/Feature/Screens/OnboardingAppleTest.php
…tings

When devnull says the terms in force haven't been accepted, the app now opens on
a screen that asks for them, like the web's terms dialog. Launch goes straight
there when the last answer said so, and any /me answer that says so sends you
there from whatever screen you're on. Accepting sends the version /me named,
so terms that change again while the screen is open get a 422 and are asked
for again. Sign out and Delete account are the other ways out.

Account settings gets a Terms and privacy section just before Delete account:
links to both pages in the in-app browser, and the version in force beside the
one you agreed to and when. devnull only keeps when you accepted, so an older
version shows as "an older version" rather than a date.

Sign out and delete account move into a LeavesDevnull concern so the new
screen can share them with Settings, and the two page links into
OpensLegalPages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@simonhamp simonhamp changed the title Ask people to agree to the terms and privacy policy before they sign in Ask people to agree to the terms when they sign in and again when the terms change Nov 3, 2026
The current, agreed to and accepted rows put two version names and one
acceptance day side by side, all as dates, and agreed to always matched
current because the terms screen takes over when they differ. One
sentence says it plainly: "You accepted the terms of Nov 1, 2026 on
Nov 3, 2026."

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@simonhamp
simonhamp merged commit a598193 into main Nov 3, 2026
3 checks passed
@simonhamp
simonhamp deleted the feat/accept-terms branch November 3, 2026 19:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants