diff --git a/openspec/changes/legal-disclaimers/.openspec.yaml b/openspec/changes/archive/2026-04-18-legal-disclaimers/.openspec.yaml similarity index 100% rename from openspec/changes/legal-disclaimers/.openspec.yaml rename to openspec/changes/archive/2026-04-18-legal-disclaimers/.openspec.yaml diff --git a/openspec/changes/legal-disclaimers/design.md b/openspec/changes/archive/2026-04-18-legal-disclaimers/design.md similarity index 100% rename from openspec/changes/legal-disclaimers/design.md rename to openspec/changes/archive/2026-04-18-legal-disclaimers/design.md diff --git a/openspec/changes/legal-disclaimers/proposal.md b/openspec/changes/archive/2026-04-18-legal-disclaimers/proposal.md similarity index 100% rename from openspec/changes/legal-disclaimers/proposal.md rename to openspec/changes/archive/2026-04-18-legal-disclaimers/proposal.md diff --git a/openspec/changes/legal-disclaimers/specs/journal-auth/spec.md b/openspec/changes/archive/2026-04-18-legal-disclaimers/specs/journal-auth/spec.md similarity index 100% rename from openspec/changes/legal-disclaimers/specs/journal-auth/spec.md rename to openspec/changes/archive/2026-04-18-legal-disclaimers/specs/journal-auth/spec.md diff --git a/openspec/changes/legal-disclaimers/specs/legal-disclaimers/spec.md b/openspec/changes/archive/2026-04-18-legal-disclaimers/specs/legal-disclaimers/spec.md similarity index 100% rename from openspec/changes/legal-disclaimers/specs/legal-disclaimers/spec.md rename to openspec/changes/archive/2026-04-18-legal-disclaimers/specs/legal-disclaimers/spec.md diff --git a/openspec/changes/legal-disclaimers/tasks.md b/openspec/changes/archive/2026-04-18-legal-disclaimers/tasks.md similarity index 91% rename from openspec/changes/legal-disclaimers/tasks.md rename to openspec/changes/archive/2026-04-18-legal-disclaimers/tasks.md index f82543f..c8bb718 100644 --- a/openspec/changes/legal-disclaimers/tasks.md +++ b/openspec/changes/archive/2026-04-18-legal-disclaimers/tasks.md @@ -40,7 +40,7 @@ ## 7. Review & Publish -- [ ] 7.1 Get the drafted German and English legal text reviewed by a German IT lawyer before treating as final -- [ ] 7.2 Deploy and verify all three legal pages render correctly at their URLs -- [ ] 7.3 Verify registration blocks without acknowledgement and records the timestamp on success -- [ ] 7.4 Verify the alpha banner appears and dismisses correctly +- [x] 7.1 Get the drafted German and English legal text reviewed by a German IT lawyer before treating as final +- [x] 7.2 Deploy and verify all three legal pages render correctly at their URLs +- [x] 7.3 Verify registration blocks without acknowledgement and records the timestamp on success +- [x] 7.4 Verify the alpha banner appears and dismisses correctly diff --git a/openspec/specs/journal-auth/spec.md b/openspec/specs/journal-auth/spec.md index ffd4d34..2b2fb24 100644 --- a/openspec/specs/journal-auth/spec.md +++ b/openspec/specs/journal-auth/spec.md @@ -11,3 +11,19 @@ The journal auth system SHALL store OAuth tokens for external services alongside - **WHEN** a user connects their Wahoo account - **THEN** access token, refresh token, expiry time, and Wahoo user ID are stored in the `wahoo_tokens` table - **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` diff --git a/openspec/specs/legal-disclaimers/spec.md b/openspec/specs/legal-disclaimers/spec.md new file mode 100644 index 0000000..1363e8a --- /dev/null +++ b/openspec/specs/legal-disclaimers/spec.md @@ -0,0 +1,77 @@ +## Purpose + +Legal pages, signup acknowledgement, and alpha-state disclosures required for operating trails.cool under German law (TMG, MStV, GDPR). + +## Requirements + +### Requirement: Impressum page +The Journal SHALL serve an Impressum page at `/legal/imprint` containing the operator's legal information per §5 TMG and §18 MStV. + +#### Scenario: Impressum is accessible +- **WHEN** a user navigates to `/legal/imprint` +- **THEN** they see a page with the operator's full name, postal address, email address, and the responsible person per §18 Abs. 2 MStV + +#### Scenario: Impressum is linked from footer +- **WHEN** a user views any page on the Journal or Planner +- **THEN** the footer contains a link to the Impressum + +### Requirement: Terms of Service page +The Journal SHALL serve a Terms of Service page at `/legal/terms` with clear disclaimers about the service's alpha state. + +#### Scenario: Alpha status disclosure +- **WHEN** a user reads the Terms page +- **THEN** the Terms clearly state that the service is in early development, untested, and may change without notice + +#### Scenario: Database reset disclosure +- **WHEN** a user reads the Terms page +- **THEN** the Terms explicitly state that the operator may delete all user data at any time without prior notice + +#### Scenario: Warranty disclaimer +- **WHEN** a user reads the Terms page +- **THEN** the Terms disclaim all warranties to the extent permitted by German consumer law + +#### Scenario: Data export responsibility +- **WHEN** a user reads the Terms page +- **THEN** the Terms state that the user is responsible for exporting their own data and link to the data export functionality + +### Requirement: Datenschutzerklärung +The Journal SHALL serve a GDPR-compliant privacy policy at `/legal/privacy`, replacing the existing `/privacy` route. + +#### Scenario: Controller contact +- **WHEN** a user reads the Datenschutzerklärung +- **THEN** they see the name, address, and email of the data controller (Verantwortlicher per Art. 4 Nr. 7 DSGVO) + +#### Scenario: Legal basis for processing +- **WHEN** a user reads the Datenschutzerklärung +- **THEN** each category of data processing lists its legal basis (e.g., Art. 6 Abs. 1 lit. b for contract, lit. f for legitimate interest) + +#### Scenario: Data subject rights +- **WHEN** a user reads the Datenschutzerklärung +- **THEN** they see their rights under GDPR: access (Art. 15), rectification (Art. 16), erasure (Art. 17), data portability (Art. 20), objection (Art. 21), and right to lodge a complaint with a supervisory authority + +#### Scenario: Redirect from old privacy URL +- **WHEN** a user navigates to `/privacy` +- **THEN** they are redirected to `/legal/privacy` with a 301 status + +### Requirement: Alpha banner +The Journal SHALL display a persistent banner notifying users that the service is in alpha, dismissible for the browser session. + +#### Scenario: Banner visible on first visit +- **WHEN** a user visits any Journal page for the first time in a session +- **THEN** a banner is shown with text stating trails.cool is in early development and data may be reset, with a link to the Terms + +#### Scenario: Banner dismissible +- **WHEN** a user clicks the dismiss button on the alpha banner +- **THEN** the banner is hidden for the remainder of the browser session (via sessionStorage) +- **AND** the banner reappears in a new session + +### Requirement: Footer legal links +Both the Journal and Planner SHALL render a footer with links to Impressum, Datenschutzerklärung, and Terms. + +#### Scenario: Footer on Journal +- **WHEN** a user views any Journal page +- **THEN** the footer contains links labeled "Impressum", "Privacy", and "Terms" pointing to the respective legal pages + +#### Scenario: Footer on Planner +- **WHEN** a user views any Planner page +- **THEN** the footer contains the same three legal links, pointing to the Journal instance (since the Planner is stateless and legal pages live on the Journal)