Merge pull request 'Add the Calendula and Agendula privacy policies' (#7) from calendula-privacy-policy into main

Reviewed-on: #7
This commit was merged in pull request #7.
This commit is contained in:
2026-09-09 14:02:01 +00:00
4 changed files with 336 additions and 8 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ const year = new Date().getFullYear();
<footer class="site-footer">
<div class="site-footer__inner">
<p>
© {year} {SITE.author} · <a href="/uses">Uses</a> ·
© {year} {SITE.author} · <a href="/uses">Uses</a> ·{' '}
<a href="/impressum">Impressum</a> · <a href="/datenschutz">Datenschutz</a>
</p>
{
+328
View File
@@ -0,0 +1,328 @@
---
import BaseLayout from '../../layouts/BaseLayout.astro';
import { LEGAL } from '../../consts';
// App privacy policy for Agendula — required as a public URL by the Google Play
// Console (mandatory for every app) and linked from the app's About card.
// Deliberately separate from /datenschutz, which covers this website only.
//
// Kept in English because SITE.lang is 'en' and Play's default store listing is
// en-US; /datenschutz and /impressum stay German for legal reasons.
//
// Source of truth for the facts below: the Agendula repository (docs/PRIVACY.md,
// docs/SYNC.md, AndroidManifest.xml, backup_rules.xml). Unlike Calendula,
// Agendula *does* hold INTERNET — it has its own CalDAV sync — so the wording
// here turns on "only to the server you entered", not on the absence of the
// permission. If sync, permissions or data paths change, update this page and
// the "Last updated" date.
const lastUpdated = '9 September 2026';
---
<BaseLayout
title="Agendula — Privacy Policy"
description="Privacy policy for the Agendula Android task app. No accounts, no analytics, no tracking — data leaves your device only for the CalDAV server you choose."
width="narrow"
>
<article class="prose">
<h1 class="page-title">Privacy Policy — Agendula</h1>
<p>
<strong>Last updated:</strong> {lastUpdated}<br />
Applies to the Android app <strong>Agendula</strong>{' '}
(package <code>de.jeanlucmakiola.agendula</code>), all versions and all
distribution channels.
</p>
<h2>In short</h2>
<p>
Agendula has no servers, no user accounts and no analytics. Your tasks live
on your device. They leave it in exactly one case: if you set up a CalDAV
account yourself, they are synchronised with <strong>the server you
entered</strong> — and with nothing and no one else. Nothing is ever sent
to the developer.
</p>
<h2>1. Controller</h2>
<p>
{LEGAL.business}<br />
{LEGAL.street}<br />
{LEGAL.city}<br />
Email: <a href={`mailto:${LEGAL.email}`}>{LEGAL.email}</a>
</p>
<h2>2. No data collection by the developer</h2>
<p>
Agendula contains <strong>no analytics, no tracking, no advertising, no
crash-reporting SDK and no third-party service that reports anything
anywhere</strong>. No user profile is created, no advertising or device
identifier is generated, and no data is shared with or sold to anyone.
There is no Agendula account, and the developer operates no server that the
app talks to.
</p>
<p>
All of this is verifiable in the{' '}
<a href="https://codeberg.org/jlmakiola/agendula" rel="noopener">source code</a>,
which is public.
</p>
<h2>3. Where your tasks live — your choice</h2>
<p>
Agendula offers two storage modes, and you pick one:
</p>
<ul>
<li>
<strong>On your device (the default)</strong> — your task lists, tasks and
reminders are kept in Agendula's own database inside the app's private
storage. Nothing is published to other apps, and uninstalling the app
removes it.
</li>
<li>
<strong>In a tasks provider you already use</strong> — OpenTasks or
tasks.org. Agendula then reads and writes that app's task database
through Android's provider mechanism, after you grant its read/write
permission. Whatever already synchronises that provider (DAVx5,
SmoothSync, DecSync CC, …) keeps doing so, unchanged; that synchronisation
is performed by those apps, not by Agendula, and their privacy policies
apply to it.
</li>
</ul>
<h2>4. CalDAV sync — the only case where your tasks leave the device</h2>
<p>
Sync is optional and off until you add an account. If you add one,
everything below happens between your device and <strong>the server you
nominated</strong>, and nowhere else.
</p>
<h3>What is stored on your device</h3>
<p>
The server address, your username, and your password or app password. The
password is encrypted with a key held in the Android Keystore, which cannot
be exported from the device.
</p>
<h3>What is transmitted, and to whom</h3>
<ul>
<li>
The tasks in the synchronised lists, as standard iCalendar
(<code>VTODO</code>) data, and the credentials needed to authenticate.
</li>
<li>
Requests carry the user agent <code>Agendula (Android)</code> — a fixed
string, so that you can recognise and revoke the session on your server.
No device identifier is sent.
</li>
<li>
Connections are HTTPS. Cleartext HTTP is refused, so credentials are
never sent over an unencrypted connection.
</li>
</ul>
<p>
Under Google Play's Data Safety definitions this counts as{' '}
<strong>collected</strong> — Play defines collection as transmitting data
off the device, regardless of who receives it — and <strong>not
shared</strong>, because the only recipient is the server you chose. Data is
encrypted in transit.
</p>
<h3>Finding your server</h3>
<p>
When you type a server address or an email domain, Agendula follows the
standard discovery procedure (RFC 6764): a DNS lookup for the{' '}
<code>_caldavs._tcp</code> service record of that domain, then{' '}
<code>/.well-known/caldav</code> on the host. The DNS query goes to whichever
resolver your device or network uses, and the requests go to the domain you
typed — no directory of servers is consulted and no lookup is sent to the
developer.
</p>
<h3>Signing in to a Nextcloud</h3>
<p>
If the server is a Nextcloud, Agendula uses Nextcloud's Login Flow v2: your
browser opens <em>your own server's</em> login page, you authorise there,
and the server hands the app a dedicated app password. Agendula never sees
your actual account password. The app password appears in your server's
“Devices &amp; sessions” list as <code>Agendula (Android)</code>, and you can
revoke it there at any time. Removing the account in Agendula revokes it too,
where the server supports that.
</p>
<h3>Your server's own policy</h3>
<p>
Your CalDAV provider has its own privacy policy, and your data on their
server is governed by it. Agendula has no relationship with them.
</p>
<p>
A note on certificates: Agendula trusts private certificate authorities that
you have installed in your device's user store, because self-hosted servers
routinely use them. That is a deliberate trade-off in favour of
self-hosters — any CA installed on your device (for example by an employer's
management profile) can, in principle, intercept traffic from the app, as it
can from other apps that make the same choice.
</p>
<h2>5. Other data Agendula handles on your device</h2>
<h3>Reminders and notifications</h3>
<p>
Due-date reminders are scheduled by the app itself and displayed as local
notifications. Nothing is sent to a push service — there is no push service.
</p>
<h3>Export files</h3>
<p>
You can export your tasks as standard iCalendar <code>.ics</code> files.
Agendula writes exactly the file you select through Android's system file
picker, and has no access to other files.
</p>
<h3>App settings</h3>
<p>
Your preferences (theme, language, list and reminder defaults and similar)
are stored locally on your device and are removed when you uninstall the
app.
</p>
<h2>6. Backups</h2>
<p>
If Android Auto Backup is enabled on your device, your tasks and settings
may be backed up to your own Google account, under Google's terms — the
developer has no access to it. Two things are deliberately excluded from
that backup: your stored CalDAV password, and Agendula's per-device sync
bookkeeping. After restoring onto a new device you therefore sign in to your
server again.
</p>
<h2>7. Crash reports</h2>
<p>
If Agendula crashes, it offers to report the problem. Nothing is sent
automatically, even though the app has network access. The report is copied
to your clipboard and your browser is opened with the project's issue
tracker, the text pre-filled. <strong>You see the full content, you decide
whether to submit it, and you can edit or discard it.</strong>
</p>
<p>Such a report contains:</p>
<ul>
<li>app version,</li>
<li>Android version,</li>
<li>device manufacturer and model,</li>
<li>your device language,</li>
<li>the timestamp,</li>
<li>and the technical stack trace.</li>
</ul>
<p>
It is built from that fixed list and nothing else: <strong>no</strong> task
data, <strong>no</strong> server address or credentials, <strong>no</strong>{' '}
account names, <strong>no</strong> log files and <strong>no</strong> personal
identifiers.
</p>
<p>
If you choose to submit it, the report becomes a public issue on the
project's issue tracker at Codeberg, operated by Codeberg&nbsp;e.&nbsp;V.
Their privacy policy then applies to that submission.
</p>
<h2>8. External links</h2>
<p>
The app links to the source code, the licence, the issue tracker, the
translation platform (Weblate) and a voluntary donation page (Ko-fi).
Following one of these links opens your browser and leaves the app; the
privacy policy of the respective website then applies. Agendula transmits no
data of yours in the process — it only opens the address.
</p>
<h2>9. Permissions and why they exist</h2>
<ul>
<li>
<code>INTERNET</code>, <code>ACCESS_NETWORK_STATE</code> — CalDAV sync with
the server you configure, and checking whether a connection exists before
trying. Without a CalDAV account, no connection is made.
</li>
<li>
<code>READ_SYNC_SETTINGS</code>, <code>WRITE_SYNC_SETTINGS</code> — register
the sync account with Android's sync framework so it can be scheduled.
</li>
<li><code>POST_NOTIFICATIONS</code> — show reminders.</li>
<li>
<code>USE_EXACT_ALARM</code>, <code>SCHEDULE_EXACT_ALARM</code> — deliver
reminders at the exact due time.
</li>
<li>
<code>RECEIVE_BOOT_COMPLETED</code> — re-register pending reminders after a
restart.
</li>
<li>
<code>org.dmfs.permission.READ_TASKS</code> /{' '}
<code>WRITE_TASKS</code> and <code>org.tasks.permission.READ_TASKS</code> /{' '}
<code>WRITE_TASKS</code> — optional, requested only if you choose the
external-provider storage mode, and only for the provider you selected
(OpenTasks or tasks.org).
</li>
<li>
<code>WAKE_LOCK</code>, <code>FOREGROUND_SERVICE</code> — required by the
Android system component used for scheduled background work
(WorkManager); on older Android versions it needs them to run an
expedited sync.
</li>
</ul>
<p>
Agendula publishes no content provider of its own and declares no
permissions that other apps could request.
</p>
<h2>10. Distribution channels</h2>
<p>
Agendula is distributed via F-Droid, Obtainium, a self-hosted repository
and, where applicable, the Google Play Store. When you download or update
the app, the operator of that channel processes data (such as your IP
address) under their own privacy policy. This is outside the developer's
control and unrelated to the app's own behaviour.
</p>
<h2>11. Children</h2>
<p>
Agendula is not directed at children and collects nothing about anyone.
</p>
<h2>12. Deleting your data</h2>
<ul>
<li>
<strong>Remove a CalDAV account</strong> (Settings → Accounts) deletes the
stored credential and, where the server supports it, revokes the app
password. The task lists become device-only lists rather than being
destroyed.
</li>
<li>
<strong>Remove an account and delete its local data</strong> removes those
lists and their tasks as well.
</li>
<li>
<strong>Uninstalling the app</strong> removes everything Agendula stored on
the device.
</li>
</ul>
<p>
Data on your CalDAV server is deleted on that server; data in an external
tasks provider is deleted in that app.
</p>
<h2>13. Your rights</h2>
<p>
The developer stores no personal data of yours — the only data transfer the
app performs is between your device and a server you operate or chose. There
is therefore no data held by the developer to which rights of access,
rectification, erasure, restriction, data portability or objection
(Art.&nbsp;1521 GDPR) could apply. Your tasks are exportable as standard{' '}
<code>.ics</code> files from within the app at any time. You may contact the
address above with any question, and you have the right to lodge a complaint
with a supervisory authority.
</p>
<h2>14. Changes to this policy</h2>
<p>
Should the app's functionality change in a way that affects data processing,
this policy will be updated and the date at the top adjusted. The version
history is publicly traceable in the project's source repository.
</p>
</article>
</BaseLayout>
+2 -2
View File
@@ -26,7 +26,7 @@ const lastUpdated = '28 July 2026';
<p>
<strong>Last updated:</strong> {lastUpdated}<br />
Applies to the Android app <strong>Calendula</strong>
Applies to the Android app <strong>Calendula</strong>{' '}
(package <code>de.jeanlucmakiola.calendula</code>), all versions and all
distribution channels.
</p>
@@ -174,7 +174,7 @@ const lastUpdated = '28 July 2026';
system dialog for the “Reliable delivery” setting.
</li>
<li>
<code>WAKE_LOCK</code>, <code>FOREGROUND_SERVICE</code>, <code>ACCESS_NETWORK_STATE</code>
<code>WAKE_LOCK</code>, <code>FOREGROUND_SERVICE</code>, <code>ACCESS_NETWORK_STATE</code>{' '}
— required by the Android system component used for scheduled background
work (WorkManager).
</li>
+5 -5
View File
@@ -15,7 +15,7 @@ import { LEGAL } from '../consts';
<article class="prose">
<h1 class="page-title">Uses</h1>
<p>
A running colophon of the tools and stack behind this site, the
A running colophon of the tools and stack behind this site, the{' '}
<a href="/work">Floret apps</a>, and the infrastructure they run on. The
throughline: open, self-hostable standards, and as little reliance on
third-party services as I can manage.
@@ -29,14 +29,14 @@ import { LEGAL } from '../consts';
the repo.
</li>
<li>
Typefaces are <a href="https://rsms.me/inter/" rel="noopener">Inter</a>
Typefaces are <a href="https://rsms.me/inter/" rel="noopener">Inter</a>{' '}
and <a href="https://www.jetbrains.com/lp/mono/" rel="noopener">JetBrains
Mono</a>, self-hosted via Fontsource — no Google Fonts CDN, so no
third-party request on page load.
</li>
<li>
Analytics is self-hosted <a href="https://umami.is" rel="noopener">Umami</a>:
cookieless, no cross-site tracking, no personal profiles. See the
cookieless, no cross-site tracking, no personal profiles. See the{' '}
<a href="/datenschutz">Datenschutzerklärung</a> for what that means.
</li>
<li>Icons from <a href="https://iconify.design" rel="noopener">Iconify</a> (Material Design Icons + Simple Icons).</li>
@@ -47,7 +47,7 @@ import { LEGAL } from '../consts';
<li><strong>Kotlin</strong> and <strong>Jetpack Compose</strong>, designed in <strong>Material 3 Expressive</strong>.</li>
<li>
No reinvented sync stack — each app is a front-end over a platform
provider (<code>CalendarContract</code>, the OpenTasks
provider (<code>CalendarContract</code>, the OpenTasks{' '}
<code>TaskContract</code>) and open standards like CalDAV, iCalendar, and
DecSync.
</li>
@@ -69,7 +69,7 @@ import { LEGAL } from '../consts';
</ul>
<p class="muted">
This list grows as the stack does. Spotted something you'd ask about?
This list grows as the stack does. Spotted something you'd ask about?{' '}
<a href={`mailto:${LEGAL.email}`}>Get in touch</a>.
</p>
</article>