Wekan logo

Wekan

Open source kanban board application built with Meteor

Alternative to: trello


About Versions (100)

v9.78

2026-07-06

v9.78 2026-07-06 WeKan ® release

This release fixes the following bugs:

  • Fix “Internal Server Error” when signing up despite the account being created: Registering a new account showed a red “Internal server error” on the sign-up form even though the account was created and could sign in — which typically happens when SMTP is not configured. Root cause: useraccounts’ ATCreateUserServer creates the account and then calls Accounts.sendVerificationEmail() (because sendVerificationEmail: true); when SMTP is missing/misconfigured that send throws after the user row is inserted, and with no try/catch the exception leaves the createUser method as an opaque HTTP 500. The verification email is best-effort at sign-up, so Accounts.sendVerificationEmail is now wrapped to log and swallow a transport failure — registration completes and redirects to sign-in — while an “already verified” error is re-thrown so the resend-verification flow still reports it. This mirrors the #5706 reset-password hardening. Covered by tests/verificationEmail.test.cjs. Thanks to Firas-Git and xet7.

  • Fix can not add members to a Linked Card: A linked card (created by “Link card to this card”) is only a placeholder on the board that links it — its members are stored on the real card it points at (linkedId), which lives on another board, and Card.getMembers() / assignMember() / unassignMember() already read and write that real card. But the member picker listed the members of the board you were viewing the linked card on, not the board the real card lives on. So on a board that links a card from another board, the picker offered the wrong set of members and toggling them did not behave as a consistent add/remove — “can not add members to the linked card”. The picker now resolves a linked card to its real card’s board and offers that board’s active members (matching where the membership is actually stored), falling back to the current board for normal cards or when the real card isn’t loaded yet. Extracted the target-card/target-board resolution into models/lib/linkedCardMembers.js, covered by tests/linkedCardMembers.test.cjs. Thanks to ITT5 and xet7.

  • Fix can’t search numbers in custom fields: Searching a board for the value of a number or currency custom field (e.g. a transaction number 2025001, or a currency amount 123) found nothing. Those field types store their value as a JS Number (the inputs save parseInt(...) / Number(...)), but Board.searchCards() only matched custom fields with { value: <regex> } — and a MongoDB / Minimongo regex only matches string values, so it silently skipped every numeric custom field. The search now also adds an exact numeric-equality clause when the term is a plain number (a comma is accepted as a decimal separator, matching the currency input), so numeric custom fields match too; text/title/description matching is unchanged. Card search runs against Minimongo on the client, which — like MongoDB — cannot regex a numeric field, so equality is the correct cross-environment match. Covered by tests/cardSearch.test.cjs. Thanks to MarcusDger and xet7.

  • Fix “Removed nonexistent document” crash during notification_cleanup: The scheduled notification-tray cleanup logged Exception in removed observeChanges callback: Error: Removed nonexistent document …. The crash itself came from the old cottz:publish-relations package (since replaced by reywood:publish-composite), but the cleanup that provoked it still fired one un-awaited removeNotification() per expired notification — a separate Users.update $pull each time — so a user with K stale notifications produced K writes to the Users collection, and every publication that republishes user documents re-ran its observers K times in quick bursts (the churn that surfaced the removed-document error), while any rejected write went unhandled. The cleanup now scans only users that have notifications and prunes each user’s stale notifications in a single awaited $pull … $in. It also removes an activity’s notifications only when every entry for that activity is read and past its removal age (so a freshly re-created unread notification sharing an activity id is not dropped), and guards missing/invalid read timestamps. Covered by tests/notificationCleanup.test.cjs. Thanks to xet7.

  • Fix impossible to select another board in rules: In the IFTTT-Rules “Move card to the board” and “Link card to the board” actions, the board dropdown was empty for some users — the current board included — while colleagues in the same company could pick boards normally. Root cause: the dropdown filtered the (already access-scoped) client cache with 'members.userId': me, i.e. it only kept boards where the user has a direct member entry. A user who reaches a board through an Organization, Team or email-domain share — but is not listed individually in board.members — matched nothing, so the whole selector came up empty. The dropdown now filters by the same visibility rule as Boards.userBoards() (public OR active member OR active org OR active team OR active domain), so org/team/domain-shared boards appear too, while archived boards, template containers, the user’s templates board and internal helper boards stay excluded. Thanks to Augustin356 and xet7.

  • Fix board disappeared after adding another user: A board admin adding another user could make the whole board silently vanish from a user’s board list, with no archive and “nothing out of order” in the logs. Root cause: the setBoardTeams server method (used by the board Teams/Members management popups) blindly overwrote the board’s entire members array with a snapshot sent by the client. When that client’s board document was stale — e.g. a member had just been added via inviteUserToBoard on the server and the change had not yet propagated to the client — the overwrite dropped members, and in the worst case the board’s own admin, so the board no longer matched the board-list publication (which requires an active membership) and disappeared. Because a wholesale $set: { members } never passes through foreachRemovedMember(), no removeBoardMember activity was logged and no card/watcher/star cleanup ran, which is why the logs looked normal. setBoardTeams now reconciles against the authoritative server-side members instead of trusting the client snapshot: it never drops an active admin, keeps every existing member the client still lists, adds the members the client introduces, and only removes non-admin members the client explicitly omitted (an intentional team-leave) — logging and cleaning up each such removal so it is auditable rather than silent. Thanks to DVNBLMHC and xet7.

Thanks to above GitHub users for their contributions and translators for their translations.