diff --git a/internal/api/routes/web.go b/internal/api/routes/web.go index f35c9d8..3448fbb 100644 --- a/internal/api/routes/web.go +++ b/internal/api/routes/web.go @@ -30,6 +30,9 @@ func RegisterWebRoutes(r chi.Router, oauthClient *oauth.OAuthClient, userService r.Post("/delete-account", handlers.DeleteAccountSubmitHandler) r.Get("/delete-account/success", handlers.DeleteAccountSuccessHandler) + // Legal pages + r.Get("/privacy", handlers.PrivacyHandler) + // Static files (images, etc.) r.Get("/static/*", func(w http.ResponseWriter, r *http.Request) { // Serve from project's static directory diff --git a/internal/web/handlers.go b/internal/web/handlers.go index acff087..9fad31a 100644 --- a/internal/web/handlers.go +++ b/internal/web/handlers.go @@ -173,3 +173,11 @@ func (h *Handlers) clearSessionCookie(w http.ResponseWriter) { MaxAge: -1, }) } + +// PrivacyHandler handles GET /privacy requests and renders the privacy policy page. +func (h *Handlers) PrivacyHandler(w http.ResponseWriter, r *http.Request) { + if err := h.templates.Render(w, "privacy.html", nil); err != nil { + slog.Error("failed to render privacy policy template", "error", err) + http.Error(w, "Internal server error", http.StatusInternalServerError) + } +} diff --git a/internal/web/templates/privacy.html b/internal/web/templates/privacy.html new file mode 100644 index 0000000..28ad9ee --- /dev/null +++ b/internal/web/templates/privacy.html @@ -0,0 +1,290 @@ + + + + + + Privacy Policy - Coves + + + + +
+ ← Back to Coves + +

Privacy Policy

+

Effective Date: January 16, 2026

+ +

Coves Team ("we," "our," or "us") operates the Coves mobile application and website. This Privacy Policy explains how we collect, use, and protect your information when you use our service.

+ +
+

Summary: Coves is built on the atProto protocol. Your data is stored on your Personal Data Server (PDS), which you control. We only index and cache publicly available data from the network to provide our service.

+
+ +

1. Information We Collect

+ +

1.1 Account Information

+

When you sign in to Coves, we receive the following from your atProto identity:

+ + +

1.2 Content You Create

+

When you use Coves, the content you create is written to your PDS:

+ + +

1.3 Information We Do NOT Collect

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Data TypeCollected?
PasswordsNo - OAuth only
Device identifiers (IMEI, serial numbers)No
Location dataNo
ContactsNo
Photos/media from your deviceNo
Analytics or telemetryNo
Advertising identifiersNo
Crash reportsNo
+ +

2. How We Use Your Information

+

We use the information we collect to:

+ +

We do not use your information for advertising, profiling, or selling to third parties.

+ +

3. The atProto Protocol and Federation

+ +
+

Important: Coves is built on the atProto (AT Protocol), a federated social networking protocol. This affects how your data works.

+
+ +

3.1 Your Personal Data Server (PDS)

+

Your content (posts, comments, votes) is stored on your PDS, not on Coves servers. You may host your own PDS or use a hosted provider. You maintain control over your data at the PDS level.

+ +

3.2 What Coves Stores

+

Coves operates an AppView that indexes publicly available data from the atProto network firehose. This means:

+ + +

3.3 Federation

+

Because atProto is federated, your public content may be visible on other applications and services that use the protocol. This is a feature of the protocol, not something Coves controls. When you post content, consider that it may be indexed and displayed by other atProto services.

+ +

4. Data Storage and Security

+ +

4.1 Where Data is Stored

+ + +

4.2 Security Measures

+ + +

5. Third-Party Services

+

We use the following third-party services:

+ +

We do not use third-party analytics, advertising networks, or tracking services.

+ +

6. Data Retention and Deletion

+ +

6.1 On Coves Servers

+

When you delete content or your account:

+ + +

6.2 On Your PDS

+

Content stored on your PDS is managed by you or your PDS provider. Deleting content from Coves removes it from our index, but the original data on your PDS must be managed separately according to your PDS provider's policies.

+ +

6.3 Federation Caveat

+

Due to the federated nature of atProto, content that was public may have been indexed or cached by other services before deletion. We cannot control data held by other parties on the network.

+ +

7. Your Rights

+

You have the right to:

+ +

To exercise these rights, contact us at support@coves.social.

+ +

8. Age Requirement

+

Coves is intended for users who are 18 years of age or older. We do not knowingly collect information from anyone under 18. If you are under 18, please do not use this service.

+

If we learn that we have collected personal information from a user under 18, we will take steps to delete that information promptly.

+ +

9. Changes to This Policy

+

We may update this Privacy Policy from time to time. We will notify you of significant changes by:

+ +

We encourage you to review this policy periodically.

+ +

10. Future Features

+

We may introduce analytics, crash reporting, or other features in the future to improve the service. If we do, we will:

+ + +

11. Contact Us

+

If you have questions about this Privacy Policy or our practices, contact us at:

+

+ Coves Team
+ Email: support@coves.social +

+
+ + diff --git a/internal/web/templates_test.go b/internal/web/templates_test.go index 64fc28b..3f80d45 100644 --- a/internal/web/templates_test.go +++ b/internal/web/templates_test.go @@ -132,3 +132,33 @@ func TestTemplatesRender_NotFound(t *testing.T) { t.Fatal("Render() should return error for nonexistent template") } } + +func TestTemplatesRender_Privacy(t *testing.T) { + templates, err := NewTemplates() + if err != nil { + t.Fatalf("NewTemplates() error = %v", err) + } + + w := httptest.NewRecorder() + err = templates.Render(w, "privacy.html", nil) + if err != nil { + t.Fatalf("Render() error = %v", err) + } + + body := w.Body.String() + if !bytes.Contains([]byte(body), []byte("Privacy Policy")) { + t.Error("Privacy page does not contain title") + } + if !bytes.Contains([]byte(body), []byte("Coves Team")) { + t.Error("Privacy page does not contain company name") + } + if !bytes.Contains([]byte(body), []byte("support@coves.social")) { + t.Error("Privacy page does not contain contact email") + } + if !bytes.Contains([]byte(body), []byte("atProto")) { + t.Error("Privacy page does not mention atProto") + } + if !bytes.Contains([]byte(body), []byte("18 years of age or older")) { + t.Error("Privacy page does not contain age requirement") + } +}