Download Latest Version wekan-11.72-s390x.zip (286.8 MB)
Email in envelope

Get an email when there's a new version of wekan

Home / v9.69
Name Modified Size InfoDownloads / Week
Parent folder
wekan_9.69_amd64.snap 2026-06-23 398.8 MB
wekan_9.69_arm64.snap 2026-06-23 375.4 MB
wekan-9.69-ppc64le.zip 2026-06-23 191.3 MB
wekan-9.69-s390x.zip 2026-06-23 191.4 MB
wekan-9.69-win64.zip 2026-06-23 284.9 MB
wekan-9.69-mac-arm64.zip 2026-06-23 190.8 MB
wekan-9.69-amd64.zip 2026-06-23 182.1 MB
wekan-9.69-arm64.zip 2026-06-23 190.8 MB
README.md 2026-06-23 7.2 kB
v9.69 source code.tar.gz 2026-06-23 30.7 MB
v9.69 source code.zip 2026-06-23 31.6 MB
Totals: 11 Items   2.1 GB 0

v9.69 2026-06-23 WeKan ® release

This release fixes the following bugs:

  • Can't edit a card's members in the UI after removing them via the REST API, #3697: clearing a card's members (or assignees) over REST left the field uneditable in the UI. The card PUT handler guarded with if (req.body.members) — falsy for the two natural clear payloads (null and "") — so "remove the last member" was a silent no-op, and its string branch was written to store null rather than []; a card with members: null then breaks UI code that treats it as an array. The handler now uses an !== undefined guard plus a shared coercion helper so any clear payload (null / "" / []) stores a clean String[] (never null), a single id is wrapped into an array, and stray non-string entries are dropped; getMembers()/getAssignees() also coerce a legacy null to [] on read so existing corrupted documents edit cleanly. Pure logic in models/lib/restArrayParam.js with a Meteor-free Node unit test (tests/restArrayParam.test.cjs, npm run test:unit:node, incl. a negative test reproducing the old null-writing logic), plus a REST regression in tests/playwright/specs/17-rest-api.e2e.js.
  • Can't create a card with no member via the REST API, #2875: the card-create endpoints (POST .../cards and POST .../cards/bulk) wrote req.body.members/assignees straight to the insert with no normalization — the create-side twin of [#3697] — so a null/"" payload persisted as null (breaking later UI editing). Both handlers now run the same coerceRestArrayParam helper: the field is omitted when not provided (so the schema default [] applies), any clear payload becomes [] (never null), and a single id is wrapped into an array. REST regression in tests/playwright/specs/17-rest-api.e2e.js.
  • Board created through the REST API shows in the API but not in the browser UI, #5650: POST /api/boards set the board's sole member's userId from req.body.owner with no fallback, so a request that omits owner created a board whose only member had userId: undefined. The board-list publication matches members.$elemMatch: { userId, isActive: true }, which can never match an undefined id — so the board was returned by the REST API but invisible in the browser. owner now falls back to the authenticated caller (req.body.owner || req.userId), mirroring the Meteor create method. REST + DB regression in tests/playwright/specs/17-rest-api.e2e.js.
  • Copying a card to another board left its comments on the wrong board, #5166: CardComments.copy() cloned a comment but only changed its cardId, so a card copied to another board produced comments that kept the source board's boardId. Comment permission checks key off the comment's boardId, so edit/delete on a copied comment was validated against the wrong board, and any board-scoped query saw it on the old board. copy() now also sets the destination boardId (the author userId is intentionally preserved). Cross-board copy regression in tests/playwright/specs/17-rest-api.e2e.js. Note: the related "wrong author shown" symptom is a separate display issue — when a copied comment's author is not a member of the destination board, their user document isn't published there, so the UI can't resolve the name; adding those users to the board resolves it. A broader fix (publishing comment authors' minimal profile on boards where their comments appear) is left as a follow-up.
  • Exception "Removed nonexistent document" when deleting a card detail, #3252 (partial): deleting a comment or checklist/checklist-item could throw Removed nonexistent document on the client. The delete handlers called Collection.remove(_id) directly, but under heavy archive/delete churn the target doc can already have been evicted from the client's Minimongo cache, and removing a missing _id throws. The comment / checklist / checklist-item delete handlers now check the doc still exists in the local cache before removing it (client/components/activities/comments.js, client/components/cards/checklists.js). The server-side before.remove hooks were already hardened to guard + log instead of throwing. (No automated regression for the thrown exception — the eviction race is not deterministically reproducible; the guard itself is a self-evident findOne-then-remove.) The high CPU on bulk delete the issue also reports is reduced by the cascade change below; the remaining cost is on the archive path (a bulk update, not a delete) and is a separate follow-up.
  • Performance: deleting a card no longer fans out per-child activity churn (#3252, #5322). cardRemover removed a card's checklist items, checklists and comments with the hooked removeAsync, so collection-hooks fired each child's before.remove once per document — every one doing a getCard and inserting an activity (e.g. a removedChecklistItem per item), which then triggered the notification + publication observers. Deleting (or bulk-deleting) a card with many children produced an activity-insert storm and pegged the CPU. cardRemover now removes those children with .direct (skipping the per-child hooks — they only logged activities that are unviewable once the card is gone) and clears all of the card's activities in a single bulk op, which also removes the activities that a delete previously left orphaned. The deleteCard activity is still logged afterward (so the outgoing webhook fires), and attachments still go through the normal remove so their files are deleted. Cascade + activity-cleanup regression (also a negative test) in tests/playwright/specs/17-rest-api.e2e.js.

and this issue is verified resolved in current code (could not reproduce / no error observed here; re-test on the reporter's data requested):

  • #2292 (archiving a swimlane appeared to delete all its cards): Swimlane.archive() (models/swimlanes.js) only sets archived: true on the swimlane — it does not touch or delete the cards, and restore() brings the swimlane and its cards back. While a swimlane is archived its cards are merely hidden from the board view (board queries filter to archived: false swimlanes), not lost — the v2.27-era cascade described in the report no longer happens. (A dedicated way to view an archived swimlane's cards before restoring would be a separate UX improvement.)
Source: README.md, updated 2026-06-23