diff --git a/openspec/specs/legal-disclaimers/spec.md b/openspec/specs/legal-disclaimers/spec.md index 1363e8a..d383972 100644 --- a/openspec/specs/legal-disclaimers/spec.md +++ b/openspec/specs/legal-disclaimers/spec.md @@ -5,7 +5,7 @@ Legal pages, signup acknowledgement, and alpha-state disclosures required for op ## 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. +The Journal SHALL serve an Impressum page at `/legal/imprint` containing the operator's legal information per §5 TMG and §18 MStV, an EU online-dispute-resolution notice, and an English translation. #### Scenario: Impressum is accessible - **WHEN** a user navigates to `/legal/imprint` @@ -15,63 +15,123 @@ The Journal SHALL serve an Impressum page at `/legal/imprint` containing the ope - **WHEN** a user views any page on the Journal or Planner - **THEN** the footer contains a link to the Impressum +#### Scenario: EU ODR notice +- **WHEN** a user reads the Impressum +- **THEN** they see a link to the EU online-dispute-resolution platform (ec.europa.eu/consumers/odr) and a statement that the operator is not willing or obliged to participate in consumer arbitration proceedings + +#### Scenario: English translation +- **WHEN** a user reads the Impressum +- **THEN** an English version of each section is rendered below its German counterpart and the page notes that the German version is authoritative + ### 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. +The Journal SHALL serve a Terms of Service page at `/legal/terms` with disclosures about alpha state, service availability, minimum age, content usage rights, and acceptable use. #### 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 +- **THEN** the Terms clearly state that the service is in early development, currently free of charge, and may change without notice + +#### Scenario: Service availability +- **WHEN** a user reads the Terms page +- **THEN** the Terms state that the operator may modify, limit, interrupt, or discontinue the service or individual accounts at any time #### 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 +#### Scenario: Warranty and liability - **WHEN** a user reads the Terms page -- **THEN** the Terms disclaim all warranties to the extent permitted by German consumer law +- **THEN** the Terms disclaim warranties and tier liability consistent with German law (unlimited for intent / gross negligence / life-body-health; limited-to-foreseeable for cardinal-duty breach under slight negligence; otherwise excluded) #### 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 +- **THEN** the Terms state that the user is responsible for exporting their own data and reference the GPX / JSON export functionality + +#### Scenario: Minimum age for accounts +- **WHEN** a user reads the Terms page +- **THEN** the Terms state that Journal accounts require a minimum age of 16, while anonymous Planner use has no age requirement + +#### Scenario: Content usage rights +- **WHEN** a user reads the Terms page +- **THEN** the Terms state that users retain ownership of their content and grant the operator only a limited, non-transferable licence to store, process, and display that content for the purpose of operating the service + +#### Scenario: Acceptable use +- **WHEN** a user reads the Terms page +- **THEN** the Terms prohibit illegal content, abusive use (spam, flooding, DoS), circumvention of technical protections, and mass automated data extraction + +#### Scenario: English translation +- **WHEN** a user reads the Terms page +- **THEN** each German section has a short English summary, and the page notes that the German version is authoritative ### Requirement: Datenschutzerklärung -The Journal SHALL serve a GDPR-compliant privacy policy at `/legal/privacy`, replacing the existing `/privacy` route. +The Journal SHALL serve a GDPR-compliant privacy policy at `/legal/privacy`, replacing the existing `/privacy` route. It SHALL follow classical GDPR structure with a developer-friendly Privacy Manifest appended at the end. #### 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: Data categories and purposes +- **WHEN** a user reads the Datenschutzerklärung +- **THEN** they see an explicit enumeration of the data categories processed (account data, user content, auth artefacts, Planner session state, server logs, Sentry error data) together with the purpose of each + #### 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) +- **THEN** each category of data processing lists its legal basis (Art. 6 Abs. 1 lit. b for accounts / login / stored content / transactional email; lit. f for server logs, rate-limiting, error monitoring) + +#### Scenario: Terms acceptance is not consent +- **WHEN** a user reads the Datenschutzerklärung +- **THEN** acceptance of the Terms of Service is classified under Art. 6 Abs. 1 lit. b (contract) and NOT under lit. a (consent), and the policy states this explicitly + +#### Scenario: Server logs disclosure +- **WHEN** a user reads the Datenschutzerklärung +- **THEN** a dedicated section describes that HTTP requests are logged (IP address, timestamp, method, path, status code, user-agent), the purpose (security / operations / debugging), the legal basis (Art. 6 Abs. 1 lit. f), and a retention period of at most 14 days + +#### Scenario: Storage durations +- **WHEN** a user reads the Datenschutzerklärung +- **THEN** a list of storage durations is shown covering at minimum: account and user content (until deletion by the user), Planner sessions (≤7 days), magic-link tokens (≤15 minutes), server logs (≤14 days), Sentry events (≤90 days) + +#### Scenario: Alpha reset caveat +- **WHEN** a user reads the storage-durations section +- **THEN** the section notes that during alpha the operator may reset the database or delete individual records, which can cause data loss before a user requests deletion, and points to the Terms of Service + +#### Scenario: Third-party disclosures +- **WHEN** a user reads the Datenschutzerklärung +- **THEN** each third party receives its own entry describing what is transmitted and why, covering at minimum: Sentry (error tracking; sendDefaultPii disabled; no session replays), OpenStreetMap tile servers (browser transmits IP and user-agent directly to OSM), Overpass (queries proxied through the Planner server so upstream only sees our server IP), BRouter (self-hosted, no third party involved), and the SMTP service used for transactional email + +#### Scenario: Third-country transfer note for Sentry +- **WHEN** a user reads the Sentry disclosure +- **THEN** the policy notes that Sentry is a US-based provider and that transfers into a third country within the meaning of Art. 44 ff. DSGVO may occur, with the legal mechanism (Standard Contractual Clauses) named #### 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 +- **THEN** they see their rights under GDPR: access (Art. 15), rectification (Art. 16), erasure (Art. 17), restriction (Art. 18), data portability (Art. 20), objection (Art. 21), and the right to lodge a complaint with a supervisory authority + +#### Scenario: Complaint authority +- **WHEN** a user reads the Datenschutzerklärung +- **THEN** they see the address and website of the Berlin data-protection commissioner as the competent supervisory authority + +#### Scenario: Privacy Manifest appendix +- **WHEN** a user reads the Datenschutzerklärung +- **THEN** a developer-friendly Privacy Manifest follows the formal sections, summarising Planner (no cookies / no localStorage / no sessionStorage / no browser-side Sentry), Journal (what is stored, exportable), Sentry scope by login state, and security practices #### 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. +The Journal SHALL display a persistent, non-dismissable banner on every page notifying users that the service is in alpha and that their data may be reset. -#### 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 +#### Scenario: Banner always visible +- **WHEN** a user views any Journal page at any time during the alpha phase +- **THEN** the alpha banner is rendered with text stating trails.cool is in early development and data may be reset +- **AND** there is no dismiss control; the banner does not use cookies, localStorage, or sessionStorage ### Requirement: Footer legal links -Both the Journal and Planner SHALL render a footer with links to Impressum, Datenschutzerklärung, and Terms. +Both the Journal and Planner SHALL render a footer with links to Impressum, Datenschutzerklärung, Terms of Service, and the source repository. #### 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 +- **THEN** the footer contains links labeled "Impressum", "Privacy", and "Terms" pointing to the respective `/legal/*` pages, plus a link to the source repository #### 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) +- **THEN** the footer contains the same legal links, pointing at absolute URLs on the Journal instance (since the Planner is stateless and legal pages live on the Journal), plus a link to the source repository