github ulsklyc/yuvomi v2.74.0

2 hours ago

Added

  • The Singapore dollar is a currency a household can pick, and Singapore is a region (#1697,
    from D#982). SGD was missing from the list the household setting, subscriptions and shared
    expenses all read, and the server checks a saved currency against that same list - so a
    household in Singapore could not record its money in its own currency at all. Choosing
    English (Singapore) as the region now sets the dollar together with the local date and time
    format in one step (06/10/2026, twelve-hour clock), and amounts are grouped the way they are
    written there.

  • A meal can name the member who cooks it, and the week plan and the overview show who that
    is
    (#1679, from D#1661, asked by @matejhermanek for a shared flat that plans who cooks which
    meal). A planned meal carried a date, a type, a title, notes and a recipe, and the only person on it was whoever
    entered it. The meal dialog now offers the household members in the same person picker the task
    dialog uses, limited to one person; the cook's avatar then stands on the meal in the week plan
    and on today's meal on the overview. On a wall tablet, cooking counts under "Who's up today"
    like a task does. A meal without a cook looks as it did. A repeating meal
    keeps its cook: every meal the series creates starts with it, changing the cook of one meal
    leaves the series alone, and choosing one for the whole series reaches all its meals. Saving
    for the whole series changes the cook only when you picked one in that dialog: a new title for
    the series leaves every cook where it is, including the ones set for single weeks, and while
    nothing is picked the dialog shows the cook of the series there, not of the one meal.
    A series whose cook is no longer a household member keeps running; its new meals start
    without a cook, and the meals that already exist keep the name. Weeks created while the
    account was deactivated stay without a cook; once it is a member again, the next new week
    starts with it. The cook
    is a responsibility, not ownership - the plan stays the household's, and who sees or edits a
    meal still depends on the meal plan right alone; with read access the cook is shown and cannot
    be chosen. Only household members can be picked, so housekeeping staff, guests of shared
    expenses and wall tablets are not offered, while a meal that already carries such a cook still
    saves. An account that cooks a meal is deactivated rather than deleted when it is removed, like
    an account a task is assigned to, and the meal keeps the name. One cook per meal; meals in the
    calendar, a reminder for the cook and a view per person are not part of this. For API clients:
    cook_user_id on POST /api/v1/meals, PUT /api/v1/meals/{id} (with ?scope=series for the
    series) and on each assignment of POST /api/v1/meals/apply-plan; meals come back with
    cook_user_id, cook_name and cook_color, also in todayMeals of the overview (migration
    235); the cook's picture is not repeated on every meal, it is on the member
    (GET /api/v1/family/members, which a scoped token reads with family:read). The id is a positive integer or null; an empty string or any other
    form is refused with 400. A meal of a series also returns recurrence_cook_user_id, the cook
    stored on the series.

  • A household can put its members in an order of its own, and every list of people follows it
    (#1644, from D#1605, asked by @ChaCha500). Until now members were listed alphabetically
    everywhere, so "parents first" or "oldest first" was not possible. Under Settings, Family, an
    administrator now drags the members into the wanted order - or focuses a handle and presses
    the arrow keys. There is one order per household, the same for everyone who looks: the
    calendar's person filter, the timetable, the assignee pickers in tasks, budget and shared
    expenses, rewards, the family card and the wall display all use it. A member who has not been
    placed (a new one, and everyone in a household that never touches the setting) comes after
    the placed ones, sorted by name, so a household that leaves it alone sees the order it had.
    Not by age, as first suggested: birth dates are optional, and "parents first, then the
    children" cannot be read from a date. Two things changed for everyone, placed or not. Lists
    that sorted names by the language of the device now sort them the way the server does, so
    two devices of one household agree; and a few lists that put a lower-case name after all
    capitalised ones (the account list, the task filter and the overview among them) now ignore
    letter case like the others. Housekeeping staff, guests of shared expenses, wall tablets and deactivated
    accounts have no place in the order. For API clients: PATCH /api/v1/family/members/reorder
    with { order }, administrators only; sort_order on GET /api/v1/family/members and
    GET /api/v1/auth/users, and is_household_member on every user object (migration 232).

  • Each device chooses how long it waits before the photo screensaver starts (#885). Settings →
    Appearance, next to wall mode, offers 1, 2, 5, 10 or 15 minutes; five stays the default, so
    nothing changes on a device that never touches it. The choice is stored in the browser like wall
    mode, because the devices in one household want different delays: a photo frame on the wall
    wants its pictures back after a minute, a kitchen tablet people work on should wait longer, and a
    household value would also reach every phone. The value is applied before the page renders, so
    the first idle period already uses it, and a change takes effect at once without a reload, in
    other open tabs too. The settings search finds it under "screensaver", and the Immich page no
    longer promises five minutes.

  • Revoked and expired API tokens can be removed from the list (D#1672, asked by @torbenvanassche). Under
    Settings, API access, a revoked token stayed in the list for good, with a greyed-out button
    next to it. The list now has two parts: the tokens that work, each with "Revoke", and below
    them the ones that are revoked or expired, each with "Remove". Removing asks first and cannot
    be undone. A token that still works cannot be removed, only revoked, so ending someone's
    access always leaves a trace until you decide to clear it. The same goes for wall tablets:
    every new pairing revokes the device before it, and those old entries can now be removed as
    well. For API clients: POST /api/v1/auth/api-tokens/{id}/remove and
    POST /api/v1/displays/{id}/devices/{deviceId}/remove; both answer 409 for a credential
    that is still active, and DELETE /api/v1/auth/api-tokens/{id} keeps meaning "revoke".

  • The Calendar tile on the overview can list 8 or 12 appointments instead of 5 (D#1676, #1680).
    The tile always showed the next five, and a household with a full week had to open the
    calendar for the rest. Its options in Customize mode - where "Which appointments?" and the
    birthdays switch already live - now ask "How many appointments?" with three steps: 5, 8 and
    12. Five stays the default, so a tile nobody touched looks as before. The choice belongs to
    the person who made it, travels with a household default like the other tile options, and
    applies on a phone as well. Appointments of today that are already over still stand above
    the list and do not use up the number. The tile grows with its list instead of scrolling,
    in every list size, and the tiles next to it in the grid grow with it: with 12 it is
    roughly twice as tall as with 5. At "Wide (2x1)" the tile remains the week strip, and the
    Today sheet and wall mode keep their own number of rows. For API clients:
    GET /api/v1/dashboard takes events_limit with exactly 5, 8 or 12; any other value
    means 5. "Set as household default" now shows the result at once when a tile option changed
    what the overview asks for; until now the tile kept its old list until the next refresh.

  • A loan can carry a due day, and "Mark paid" dates the installment on it (#1631, #1741,
    D#1481, asked by @iHatim1). A loan knew the month an installment is due but no day, so "Mark paid" dated the
    entry on the day you tapped it: with a debit on the 27th, marking it on the 25th put it two days
    early, and marking it on 2 November put October's installment into November's budget. The loan
    dialog now has an optional "Due day" field, 1 to 31. With it set, the installment is dated on that
    day in the month it is due, whether you mark it early or late, and a month that is shorter takes
    its last day (the 31st becomes 30 April, or 28 or 29 February). The confirmation names the date
    that was used, because the entry is booked without a dialog, and the loan card shows the full
    date of the next installment instead of only the month. "Installments already paid" on a new
    loan use the day as well. A loan without a due day keeps today's date for the installment of
    the current month, and its card keeps naming the month. An installment whose month is already
    over is dated on the 1st of that month instead of today (#1741, D#1021, reported by @mamo79):
    catching up a loan that started in 2022 used to put every past installment, and its budget
    entry, into the month you tapped in. The 1st is what "Installments already paid" already uses
    for such a loan. Nothing that is already booked is moved: setting or changing the day later
    leaves existing installments and their budget entries where they are. Marking early books an entry dated a few days ahead; it
    counts in that month's totals at once and in the account's current balance from its date on. For
    API clients: loans accept and return due_day, and return next_due_date next to
    next_due_month. Without a due day it is the 1st of next_due_month once that month lies
    before the household's current month, and null otherwise.
    POST /api/v1/budget/loans/{id}/payments is unchanged, paid_date stays required and is
    stored as sent.

Changed

  • Overlapping events in the day and week view are placed by person, not by start time
    (D#1605, #1633). Events at the same time used to be packed by the clock alone: whoever
    started first stood on the left, so the same person could be left at nine and right at
    eleven, and two events with the same start and end could swap places from one load to the
    next. Now every person in a group of overlapping events gets a column of their own, in the
    order in which the household's members are listed - the order of the people filter. An event with several people stands where the first of them in
    that order stands; events of people who are not household members follow after the members,
    and an event with nobody assigned comes last. Two events of the same person at the same
    time stand next to each other. Nothing is reserved: an event that overlaps nothing keeps
    the full width, and a person who is not part of a group takes no room in it. The price is
    width in a chain: with 9:00-10:00, 9:30-11:00 and 10:30-12:00 for three people, the third
    used to take the place the first had left and the group was two columns wide; now it is
    three, because the third may not stand in the first one's column, and a longer chain of
    different people grows by a column per person. Schedule blocks, the all-day row, the month
    and the agenda are unchanged.

  • Two people with the same initials no longer look the same (#1464). Linda Johnson and Leo
    Johnson both showed "LJ" on their avatars, in the people picker, in avatar stacks and on the
    overview, and colour was the only difference. Whoever shares their initials with somebody
    else in the household now gets the first letter of their first name and the next letter of
    it that nobody carries yet: "LI" and "LE". If that letter is taken as well - by Lisa Imhof,
    "LI" - the next one is used ("LN"), and after the first name the letters of the last name.
    Everybody whose initials are theirs alone keeps them, it stays at two characters, and the
    result is the same in every view and for everyone who looks, because it is worked out from
    the names of all accounts and not from the list a page happens to show. A deactivated
    account still counts, so nobody's initials change when somebody leaves; they can change
    when a new person joins or somebody is renamed. Names written without a space in Hangul,
    Han or Kana take the family name's first character and the given name's last (김민수 and
    박민수 become 김수 and 박수). Two accounts with exactly the same name stay the same. For
    API clients: GET /api/v1/auth/me and the login answer carry initialsRoster, the display
    names of all accounts; a shared-expenses guest gets an empty list.

  • Removing a member no longer takes their entries with it (#1381). Deleting someone under
    Settings, Family used to delete everything that person had created as well - appointments,
    tasks, notes, documents, and payments they had recorded for others, which silently changed
    everybody else's balances in shared expenses. And anyone who had taken part in a shared
    expense, or had ever added a quick link, could not be removed at all: the app answered with
    "Internal server error". Now it depends on what the person leaves behind. If anything shared
    still refers to them, the account is deactivated instead of deleted: every entry stays and
    keeps their name, balances stay as they are, and the person stands at the end of the list
    marked "Former member". If nothing shared refers to them, the account is deleted as before.
    The dialog says both, and the message afterwards tells you which one happened.
    Access ends at once. A deactivated person is signed out everywhere and cannot sign in
    again, neither with a password nor through single sign-on, which recognises the account and
    turns it away instead of creating a second one. API tokens acting as that person are
    revoked, and so are tokens they issued for somebody else, because only the person who
    issues a token ever sees it - issue those again if an integration still needs them.
    Invitation links and wall tablet pairing codes they created and nobody has used yet stop
    working; a tablet that is already paired stays. Their calendar feed addresses stop working,
    a wall tablet can no longer tick off anything in their name, password reset links are
    dropped and no new ones are sent, and their two-factor recovery codes are deleted. They get no more push messages, mails or reminders. An
    administrator who is deactivated stops being one, and the last administrator still cannot
    be removed.
    Private data stays where it is. Health and cycle records, private notes, shift plans and
    the person's own contact card and birthday are kept when an account is deactivated; nobody
    can sign in to read them, and people who look after that person keep the access they had,
    but nobody new can be given it. Removing that data is not part of this change. A deactivated person can no longer be picked
    as assignee, attendee or group member, while everything they were already part of keeps
    them. Bringing an account back is not possible yet. For API clients:
    DELETE /api/v1/auth/users/{id} still answers 200 { "ok": true } and now adds
    outcome ("deactivated" or "deleted") and traces; GET /api/v1/auth/users carries
    deactivated_at per account.

  • Housekeeping chores work like every other list. A chore row carried a pencil and a bin
    side by side, 4px apart; the pencil opened the same dialog as a tap on the row, and on a
    phone the name was left with 198 of 358px. The row now opens the dialog when tapped, "Delete"
    sits in the dialog footer, and on a touch screen a swipe to the end of the row deletes and a
    swipe from the start marks the chore done. Deleting no longer asks first: it shows "Undo" for
    five seconds, and undoing brings the chore back with its last completion. The circle is the
    same one as in Tasks - 20px and neutral until you tick it, instead of 24px and green at rest.

  • Row titles share one type size. The name of a list row was set in four ways - 15px
    semibold in Tasks, 16px regular in Budget entries and subscriptions, 16px medium in most
    modules, 17px semibold in the agenda, contacts and birthdays. It is 16px medium everywhere
    now; card titles keep their heading size.

  • Budget: the seven tabs share one skeleton. Figures use one size everywhere (28px; the
    side columns of the overview and the loans tab showed the same card at 20px), and on a phone
    every tab with figures shows them as one row, accounts included. On subscriptions and split
    expenses the section titles now stand above their lists, with search and tools to the right,
    as on the overview; the lists themselves are plain row lists instead of rows inside a padded
    card.

  • Budget statistics: the share ring sits with the categories it explains. On a phone it
    stood 874px below the category bars next to an empty area; on a desktop it sat in a side
    column that was empty beneath it. It now shares the first row with the trend chart, the bars
    use the full width below, and a line next to the ring names the number of segments, the
    largest one and the total. The marker line no longer stands at the last data point before you
    touch the chart.

  • One period stepper in calendar, meal plan, budget, housekeeping reports and shift plan.
    The five modules now share the same control. The shift plan's "Today" disappears while today
    is on screen, like everywhere else. In the budget on a phone, the month is shown in the
    module colour while you are somewhere else, and a tap on it jumps back to the current one.

  • Pantry: swipe a row to delete, and "Manage locations" is a button. A swipe to the end of
    a pantry row deletes it, with "Undo"; the stepper and the cart button are excluded from the
    gesture. The header's "..." menu had a single entry and is now that action itself.

  • Housekeeping: section titles stand above their cards, as in the other modules.

  • Headers have one height on a desktop. Single-row headers measured 65 or 69px depending on
    the module, and the "New" button moved by 2px when switching; all are 69px now.

  • Settings: headings follow one scale. On a sheet with "For me" and "For the household",
    that scope title was the smallest heading on the page. It now ranks above the sections it
    groups (sheet 22px, scope 20, section 17, card 16), also for screen readers.

  • Sign-in, setup, invitation and password reset look like one family. All of them show the
    app mark and name, every password field has the eye to show what you typed (new on the
    invitation and reset pages and on the repeat field of setup), and errors are announced the
    same way on each page.

  • Contacts: phone numbers, mail addresses and map links are no longer pink. They stood in
    the contacts colour right above a red "Delete"; the value is plain text now and the icon of
    its row carries the colour.

  • The shift plan steps through weeks like every other period. The compare view read
    "back, Today, forward, week"; it now reads back, week, forward and then "Today", as in the
    calendar and the budget, and the arrows say what they move ("Previous week").

  • Dialogs carry their module's colour. The active chip in the Tasks filter sheet was violet
    next to the same chip in green on the page behind it.

  • Budget: amounts have one weight, and zero is not a gain. The amount of a split expense
    stood heavier than an account balance, which stood heavier than a booking; all of them are
    semibold now. "You are owed 0.00" in Split no longer shows in green, "You owe 0.00" no longer
    in red. "Loan transactions" is a real heading, so a screen reader finds the list.

  • Rewards: the history rows are the shared list rows, and section headings carry no icon.
    The heading "Rewards" under the tab "Rewards" is no longer shown on a desktop either.

  • Rewards, Waste and Housekeeping use the width of a desktop window. These three stood as a
    720px column next to an empty right half, and where one tab was wider than the others, the
    header and its primary button jumped when you switched tabs - in Rewards by up to 431px. Each
    module now has one outer edge for all of its tabs, and the button stays where it is. From a
    window of about 1280px the lists get a second column with what was already there: the latest
    bookings next to the point balances in Rewards (the heading leads to the full history) and
    the balances next to the history, waste types and import sources next to the next pickups,
    the month's figures next to the visit reports and a person's visit log next to the staff list
    in Housekeeping. The lists themselves keep their reading width. Nothing changes on a phone
    except that the Rewards overview ends with the latest bookings.

  • Every Budget tab ends at the same edge on a desktop, and so does the header. The "new"
    button stood 276px (at 1280) or 404px (at 1440) short of the content it belongs to. The plan
    was a single 720px column, loans changed their right edge four times on the way down, and the
    net worth of the accounts sat in a 232px tile next to an empty row. Now the plan shows the
    category budgets with the savings goal beside them, loans show the filter, the loans and their
    transactions in one column with the three figures beside it, and the net worth runs across the
    row above the accounts. In "Split" the recent expenses take the wider column, balances and
    activity the narrower one. Phones are unchanged.

  • "Latest vitals" in the Health overview uses the width instead of one long column. On a
    desktop the nine tiles stood one below the other, 930px tall, next to 640px of empty space.
    The card now runs across the overview with four or five tiles per row, about a third as tall.

  • The calendar's day view shows what comes next beside the day. On a desktop the day was a
    single 932px column, the phone layout stretched. From a window of about 1280px the next seven
    days stand beside the hour timeline as agenda rows; a row opens the event, the heading leads
    to the agenda. The phone's day view is unchanged.

  • The Budget header is one row shorter on a phone. Title, month stepper and tabs stood in
    three rows (162px), and on the four tabs without a month the middle row only carried a
    caption. The month now sits at the end of the title row with a short label ("Oct 2026"), the
    caption of the other tabs stands in the same place, and the header is 117px on every tab, so
    nothing moves when you switch. While you look at another month, a tap on the month label
    returns to the current one; the arrows stay where they are.

  • Contacts, Birthdays, Waste, Notes, Documents and Settings lose their second header row on a
    phone.
    That row only carried one or two icons (search, "more"). They now sit at the end of
    the title row, and the list starts about 50px higher; an open search takes the row. In Waste,
    "Add waste type" moves into the "more" menu on a phone, and in Documents the grid/list choice
    moves into the sort menu. The note "Birthdays also appear in the calendar" no
    longer stands above the list - it is still in the dialog where you add one.

  • "Split" shows the first expense on the first screen of a phone. The group list, the group
    header and the balances stood as three cards in front of it, and the first expense came after
    more than a full screen. The group choice is now one row that names the active group and
    opens the list with search, "new group" and Active/Archived; the group header is just its
    actions, and the balances are tighter. On a wide window nothing changes.

  • Shift schedule: "Compare" and "Statistics" start with two rows of controls on a phone
    instead of a third of the screen.
    In "Compare" the people are one row you swipe through,
    next to Week/Day, with the week stepper below; in "Statistics" person and period stand side
    by side above the two buttons. The comparison or the figures begin about 170px higher.

  • Inventory and the Housekeeping overview show their figures as one row on a phone. Three
    and four tiles stood in front of the list, one of them for "0". Now one row names the main
    figure and up to two others, and a tap opens the tiles; a figure that is zero is left out.
    The first category in Inventory starts 106px higher, the first visit in Housekeeping 57px.

  • Rewards fit about five to a phone screen instead of two and a half. A reward was a tall
    tile with its emoji on a line of its own; on a phone it is now a compact card with emoji and
    text side by side. The heading "Rewards" under the tab "Rewards" no longer takes a row, and
    the overview ends with the three latest bookings instead of six.

  • Shopping: checked items keep their way into the pantry. "To pantry" and "Remove checked"
    lived only in the pill that appears for five seconds after the first tick and then stays
    away until nothing is checked. Both now also stand in the list menu, in a group of their own
    while something is checked; the menu is grouped into checked items, the list, master data
    and delete. The pill stays as the shortcut.

  • Tasks: the dialog asks when, who and how important first. Due date and time, assignee,
    priority and category follow the title; the note comes after them. Recurrence and reminder
    wait behind "More settings" while they are empty and stay open once set. On a phone the due
    date is on the first screen (it stood at 700 of 844px) and the dialog is a quarter shorter.

  • The formatting toolbar appears with the focus. Above a note it took three rows on a phone
    (162px) and twelve tab stops. It now shows when you enter the text field, runs as one row you
    can scroll, and is a single tab stop: Shift+Tab from the field enters it, the arrow keys move.

  • Notes: the editor is a workspace. The text field was six lines high and started below the
    keyboard line on a phone. Title and text no longer carry label rows, and the text field fills
    the sheet (about 320px on a phone, 400px on a desktop) and grows with what you write.

  • Tasks: the filter sheet is shorter. Category and tag fold while nothing in them is
    chosen, and grouping and "Show scheduled" form a separate "View" section at the end.

  • Recipes: the uploaded picture opens the detail as a 3:2 header; without a picture
    nothing takes its place.

  • Health on a phone: the start page is half as long. Below "Due today" and the area list it
    shows the two most recent vitals - the card title leads to all of them - and one row "Show
    all values" for the rest. The CSV export is a button in the head that opens a dialog, on
    every screen size.

  • Settings: long sheets start with jump marks. A sheet with more than three sections opens
    with a row of links to them. On a phone that row stands in place of the sheet description, and
    a sheet without it shows the description in two lines.

  • Subscriptions on a phone: the billing cycle stands under the amount, so the line with the
    due date no longer wraps. Budget accounts: a long account name wraps to a second line
    instead of being cut after "Gemeinsames Gi...".

  • Movement follows one curve. Hover and press feedback ran on a different easing curve than
    pages, dialogs and lists; buttons, rows, chips and toggles now share the curve of the rest of
    the app.

  • Sheets from below move the same way. The dialog sheet, the "More" sheet and the search on
    a phone were three different movements; all three now rise by a short lift with a fade and
    leave faster than they arrive. Menus fade out instead of vanishing.

  • Switching a tab or a period no longer cuts. Tabs inside Rewards, Housekeeping and the
    shift schedule fade to the new content as Budget's already did, in the direction of the tab
    you switch to, and paging by month or week (Budget, calendar,
    meal plan, housekeeping reports, shift overview) brings the new period in from the side you
    page to - with the arrows and shortcuts too, not only with a swipe. Health fades between
    areas on a desktop as it did on a phone. With "reduce motion" switched on only a short fade
    remains.

  • Lists show what changed. In Housekeeping, Waste collection, Pantry and Rewards a deleted
    or decided row folds away, a new one unfolds and a reordered one glides to its place, instead
    of the whole list being rebuilt in one step. Checked shopping items fade to their muted
    colour.

  • Rewards and the shift schedule no longer flash a loading state. Rewards emptied the page
    into a placeholder on every tab change and after every action; the shift overview did the
    same on every week step. Both keep what is shown until the new content is there. Where
    something does load for the first time, the shift schedule and the budget statistics show a
    placeholder in the shape of what follows instead of a "Loading..." card or a list.

  • Overview: customising no longer jumps. Entering and leaving the customise mode slides
    the tiles to their new position, and "+N more today" unfolds in place.

  • Shopping on a phone: the add field unfolds instead of pushing the list down in one step.

  • Inventory on a phone: Edit sits at the bottom of the detail sheet (#1463). The sheet had
    Delete at the bottom, where the thumb rests, and Edit at the top, out of reach - the
    riskiest action was the easiest one to hit. Edit is now the main button at the end of the
    footer and Delete stands back at its start, as in the calendar. Deleting still asks first,
    and without write access neither button is shown.

  • Deleting a shared expense now leaves a trace instead of rewriting the books. Until now
    deleting an expense removed its bookings, so the balances changed and nothing showed why. The
    expense now stays in the ledger and a counter-entry cancels it, so balances end up exactly where
    they would be without it, the same way a reversed payment works. The activity names the deleted
    expense with its title and amount, and the entry that added it is struck through and marked
    "Deleted" at every access level. A payment recorded against the expense stays as it is: payments
    are not tied to single expenses, so after the delete the balances show what was paid too much.
    An expense in another currency is cancelled in the currency it was booked in. Expenses deleted
    before this change keep their balances; only their trace is missing. (#1382)

Fixed

  • The API description of PUT /api/v1/meals/{id} names the two fields a series edit reads
    (follow-up to #1679). With ?scope=series the route has long taken repeat_until (the end of
    the series; an empty string removes it) and ingredients (replacing those of the series and of
    all its meals), but the OpenAPI document listed them for creating a meal only. Both are now
    described for the update as well, with the note that they are read in a series edit alone.

  • Holiday countries and regions are named in your language, and the delete button of the task
    selection is no longer announced as a question
    (#1723). Under Settings, Calendar, the list of
    countries for public holidays showed English names in every language, in English order. The
    names now follow the language of the app and the list is sorted in it; a country the browser
    cannot name keeps the name it had. The regions below a country (federal states, cantons) come
    from the holiday service, which carries them in several languages: the app now asks for yours
    and falls back to English where the service has none. The three nations of the United Kingdom
    stay in English. In Tasks, with several tasks selected, a screen reader read the delete button
    as "Delete 3 tasks?" where the screen says "Delete" - the question belongs to the confirmation
    step that follows. The button is now called "Delete 3 tasks". That name is new in all 26
    languages; in Vietnamese, Hindi, Arabic, Persian, Korean, Japanese, Chinese and Filipino it was
    not written by a native speaker. For API clients:
    GET /api/v1/preferences/holidays/subdivisions/{countryCode} takes an optional lang; without
    it the answer is in English, as before.

  • A monthly shared expense on the 29th, 30th or 31st no longer skips a month (#1721). A
    recurring shared expense only knew its next date, not the day it was meant for. After a
    booking on 31 January the next date overflowed to 3 March: February got no booking at all,
    nothing said so, and the series stayed on the 3rd from then on (on the 2nd or 1st when it
    started on the 30th or 29th, or after a 30-day month). A series now remembers its day. In a
    shorter month it books on the last day and returns to its day afterwards: 31 January,
    28 February (29 in a leap year), 31 March. A yearly series from 29 February books on
    28 February and on 29 February again in a leap year, instead of moving to 1 March for good.
    Resuming a paused series counts the same way. Weekly series were not affected.
    Existing series that demonstrably drifted off the 29th-31st return to their day; the month
    that was skipped is not booked afterwards.
    The evidence is the first expense the series
    booked: if it lies on the 29th, 30th or 31st and the next date sits on the 1st, 2nd or 3rd
    where the overflow left it, the next date moves to that day (or the last day) of the same
    month. If the skipped month is still ahead at the time of the update - the series booked on
    31 October and waits for 1 December, and it is 10 November - the date moves into that month
    instead (30 November), so it is not left empty; that is a date in the future, not a booking
    made up afterwards. A series that was really created on the 1st to 3rd stays there. So does
    one whose first expense has been deleted or was ever edited, because then nothing shows
    reliably where the series started: an edit can have changed the date, and the app does not
    record what an edit changed, so an edit of the title alone counts as well. Two more cases
    keep the date where it is. If the series already has an expense in that month, the series
    returns with the following booking. And no date is ever moved into the past, where the next
    run would book it at once: a paused series whose date already lies behind returns when it is
    resumed. A yearly series that stands on 1 March and cannot be moved back for one of these
    reasons stays on 1 March. If a month is missing in your group, add that expense by hand.
    Shared expenses only: subscriptions and tasks keep their own rules. For API clients:
    recurring expenses carry anchor_day (migration 234).

  • Meal plan and recipes with read-only access: no more buttons that end in an error message
    (#1265). A member who may only read the Kitchen still saw every control on both tabs: the plus
    buttons and the empty slots, the edit dialog with Save and Delete, the bin on a meal, the drag
    handle, "Fill plan at random", the recipe column, and on a recipe Edit, Duplicate, Delete and
    "Add to meal plan". Each of them ended in "no permission"; a dragged meal jumped back, and a
    deleted one came back after the undo window. Those controls are now gone for such a member.
    What the plan and the list show stays, and is readable in full: tapping a meal opens a
    read-only view with everything the form shows - date, meal, ingredients with their shopping
    category, the saved recipe, notes, the recipe link and whether it repeats. A recipe opens its
    details as before, which now also name the meals it is meant for and the category of each
    ingredient. An empty week or an empty recipe list only says so, instead of inviting you to add
    something. "Add to shopping list" on a recipe keeps following the right it needs: it stays
    for a member who may read the Kitchen and edit Shopping. Assigning a recipe ingredient to a
    pantry row needs write access to both the Kitchen and the Pantry, as the server requires; with
    only the Pantry right the button used to be offered and the save was refused.

  • The PDFs in the demo data are real PDFs (#1511). The demo documents carried a line of
    placeholder text under a .pdf name, so the built-in preview could not open them and
    every screenshot of an opened document showed an error. Each one is now a one-page PDF with
    the title and description of its entry, in the language the demo was seeded in, and it opens
    in the preview and in the browser's own viewer. The three demo images are still placeholders.
    Only a database filled by scripts/seed-demo.js is affected.

  • The reminder-list settings have one name: "Reminder sync" (#1524). The section under
    Settings, Tasks was headed "Show/hide reminder lists", while the settings search and the link
    from the task defaults called it "Reminder sync" - whoever searched for the one found the
    other. The heading now carries the name the search and the links use. It is also the name
    that says what the section does: its switches decide which CalDAV lists the household syncs
    and whether a list feeds Tasks or Shopping, nothing in it merely hides a list.

  • Wording: waste colours are named after what they show, and two stale sentences are gone
    (#1507). In the waste type dialog the swatch called "Violet" was fuchsia and the one called
    "Teal" was emerald; both now carry those names, which is what a screen reader announces. The
    hint above the module order under Settings, Navigation listed groups that no longer exist
    ("Overview, Plan, Home") and now simply says the modules are sorted within their group. In
    German, the empty waste page read "Papier -, um".

  • Wording: one word for the housekeeper, a pink that is called pink, "Square (2×2)", and a
    real sentence when weather coordinates are missing
    (#1723). In Housekeeping the person had
    four names: the tab said "Staff", its heading "Housekeeping staff", the add button
    "Housekeeper", and in German the short add label just "Person". It is "Housekeeper"
    ("Haushaltshilfe") everywhere now; the tab and its heading read "Housekeepers", and a
    housekeeper's account under Settings, Family carries that word as its role instead of
    "Staff". The module keeps its name. In the waste type dialog the swatch called "Magenta" is a
    pink and is now called that - only the name a screen reader announces changes, saved waste
    types keep their colour. On the overview, the largest of the four tile sizes was called
    "Standard (2×2)" although no tile starts in it; it is "Square (2×2)", saved layouts are
    untouched. And in the weather settings, saving without valid coordinates showed the two
    field names, "Latitude / Longitude", as the error; it now says "Enter valid coordinates."
    The new wording is in all 26 languages; in Vietnamese, Hindi, Arabic, Persian, Korean,
    Japanese, Chinese and Filipino it was not written by a native speaker.

  • Resuming a paused recurring shared expense no longer books every date it missed (#1647).
    A recurring expense that was paused for six months and then resumed got six expenses within
    six hours, one per hourly run, each with its original date. Resuming now skips the missed
    dates: the series continues at its next date that is not in the past, in its own rhythm, and
    nothing is booked for the time it was paused. A date that falls on today is still booked.
    The app has no control for this yet, so it concerns API clients: this changes what
    POST /api/v1/split-expenses/recurring/{id}/pause does by default when it resumes. To get
    the previous behaviour, send { "missed": "book" }; "skip" is the default, and any other
    value answers 400 with reason: "invalid_missed".

  • An avatar never shows more than one character per name part (#1464). A name starting
    with "ß" put three letters on the disc ("ßeta Schmidt" showed "SSS"), because writing a
    letter in capitals can turn it into two; the same went for the ligatures "fi" and "fl". The
    disc now keeps one character each ("SS"). Along with it: brackets, quotation marks and
    other punctuation at the start of a name are skipped ("(Grandma) Erika" shows "GE", not
    "(E"), and a name part made of punctuation only does not count; an invisible direction
    mark in front of an Arabic or Hebrew name no longer leaves the disc empty; two Arabic
    initials stand side by side instead of joining into a word; Georgian letters stay as
    typed instead of turning into a capital form most fonts cannot draw; the flags of England,
    Scotland and Wales stay whole on browsers without Intl.Segmenter; and two half-width
    katakana fit the small disc, so they are no longer cut to one. Capitals are formed the
    same way in every language of the interface, so a person does not show different initials
    depending on who looks: "ipek" gives "I", and whoever types "İpek" keeps the "İ".

  • Documents: Esc closes the viewer again when the PDF took the focus by itself. Opened by
    keyboard, a file whose preview fails - one that claims to be a PDF and is not one - left the
    focus inside the browser's built-in PDF viewer without anyone having touched it, and from
    there no key reaches the page: Esc did nothing. The same happened after Tab from a blank spot
    of the dialog. Focus that arrives in the PDF while you are on the keyboard now goes back to
    the control that had it, so Esc closes and the focus returns to the document you opened. What
    stays as it is: after a click into the PDF, Esc does not close until you click the dialog or
    its X. The built-in viewer is a separate part of the browser that keeps its keystrokes, and
    taking the focus away from a click would break selecting and copying in the PDF (#1511).

  • Settings: the sheet you are on is visible in the sidebar, not hidden under its search. The
    sidebar scrolls on its own and its search field stays at the top while it does. When the open
    sheet lay above the visible part - after Back, from the command palette, from a link - the
    sidebar scrolled it to its very top edge, exactly where the search sits: at 1280x700 the active
    entry stood at 32-72 under a search at 32-100, all 40px of it covered. An entry half behind
    the search was not moved at all. The sidebar now brings the entry to just below the search
    (#1509).

  • Calendar: the week follows the screen when it crosses the phone width. On a phone the week
    is a window of three days around the selected day, on a wider screen the whole week, and the
    label, the arrows and the loaded range follow the same threshold. Only the month was redrawn
    when the width crossed it. Rotating a tablet or resizing the window from 1280px to 390px left
    seven columns of 49px each under "CW 41"; the other way round, three columns of 311px each
    under "05.10. - 07.10.2026", with arrows that still stepped by three days. The week is now
    rebuilt on that change, its range reloaded first when the other form shows a day that was not
    loaded (the selected day at the edge of the week), and the day view switches between the long
    and the short weekday in its label (#1504).

  • Phones: the tab you are on stays inside the tab strip. A tab strip that does not fit the
    screen scrolls, and it snaps to the start of a tab. Opening a tab that lay past the edge moved
    the strip by exactly the missing pixels, and the snapping then pulled it back to the nearest
    snap point, which could be the one behind it. Budget "Loans" at 390px stood at 327-404 in a
    strip that ends at 374, 30px outside and without the strip having moved at all; the same at
    320px (subscriptions, 21px), 360px (reports, 8px) and 414px (loans 6px, reports 20px), on a tap
    as well as after a reload. At 375px it happened to work, which is why it looked fixed. The
    strip now moves to the first snap point at which the tab fits with its padding, so there is
    nothing left to pull back, and it does so in right-to-left languages too (#1504).

  • A refused change is sent to the server once, not twice. When the server turned a change
    down with a reason - a locked task, a read-only module, a recipe managed elsewhere - the app
    sent the same request a second time before showing the message. The repeat exists to recover
    from an expired security token, and it ran for every refusal. It now runs only when the
    server names the token as the reason, or names no reason at all; a refusal with any other
    reason is shown straight away. Nothing was saved twice, since the second attempt was refused
    as well, but each such refusal cost a second round trip (#1669).

  • A failed single sign-on says why in the log. When the identity provider turned the token
    request down, the server log showed only "server responded with an error in the response
    body" and a stack trace - the same line for a wrong client secret, a mismatched redirect URI
    and an expired code. The entry now carries the provider's error, error_description and
    HTTP status, the challenge of a 401 answer, and the network error underneath a failed
    discovery (certificate, DNS, connection). Secret, authorization code and tokens are not
    logged (#1675).

  • Health: "month" and "week" no longer start empty. The default month was the calendar
    month and the activity week the calendar week, so on the 5th the trend said "too few
    readings" over four measurements from the week before, and on a Monday the week was empty
    although yesterday's run was listed. The current period is now the last 30 or 7 days up to
    today and says so in its label; paging back still shows the calendar month or week.

  • Health: adherence shows one figure. The overview counted 30 days and the medication page
    7, so the same figure read 21 % here and 86 % there. Both use the last 7 days and name them.

  • Health: the year chart labels months instead of the first day of each month.

  • Tasks: "Filter 1" is no longer the resting state. The default status "open" counted as an
    active filter, so the button always carried a number and its active colour, and "Clear all
    filters" led to a third state that also showed finished tasks. The button now marks only
    what differs from the default, and "Reset filters" restores it.

  • Meal plan: a dragged meal lands at once, and a move the server refuses says so instead of
    silently snapping back. Saving a meal confirms with "Meal saved." instead of the dialog
    title "Add meal".

  • Recipes: your own recipes show their picture in the list. The thumbnail appeared only for
    recipes mirrored from Mealie or Tandoor.

  • Shopping: the tick is felt when you tap, not after the server has answered.

  • Housekeeping staff: the row's button is as high as the row (it was 25px) for keyboard and
    assistive technology.

  • Required fields: the star is no longer part of the label text. In thirteen labels the
    " *" was written into the translated text, so screen readers read it out, it lacked the
    warning colour of the other stars, and a loan's read-only view showed "Total amount *".

  • Charts: the lowest axis value no longer runs into the first date on a phone ("0 EUR" stood
    3px next to "01.10.2026" in the budget trend; the health charts share the fix).

  • Sign-in pages no longer stack inside each other. Going from one page without sign-in to
    the next inside the app - "Back to sign in" on the forgotten-password page, or the back button
    between them - put the new page inside the old one. The card then shrank to the width of its
    content (338px on the sign-in page, 307px on the reset page, instead of 380px), and a screen
    reader met two nested main regions. Each of these pages now replaces the one before it.

  • A module switched off for the household no longer works in the background (#1660). With
    Health switched off, the medication scheduler kept creating the due doses and sending their
    reminders - as a push and on notification channels, to the person and to their caregivers - and
    tapping one opened a page that turned you away. It now does nothing while Health is off. After
    switching Health back on, only today's doses that are already due come up, at most one reminder
    per time of day; the days in between are not caught up. Two quieter cases follow the same rule:
    check-up and vaccination reminders are no longer prepared while Health is off (they were held
    back from delivery already, and come back on the first run after switching it on), and the
    hourly import from a recipe provider (Mealie, Tandoor) pauses while Recipes is off. "Sync now"
    in the settings still works, and the module's own pages and API stay reachable as before.

  • A module switched off for the household is left out of the overview's data and of the
    calendar
    (#1660). The app already hid the tiles, but the server kept sending their content:
    with tasks, budget or health switched off, the overview's answer still carried the tasks, the
    month's figures and the medication - visible to anything that reads the API, a wall display or
    a script included. It now sends those parts empty, in the same shape as before. With Birthdays
    switched off, birthdays and name days no longer appear among the calendar's events, in the
    event search, in the overview's event lists or in the calendar feed subscribed in another
    app; they return when the module is switched back on. Switching the calendar off does not
    take the birthday tile along. A module that is switched off is still not locked: its own
    pages, API routes and exports answer as before, and what a member may not reach is decided by
    permissions. The rule is written down in docs/DECISIONS.md, entry 11.

  • A time stored with a fraction of a second keeps its exact moment (#1658). A time saved
    without a time zone and with milliseconds - which only happens to rows brought in by hand, the
    app itself never writes one - was read up to two seconds late, because the fraction was added
    two or three times. Just before midnight that was enough to move an event, a reminder or a
    housekeeping visit to the next day, and on the last of a month into the next month. Such a
    value is now read as the moment it says, in every time zone and across the nights the clocks
    change. Nothing stored is rewritten.

  • The loan dialog checks "Installments already paid" at the field and reports errors in your
    language
    (#1656). Typing more paid installments than the loan has, a negative number or a
    fraction used to be sent off, refused by the server, and shown as a short English message at
    the bottom of the screen, whatever language the app was set to. The field is now checked
    before saving, in both places a loan can be created: it is marked, says what is wrong, and the
    dialog stays open with everything you typed. For a loan with interest the number is compared
    with the term the server works out, the same one the preview shows. When the server does
    refuse a loan, the message appears at the field it belongs to and in the app's language. The
    name, title and notes fields no longer accept more text than can be saved. For the API:
    POST /budget/loans and PUT /budget/loans/:id now add a reason code to a 400 answer; the
    error text is unchanged.

  • Budget: the category bars grow to their value. They were built to animate and never did;
    they now grow from the previous month's value when you page, and from zero the first time.

  • Meal plan: a dragged meal lifts off with a short movement, and its slot fades instead of
    switching to pale in one step.

  • The page title in Budget, calendar, notes and contacts no longer stutters while the header
    collapses
    on a phone; it changed its size across several layout steps during scrolling.

  • Pantry: read-only access no longer offers what the server refuses. With read-only access
    to the pantry, the plus and minus buttons still changed the quantity until the server said no
    and the row jumped back, a tap on a row opened the edit dialog with "Save" and "Delete", and
    "Manage locations" and the "Add item" button of the empty pantry were there as well. The row
    now shows its quantity without the buttons, and a tap opens a read-only view with everything
    the dialog shows - quantity, location, category, best-before date, minimum stock and note.
    The cart button stays for members who may write to the shopping list.

  • The budget shows the whole list again when you come back to it (#1593). Tapping a
    person's avatar on an entry narrows the list to what that person is responsible for. That
    filter survived leaving the budget: you opened another page, came back, and still saw only
    those entries. It now falls back when the budget is opened, like the account filter and the
    loan filters always did. Within the budget it stays as it was, also across months.

  • The budget page answers a refused action in your language, at the field it is about
    (#1668). Outside the loan dialog the page still showed whatever the server answered - in
    English, or for an account that no longer exists in German ("Konto nicht gefunden.") - as a
    toast, in every language. Saving an entry, a series or an account, booking an expected
    entry, adding a category, ticking off or deleting an installment, and deleting an entry, a
    series, an account or a loan now say it in the app's own sentence. Where the refusal is
    about one field of an open dialog, the sentence stands at that field: an account that was
    deleted in the meantime at "Account", an amount above what is left of a loan at "Amount".
    The loan dialog got more precise as well: a loan that would run too long says so, with the
    limit of 600 months, instead of "does not amortize" - in the preview and on saving; 361
    installments are answered with the allowed range of 1 to 360; too many installments
    already paid names how many the loan has; and title, notes, currency and account each have
    a sentence of their own instead of the general "could not be saved". For API clients:
    every 400 and 409 of the write routes for entries, series, accounts, categories and loans
    now carries a reason next to error, three of them with max (the limit the refusal is
    about); budget plans are unchanged. A refused POST /api/v1/budget/loans/preview says why
    (reason, max). An unknown account_id was answered in German and now reads "Account
    not found." or "account_id must be a valid account id."; the other German error sentences
    of the budget routes are the next entry.

  • Budget API: the error sentences are English throughout. For API clients only - the app
    does not show these sentences, it reads reason. Some refusals of the budget routes were
    still German or half German, because a German field name was put into an English sentence:
    "month muss YYYY-MM sein", "Betrag muss größer als 0 sein.", "Titel is required.", "Kontotyp
    must be one of: ...". They now read "month must be in YYYY-MM format.", "Amount must be
    greater than zero.", "Title is required.", "Account type must be one of: ...", and the same
    goes for the other field names: Amount, Category, Date, Interval, Interval count, Starting
    balance, Credit limit, Color, Type, and recurrence_rule for an invalid rule. Affected are
    entries, series, booking an expected entry, accounts, categories, budget plans, and the
    month, q, range and anchor parameters of the list, the summary, the search and the
    statistics. Status codes and every reason are exactly as before; reason is the stable
    key, so a client that compared the error text should switch to it. Where a sentence lists
    the allowed category keys, the keys of the built-in income categories are still German
    words - they are stored keys, not wording. Other modules are unchanged (#1668).

  • Three layout points from a Korean household: a long title stays on its card, hints wrap
    at word boundaries, and the chart's amounts are no longer cut off
    (#1607, reported by
    @soonJ817). On the task board, a title without spaces - a web address, one very long
    word - ran out of its card and across the neighbouring columns; it now wraps inside the
    card. In the Korean interface, hints and descriptions broke between any two syllables and
    left a single one on the next line ("선택합니 / 다."); Korean now wraps between words, as
    it is written, and the other languages wrap as before. In the Budget statistics, the
    amounts along the left edge of the chart lost their beginning once they got long -
    "₩6,000,000" was cut off at its currency sign, on a phone and on a desktop alike. The
    chart now measures its amounts and leaves them the room they need, whatever the currency
    and region; a chart with short amounts looks exactly as before.

  • Inventory and Documents with read-only access: no more buttons that end in an error message
    (#1265). A member who may only read the Inventory still saw Add, Edit and Delete, "Done" on a
    due deadline, and the menu that manages locations and categories; a member who may only read
    Documents still saw Upload, the folder buttons, the menu on every document and "Select
    multiple". Each of them ended in "no permission". Those controls are now gone for such a
    member. What the pages show stays and is readable in full: an inventory item opens its
    details, which now also name a deadline's reminder lead time and its repeat interval, and a
    document opens in the viewer with preview, download and share, which now also shows its
    description, who may see it, the reminder lead time and whether it is archived. An empty
    page only says that it is empty instead of inviting you to add something.

  • Documents: Edit, Move, Archive and Delete are only offered on documents you may change
    (#1265). A document can be changed by the person who uploaded it and by an admin. The page
    did not know that rule: every document that was shared with you carried the full menu, and
    saving, archiving or deleting somebody else's document ended in "Not authorized" - a deleted
    one disappeared first and came back a few seconds later. Now the menu, the pencil in the
    viewer and the selection circle of "Select multiple" appear only on your own documents (on
    all of them for an admin). Viewing, downloading and sharing stay available on every document
    you can see, and on a narrow phone a document without a menu keeps its view button.

  • With read-only access, a screen reader now says that a row opens its details (#1682).
    In the pantry and under Birthdays, a row announced only its content when you may read
    but not change: with write access it ends on "Edit", and with read access that word was
    removed and nothing took its place. The row now ends on "Show details". The info button of
    a shopping item says the same, followed by the item's name. Along with it, in the pantry on
    a narrow phone: a row with a cart button hid its best-before date to make room for the
    plus and minus buttons. A read-only row has no such buttons, so the date stays visible
    there. Behind the scenes the three read views (birthdays, shopping, pantry) now draw their
    rows with one shared building block instead of three copies.

  • Every chart leaves its axis values the room they need, not only the Budget trend
    (#1722). The Health charts (vitals, lab values, activity, and the cycle trends) and the
    odometer chart of an inventory item kept a fixed margin sized for short numbers. The
    severity trend of a cycle symptom writes words on that axis, and their length depends on
    the language: in Polish, "Umiarkowane" started to the left of its chart and ended up one
    pixel from the edge of its card on a phone; Filipino and Russian stuck out as well. Each
    of these charts is now measured the moment it appears, the same way the Budget trend
    already was, so a long word or a seven-digit odometer reading stays inside its chart. A
    chart with short values looks exactly as before.

Don't miss a new yuvomi release

NewReleases is sending notifications on new releases.