Barazo default frontend barazo.forum
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(legal): add privacy, terms, and cookie policy pages (#28)

Static legal pages required for GDPR compliance per decisions/legal.md.
Privacy policy covers data collection, GDPR rights, and breach notification.
Terms of service covers eligibility (16+), content rules, AI summaries, and labels.
Cookie policy documents the single HTTP-only refresh token cookie.
Footer updated to include cookies link alongside existing privacy and terms links.

authored by

Guido X Jansen and committed by
GitHub
05c97f5a 13dd73b8

+726
+79
src/app/legal/cookies/page.test.tsx
··· 1 + /** 2 + * Tests for cookie policy page. 3 + * @see decisions/legal.md 4 + */ 5 + 6 + import { describe, it, expect, vi } from 'vitest' 7 + import { render, screen } from '@testing-library/react' 8 + import { axe } from 'vitest-axe' 9 + import CookiePolicyPage from './page' 10 + 11 + // Mock next/navigation 12 + vi.mock('next/navigation', () => ({ 13 + usePathname: () => '/legal/cookies', 14 + useRouter: () => ({ push: vi.fn() }), 15 + })) 16 + 17 + // Mock next-themes 18 + vi.mock('next-themes', () => ({ 19 + useTheme: () => ({ theme: 'dark', setTheme: vi.fn() }), 20 + ThemeProvider: ({ children }: { children: React.ReactNode }) => children, 21 + })) 22 + 23 + // Mock useAuth hook 24 + vi.mock('@/hooks/use-auth', () => ({ 25 + useAuth: () => ({ 26 + user: null, 27 + isAuthenticated: false, 28 + isLoading: false, 29 + getAccessToken: () => null, 30 + login: vi.fn(), 31 + logout: vi.fn(), 32 + setSessionFromCallback: vi.fn(), 33 + authFetch: vi.fn(), 34 + }), 35 + })) 36 + 37 + describe('CookiePolicyPage', () => { 38 + it('renders page heading', () => { 39 + render(<CookiePolicyPage />) 40 + expect(screen.getByRole('heading', { name: /cookie policy/i, level: 1 })).toBeInTheDocument() 41 + }) 42 + 43 + it('describes the single essential cookie', () => { 44 + render(<CookiePolicyPage />) 45 + expect(screen.getByRole('heading', { name: /cookies we use/i })).toBeInTheDocument() 46 + // Table shows the refresh token cookie details 47 + expect(screen.getByRole('table')).toBeInTheDocument() 48 + expect(screen.getByText('Refresh token')).toBeInTheDocument() 49 + }) 50 + 51 + it('lists cookie security properties', () => { 52 + render(<CookiePolicyPage />) 53 + expect(screen.getByText(/HTTP-only/i)).toBeInTheDocument() 54 + expect(screen.getByText(/SameSite=Strict/i)).toBeInTheDocument() 55 + }) 56 + 57 + it('states no tracking cookies are used', () => { 58 + render(<CookiePolicyPage />) 59 + expect(screen.getByRole('heading', { name: /what we do not use/i })).toBeInTheDocument() 60 + expect(screen.getByText(/no tracking or advertising cookies/i)).toBeInTheDocument() 61 + }) 62 + 63 + it('explains cookie consent exemption', () => { 64 + render(<CookiePolicyPage />) 65 + expect(screen.getByRole('heading', { name: /cookie consent/i })).toBeInTheDocument() 66 + expect(screen.getByText(/ePrivacy Directive/i)).toBeInTheDocument() 67 + }) 68 + 69 + it('renders breadcrumbs', () => { 70 + render(<CookiePolicyPage />) 71 + expect(screen.getByText('Home')).toBeInTheDocument() 72 + }) 73 + 74 + it('passes axe accessibility check', async () => { 75 + const { container } = render(<CookiePolicyPage />) 76 + const results = await axe(container) 77 + expect(results).toHaveNoViolations() 78 + }) 79 + })
+127
src/app/legal/cookies/page.tsx
··· 1 + /** 2 + * Cookie policy page. 3 + * URL: /legal/cookies 4 + * Static placeholder content -- admin-editable in P3+. 5 + * @see decisions/legal.md 6 + */ 7 + 8 + import type { Metadata } from 'next' 9 + import { ForumLayout } from '@/components/layout/forum-layout' 10 + import { Breadcrumbs } from '@/components/breadcrumbs' 11 + 12 + export const metadata: Metadata = { 13 + title: 'Cookie Policy', 14 + description: 15 + 'How Barazo uses cookies. We use a single essential cookie for authentication -- no tracking or analytics cookies.', 16 + alternates: { 17 + canonical: '/legal/cookies', 18 + }, 19 + } 20 + 21 + export default function CookiePolicyPage() { 22 + return ( 23 + <ForumLayout> 24 + <div className="mx-auto max-w-2xl space-y-8"> 25 + <Breadcrumbs items={[{ label: 'Home', href: '/' }, { label: 'Cookie Policy' }]} /> 26 + 27 + <h1 className="text-2xl font-bold text-foreground">Cookie Policy</h1> 28 + 29 + <section className="space-y-3"> 30 + <h2 className="text-lg font-semibold text-foreground">Overview</h2> 31 + <p className="text-sm leading-relaxed text-muted-foreground"> 32 + Barazo uses a minimal number of cookies. We do not use tracking cookies, advertising 33 + cookies, or third-party analytics cookies. This page explains the cookies we do use and 34 + why. 35 + </p> 36 + </section> 37 + 38 + <section className="space-y-3"> 39 + <h2 className="text-lg font-semibold text-foreground">Cookies We Use</h2> 40 + <p className="text-sm leading-relaxed text-muted-foreground"> 41 + Barazo uses a single essential cookie: 42 + </p> 43 + <div className="overflow-x-auto"> 44 + <table className="w-full text-sm text-muted-foreground"> 45 + <thead> 46 + <tr className="border-b border-border text-left"> 47 + <th className="pb-2 pr-4 font-semibold text-foreground">Cookie</th> 48 + <th className="pb-2 pr-4 font-semibold text-foreground">Purpose</th> 49 + <th className="pb-2 pr-4 font-semibold text-foreground">Duration</th> 50 + <th className="pb-2 font-semibold text-foreground">Type</th> 51 + </tr> 52 + </thead> 53 + <tbody> 54 + <tr className="border-b border-border/50"> 55 + <td className="py-2 pr-4">Refresh token</td> 56 + <td className="py-2 pr-4"> 57 + Keeps you logged in across page reloads by enabling silent access token renewal. 58 + </td> 59 + <td className="py-2 pr-4">Session</td> 60 + <td className="py-2">Essential</td> 61 + </tr> 62 + </tbody> 63 + </table> 64 + </div> 65 + </section> 66 + 67 + <section className="space-y-3"> 68 + <h2 className="text-lg font-semibold text-foreground">Technical Details</h2> 69 + <p className="text-sm leading-relaxed text-muted-foreground"> 70 + The refresh token cookie has the following security properties: 71 + </p> 72 + <ul className="list-inside list-disc space-y-2 text-sm text-muted-foreground"> 73 + <li> 74 + <strong>HTTP-only</strong> -- the cookie is not accessible to JavaScript, preventing 75 + cross-site scripting (XSS) attacks. 76 + </li> 77 + <li> 78 + <strong>Secure</strong> -- the cookie is only sent over HTTPS connections. 79 + </li> 80 + <li> 81 + <strong>SameSite=Strict</strong> -- the cookie is not sent with cross-site requests, 82 + preventing cross-site request forgery (CSRF) attacks. 83 + </li> 84 + </ul> 85 + <p className="text-sm leading-relaxed text-muted-foreground"> 86 + Access tokens (used to authenticate API requests) are held in memory only and are never 87 + stored in cookies, localStorage, or sessionStorage. 88 + </p> 89 + </section> 90 + 91 + <section className="space-y-3"> 92 + <h2 className="text-lg font-semibold text-foreground">What We Do Not Use</h2> 93 + <ul className="list-inside list-disc space-y-2 text-sm text-muted-foreground"> 94 + <li>No tracking or advertising cookies.</li> 95 + <li>No third-party analytics (Google Analytics, etc.).</li> 96 + <li>No social media tracking pixels.</li> 97 + <li>No fingerprinting or behavioral profiling.</li> 98 + </ul> 99 + </section> 100 + 101 + <section className="space-y-3"> 102 + <h2 className="text-lg font-semibold text-foreground">Cookie Consent</h2> 103 + <p className="text-sm leading-relaxed text-muted-foreground"> 104 + Because we only use a single essential cookie required for the service to function, a 105 + cookie consent banner is not required under the ePrivacy Directive (EU Directive 106 + 2002/58/EC, Art. 5(3)). Essential cookies that are strictly necessary for the service 107 + requested by the user are exempt from the consent requirement. 108 + </p> 109 + </section> 110 + 111 + <section className="space-y-3"> 112 + <h2 className="text-lg font-semibold text-foreground">Theme Preference</h2> 113 + <p className="text-sm leading-relaxed text-muted-foreground"> 114 + Your light/dark mode preference is stored in localStorage (not a cookie). This is a 115 + client-side preference that is never sent to our servers. 116 + </p> 117 + </section> 118 + 119 + <section className="space-y-3"> 120 + <p className="text-xs text-muted-foreground"> 121 + This policy was last updated on February 2026. 122 + </p> 123 + </section> 124 + </div> 125 + </ForumLayout> 126 + ) 127 + }
+75
src/app/legal/privacy/page.test.tsx
··· 1 + /** 2 + * Tests for privacy policy page. 3 + * @see decisions/legal.md 4 + */ 5 + 6 + import { describe, it, expect, vi } from 'vitest' 7 + import { render, screen } from '@testing-library/react' 8 + import { axe } from 'vitest-axe' 9 + import PrivacyPolicyPage from './page' 10 + 11 + // Mock next/navigation 12 + vi.mock('next/navigation', () => ({ 13 + usePathname: () => '/legal/privacy', 14 + useRouter: () => ({ push: vi.fn() }), 15 + })) 16 + 17 + // Mock next-themes 18 + vi.mock('next-themes', () => ({ 19 + useTheme: () => ({ theme: 'dark', setTheme: vi.fn() }), 20 + ThemeProvider: ({ children }: { children: React.ReactNode }) => children, 21 + })) 22 + 23 + // Mock useAuth hook 24 + vi.mock('@/hooks/use-auth', () => ({ 25 + useAuth: () => ({ 26 + user: null, 27 + isAuthenticated: false, 28 + isLoading: false, 29 + getAccessToken: () => null, 30 + login: vi.fn(), 31 + logout: vi.fn(), 32 + setSessionFromCallback: vi.fn(), 33 + authFetch: vi.fn(), 34 + }), 35 + })) 36 + 37 + describe('PrivacyPolicyPage', () => { 38 + it('renders page heading', () => { 39 + render(<PrivacyPolicyPage />) 40 + expect(screen.getByRole('heading', { name: /privacy policy/i, level: 1 })).toBeInTheDocument() 41 + }) 42 + 43 + it('describes what data is collected', () => { 44 + render(<PrivacyPolicyPage />) 45 + expect(screen.getByRole('heading', { name: /what we collect/i })).toBeInTheDocument() 46 + expect(screen.getByText(/AT Protocol identifiers/i)).toBeInTheDocument() 47 + }) 48 + 49 + it('describes what data is not collected', () => { 50 + render(<PrivacyPolicyPage />) 51 + expect(screen.getByRole('heading', { name: /what we do not collect/i })).toBeInTheDocument() 52 + }) 53 + 54 + it('lists user rights under GDPR', () => { 55 + render(<PrivacyPolicyPage />) 56 + expect(screen.getByRole('heading', { name: /your rights/i })).toBeInTheDocument() 57 + expect(screen.getByText(/right to be forgotten/i)).toBeInTheDocument() 58 + }) 59 + 60 + it('mentions GDPR compliance', () => { 61 + render(<PrivacyPolicyPage />) 62 + expect(screen.getByText(/General Data Protection Regulation/i)).toBeInTheDocument() 63 + }) 64 + 65 + it('renders breadcrumbs', () => { 66 + render(<PrivacyPolicyPage />) 67 + expect(screen.getByText('Home')).toBeInTheDocument() 68 + }) 69 + 70 + it('passes axe accessibility check', async () => { 71 + const { container } = render(<PrivacyPolicyPage />) 72 + const results = await axe(container) 73 + expect(results).toHaveNoViolations() 74 + }) 75 + })
+196
src/app/legal/privacy/page.tsx
··· 1 + /** 2 + * Privacy policy page. 3 + * URL: /legal/privacy 4 + * Static placeholder content -- admin-editable in P3+. 5 + * @see decisions/legal.md 6 + */ 7 + 8 + import type { Metadata } from 'next' 9 + import { ForumLayout } from '@/components/layout/forum-layout' 10 + import { Breadcrumbs } from '@/components/breadcrumbs' 11 + 12 + export const metadata: Metadata = { 13 + title: 'Privacy Policy', 14 + description: 15 + 'How Barazo collects, uses, and protects your personal data. GDPR-compliant privacy policy.', 16 + alternates: { 17 + canonical: '/legal/privacy', 18 + }, 19 + } 20 + 21 + export default function PrivacyPolicyPage() { 22 + return ( 23 + <ForumLayout> 24 + <div className="mx-auto max-w-2xl space-y-8"> 25 + <Breadcrumbs items={[{ label: 'Home', href: '/' }, { label: 'Privacy Policy' }]} /> 26 + 27 + <h1 className="text-2xl font-bold text-foreground">Privacy Policy</h1> 28 + 29 + <section className="space-y-3"> 30 + <h2 className="text-lg font-semibold text-foreground">Overview</h2> 31 + <p className="text-sm leading-relaxed text-muted-foreground"> 32 + Barazo is committed to protecting your privacy. This policy explains what personal data 33 + we collect, why we collect it, how long we keep it, and what rights you have. Barazo is 34 + operated from the Netherlands and complies with the General Data Protection Regulation 35 + (GDPR). 36 + </p> 37 + </section> 38 + 39 + <section className="space-y-3"> 40 + <h2 className="text-lg font-semibold text-foreground">What We Collect</h2> 41 + <p className="text-sm leading-relaxed text-muted-foreground"> 42 + When you use Barazo, we process the following data: 43 + </p> 44 + <ul className="list-inside list-disc space-y-2 text-sm text-muted-foreground"> 45 + <li> 46 + <strong>AT Protocol identifiers</strong> -- your DID (decentralized identifier) and 47 + handle, used to identify your account. 48 + </li> 49 + <li> 50 + <strong>Profile information</strong> -- display name and profile data retrieved from 51 + your AT Protocol PDS. 52 + </li> 53 + <li> 54 + <strong>Content</strong> -- posts, replies, and reactions you create on the forum, 55 + indexed from the AT Protocol firehose. 56 + </li> 57 + <li> 58 + <strong>IP addresses</strong> -- collected for API rate limiting and security 59 + purposes. 60 + </li> 61 + <li> 62 + <strong>Session data</strong> -- OAuth tokens for authentication. 63 + </li> 64 + <li> 65 + <strong>Moderation records</strong> -- actions taken by moderators on your content or 66 + account. 67 + </li> 68 + </ul> 69 + </section> 70 + 71 + <section className="space-y-3"> 72 + <h2 className="text-lg font-semibold text-foreground">What We Do Not Collect</h2> 73 + <ul className="list-inside list-disc space-y-2 text-sm text-muted-foreground"> 74 + <li> 75 + We do not collect or store your password (authentication is handled via AT Protocol 76 + OAuth). 77 + </li> 78 + <li> 79 + We do not collect email addresses unless provided by a community admin for billing. 80 + </li> 81 + <li>We do not collect payment card details (processed by our payment provider).</li> 82 + <li>We do not use tracking cookies or analytics that profile your behavior.</li> 83 + </ul> 84 + </section> 85 + 86 + <section className="space-y-3"> 87 + <h2 className="text-lg font-semibold text-foreground">Legal Basis</h2> 88 + <p className="text-sm leading-relaxed text-muted-foreground"> 89 + We process your data under the following legal bases (GDPR Art. 6): 90 + </p> 91 + <ul className="list-inside list-disc space-y-2 text-sm text-muted-foreground"> 92 + <li> 93 + <strong>Contract performance</strong> -- processing necessary to provide the forum 94 + service you signed up for. 95 + </li> 96 + <li> 97 + <strong>Legitimate interest</strong> -- indexing public AT Protocol content, spam 98 + prevention, platform security, and moderation. 99 + </li> 100 + </ul> 101 + </section> 102 + 103 + <section className="space-y-3"> 104 + <h2 className="text-lg font-semibold text-foreground">Data Storage and Transfers</h2> 105 + <p className="text-sm leading-relaxed text-muted-foreground"> 106 + Our servers are hosted in the European Union (Hetzner, Germany). We use the following 107 + sub-processors: 108 + </p> 109 + <ul className="list-inside list-disc space-y-2 text-sm text-muted-foreground"> 110 + <li>Hetzner (EU) -- hosting infrastructure.</li> 111 + <li>Bunny.net (EU, Slovenia) -- content delivery network.</li> 112 + <li>Stripe (EU-US Data Privacy Framework certified) -- payment processing.</li> 113 + </ul> 114 + <p className="text-sm leading-relaxed text-muted-foreground"> 115 + A full sub-processor list is maintained at{' '} 116 + <strong>barazo.forum/legal/sub-processors</strong>. 117 + </p> 118 + </section> 119 + 120 + <section className="space-y-3"> 121 + <h2 className="text-lg font-semibold text-foreground">Data Retention and Deletion</h2> 122 + <p className="text-sm leading-relaxed text-muted-foreground"> 123 + Your indexed data is retained while the source exists on your AT Protocol PDS. When you 124 + delete content or your account via the AT Protocol, we process the deletion event and 125 + remove the indexed data from our systems. 126 + </p> 127 + <p className="text-sm leading-relaxed text-muted-foreground"> 128 + You may also request deletion directly by contacting us, independent of AT Protocol 129 + signals. We respond to deletion requests within one month (GDPR Art. 12(3)). 130 + </p> 131 + <p className="text-sm leading-relaxed text-muted-foreground"> 132 + Please note that Barazo cannot guarantee deletion from external systems such as AT 133 + Protocol relays, other AppViews, search engine caches, or web archives. We take 134 + reasonable steps including propagating AT Protocol delete events and requesting removal 135 + from search engines. 136 + </p> 137 + </section> 138 + 139 + <section className="space-y-3"> 140 + <h2 className="text-lg font-semibold text-foreground">Content Labels</h2> 141 + <p className="text-sm leading-relaxed text-muted-foreground"> 142 + We subscribe to content labeling services (such as Bluesky&apos;s Ozone) for spam 143 + detection and content moderation. Labels applied to your account may affect posting 144 + limits and content visibility. Labels are stored by the labeler service, not on your 145 + PDS. You can dispute labels by contacting us. 146 + </p> 147 + </section> 148 + 149 + <section className="space-y-3"> 150 + <h2 className="text-lg font-semibold text-foreground">Your Rights</h2> 151 + <p className="text-sm leading-relaxed text-muted-foreground"> 152 + Under the GDPR, you have the right to: 153 + </p> 154 + <ul className="list-inside list-disc space-y-2 text-sm text-muted-foreground"> 155 + <li>Access the personal data we hold about you.</li> 156 + <li>Rectify inaccurate data.</li> 157 + <li>Request erasure of your data (right to be forgotten).</li> 158 + <li>Object to processing based on legitimate interest.</li> 159 + <li>Data portability (built into the AT Protocol).</li> 160 + <li> 161 + Lodge a complaint with the Dutch Data Protection Authority (Autoriteit 162 + Persoonsgegevens). 163 + </li> 164 + </ul> 165 + <p className="text-sm leading-relaxed text-muted-foreground"> 166 + To exercise these rights, contact us through our{' '} 167 + <a 168 + href="https://github.com/barazo-forum/barazo-web/issues" 169 + className="text-primary underline hover:text-primary/80" 170 + target="_blank" 171 + rel="noopener noreferrer" 172 + > 173 + GitHub issue tracker 174 + </a>{' '} 175 + or via the contact details provided by your community administrator. 176 + </p> 177 + </section> 178 + 179 + <section className="space-y-3"> 180 + <h2 className="text-lg font-semibold text-foreground">Data Breach Notification</h2> 181 + <p className="text-sm leading-relaxed text-muted-foreground"> 182 + In the event of a data breach, we will notify the Dutch Data Protection Authority within 183 + 72 hours (GDPR Art. 33). For high-risk breaches, we will notify affected users without 184 + undue delay via AT Protocol notifications and public announcements. 185 + </p> 186 + </section> 187 + 188 + <section className="space-y-3"> 189 + <p className="text-xs text-muted-foreground"> 190 + This policy was last updated on February 2026. 191 + </p> 192 + </section> 193 + </div> 194 + </ForumLayout> 195 + ) 196 + }
+79
src/app/legal/terms/page.test.tsx
··· 1 + /** 2 + * Tests for terms of service page. 3 + * @see decisions/legal.md 4 + */ 5 + 6 + import { describe, it, expect, vi } from 'vitest' 7 + import { render, screen } from '@testing-library/react' 8 + import { axe } from 'vitest-axe' 9 + import TermsOfServicePage from './page' 10 + 11 + // Mock next/navigation 12 + vi.mock('next/navigation', () => ({ 13 + usePathname: () => '/legal/terms', 14 + useRouter: () => ({ push: vi.fn() }), 15 + })) 16 + 17 + // Mock next-themes 18 + vi.mock('next-themes', () => ({ 19 + useTheme: () => ({ theme: 'dark', setTheme: vi.fn() }), 20 + ThemeProvider: ({ children }: { children: React.ReactNode }) => children, 21 + })) 22 + 23 + // Mock useAuth hook 24 + vi.mock('@/hooks/use-auth', () => ({ 25 + useAuth: () => ({ 26 + user: null, 27 + isAuthenticated: false, 28 + isLoading: false, 29 + getAccessToken: () => null, 30 + login: vi.fn(), 31 + logout: vi.fn(), 32 + setSessionFromCallback: vi.fn(), 33 + authFetch: vi.fn(), 34 + }), 35 + })) 36 + 37 + describe('TermsOfServicePage', () => { 38 + it('renders page heading', () => { 39 + render(<TermsOfServicePage />) 40 + expect(screen.getByRole('heading', { name: /terms of service/i, level: 1 })).toBeInTheDocument() 41 + }) 42 + 43 + it('states minimum age requirement', () => { 44 + render(<TermsOfServicePage />) 45 + expect(screen.getByText(/at least 16 years old/i)).toBeInTheDocument() 46 + }) 47 + 48 + it('covers content and conduct rules', () => { 49 + render(<TermsOfServicePage />) 50 + expect(screen.getByRole('heading', { name: /content and conduct/i })).toBeInTheDocument() 51 + }) 52 + 53 + it('discloses AI summary behavior', () => { 54 + render(<TermsOfServicePage />) 55 + expect(screen.getByRole('heading', { name: /ai-generated summaries/i })).toBeInTheDocument() 56 + expect(screen.getByText(/summaries may persist/i)).toBeInTheDocument() 57 + }) 58 + 59 + it('discloses moderation labels', () => { 60 + render(<TermsOfServicePage />) 61 + expect(screen.getByRole('heading', { name: /moderation and labels/i })).toBeInTheDocument() 62 + }) 63 + 64 + it('specifies governing law', () => { 65 + render(<TermsOfServicePage />) 66 + expect(screen.getByText(/laws of the Netherlands/i)).toBeInTheDocument() 67 + }) 68 + 69 + it('renders breadcrumbs', () => { 70 + render(<TermsOfServicePage />) 71 + expect(screen.getByText('Home')).toBeInTheDocument() 72 + }) 73 + 74 + it('passes axe accessibility check', async () => { 75 + const { container } = render(<TermsOfServicePage />) 76 + const results = await axe(container) 77 + expect(results).toHaveNoViolations() 78 + }) 79 + })
+165
src/app/legal/terms/page.tsx
··· 1 + /** 2 + * Terms of service page. 3 + * URL: /legal/terms 4 + * Static placeholder content -- admin-editable in P3+. 5 + * @see decisions/legal.md 6 + */ 7 + 8 + import type { Metadata } from 'next' 9 + import { ForumLayout } from '@/components/layout/forum-layout' 10 + import { Breadcrumbs } from '@/components/breadcrumbs' 11 + 12 + export const metadata: Metadata = { 13 + title: 'Terms of Service', 14 + description: 15 + 'Terms and conditions for using Barazo forum communities. Covers usage rules, content policies, and user responsibilities.', 16 + alternates: { 17 + canonical: '/legal/terms', 18 + }, 19 + } 20 + 21 + export default function TermsOfServicePage() { 22 + return ( 23 + <ForumLayout> 24 + <div className="mx-auto max-w-2xl space-y-8"> 25 + <Breadcrumbs items={[{ label: 'Home', href: '/' }, { label: 'Terms of Service' }]} /> 26 + 27 + <h1 className="text-2xl font-bold text-foreground">Terms of Service</h1> 28 + 29 + <section className="space-y-3"> 30 + <h2 className="text-lg font-semibold text-foreground">Acceptance of Terms</h2> 31 + <p className="text-sm leading-relaxed text-muted-foreground"> 32 + By accessing or using Barazo, you agree to be bound by these Terms of Service. If you do 33 + not agree to these terms, you may not use the service. Barazo reserves the right to 34 + update these terms at any time, with notice provided through the platform. 35 + </p> 36 + </section> 37 + 38 + <section className="space-y-3"> 39 + <h2 className="text-lg font-semibold text-foreground">Eligibility</h2> 40 + <p className="text-sm leading-relaxed text-muted-foreground"> 41 + You must be at least 16 years old to use Barazo (in accordance with the Dutch 42 + implementation of GDPR, UAVG). By using the service, you confirm that you meet this age 43 + requirement. Access to mature content may require additional age verification as 44 + required by applicable law. 45 + </p> 46 + </section> 47 + 48 + <section className="space-y-3"> 49 + <h2 className="text-lg font-semibold text-foreground">Account and Authentication</h2> 50 + <p className="text-sm leading-relaxed text-muted-foreground"> 51 + Barazo uses the AT Protocol for authentication. You log in using your existing AT 52 + Protocol identity (e.g., a Bluesky account). You are responsible for maintaining the 53 + security of your AT Protocol account. Barazo does not store your password. 54 + </p> 55 + </section> 56 + 57 + <section className="space-y-3"> 58 + <h2 className="text-lg font-semibold text-foreground">Content and Conduct</h2> 59 + <p className="text-sm leading-relaxed text-muted-foreground"> 60 + You retain ownership of content you post on Barazo. By posting, you grant Barazo a 61 + license to display, index, and distribute your content as part of the forum service and 62 + via the AT Protocol. 63 + </p> 64 + <p className="text-sm leading-relaxed text-muted-foreground"> 65 + You agree not to post content that: 66 + </p> 67 + <ul className="list-inside list-disc space-y-2 text-sm text-muted-foreground"> 68 + <li>Violates applicable laws or regulations.</li> 69 + <li>Infringes on the intellectual property rights of others.</li> 70 + <li>Contains spam, malware, or deceptive content.</li> 71 + <li>Harasses, threatens, or promotes violence against individuals or groups.</li> 72 + <li>Contains child sexual abuse material (CSAM).</li> 73 + </ul> 74 + <p className="text-sm leading-relaxed text-muted-foreground"> 75 + Community administrators may enforce additional content policies specific to their 76 + community. Repeated violations may result in content removal, account restrictions, or 77 + bans. 78 + </p> 79 + </section> 80 + 81 + <section className="space-y-3"> 82 + <h2 className="text-lg font-semibold text-foreground">Content Maturity Ratings</h2> 83 + <p className="text-sm leading-relaxed text-muted-foreground"> 84 + Communities and categories may be rated for content maturity (Safe for Work, Mature, or 85 + Adult). You are responsible for accurately labeling your content. Communities may 86 + require age verification to access mature content. New accounts default to safe-mode 87 + with mature content hidden. 88 + </p> 89 + </section> 90 + 91 + <section className="space-y-3"> 92 + <h2 className="text-lg font-semibold text-foreground">Cross-Posting</h2> 93 + <p className="text-sm leading-relaxed text-muted-foreground"> 94 + Barazo may cross-post your content to connected platforms (such as Bluesky or Frontpage) 95 + when you enable this feature. Cross-posting is optional and can be controlled in your 96 + settings. Cross-posted content is subject to the terms of the destination platform. 97 + </p> 98 + </section> 99 + 100 + <section className="space-y-3"> 101 + <h2 className="text-lg font-semibold text-foreground">Moderation and Labels</h2> 102 + <p className="text-sm leading-relaxed text-muted-foreground"> 103 + Your account may be labeled by independent moderation services (such as Bluesky&apos;s 104 + Ozone). Labels affect posting limits and content visibility. You cannot delete labels 105 + applied by labeler services, but you can dispute inaccuracies by contacting us or the 106 + labeler service. Community administrators may also apply local moderation overrides. 107 + </p> 108 + </section> 109 + 110 + <section className="space-y-3"> 111 + <h2 className="text-lg font-semibold text-foreground">AI-Generated Summaries</h2> 112 + <p className="text-sm leading-relaxed text-muted-foreground"> 113 + Barazo may generate AI-powered summaries of discussion threads. These summaries are 114 + anonymized derivative works that do not contain personal data (no usernames or verbatim 115 + quotes). AI summaries may persist after individual content is deleted, as they are 116 + regenerated from remaining content. Community administrators can disable summary 117 + preservation. 118 + </p> 119 + </section> 120 + 121 + <section className="space-y-3"> 122 + <h2 className="text-lg font-semibold text-foreground">AT Protocol and Federation</h2> 123 + <p className="text-sm leading-relaxed text-muted-foreground"> 124 + Barazo is built on the AT Protocol, which is a federated, open network. Content you post 125 + may be indexed by other services on the AT Protocol network. Barazo cannot control how 126 + third-party services handle your data once it is published via the protocol. 127 + </p> 128 + </section> 129 + 130 + <section className="space-y-3"> 131 + <h2 className="text-lg font-semibold text-foreground">Termination</h2> 132 + <p className="text-sm leading-relaxed text-muted-foreground"> 133 + Barazo may suspend or terminate your access if you violate these terms. You may stop 134 + using the service at any time. Deleting your AT Protocol account or content will trigger 135 + removal of indexed data from Barazo (see our Privacy Policy for details). 136 + </p> 137 + </section> 138 + 139 + <section className="space-y-3"> 140 + <h2 className="text-lg font-semibold text-foreground">Limitation of Liability</h2> 141 + <p className="text-sm leading-relaxed text-muted-foreground"> 142 + Barazo is provided &quot;as is&quot; without warranties of any kind. We are not liable 143 + for any damages arising from your use of the service, including but not limited to loss 144 + of data, service interruptions, or actions taken by community moderators or 145 + administrators. 146 + </p> 147 + </section> 148 + 149 + <section className="space-y-3"> 150 + <h2 className="text-lg font-semibold text-foreground">Governing Law</h2> 151 + <p className="text-sm leading-relaxed text-muted-foreground"> 152 + These terms are governed by the laws of the Netherlands. Any disputes arising from these 153 + terms will be subject to the exclusive jurisdiction of the courts of the Netherlands. 154 + </p> 155 + </section> 156 + 157 + <section className="space-y-3"> 158 + <p className="text-xs text-muted-foreground"> 159 + These terms were last updated on February 2026. 160 + </p> 161 + </section> 162 + </div> 163 + </ForumLayout> 164 + ) 165 + }
+5
src/components/layout/forum-layout.tsx
··· 113 113 Terms 114 114 </Link> 115 115 </li> 116 + <li> 117 + <Link href="/legal/cookies" className="transition-colors hover:text-foreground"> 118 + Cookies 119 + </Link> 120 + </li> 116 121 </ul> 117 122 </nav> 118 123 </div>