···974 w.WriteHeader(http.StatusOK)
975}
976000000000000000000000000000000000000977// fetchAllData is a helper that fetches all data types in parallel using errgroup.
978// This is used by handlers that need beans, roasters, grinders, and brewers.
979func fetchAllData(ctx context.Context, store database.Store) (
···974 w.WriteHeader(http.StatusOK)
975}
976977+// About page
978+func (h *Handler) HandleAbout(w http.ResponseWriter, r *http.Request) {
979+ // Check if user is authenticated
980+ didStr, err := atproto.GetAuthenticatedDID(r.Context())
981+ isAuthenticated := err == nil && didStr != ""
982+983+ data := &bff.PageData{
984+ Title: "About",
985+ IsAuthenticated: isAuthenticated,
986+ UserDID: didStr,
987+ }
988+989+ if err := bff.RenderTemplate(w, "about.tmpl", data); err != nil {
990+ http.Error(w, "Failed to render page", http.StatusInternalServerError)
991+ log.Error().Err(err).Msg("Failed to render about page")
992+ }
993+}
994+995+// Terms of Service page
996+func (h *Handler) HandleTerms(w http.ResponseWriter, r *http.Request) {
997+ // Check if user is authenticated
998+ didStr, err := atproto.GetAuthenticatedDID(r.Context())
999+ isAuthenticated := err == nil && didStr != ""
1000+1001+ data := &bff.PageData{
1002+ Title: "Terms of Service",
1003+ IsAuthenticated: isAuthenticated,
1004+ UserDID: didStr,
1005+ }
1006+1007+ if err := bff.RenderTemplate(w, "terms.tmpl", data); err != nil {
1008+ http.Error(w, "Failed to render page", http.StatusInternalServerError)
1009+ log.Error().Err(err).Msg("Failed to render terms page")
1010+ }
1011+}
1012+1013// fetchAllData is a helper that fetches all data types in parallel using errgroup.
1014// This is used by handlers that need beans, roasters, grinders, and brewers.
1015func fetchAllData(ctx context.Context, store database.Store) (
+2
internal/routing/routing.go
···4849 // Page routes (must come before static files)
50 mux.HandleFunc("GET /{$}", h.HandleHome) // {$} means exact match
0051 mux.HandleFunc("GET /manage", h.HandleManage)
52 mux.HandleFunc("GET /brews", h.HandleBrewList)
53 mux.HandleFunc("GET /brews/new", h.HandleBrewNew)
···4849 // Page routes (must come before static files)
50 mux.HandleFunc("GET /{$}", h.HandleHome) // {$} means exact match
51+ mux.HandleFunc("GET /about", h.HandleAbout)
52+ mux.HandleFunc("GET /terms", h.HandleTerms)
53 mux.HandleFunc("GET /manage", h.HandleManage)
54 mux.HandleFunc("GET /brews", h.HandleBrewList)
55 mux.HandleFunc("GET /brews/new", h.HandleBrewNew)
···1+{{template "layout" .}}
2+3+{{define "content"}}
4+<div class="max-w-3xl mx-auto">
5+ <h1 class="text-4xl font-bold text-brown-800 mb-8">About Arabica</h1>
6+7+ <div class="prose prose-lg max-w-none space-y-6">
8+ <section>
9+ <h2 class="text-2xl font-semibold text-brown-800 mb-4">Your Coffee Journey, Your Data</h2>
10+ <p class="text-gray-700 leading-relaxed">
11+ Arabica is a coffee brew tracking application built on the AT Protocol, a decentralized social networking protocol.
12+ Unlike traditional apps where your data is locked in a company's database, Arabica stores your brew logs,
13+ coffee beans, and equipment information in <strong>your own Personal Data Server (PDS)</strong>.
14+ </p>
15+ </section>
16+17+ <section class="bg-brown-50 p-6 rounded-lg">
18+ <h3 class="text-xl font-semibold text-brown-800 mb-3">What Makes Arabica Different?</h3>
19+ <ul class="list-disc list-inside space-y-2 text-gray-700">
20+ <li><strong>You own your data</strong> - All your brew logs live in your PDS, not our servers</li>
21+ <li><strong>Portable identity</strong> - Switch PDS providers anytime without losing your data</li>
22+ <li><strong>Privacy by design</strong> - You control who sees your brews</li>
23+ <li><strong>Open protocol</strong> - Built on the AT Protocol, the same technology powering Bluesky</li>
24+ </ul>
25+ </section>
26+27+ <section>
28+ <h2 class="text-2xl font-semibold text-brown-800 mb-4">Features</h2>
29+ <div class="grid md:grid-cols-2 gap-4">
30+ <div class="bg-white border border-gray-200 p-4 rounded-lg">
31+ <h4 class="font-semibold text-brown-800 mb-2">Track Your Brews</h4>
32+ <p class="text-gray-600 text-sm">Log every detail: beans, grind size, water temp, brew time, and tasting notes</p>
33+ </div>
34+ <div class="bg-white border border-gray-200 p-4 rounded-lg">
35+ <h4 class="font-semibold text-brown-800 mb-2">Manage Equipment</h4>
36+ <p class="text-gray-600 text-sm">Keep track of your grinders, brewers, beans, and roasters</p>
37+ </div>
38+ <div class="bg-white border border-gray-200 p-4 rounded-lg">
39+ <h4 class="font-semibold text-brown-800 mb-2">Community Feed</h4>
40+ <p class="text-gray-600 text-sm">Share your best brews with the community (coming soon: likes and comments!)</p>
41+ </div>
42+ <div class="bg-white border border-gray-200 p-4 rounded-lg">
43+ <h4 class="font-semibold text-brown-800 mb-2">Export Your Data</h4>
44+ <p class="text-gray-600 text-sm">Export all your brews anytime in JSON format</p>
45+ </div>
46+ </div>
47+ </section>
48+49+ <section>
50+ <h2 class="text-2xl font-semibold text-brown-800 mb-4">The AT Protocol Advantage</h2>
51+ <p class="text-gray-700 leading-relaxed">
52+ The AT Protocol is a decentralized social networking protocol that gives users true ownership of their data
53+ and identity. When you use Arabica:
54+ </p>
55+ <ul class="list-disc list-inside space-y-2 text-gray-700 mt-3">
56+ <li>Your brew data is stored as ATProto records in collections on your PDS</li>
57+ <li>You authenticate via OAuth with your PDS, not with us</li>
58+ <li>References between records (like linking a brew to a bean) use AT-URIs</li>
59+ <li>Your identity is portable - change PDS providers without losing your account</li>
60+ </ul>
61+ </section>
62+63+ <section class="bg-blue-50 border border-blue-200 p-6 rounded-lg">
64+ <h3 class="text-xl font-semibold text-blue-900 mb-3">Getting Started</h3>
65+ <p class="text-gray-700 mb-4">
66+ To use Arabica, you'll need an account on a PDS that supports the AT Protocol.
67+ The easiest way is to create a Bluesky account at <a href="https://bsky.app" class="text-blue-600 hover:underline" target="_blank" rel="noopener noreferrer">bsky.app</a>.
68+ </p>
69+ <p class="text-gray-700">
70+ Once you have an account, simply log in with your handle (e.g., yourname.bsky.social) and start tracking your brews!
71+ </p>
72+ </section>
73+74+ <section>
75+ <h2 class="text-2xl font-semibold text-brown-800 mb-4">Open Source</h2>
76+ <p class="text-gray-700 leading-relaxed">
77+ Arabica is open source software. You can view the code, contribute, or even run your own instance.
78+ Visit our <a href="https://github.com/placeholder/arabica" class="text-blue-600 hover:underline" target="_blank" rel="noopener noreferrer">GitHub repository</a> to learn more.
79+ </p>
80+ </section>
81+ </div>
82+83+ <div class="mt-12 text-center">
84+ {{if not .IsAuthenticated}}
85+ <a href="/login" class="inline-block bg-brown-800 text-white px-8 py-3 rounded-lg hover:bg-brown-700 transition-colors font-semibold">
86+ Get Started
87+ </a>
88+ {{else}}
89+ <a href="/brews/new" class="inline-block bg-brown-800 text-white px-8 py-3 rounded-lg hover:bg-brown-700 transition-colors font-semibold">
90+ Log Your Next Brew
91+ </a>
92+ {{end}}
93+ </div>
94+</div>
95+{{end}}
···1+{{template "layout" .}}
2+3+{{define "content"}}
4+<div class="max-w-3xl mx-auto">
5+ <h1 class="text-4xl font-bold text-brown-800 mb-8">Terms of Service</h1>
6+7+ <div class="prose prose-lg max-w-none space-y-6">
8+ <section class="bg-green-50 border border-green-200 p-6 rounded-lg mb-8">
9+ <h2 class="text-2xl font-semibold text-green-900 mb-4">The Simple Truth</h2>
10+ <p class="text-gray-800 text-lg leading-relaxed">
11+ <strong>You own all of your data.</strong> Period. Your brew logs, coffee beans, equipment information,
12+ and any other data you create in Arabica belongs to you and is stored in your Personal Data Server (PDS),
13+ not on our servers.
14+ </p>
15+ </section>
16+17+ <section>
18+ <h2 class="text-2xl font-semibold text-brown-800 mb-4">1. Your Data Ownership</h2>
19+ <p class="text-gray-700 leading-relaxed">
20+ All data you create through Arabica is stored in your AT Protocol Personal Data Server (PDS).
21+ Arabica acts as an interface to your PDS but does not own, claim rights to, or permanently store your data.
22+ </p>
23+ <ul class="list-disc list-inside space-y-2 text-gray-700 mt-3">
24+ <li>You retain full ownership and control of your data</li>
25+ <li>You can export your data at any time</li>
26+ <li>You can delete your data at any time</li>
27+ <li>You can switch PDS providers without losing your data</li>
28+ <li>You can stop using Arabica and your data remains in your PDS</li>
29+ </ul>
30+ </section>
31+32+ <section>
33+ <h2 class="text-2xl font-semibold text-brown-800 mb-4">2. What We Store</h2>
34+ <p class="text-gray-700 leading-relaxed mb-3">
35+ Arabica's servers store minimal data necessary for the application to function:
36+ </p>
37+ <ul class="list-disc list-inside space-y-2 text-gray-700">
38+ <li><strong>Session information</strong> - Temporary authentication tokens to keep you logged in</li>
39+ <li><strong>Feed registry</strong> - List of users who've opted into the community feed</li>
40+ <li><strong>Temporary cache</strong> - Short-lived cache (5 minutes) of your data to improve performance</li>
41+ </ul>
42+ <p class="text-gray-700 leading-relaxed mt-3">
43+ We do <strong>not</strong> store your brew logs, beans, equipment, or any other user-generated content
44+ on our servers. That data lives exclusively in your PDS.
45+ </p>
46+ </section>
47+48+ <section>
49+ <h2 class="text-2xl font-semibold text-brown-800 mb-4">3. Authentication</h2>
50+ <p class="text-gray-700 leading-relaxed">
51+ Arabica uses OAuth to authenticate with your PDS. We never see or store your PDS password.
52+ Authentication is handled between your browser and your PDS, with Arabica receiving only
53+ temporary access tokens to read and write data on your behalf.
54+ </p>
55+ </section>
56+57+ <section>
58+ <h2 class="text-2xl font-semibold text-brown-800 mb-4">4. Community Feed</h2>
59+ <p class="text-gray-700 leading-relaxed">
60+ If you opt into the community feed, Arabica will periodically read your public brew records
61+ from your PDS to display them to other users. This is done by:
62+ </p>
63+ <ul class="list-disc list-inside space-y-2 text-gray-700 mt-3">
64+ <li>Making public API calls to your PDS</li>
65+ <li>Temporarily caching brew data for feed display</li>
66+ <li>Not storing your data permanently on our servers</li>
67+ </ul>
68+ <p class="text-gray-700 leading-relaxed mt-3">
69+ You can opt out of the community feed at any time, and we'll stop reading your brews.
70+ </p>
71+ </section>
72+73+ <section>
74+ <h2 class="text-2xl font-semibold text-brown-800 mb-4">5. Service Availability</h2>
75+ <p class="text-gray-700 leading-relaxed">
76+ Arabica is provided "as is" without warranties of any kind. We make reasonable efforts to keep
77+ the service running but do not guarantee uptime or availability. Since your data is stored in
78+ your PDS (not our servers), you won't lose your data if Arabica goes offline.
79+ </p>
80+ </section>
81+82+ <section>
83+ <h2 class="text-2xl font-semibold text-brown-800 mb-4">6. Privacy</h2>
84+ <p class="text-gray-700 leading-relaxed">
85+ We respect your privacy and follow these principles:
86+ </p>
87+ <ul class="list-disc list-inside space-y-2 text-gray-700 mt-3">
88+ <li>We don't sell your data (because we don't have it to sell!)</li>
89+ <li>We don't track you across websites</li>
90+ <li>We use minimal analytics to understand service usage</li>
91+ <li>We don't share your data with third parties</li>
92+ <li>Your PDS and the AT Protocol control the privacy of your brew data</li>
93+ </ul>
94+ </section>
95+96+ <section>
97+ <h2 class="text-2xl font-semibold text-brown-800 mb-4">7. Open Source</h2>
98+ <p class="text-gray-700 leading-relaxed">
99+ Arabica is open source software. You can review the code, run your own instance, or contribute
100+ improvements. The transparency of open source means you can verify that we're handling your data
101+ as described in these terms.
102+ </p>
103+ </section>
104+105+ <section>
106+ <h2 class="text-2xl font-semibold text-brown-800 mb-4">8. Changes to Terms</h2>
107+ <p class="text-gray-700 leading-relaxed">
108+ We may update these terms occasionally. If we make significant changes, we'll notify users through
109+ the application. Continued use of Arabica after changes constitutes acceptance of the new terms.
110+ </p>
111+ </section>
112+113+ <section>
114+ <h2 class="text-2xl font-semibold text-brown-800 mb-4">9. Acceptable Use</h2>
115+ <p class="text-gray-700 leading-relaxed">
116+ Please use Arabica responsibly:
117+ </p>
118+ <ul class="list-disc list-inside space-y-2 text-gray-700 mt-3">
119+ <li>Don't attempt to access other users' data without permission</li>
120+ <li>Don't abuse the service with excessive API requests</li>
121+ <li>Don't use Arabica for illegal purposes</li>
122+ <li>Be respectful in community interactions</li>
123+ </ul>
124+ </section>
125+126+ <section>
127+ <h2 class="text-2xl font-semibold text-brown-800 mb-4">10. Contact</h2>
128+ <p class="text-gray-700 leading-relaxed">
129+ Questions about these terms? You can reach us through our GitHub repository or by email at
130+ <a href="mailto:contact@example.com" class="text-blue-600 hover:underline">contact@example.com</a>
131+ (placeholder).
132+ </p>
133+ </section>
134+135+ <section class="bg-gray-100 p-6 rounded-lg mt-8">
136+ <p class="text-sm text-gray-600">
137+ <strong>Last Updated:</strong> January 2026<br>
138+ <strong>Effective Date:</strong> January 2026
139+ </p>
140+ </section>
141+ </div>
142+143+ <div class="mt-12 text-center">
144+ <a href="/" class="text-blue-600 hover:underline">Back to Home</a>
145+ </div>
146+</div>
147+{{end}}