Cover Symfony backend, calendar sync (Exchange Graph API + Mail-in-a-Box CalDAV), Docker/Gitea CI, frontend stack, Diun/RSS/QR additions, and Nextcloud Tasks (CalDAV VTODO) integration. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
9.5 KiB
Nextcloud to-dos on the smart screen
Research into pulling the user's self-hosted Nextcloud to-dos onto the wall-mounted kiosk dashboard.
Which Nextcloud app actually holds "to-dos"
Nextcloud ships two apps that could plausibly be meant by "notes/to-dos":
- Tasks app — proper checkable to-do items (title, due date, priority, completion status, subtasks), stored as CalDAV
VTODOobjects inside a calendar collection. The Tasks README confirms CalDAV as the sync protocol: "Apps which sync with Nextcloud Tasks (using CalDAV)" (nextcloud/tasks README). - Notes app — plain Markdown notes with a REST/OCS-style JSON API of its own; a "to-do" here would just be a
- [ ]checkbox line inside a Markdown blob, not a structured, checkable item.
Nextcloud's own CalDAV backend explicitly supports both VEVENT and VTODO components per calendar collection — the supported-calendar-component-set capability is what lets a calendar hold events, tasks, or both (visible in the backend implementation: CalDavBackend.php, nextcloud/server), and this same VTODO-vs-VEVENT distinction is documented for calendar integrations in the developer manual's Integration of custom calendar providers page.
VTODO itself is a standard iCalendar component, not a Nextcloud invention: RFC 5545 §3.6.2 "To-Do Component" defines it, with a STATUS property whose values include NEEDS-ACTION (default), IN-PROCESS, COMPLETED, and CANCELLED (RFC 5545). CalDAV (RFC 4791) is the WebDAV extension that lets a client list/query/fetch these VTODO/VEVENT objects from a server-side calendar collection — the same protocol family the Nextcloud Calendar app research (in the companion doc) already covers for events.
Conclusion: for "current open to-dos" with due dates and a completion flag, the Tasks app / CalDAV VTODO route is the correct mapping. The Notes app is the fallback only if the user's checklist genuinely lives as checkbox lines inside a note rather than as Tasks-app items.
CalDAV path convention for task lists
Nextcloud exposes all CalDAV calendars — task lists included, since a task list is just a calendar collection with VTODO support enabled — under the same principal-based tree used for events:
https://<nextcloud-host>/remote.php/dav/calendars/<username>/<calendar-name>/
This is Nextcloud's standard CalDAV/CardDAV mount point; Nextcloud's own admin manual for Calendar/CalDAV describes the CalDAV backend (resource/room booking, differential sync tracking for offline clients like Thunderbird) as living under this DAV tree (Calendar / CalDAV — Nextcloud Administration Manual), and the same /remote.php/dav/calendars/<user>/<calendar>/ pattern is what third-party CalDAV clients (e.g. DAVx5) are configured against when pointed at a Nextcloud instance. A task list created in the Tasks app shows up as just another calendar collection at this path — there is no separate /tasks/ endpoint; Tasks is a UI on top of the same CalDAV calendars, distinguished only by the VTODO component flag on the collection.
To discover the exact per-user collection names, a client does a PROPFIND with Depth: 1 on /remote.php/dav/calendars/<username>/ and reads each collection's {urn:ietf:params:xml:ns:caldav}supported-calendar-component-set to find which ones accept VTODO.
Fetching VTODO items (not just VEVENT)
CalDAV's calendar-query REPORT can filter for VTODO specifically. Sabre's own CalDAV client guide gives this exact case: "If you're only interested in VTODO (because you're writing a todo app) you can also filter for just those," with the filter body:
<c:calendar-query xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
<d:prop>
<d:getetag />
<c:calendar-data />
</d:prop>
<c:filter>
<c:comp-filter name="VCALENDAR">
<c:comp-filter name="VTODO" />
</c:comp-filter>
</c:filter>
</c:calendar-query>
(Building a CalDAV client — sabre.io)
To further narrow to open (not-yet-completed) items, add a <c:prop-filter name="STATUS"> / <c:text-match> for anything other than COMPLETED, or simply filter client-side on the parsed STATUS/COMPLETED properties after fetching — simpler and less fragile than relying on server-side text matching.
PHP-side CalDAV client for Symfony
Nextcloud's own DAV server is built on sabre/dav (sabre-io/dav), and that same package ships a generic WebDAV/CalDAV client, Sabre\DAV\Client (lib/DAV/Client.php, sabre-io/dav). Relevant surface for this use case:
- Constructed with a settings array:
baseUri,userName,password,authType(AUTH_BASIC,AUTH_DIGEST,AUTH_NTLM). propFind($url, $properties, $depth)— for discovering calendar collections and theirsupported-calendar-component-set.request($method, $url, $body, $headers)— generic HTTP request, usable withmethod: 'REPORT'and thecalendar-queryXML body above to fetchVTODOobjects (the client has no built-incalendar-queryhelper, so the REPORT body is hand-built XML sent viarequest()).parseMultiStatus($body)— parses the WebDAV multistatus XML response into a URL → properties map.
This is the same library the calendar-sync research already points to for VEVENT — nothing extra is needed for VTODO since it is the same CalDAV REPORT mechanism against the same client class, only the filter's comp-filter name changes from VEVENT to VTODO. Requiring it from Symfony is a standard Composer dependency (sabre/dav), no custom protocol code beyond building the REPORT XML and parsing the returned VCALENDAR/VTODO blocks (a small iCalendar parser — sabre/vobject, also from the sabre.io project — handles that parsing rather than hand-rolling one).
Authentication
Nextcloud CalDAV access uses HTTP Basic Auth over HTTPS, authenticated with a Nextcloud app password rather than the user's real account password. Nextcloud's user manual documents generating one from Settings → Security → Devices & sessions: "At the bottom of the list, you can create a new device-specific password. The generated password is used for configuring the new client" — and if two-factor auth is enabled on the account, an app password becomes mandatory for any non-browser client, since the server rejects the real password for such connections (Session management — Nextcloud User Manual). This app password is passed as the Basic Auth password against the same /remote.php/dav/... URLs used above — identical to the auth approach already used for the Calendar/VEVENT sync in the companion research doc, so a single app password/credential can cover both.
Notes app as a fallback (if "to-dos" really means checklist text in Notes)
If investigation of the user's actual Nextcloud setup shows their "to-dos" are informal checkbox lines inside Notes rather than structured Tasks-app entries, the Notes app does expose its own documented REST API rather than requiring scraping:
- Base path:
/index.php/apps/notes/api/v1/(current major version; a deprecatedv0.2also exists), with supported versions advertised via the Capabilities API and anX-Notes-API-Versionsresponse header (nextcloud/notes API docs). - Auth is the same pattern: HTTP Basic Auth with username/password (or app password) on every request, since REST is stateless; the docs flag that this makes plain HTTP a credential-leak risk and recommend TLS.
- The API returns raw note content (Markdown) — it has no structured concept of a checkbox/to-do item; extracting "open to-dos" from it means the client parsing Markdown
- [ ]/- [x]lines itself, which is materially more fragile than reading structuredVTODOfields (title, due date,STATUS) directly.
This is a strictly worse fit for "current open to-dos" than Tasks/CalDAV and should only be used if the user confirms their to-dos genuinely live as note checkboxes.
Claude Code skill / MCP server for Nextcloud
No project skill or configured MCP server for Nextcloud or generic CalDAV was found in this repository or the assistant's currently loaded skill/MCP listings. Any CalDAV fetch code for this feature will need to be written directly in the Symfony backend (using sabre/dav + sabre/vobject as above) — there is nothing to delegate to an existing tool here.
Recommended integration
Use the Tasks app via CalDAV, reading VTODO objects from /remote.php/dav/calendars/<username>/<calendar>/ with a calendar-query REPORT filtered to comp-filter name="VTODO", parsed with sabre/vobject on top of an HTTP/Sabre\DAV\Client request, authenticated with a Nextcloud app password over HTTP Basic Auth. Rationale: it is the only one of the two apps that models a to-do as a structured, checkable item with due date and completion status rather than free-text, it reuses the exact same CalDAV protocol, library, and app-password credential already needed for calendar/event sync, and filtering STATUS != COMPLETED client-side after the fetch directly yields "current open to-dos."