Calendar backend groundwork: SQLite cache + Docker prep #1

Open
opened 2026-09-01 19:27:29 +00:00 by haylan · 2 comments
Owner

Destination

A locked-decisions map — not a formal spec doc, no code written by this effort — covering the calendar-backend groundwork needed before implementation starts: the local SQLite cache/store (designed generically enough that RSS/Diun can plug in later, per docs/research/smart-tablet-screen-additions.md), the calendar sync approach for all three account types (Mail-in-a-Box/Nextcloud CalDAV, Microsoft Graph, Nextcloud Tasks/VTODO), and the Docker groundwork (FrankenPHP dev/prod image, docker-compose + override) everything will run behind. Done when nothing is left to decide before a Symfony project can be bootstrapped and the schema/sync/Docker decisions executed.

Notes

  • Domain: single-context repo, no CONTEXT.md/ADRs yet (greenfield) — /domain-modeling should create them lazily as terms/decisions get pinned down on tickets.
  • Prior research already done and settled (see Decisions so far): docs/research/smart-tablet-screen-stack.md, docs/research/smart-tablet-screen-config-secrets.md, docs/research/smart-tablet-screen-nextcloud-todos.md, docs/research/smart-tablet-screen-calendar-webhooks.md. docs/research/smart-tablet-screen-additions.md (Diun/RSS) is background only — informs the generic schema shape, not ticketed in this map.
  • Access layer decided: Doctrine DBAL (not full ORM) + hand-defined typed PHP entities/DTOs hydrated from DBAL rows — not raw arrays.
  • Docker decided: FrankenPHP-based image, docker-compose.yml + docker-compose.override.yml for local dev, just the Symfony container (no reverse proxy — stays external on the host), SQLite on a named volume at var/.
  • Symfony project bootstrap itself is deliberately NOT a decision ticket on this map — it's mechanical Task work once the decisions below are locked (see Not yet specified).
  • Grilling tickets on this map: always invoke /grilling and /domain-modeling.

Decisions so far

  • Calendar sync protocol per account type — CalDAV (RFC 4791) against Nextcloud's /remote.php/dav/calendars/<user>/ for Mail-in-a-Box accounts; Microsoft Graph API (OAuth2, tenant=common, offline_access) for Outlook/Exchange — CalDAV isn't offered for Outlook.com and EWS is being retired.
  • Multi-account config & secrets storage approach — Symfony Configuration tree (useAttributeAsKey() prototype, mirroring Doctrine's dbal.connections/Messenger's transports) for the account list structure in config/packages/smart_screen.yaml, with actual secret strings (app-passwords, client secret, refresh token) in Symfony's native secrets vault, referenced via %env(...)%.
  • Nextcloud Tasks/VTODO integration approach — same CalDAV protocol/client (sabre/dav + sabre/vobject) as events, filtered to VTODO via a calendar-query REPORT, same app-password auth — no separate integration needed.
  • Calendar/Graph webhook vs polling support — sync-token polling (WebDAV RFC 6578) for Nextcloud/CalDAV (Mail-in-a-Box's bundled Nextcloud is 3 major versions behind the Webhooks app's minimum); real Microsoft Graph webhook subscriptions (/subscriptions on the event resource, max ~7-day duration) with a scheduled renewal job, plus low-frequency polling fallback for resilience.
  • FrankenPHP Docker image setup for dev/prod — base image dunglas/frankenphp:1-php8.5 (Debian); FrankenPHP's own Symfony guide (the dunglas/symfony-docker reference: shared base stage → dev stage w/ Xdebug+watch → prod_builder/prod stages); worker mode left off in prod by default (needs an app audit for state leaks first); pdo_sqlite + sodium confirmed enabled out of the box. Compose: base docker-compose.yml (single service, prod-shaped) + docker-compose.override.yaml for dev, with a named var/ volume (not anonymous) so the SQLite cache persists across rebuilds.

Not yet specified

  • Symfony project bootstrap (composer create-project, FrankenPHP scaffold) — mechanical Task once the entity-schema and Docker tickets close; tickets when the decisions below are locked (this map or the next).
  • RSS feed and Diun webhook event storage — the cache schema is designed generically enough to fit them (per the additions.md research), but they get no tickets of their own on this map; a future map picks up their concrete integration once the calendar slice is built.
  • Exact SQLite migration/versioning workflow (Doctrine Migrations Bundle setup specifics) — follows once the entity schema ticket closes.

Out of scope

(none yet)

## Destination A locked-decisions map — not a formal spec doc, no code written by this effort — covering the calendar-backend groundwork needed before implementation starts: the local SQLite cache/store (designed generically enough that RSS/Diun can plug in later, per `docs/research/smart-tablet-screen-additions.md`), the calendar sync approach for all three account types (Mail-in-a-Box/Nextcloud CalDAV, Microsoft Graph, Nextcloud Tasks/VTODO), and the Docker groundwork (FrankenPHP dev/prod image, docker-compose + override) everything will run behind. Done when nothing is left to decide before a Symfony project can be bootstrapped and the schema/sync/Docker decisions executed. ## Notes - Domain: single-context repo, no `CONTEXT.md`/ADRs yet (greenfield) — `/domain-modeling` should create them lazily as terms/decisions get pinned down on tickets. - Prior research already done and settled (see Decisions so far): `docs/research/smart-tablet-screen-stack.md`, `docs/research/smart-tablet-screen-config-secrets.md`, `docs/research/smart-tablet-screen-nextcloud-todos.md`, `docs/research/smart-tablet-screen-calendar-webhooks.md`. `docs/research/smart-tablet-screen-additions.md` (Diun/RSS) is background only — informs the generic schema shape, not ticketed in this map. - Access layer decided: Doctrine DBAL (not full ORM) + hand-defined typed PHP entities/DTOs hydrated from DBAL rows — not raw arrays. - Docker decided: FrankenPHP-based image, `docker-compose.yml` + `docker-compose.override.yml` for local dev, just the Symfony container (no reverse proxy — stays external on the host), SQLite on a named volume at `var/`. - Symfony project bootstrap itself is deliberately NOT a decision ticket on this map — it's mechanical Task work once the decisions below are locked (see Not yet specified). - Grilling tickets on this map: always invoke `/grilling` and `/domain-modeling`. ## Decisions so far - [Calendar sync protocol per account type](https://git.arthurerlich.de/haylan/Smart-Tablet-Screen/src/branch/main/docs/research/smart-tablet-screen-stack.md) — CalDAV (RFC 4791) against Nextcloud's `/remote.php/dav/calendars/<user>/` for Mail-in-a-Box accounts; Microsoft Graph API (OAuth2, `tenant=common`, `offline_access`) for Outlook/Exchange — CalDAV isn't offered for Outlook.com and EWS is being retired. - [Multi-account config & secrets storage approach](https://git.arthurerlich.de/haylan/Smart-Tablet-Screen/src/branch/main/docs/research/smart-tablet-screen-config-secrets.md) — Symfony `Configuration` tree (`useAttributeAsKey()` prototype, mirroring Doctrine's `dbal.connections`/Messenger's `transports`) for the account list structure in `config/packages/smart_screen.yaml`, with actual secret strings (app-passwords, client secret, refresh token) in Symfony's native secrets vault, referenced via `%env(...)%`. - [Nextcloud Tasks/VTODO integration approach](https://git.arthurerlich.de/haylan/Smart-Tablet-Screen/src/branch/main/docs/research/smart-tablet-screen-nextcloud-todos.md) — same CalDAV protocol/client (`sabre/dav` + `sabre/vobject`) as events, filtered to `VTODO` via a `calendar-query` REPORT, same app-password auth — no separate integration needed. - [Calendar/Graph webhook vs polling support](https://git.arthurerlich.de/haylan/Smart-Tablet-Screen/issues/2) — sync-token polling (WebDAV RFC 6578) for Nextcloud/CalDAV (Mail-in-a-Box's bundled Nextcloud is 3 major versions behind the Webhooks app's minimum); real Microsoft Graph webhook subscriptions (`/subscriptions` on the `event` resource, max ~7-day duration) with a scheduled renewal job, plus low-frequency polling fallback for resilience. - [FrankenPHP Docker image setup for dev/prod](https://git.arthurerlich.de/haylan/Smart-Tablet-Screen/issues/3) — base image `dunglas/frankenphp:1-php8.5` (Debian); FrankenPHP's own Symfony guide (the `dunglas/symfony-docker` reference: shared base stage → `dev` stage w/ Xdebug+watch → `prod_builder`/`prod` stages); worker mode left off in prod by default (needs an app audit for state leaks first); `pdo_sqlite` + `sodium` confirmed enabled out of the box. Compose: base `docker-compose.yml` (single service, prod-shaped) + `docker-compose.override.yaml` for dev, with a **named** `var/` volume (not anonymous) so the SQLite cache persists across rebuilds. ## Not yet specified - Symfony project bootstrap (`composer create-project`, FrankenPHP scaffold) — mechanical Task once the entity-schema and Docker tickets close; tickets when the decisions below are locked (this map or the next). - RSS feed and Diun webhook event storage — the cache schema is designed generically enough to fit them (per the additions.md research), but they get no tickets of their own on this map; a future map picks up their concrete integration once the calendar slice is built. - Exact SQLite migration/versioning workflow (Doctrine Migrations Bundle setup specifics) — follows once the entity schema ticket closes. ## Out of scope (none yet)
haylan added the wayfinder:map label 2026-09-01 19:27:41 +00:00
Author
Owner

Decision recorded: Calendar/Graph webhook vs polling support closed — sync-token polling (RFC 6578) for Nextcloud/CalDAV (Mail-in-a-Box's bundled Nextcloud is too old for the Webhooks app), real webhook subscriptions + scheduled renewal job for Microsoft Graph. See docs/research/smart-tablet-screen-calendar-webhooks.md. This unblocks #4 and #5.

Decision recorded: [Calendar/Graph webhook vs polling support](https://git.arthurerlich.de/haylan/Smart-Tablet-Screen/issues/2) closed — sync-token polling (RFC 6578) for Nextcloud/CalDAV (Mail-in-a-Box's bundled Nextcloud is too old for the Webhooks app), real webhook subscriptions + scheduled renewal job for Microsoft Graph. See docs/research/smart-tablet-screen-calendar-webhooks.md. This unblocks #4 and #5.
Author
Owner

Decision recorded: FrankenPHP Docker image setup for dev/prod closed — base image dunglas/frankenphp:1-php8.5 (Debian), FrankenPHP's own Symfony guide (dunglas/symfony-docker reference: shared base stage -> dev stage w/ Xdebug+watch -> prod_builder/prod stages), worker mode left off in prod by default (needs an app audit first), pdo_sqlite + sodium confirmed enabled out of the box. Compose: base docker-compose.yml (single service, prod-shaped) + docker-compose.override.yaml for dev (bind-mount source, dev target, dev env), with a NAMED var/ volume (not anonymous) so the SQLite cache persists across rebuilds. See docs/research/smart-tablet-screen-frankenphp-docker.md. This unblocks #4 and #5 — both are now on the frontier.

Decision recorded: [FrankenPHP Docker image setup for dev/prod](https://git.arthurerlich.de/haylan/Smart-Tablet-Screen/issues/3) closed — base image dunglas/frankenphp:1-php8.5 (Debian), FrankenPHP's own Symfony guide (dunglas/symfony-docker reference: shared base stage -> dev stage w/ Xdebug+watch -> prod_builder/prod stages), worker mode left off in prod by default (needs an app audit first), pdo_sqlite + sodium confirmed enabled out of the box. Compose: base docker-compose.yml (single service, prod-shaped) + docker-compose.override.yaml for dev (bind-mount source, dev target, dev env), with a NAMED var/ volume (not anonymous) so the SQLite cache persists across rebuilds. See docs/research/smart-tablet-screen-frankenphp-docker.md. This unblocks #4 and #5 — both are now on the frontier.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: haylan/Smart-Tablet-Screen#1