Added
-
Reminders can be delivered by email. Households without a native app fell back to keeping a
browser tab open: reminders reached Web Push, Gotify, ntfy or a webhook, and nothing else (#944).
Email is now a fourth channel type next to those three, configured the same way under
Settings → Personal → Notifications.It deliberately brings no credentials of its own. The SMTP access already configured for password
resets and invitations is the one it uses, so a mail server is set up once and not once per
channel - a second copy would only be a second place to forget when the server changes. A channel
therefore holds just a recipient address; a second recipient is a second channel, which keeps each
one separately switchable and separately testable. Who gets a reminder is still decided by the
channel's scope, exactly as for the other providers.Two details are worth knowing. Web Push splits a reminder across title and body, but an inbox
shows only the subject line, so the mail puts both there - "Calendar: Dentist" rather than
"Calendar". And the link back into the app needsBASE_URL; without it the mail arrives without a
link rather than with a dead one. The provider list marks email as not ready while SMTP is
unconfigured, so the settings page says so before a test send fails.A note for anyone tracking health data: an email channel carries reminder contents in the subject
line, medication names included, and subject lines stay readable in transit and permanently in the
recipient's mailbox.docs/PRIVACY-FOR-SELFHOSTERS.mdcovers what that means. -
A shopping list can be sent to whoever is doing the run. The second half of #944. An entry in
the list's overflow menu mails its open items to one household member, grouped by aisle in the same
order the screen shows them.It sends a snapshot, not an access route - no link, no token, nothing that outlives the message.
A read-only share URL was the other obvious shape and was deliberately not built: it would have
been the first unauthenticated view of household data in Yuvomi, and a leaked link stays leaked.
Someone who needs the list continuously is a household member and already has the app. Because a
snapshot goes stale the moment someone at home ticks an item off, the mail says which moment it
captured rather than pretending to be live.The recipient is picked from the household, and only members with an address on their contact
appear - the same source password reset mails use. The address is never taken from the request:
accepting one would make the instance an open mail relay for anyone with a login. Sending to
yourself works too, which is the "get the list onto my phone" case, and then the mail skips the
"X sent you this list" line.Needs SMTP configured. Three refusals are told apart rather than collapsed into one failure: the
member has no address, SMTP is not set up, or nothing on the list is still open.Only actual household members can be picked, and that is narrower than "has an account". Housekeeping
staff and shared-expense guests both have logins and both have a contact with an address on it -
guests especially are external people who are blocked from every other part of the app. The rule that
decides this is written once and used by both the picker and the send route, so the two cannot drift
apart. An address field holding a list rather than one address makes that member unreachable instead
of reaching everyone on it.
Fixed
-
The settings page works offline again. Its shell loads
dirty-guard.js- the part that asks
before you discard unsaved edits - and that file was never in the service worker's precache list.
Online nobody noticed, because the network filled the gap. Offline the import failed and took the
whole settings shell with it. The file is precached now.The date picker was missing the same way, and it is loaded by the router itself - so a first
offline visit could get the HTML fallback instead of the module, on every page with a date field.The reason both went unnoticed is the more useful half. A guard does check that every module
reachable from a precached one is itself precached, and it stayed green throughout: it read only
imports written asfrom '/absolute/path'. The settings shell writesfrom './dirty-guard.js'
and the router writesimport '/components/datepicker.js'- a relative specifier and a
side-effect import, both loaded by the browser exactly like any other. The guard now resolves both
forms, which is how these were found in the first place.