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>
83 lines
9.5 KiB
Markdown
83 lines
9.5 KiB
Markdown
# 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 `VTODO` objects inside a calendar collection. The Tasks README confirms CalDAV as the sync protocol: "Apps which sync with Nextcloud Tasks (using CalDAV)" ([nextcloud/tasks README](https://github.com/nextcloud/tasks)).
|
|
- **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](https://github.com/nextcloud/server/blob/master/apps/dav/lib/CalDAV/CalDavBackend.php)), and this same VTODO-vs-VEVENT distinction is documented for calendar integrations in the developer manual's [Integration of custom calendar providers](https://docs.nextcloud.com/server/latest/developer_manual/digging_deeper/groupware/calendar_provider.html) 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](https://www.rfc-editor.org/rfc/rfc5545)). 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](https://docs.nextcloud.com/server/stable/admin_manual/groupware/calendar.html)), 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:
|
|
|
|
```xml
|
|
<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](https://sabre.io/dav/building-a-caldav-client/))
|
|
|
|
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](https://github.com/sabre-io/dav/blob/master/lib/DAV/Client.php)). 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 their `supported-calendar-component-set`.
|
|
- `request($method, $url, $body, $headers)` — generic HTTP request, usable with `method: 'REPORT'` and the `calendar-query` XML body above to fetch `VTODO` objects (the client has no built-in `calendar-query` helper, so the REPORT body is hand-built XML sent via `request()`).
|
|
- `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](https://docs.nextcloud.com/server/latest/user_manual/en/session_management.html)). 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 deprecated `v0.2` also exists), with supported versions advertised via the Capabilities API and an `X-Notes-API-Versions` response header ([nextcloud/notes API docs](https://github.com/nextcloud/notes/blob/main/docs/api/README.md)).
|
|
- 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 structured `VTODO` fields (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."
|