From 7368bf4b26c00b970390e083115e3449b41d976f Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 25 Apr 2026 19:15:12 +0000 Subject: [PATCH] Draft privacy policy page at /privacy/ (#634, #635) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a starter privacy policy as a server-rendered Django view at jandig.app/privacy/, prerequisite for Meta Quest VRC.Publishing and VRC.Quest.Privacy submission and for LGPD/GDPR compliance. The wording is a first pass written from the engineering side: it inventories what the codebase actually collects (account fields, uploaded media, session/CSRF/language cookies, Sentry error reports, Google Analytics traffic) and walks through the standard LGPD/GDPR sections. The page itself flags that legal review and team sign-off are still required, with placeholders for the contact email and effective date. What's left for the team: - Legal pass on wording. - Fill in section 9 (contact email) and section's effective date. - Translate the strings to pt-BR (everything is wrapped in `_()`). - Submit to the Meta Quest store. - Verify each VRC.Publishing.* and VRC.Quest.Privacy.* item. Routes: - core/views/static_views.py: privacy_policy view. - core/urls.py: GET /privacy/ → name="privacy-policy". Refs #634, #635 https://claude.ai/code/session_01XC1THLWgnGXGf5wgRhdyvB --- src/core/jinja2/core/privacy.jinja2 | 134 ++++++++++++++++++++++++++++ src/core/urls.py | 2 + src/core/views/static_views.py | 4 + 3 files changed, 140 insertions(+) create mode 100644 src/core/jinja2/core/privacy.jinja2 diff --git a/src/core/jinja2/core/privacy.jinja2 b/src/core/jinja2/core/privacy.jinja2 new file mode 100644 index 00000000..aff1205f --- /dev/null +++ b/src/core/jinja2/core/privacy.jinja2 @@ -0,0 +1,134 @@ +{% extends 'core/home.jinja2' %} +{% block content %} +
+
+

{{ _("Privacy Policy") }}

+

+ {{ _("Last updated") }}: 2026-04-25 +
+ {{ _("Effective date") }}: + {{ _("Pending legal review and team approval.") }} +

+ +

+ {{ _("This privacy policy describes how memeLab (\"we\", \"our\", \"us\") collects, uses, and shares information when you use the Jandig platform — the web application at jandig.app, the documentation site at jandig.app/docs, and the Meta Quest application that consumes the same backend (collectively, \"the Service\").") }} +

+ +
+ {{ _("Status") }}: + {{ _("this document is a draft prepared by the engineering team and is not yet legally reviewed or approved. Treat it as a starting point for the privacy review required for the Meta Quest VRC.Publishing and VRC.Quest.Privacy criteria. Final wording will need a legal pass and Meta Data Use Checkup approval before the MR Viewer launch.") }} +
+ +

{{ _("1. What we collect") }}

+ +

{{ _("Information you give us") }}

+
    +
  • + {{ _("Account data") }}: + {{ _("email address, username, and password (stored hashed via Django's PBKDF2). Optional profile fields: short bio, country, and a personal-site URL.") }} +
  • +
  • + {{ _("Content you upload") }}: + {{ _("markers (image), augmented objects (GIF, MP4, WebM, GLB), sounds (MP3, OGG, WAV), audio descriptions, and the titles, descriptions, and authorship metadata you provide for each item.") }} +
  • +
  • + {{ _("Exhibits") }}: + {{ _("the names, slugs, and content groupings (artworks, augmenteds, sounds) you assemble.") }} +
  • +
+ +

{{ _("Information we collect automatically") }}

+
    +
  • + {{ _("Usage and request logs") }}: + {{ _("standard HTTP server logs (timestamp, IP address, user agent, requested path, response status), retained by our hosting provider for operational and security purposes.") }} +
  • +
  • + {{ _("Cookies set by Jandig") }}: +
      +
    • sessionid — {{ _("authentication state, HTTP-only, expires on logout or session timeout") }}
    • +
    • csrftoken — {{ _("CSRF protection") }}
    • +
    • django_language — {{ _("language preference, set when you change the site language") }}
    • +
    +
  • +
  • + {{ _("Error reports") }}: + {{ _("when the application encounters an unexpected error, we send a report to Sentry. The report contains the request path, stack trace, browser/OS, and the user ID associated with the request (no payload data). We do not capture form values or uploaded content.") }} +
  • +
  • + {{ _("Analytics") }}: + {{ _("anonymized site-traffic analytics are collected via Google Analytics. Analytics data is associated with cookies set by Google and is processed under Google's privacy terms.") }} +
  • +
+ +

+ {{ _("We do not collect") }}: + {{ _("precise geolocation (beyond what an IP can imply), payment information, advertising identifiers, microphone or camera input, voice recordings, contacts, biometric data, or information from people under 13.") }} +

+ +

{{ _("2. How we use information") }}

+
    +
  • {{ _("To operate and maintain the Service: authenticate you, store and serve your uploaded content, render exhibits.") }}
  • +
  • {{ _("To diagnose problems: error reports via Sentry, server logs.") }}
  • +
  • {{ _("To understand aggregate usage trends: analytics.") }}
  • +
  • {{ _("To communicate with you about your account when needed (password reset, security notice). We do not send marketing emails.") }}
  • +
+

{{ _("We do not sell or rent personal data.") }}

+ +

{{ _("3. Where data is stored and processed") }}

+
    +
  • {{ _("Primary database") }}: {{ _("PostgreSQL hosted by our infrastructure provider.") }}
  • +
  • {{ _("Uploaded media") }}: {{ _("object storage compatible with Amazon S3, with public read access for media that the user has chosen to publish in an exhibit.") }}
  • +
  • {{ _("Error reports") }}: Sentry.
  • +
  • {{ _("Analytics") }}: Google Analytics.
  • +
+

{{ _("Data is processed and stored in the United States and Brazil depending on the service. By using Jandig you consent to that cross-border processing.") }}

+ +

{{ _("4. Sharing with third parties") }}

+

{{ _("We share information with the following processors, only to the extent necessary for them to perform their function:") }}

+
    +
  • {{ _("Hosting provider — infrastructure (all data above)") }}
  • +
  • {{ _("Amazon S3 (or compatible) — media storage (uploaded media)") }}
  • +
  • {{ _("Sentry — error monitoring (error reports + user ID)") }}
  • +
  • {{ _("Google Analytics — usage analytics (pseudonymous traffic data)") }}
  • +
  • {{ _("Meta Platforms — MR Viewer publishing & app distribution (app identifier, install metadata as required by the Quest store)") }}
  • +
+

{{ _("We do not share personal data with advertisers.") }}

+ +

{{ _("5. Public content") }}

+

+ {{ _("When you create an exhibit and make it public (the default for exhibits), your username and the metadata you provided (titles, authorship, descriptions, content) become publicly visible at jandig.app/{your-exhibit-slug}/ and are discoverable by search engines unless excluded by robots.txt. Do not upload content you don't want to be public.") }} +

+ +

{{ _("6. Your rights") }}

+

{{ _("Depending on your jurisdiction (notably LGPD in Brazil and GDPR in the EU/EEA), you have the right to:") }}

+
    +
  • {{ _("Access the personal data we hold about you.") }}
  • +
  • {{ _("Correct inaccurate data via the profile page.") }}
  • +
  • {{ _("Delete your account and associated content.") }}
  • +
  • {{ _("Export your data in a portable format.") }}
  • +
  • {{ _("Withdraw consent for analytics by clearing cookies or using a browser do-not-track setting.") }}
  • +
+

{{ _("To exercise these rights, contact us at the address in section 9.") }}

+ +

{{ _("7. Children") }}

+

{{ _("Jandig is not directed at children under 13. We do not knowingly collect personal data from children under 13. If you believe a child has provided us with personal data, contact us and we will delete it.") }}

+ +

{{ _("8. Security") }}

+

{{ _("Passwords are stored using Django's PBKDF2 hashing (current default). HTTPS is enforced site-wide. Cookies are marked HttpOnly and Secure in production. We patch dependencies on a regular cadence.") }}

+

{{ _("No system is perfectly secure. Report a security issue privately at the address in section 9.") }}

+ +

{{ _("9. Contact") }}

+

+ memeLab — Jandig project +
+ GitHub: https://github.com/memeLab/Jandig +
+ {{ _("Email") }}: {{ _("to be filled in by the team prior to publication.") }} +

+ +

{{ _("10. Changes") }}

+

{{ _("We may update this policy from time to time. The \"last updated\" date at the top reflects the latest revision. Material changes will be communicated on the home page.") }}

+
+
+{% endblock %} diff --git a/src/core/urls.py b/src/core/urls.py index 6d8b9fc9..25d4d77a 100644 --- a/src/core/urls.py +++ b/src/core/urls.py @@ -11,6 +11,7 @@ manifest, marker_generator, me_hotsite, + privacy_policy, robots_txt, service_worker, ) @@ -47,6 +48,7 @@ path("community/", community, name="community"), path("content/delete/", delete, name="delete-content"), path("documentation/", documentation, name="documentation"), + path("privacy/", privacy_policy, name="privacy-policy"), path("exhibit_select/", exhibit_select, name="exhibit_select"), path("exhibit/", exhibit_detail, name="exhibit-detail"), path("exhibits/create-ar/", create_or_edit_ar_exhibit, name="create-ar-exhibit"), diff --git a/src/core/views/static_views.py b/src/core/views/static_views.py index 22dff02a..e9757c40 100644 --- a/src/core/views/static_views.py +++ b/src/core/views/static_views.py @@ -11,6 +11,10 @@ def documentation(request): return render(request, "core/documentation.jinja2", {}) +def privacy_policy(request): + return render(request, "core/privacy.jinja2", {}) + + def favicon(_): return redirect(static("images/icons/favicon.ico"))