First release candidate of 2.0. Nothing new since beta.4 but a language: this candidate is about correctness. A review of beta.4 found four bugs in the booking checks: calendar events stored in another timezone than the host's could be missed by round robin and approvals (#420), a guest reschedule waiting behind another booking could bring a cancelled booking back (#421), a booking's buffers did not hold against later bookings, at approval or across a clock change (#422), and calrs booking create ignored date overrides (#423). From the beta testers: an SSO login refused on purpose now says why instead of failing with a 500, and an identity provider that keeps its ID token minimal can now sign users in (#264). calrs now speaks Russian (#419), and the deployment guide lists which paths a reverse proxy can keep private. No migrations since beta.4, so upgrading from it changes no data. Coming from 1.23 or an earlier beta, read the upgrade notes of each 2.0 pre-release below, and back up your database first.
Docker: this version is published as :2.0.0-rc.1 and :next. :latest stays on the 1.23 line until 2.0 is final.
Thanks to @ilia-ae for the Russian translation, to @huntervcx, @optimistic5 and @chetan for testing beta.4 on their own setups, and to @Codrax for working through the OIDC issue with us. Unless testing turns up something serious, this is what 2.0 will be.
Added
- Russian (#419, by @ilia-ae) - A complete Russian translation of the guest side and the host side, emails and SMS included. It addresses the reader with the formal «вы», as the French translation uses "vous", carries the three plural forms Russian needs (1 минута, 2 минуты, 5 минут), and writes the month in the genitive inside a date («10 апреля 2026») while calendar headers keep its name («апрель 2026»). Browsers that ask for Russian get it, and users can pick «Русский» in Profile & Settings. Native-speaker review is welcome, as for every machine-assisted locale.
Fixed
- Round-robin and approvals see calendar events in other timezones (#420) - A calendar event stored in another timezone than the host's (a UTC event, an invitation from Tokyo) was dropped before its time was converted when it did not overlap the slot in its own wall clock, so round robin could assign a busy member, an approval could accept a conflicting request, and the booking check could let it through. Events are now read with two days of margin and compared once converted, on the booking pages and checks, shared resource feeds, the troubleshoot view, the overview and
calrs event-type slots. - A reschedule can no longer revive a cancelled booking (#421) - A guest reschedule that was waiting behind another booking while the booking was cancelled, declined, expired or rescheduled is now refused instead of putting it back to confirmed or pending with a new time.
- A booking's buffers are kept against later bookings (#422) - Only the slot being booked was padded by its buffers, so a meeting with a 30-minute buffer after let the next one start right at its end. Every booking now keeps its own event type's buffer before and after, on the slot pages, at submit, in the troubleshoot view and on the CLI, across all of a host's event types.
- Approval and daylight-saving buffers (#422) - Approving a pending request now checks its own before/after buffers against the hosts' current commitments. Buffers are added to timestamps before converting to local time, so the spring clock change cannot shorten a buffer and the autumn change cannot lengthen it. Slot display, booking checks, round-robin assignment, the CLI and the booking troubleshoot timeline use the same elapsed-minute calculation.
- Old bookings at a skipped hour stay in place (#433) - A booking stored before 1.18's UTC timestamps, at a time the spring clock change skips, was read as UTC once buffers apply to it, which moved its busy time by the zone's offset. It is now read as the first minute after the gap, as time off is.
- The troubleshoot view shades buffers on the side the slots use (#433) - Around a calendar event or a time off period, the view drew the event type's buffer before on the side its buffer after applies, and the other way round, so a type with a 30-minute buffer after showed a buffer after a meeting where the booking page offers a slot, and none before it where the page offers nothing. Bookings were already right (#422).
calrs booking createrespects date overrides (#423) - The command now refuses a date marked unavailable and a time outside the custom hours set for that date, as the booking page does, instead of checking only the weekly rules.- OIDC login reads the email from UserInfo when the ID token lacks it (#264) - calrs took the email, name,
email_verified, groups and title from the ID token only, so a provider that keeps its ID token minimal (as OpenID Connect allows with the code flow, the scope claims being those of the UserInfo endpoint) failed every login with "no email in token". When the ID token carries no email, calrs now asks the UserInfo endpoint with the access token and reads those claims from its answer, which must name the same user as the ID token. Theemail_verifiedrules are unchanged. If the UserInfo request itself fails, the login ends as a sign-in failure, with the reason in the log. - A refused SSO login says why (#431) - An SSO login calrs refuses on purpose (an address the identity provider has not verified, an address already linked to another SSO identity, an existing account with two-factor authentication, no account while auto-registration is off, an email domain that is not allowed, or no email address at all) ended on a generic "Authentication failed" page with HTTP 500, the reason only in the server log. The sign-in page now shows the reason in the reader's language, with HTTP 403, and keeps the SSO button. When the identity provider has not verified the address, the page always says so, whether an account exists or not, so it cannot be used to find out which addresses have accounts. Reported by @huntervcx while testing beta.4.
- Removed from every group, removed from every team (#435) - When the identity provider sent an empty
groupsclaim, calrs read it as no claim at all, so a user taken out of every group kept their old OIDC groups and the team memberships that came with them until an admin removed them. An empty list now clears them at the next sign-in. A list calrs cannot read still changes nothing. - Old bookings read in their own timezone everywhere (#435) - A booking stored before 1.18's UTC timestamps is a wall clock in its own meeting type's zone. The booking pages read it that way, but
calrs event-type slots,calrs booking createand the troubleshoot view read it in the host's zone, so a 09:00 New York booking showed a Paris host busy at 09:00 instead of 15:00. - Troubleshoot shows a slot blocked by the next morning's first event (#439) - An event just after midnight, or just before it, whose buffer reaches into the day blocks a slot on the booking page; the troubleshoot view dropped it and showed that slot as available.
- Troubleshoot works for hours running past 23:00 (#439) - An event type whose hours ended after 23:00 got an empty timeline.
Documentation
- Which paths a reverse proxy can keep private (#432) - The deployment guide lists every group of paths calrs serves and who needs it: guest pages and email links, the files they load, sign-in and dashboard, the REST API, MCP and OAuth. It gives an nginx example that serves guest pages to everyone and the rest to one network only, and covers what to settle before exposing anything: the first account becomes the admin, open registration lets anyone sign up, and calrs's own port must not be reachable around the proxy. Asked for by @optimistic5 while testing beta.4.
- The documentation covers v2 (#438) - A feature map, new chapters for the dashboard and profile, website embeds, on-premises Exchange and upgrading to v2, and the existing guides brought up to date with the v2 behaviour: calendar providers, availability, bookings, sign-in, the admin panel, deployment and backups (the credential key and uploads, not only the database) and the CLI. Screenshots are retaken in dark mode with fictional demo profiles. The website follows with the release.