#297 · Accounts agree to the terms and privacy policy, and it is recorded
- timeline-app
- pull request
Closes #277. ## What's enforced, and where | Path | Before | Now | | --- | --- | --- | | Password registration (`POST /api/auth/register`) | Policies linked, nothing asked | Unticked required box; server requires `acceptTerms` equal to the version in force (400 otherwise); kept on the pending registration and copied to the account at email confirmation | | Google / GitHub / Facebook first sign-in | Account made, no agreement | Same box at its `email` step (`POST /api/auth/email/enroll`), required server-side before the account can ever get a session | | Desktop sign-in | — | Approval happens on the website with a web session, so it's covered by the rows above and below | | Existing accounts, and the bootstrapped first admin | — | `user.termsRequired` in `/api/session`; a panel under the header on every page asks them to agree (`POST /api/auth/terms`) | | API keys | — | Keys made before keep working, so integrations don't stop; creating a new key needs agreement | Until an account agrees, `server/policies.mjs` `requireAgreed` refuses its browser and desktop sessions' changes with **403 and `terms`**, in `server/http.mjs` right after the API-key scope check. These stay allowed: - reads, including the query and search POSTs; - signing out, and the rest of the account's own settings and security under `/api/auth/` (but not creating API keys); - deleting the account or its timelines; - exporting a file, reporting, and asking for a moderation review. ## Recording - `oc_users.terms_version` and `terms_accepted_at`, plus the same pair on `oc_registrations`, are added by idempotent `ALTER TABLE … ADD COLUMN IF NOT EXISTS`. Existing rows are NULL, meaning "not agreed", so current accounts are asked on their next visit. - The version is `POLICY_VERSION = '2026-10-25'`, the policies' effective date. To ask everyone again after a material change, bump it along with `oc_policy_version()` in `schema.sql`. `test/policies.test.mjs` keeps the constant, the SQL function and the "Effective …" line in `legal/TERMS.md` and `legal/PRIVACY.md` equal. - `oc_policy_version()` exists so SQL that makes accounts which already agreed can say so without hardcoding the date. The 67 test inserts and 2 bench inserts now set `terms_version=oc_policy_version()`. The column default stays NULL, so production paths must record agreement explicitly. ## Analytics consent (verified) `platform/components/analytics.jsx` already loads Google's script only after **Allow analytics**. The choice is kept in the browser, and **Analytics settings** reopens it. The browser test already covered: nothing loaded before a choice, decline, settings, allow, and remembered. It now also checks that declining after allowing reloads without the script and stays off. That extra reload made WebKit report a cancelled Next.js prefetch "due to access control checks". `test/next-platform.mjs` now ignores that message, as `drafts-browser.mjs` does (#271/#273). ## Docs - `legal/TERMS.md`, `legal/PRIVACY.md` (records the agreement) and `legal/LAUNCH.md` (the item is marked done). - `docs/authentication.md` (new "Agreeing to the terms" section) and `docs/administration.md`. - The OpenAPI description: `acceptTerms`, `Session.terms`, `SessionUser.termsRequired`, `POST /api/auth/terms` and `Error.terms`. ## Tests - `npm test`: 309 of 309 pass. The new `test/policies.test.mjs` covers the version's consistency, `requireAgreement`, and the allowed and refused routes. - `account-security-postgres`: registration without or with a stale `acceptTerms` is refused, and the recorded version is checked. An account reset to "not agreed" can read but gets 403 `terms` for a write and for creating an API key. A wrong or missing agreement is refused, and agreeing makes writes work again. - `postgres.mjs`: the social account's email step is refused without or with a stale agreement. - `administration-postgres`: the bootstrapped admin is asked and is blocked from settings until it agrees. - `next-postgres`: the panel…
Sources
Open #297 · Accounts agree to the terms and privacy policy, and it is recorded in the timeline