Reviewer's follow-up: it's not enough to record when a user accepted the Terms; we also need to record which version of the text they saw. Changes: - journal.users gains a nullable `terms_version` text column (nullable so the three pre-existing users without a version are kept as-is). - New apps/journal/app/lib/legal.ts exports TERMS_VERSION as a single source of truth, reused by the legal pages' "Last updated" header and by the registration flow as the value to send/store. - Registration form posts `termsVersion` alongside `termsAccepted` on all three relevant steps (start, finish, register-magic-link). - API route validates that `termsVersion` is a non-empty string on any step that requires terms, and forwards it to the auth server. - auth.server finishRegistration and registerWithMagicLink now take `termsVersion` and persist it on the users row. - journal-auth spec gets a new scenario for version storage and a rejection scenario for missing version. PRIVACY_LAST_UPDATED is also exported from the same module and used by the Privacy page header, keeping both pages on a single legal.ts source of truth for "last updated" labels. Privacy is not per-user stored — it's informational, not contract. Existing users have NULL terms_version; if we ever prompt them to re-accept updated Terms, we can backfill with the version they re-accept at that point. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1.6 KiB
1.6 KiB
Purpose
Authentication for the Journal app, including OAuth token storage for external services in the sync_connections table.
Requirements
Requirement: Store external service tokens
The journal auth system SHALL store OAuth tokens for external services alongside user credentials.
Scenario: Wahoo token storage
- WHEN a user connects their Wahoo account
- THEN access token, refresh token, expiry time, and Wahoo user ID are stored in the
wahoo_tokenstable - AND tokens are associated with the journal user ID
Requirement: Terms acknowledgement at signup
The registration form SHALL require explicit acknowledgement of the Terms of Service before an account can be created.
Scenario: Checkbox required
- WHEN a user views the registration form
- THEN they see a required checkbox labeled "I have read and agree to the Terms of Service, including that trails.cool is in alpha and my data may be reset"
- AND the checkbox label links to the Terms page
Scenario: Cannot submit without acknowledgement
- WHEN a user attempts to register without checking the acknowledgement box
- THEN the form blocks submission and shows a validation message
Scenario: Acknowledgement recorded
- WHEN a user successfully registers
- THEN the current timestamp is stored in
users.terms_accepted_at - AND the version identifier of the Terms the user saw is stored in
users.terms_version
Scenario: Missing version rejected
- WHEN a registration request arrives without a non-empty
termsVersionfield - THEN the server responds with HTTP 400 and does not create a user