v9.47 2026-06-17 WeKan ® release
This release adds the following updates:
- Developer test tooling: "Run ALL tests" now stops an existing dev server on port 3000 instead of aborting:
rebuild-wekan.shmenu option 9 ("Run ALL tests") previously errored out with
"Port 3000 is already in use" when a dev server was already running, forcing the
user to stop it manually. It now detects and stops the existing Meteor dev server
before starting its own. Thanks to xet7 and Claude. Details:- When port 3000 is busy, option 9 finds the existing Meteor dev server
(pgrep -f 'meteor run --port 3000') and sends it a normalkill, which also
tears down the node child it spawned. - It then polls the port for up to 30s, escalating to
SIGKILLat the 15s mark
and falling back tolsof -ti tcp:3000(orfuser -k 3000/tcp) to catch
anything still holding the port whose command line does not match. - Only if the port is still occupied after all that does it print an error and
abort; otherwise it reports "Port 3000 is now free" and starts its own server.
- When port 3000 is busy, option 9 finds the existing Meteor dev server
- Fix moving/copying a card silently failing with a 403 validation error:
the move, copy, copy-many and convert-checklist-item card dialogs could leave a
card in its original list instead of moving it. Thanks to xet7 and Claude.
Details:- Root cause: the dialog's "Done" handler read the target board/swimlane/list by
scraping the DOM<select>elements. The reactiveboards()helper can
transiently return[]while aboardsubscription re-resolves, leaving the
board<select>momentarily option-less, soselectedIndexwas-1and the
scrapedboardIdwasundefined.card.move(undefined, …)then failed
server-side withValidationError: Not permitted. Untrusted code may only updateAsync documents by ID [403], and the card silently stayed put. This was
a gap in the earlier dialog fix, which bound only the swimlane and list options
to the live selection but left the board<select>on the (empty)
last-confirmed option. - Fix: the Done handler now reads
boardId/swimlaneId/listIdfrom the
dialog's live reactive selection (selectedBoardId/selectedSwimlaneId/
selectedListId), which stays correct across re-renders, and the board
<option selected>attribute is bound to the live selection in all four
dialogs for UI consistency. - Test hardening: three Playwright/Node E2E tests that flaked under the
all-parallel run (move-list-right, add-to-top/add-to-bottom, and the Node E2E
second-session list-order check) now wait for the board subscription to
populate before acting, instead of reading once after a fixed delay.
- Root cause: the dialog's "Done" handler read the target board/swimlane/list by
- Developer test tooling: run all tests in parallel against a single dev server:
rebuild-wekan.shandrebuild-wekan.batnow run all tests in parallel
against a single dev server, and fix the WebKit/Docker permission fallout.
Thanks to xet7 and Claude. Details:- "Run ALL tests" (menu option 9) now starts one WeKan server on
http://localhost:3000 (using.meteor/local) and runs every test job
concurrently with a live, refreshing progress display: import regression,
Node E2E, and Playwright Chromium + Firefox + WebKit all run against that one
server, while the Mocha server-side suite runs at the same time in its own
isolated Meteor build dir (.meteor/local-test, viaMETEOR_LOCAL_DIR) so the
two Meteor builds never share.meteor/local. A per-job PASS/FAIL summary and
per-job logs (../wekan-alltests-<job>.log) are written at the end. Previously
these ran strictly one after another. - New menu option 16, "Test Playwright ALL browsers in parallel", runs
Chromium + Firefox + WebKit at the same time against a server that is already
running on :3000 (WebKit via the Playwright Docker image on Linux arm64, native
elsewhere; the others run with--workers=3on Windows). - Each Playwright browser now writes to its own
test-results/<browser>output
dir so parallel runs do not clobber each other's artifacts, and the WebKit
Docker run executes as the host user (--user) so it no longer leaves
root-owned files behind. A guard repairs an already root-ownedtest-results/
that causedEACCES: permission denied, mkdir .../.playwright-artifacts-N.
- "Run ALL tests" (menu option 9) now starts one WeKan server on
- Run ALL tests: start the :3000 server before Mocha so it boots fast again:
the parallel "Run ALL tests" flow launched Mocha (in its own.meteor/local-test
build) before the :3000 dev server, so two full Meteor builds competed for
CPU/disk and the server took a long time to become ready — shown as a long line
of dots during the readiness wait. Mocha and the import regression do not need
the server, so they are now launched only after the server build is underway;
the server builds alone and boots fast again, while they still run in parallel
with the E2E and browser jobs. Applied to bothrebuild-wekan.shand
rebuild-wekan.bat. Thanks to xet7 and Claude. - Fix #6380: login page missing username/password fields after upgrade:
the password form is hidden by default in CSS and only revealed by JS when
isPasswordLoginEnabledreturns truthy; a slow/failed method call or a
not-yet-rendered accounts form left the login without username and password
fields. It now shows the form unless password login is explicitly disabled, and
waits for the form element to appear before showing it. Thanks to xet7 and
Claude. - Fix #6381: make the card "Mark as complete" toggle configurable, hidden by default:
a new board settingallowsDueComplete(off by default) controls whether the
"Mark as complete" toggle is shown on cards, with a checkbox in the board Card
Settings popup to enable it per board. Thanks to xet7 and Claude. - Fix #6382: stop the client auto-creating thousands of empty swimlanes:
getDefaultSwimline()inserted a swimlane whenever none was found, but on the
client it runs inside reactive renders — for a board whose swimlanes were not
yet loaded (e.g. the default subtasks board viewed via "All boards") every
re-render inserted another empty swimlane (2008 in the report), freezing the
browser. The default swimlane is now auto-created only on the server. Thanks to
xet7 and Claude. - Move/Copy/Convert card dialogs: bind swimlane and list select to live selection:
the swimlane and list<select>selectedoption in the move, copy, copy-many
and convert-checklist-item card dialogs now follows the live selection instead
of the last-confirmed option, so a Blaze reactive re-render can no longer
silently revert the user's in-progress choice. Thanks to xet7 and Claude. - Playwright: probe browsers and skip ones that cannot launch on the host:
the test runner now probes each browser and skips any that cannot launch (e.g.
the bundled WebKit needs old system libraries that newer Linux arm64 distros
like Ubuntu 26.04 no longer ship), removing false WebKit failures locally while
still running every browser on CI. Override withWEKAN_PLAYWRIGHT_PROBE=1/0.
Thanks to xet7 and Claude. - rebuild-wekan.sh: platform detection, Docker WebKit on Linux arm64, all browsers in ALL tests:
detect OS/arch (Linux amd64/arm64, macOS arm64); run the WebKit Playwright specs
via the official Playwright Docker image on Linux arm64 where the bundled WebKit
cannot launch natively; and run Chromium, Firefox and WebKit in the "Run ALL
tests" option. Thanks to xet7 and Claude. - rebuild-wekan.bat: Windows menu parity for building, running and testing WeKan:
the Windows batch script now mirrors rebuild-wekan.sh's interactive menu so
building, running and testing WeKan (Mocha, import regression, Node E2E and
Playwright Chromium/Firefox/WebKit) works on Windows amd64/arm64 too. Thanks to
xet7 and Claude. - Bumped form-data from 2.5.5 to 2.5.6:
security fix for the CRLF-injection issue (CVE-2026-12143, GHSA-hmw2-7cc7-3qxx)
where CR/LF/"in multipart field names and filenames were not escaped. It is a
transitive dependency (pulled in via@google-cloud/storage); lockfile-only
change. Thanks to Dependabot, xet7 and Claude. - Bumped launch-editor from 2.13.2 to 2.14.1:
a dev-only dependency (used bywebpack-dev-server/@rsdoctor/sdk, not in the
production bundle); lockfile-only change. Thanks to Dependabot, xet7 and Claude. - Bumped docker/setup-buildx-action from 3 to 4:
GitHub Actions workflow action update used by the Docker image build. Thanks to
Dependabot, xet7 and Claude. - Bumped azure/setup-helm from 4 to 5:
GitHub Actions workflow action update used by the Helm chart release workflow.
Thanks to Dependabot, xet7 and Claude. - Bumped dompurify from 3.4.6 to 3.4.9:
update of the HTML sanitizer used to sanitize card descriptions, comments and
other rendered markdown (XSS protection). Thanks to Dependabot, xet7 and Claude.
and adds the following new features:
- Added card dependency "Red Strings" / PI program board:
visualize card-to-card dependencies as red, arrow-headed connection lines drawn on
top of the board (for SAFe PI-planning program boards). A card now has a
cardDependencieslist edited from a new "Dependencies" section in the card detail
(pick or remove other cards on the same board), and a board header toggle
(showDependencies) renders an SVG overlay that draws a red curve from each card to
each of its dependencies, following the live card positions on scroll/resize. The
overlay is non-interactive (pointer-events: none) so cards stay clickable.
Each dependency is now typed and customizable: a relationtype
(related-to,blocks,is-blocked-by,fixes,is-fixed-by— the type sets
the arrow direction;related-tois undirected), a per-linecolor(any color,
via a color picker, not just red) and anicon(FontAwesome). The card detail
"Dependencies" section edits all three (relation type, color, icon picker), with a
search-by-title picker to add one; a colored icon+count badge is shown on the
minicard; and the board Filter sidebar can filter cards by dependency relation
type. A REST API was added (tagDependencies, documented in the OpenAPI
docs andapi.py):GET /api/boards/:boardId/dependencies,
GET/POST /api/boards/:boardId/cards/:cardId/dependenciesand
PUT/DELETE /api/boards/:boardId/cards/:cardId/dependencies/:targetId, each
acceptingtype/color/icon. Dependency lines can be exported (Board
Settings → Export → Dependencies / JSON and / SVG; the SVG is a standalone,
round-trippable diagram) and imported (All Boards → New → Import →
Dependencies (JSON/SVG)) into a chosen board, matching cards by id, then card
number, then title. Importing a Jira board now maps Jiraissuelinks
best-effort to dependency relations. Card dependencies and the board's
showDependenciestoggle are preserved through card/board copy and WeKan
board export/import/migrate (target ids are remapped, dangling ones dropped), and
a card moved to another board drops its now cross-board dependencies and
cleans inbound references. Covered by tests
(Part 1,
Part 2,
Part 3):
e2e specs27-red-strings(overlay, toggle, typed lines, minicard badge,
copyCard preservation, import matching) and28-dependencies-rest(REST CRUD +
schema validation), plus mocha unit tests for the metadata helpers, the REST
OpenAPI annotations, the filter selector, the cross-board move cleanup and the
Jira issue-link mapping.
Fixed editing an existing dependency from the card detail throwing a client
403
("Untrusted code may only updateAsync documents by ID") — changing a relation's
type/color/icon or removing it now rewrites thecardDependenciesarray and
updates by_idinstead of using a forbidden positional-$selector update, and
fixed the dependency icon picker not applying the chosen
icon
(the popup now edits the source card, not the dependency row), with an e2e test
for editing a dependency's type/color/icon.
Added a piplanning.io / Kendis / Miro-style drag-to-connect
(Part 1,
Part 2):
when the overlay is on, each minicard shows a small connect handle (right
edge, on hover) — drag it onto another card to create a dependency (a dashed
guide line follows the cursor) — and a connection line is clickable to
change its type/color/icon or delete it. It is not a mode: cards stay
clickable and the rest of the overlay is click-through.
The Dependencies (JSON/SVG) importer now also best-effort maps Miro REST
API data (items + connectors, resolved to card titles; "block"/"fix" captions →
relation type); Kendis/piplanning.io (and GitHub/GitLab) have no public
dependency format, so a generic{ "lines": [...] }JSON interchange is
documented for them. Documented in
Features/RedStrings.
Fixes #3392. Thanks to CodeFreezr, dbt4u, helioguardabaxo, xet7 and Claude. - Added an Admin Panel "Shared templates" view grouped by Organization / Team / email
Domain:
a new admin-only "Shared templates" tab under Admin Panel → People lists users'
shareable template boards, grouped by Organization, Team or email Domain. The three
scope checkboxes are live view filters (default unchecked); checking one or more shows
the matching groups, and only users whose Templates board is non-empty are listed. A new
admin-onlyadminSharedTemplatesmethod enumerates each user's linked template boards
(thecardType-linkedBoardcards in their Board Templates swimlane) and returns them with
the user's orgs/teams/email domains; the boards are shown as links into each template
board. Covered by an e2e suite (tests/playwright/specs/26-shared-templates.e2e.js).
Documented in
Features/Templates.
Fixes #3313. Thanks to xet7 and Claude.
and fixes the following bugs:
- Fixed duplicate
MONGO_URLenvironment variable generated by the Helm chart,
which madehelm install/upgradefail withduplicate entries for key [name="MONGO_URL"]
when the defaultenvlist (which already includesMONGO_URL) was used. The chart now
emits its computedMONGO_URLonly when one is not already provided viaenvorsecretEnv.
Fixes #6289. Thanks to the reporter, xet7 and Claude. - Fixed GFM strikethrough (
~~text~~) no longer rendering in card descriptions:
markdown-it renders~~text~~to<s>…</s>, but the DOMPurify allow-list did not
includes/del/strike, so the sanitizer stripped the tag (keeping the bare text).
Those inline tags are now allowed in both DOMPurify configs. Fixes #6008. Thanks to
Buo-ren Lin, xet7 and Claude. - Fixed the release pipeline's OpenAPI docs generator crashing on template-literal route
paths,
which failed the GitHub Actions "release-all" bump job (AttributeError: 'NoneType' object has no attribute 'rstrip') when a REST route is registered with a backtick path
such as`/api/boards/:boardId/export/${format}`. The generator now resolves such
paths (a${identifier}becomes a{identifier}path parameter) and skips any route
whose path cannot be resolved statically instead of aborting the whole release. Thanks
to xet7 and Claude. - Fixed the Member Settings "Change Avatar" entry rendering in a different (uppercase-looking)
style than the other menu items:
its label was mis-nested inside the<i class="fa fa-picture-o">icon element instead of
being a sibling of it, so it inherited the FontAwesome icon font styling. The label now sits
directly under the menu link like every other entry. Thanks to xet7 and Claude. - Hardened the reactive
DataCacheteardown to re-check for dependents before stopping a
still-used entry:
the 60s teardown timeout could stop the computation and delete a value that a dependent
re-attached to during the window, surfacing as a transientundefined(a contributor to the
"Board not found" flicker). Thanks to xet7 and Claude. - Fixed board export error responses returning HTTP 200 with an empty body:
the export endpoints passed a bare number tosendJsonResult, which treats its argument as an
options object, so 404/400/403/auth failures returned 200 with no body. They now return the
correct status code and a JSON error body. Thanks to xet7 and Claude. - Fixed the board create/delete REST handlers masking errors as success:
POST /api/boardsandDELETE /api/boards/:boardIdcaught errors and returnedcode: 200
with the error as data; they now report the real status code (so e.g. an unauthorized delete
returns a 4xx). Thanks to xet7 and Claude. - Hardened board import against out-of-range swimlane/card colors:
like the earlier board-color fix, a card or swimlane color is now applied only when it is a
recognized color value, so a foreign/old export carrying an unknown color can no longer fail
collection2 validation and abort the import. Thanks to xet7 and Claude. - Fixed the GitHub Actions Playwright E2E workflow so the Firefox and WebKit
browsers can actually run
(Firefox/WebKit,
mongosh):
the test step now setsWEKAN_PLAYWRIGHT_ALL=1(so
--project=firefox/webkitresolve instead of failing with "Project not
found"), WebKit was added to the CI matrix (Playwright's bundled WebKit runs
headless on the Linux runner), andmongoshis now installed in the Playwright
and Puppeteer-regression jobs (the e2e DB helpers shell out to it, which was
failing withspawnSync mongosh ENOENT).npm run test:playwright:allgot the
sameWEKAN_PLAYWRIGHT_ALL=1fix. Thanks to xet7 and Claude. - Translated the remaining untranslated English strings in the Finnish
translation
(fi.i18n.json) — the Shared Templates, card-dependency ("Red Strings") and
dependency import/export strings — using the existing Finnish terminology.
Thanks to xet7 and Claude.- Fix flaky Playwright card/board tests under the parallel run:
the new 3-browser parallel run surfaced three load-induced (not product)
failures that took DOM snapshots before the UI had settled. Thanks to xet7 and
Claude. Details: 03-cards-operations"move does not create duplicate cards" read the card
titles immediately after the move and could catch the card mid-flight
(already removed from the source list, not yet rendered in the target). It
now waits for the card to be visible in the target list and gone from the
source list before snapshotting.03-cards-operations"add-to-bottom places the card last" polls until the
reactive re-sort places the new card last, sincesubmitNewCardonly waits
for the card to exist, not for its final sort position.helpers/auth.jsopenBoardnow retries up to 5 times at 20s each so the
slowest browser (WebKit) survives the contention of the 3-browser parallel
run against one shared dev server, instead of failing in test setup.
- Fix flaky Playwright card/board tests under the parallel run:
- Build scripts: At tests option 9, run option 2 build if .build or node_modules missing.
Thanks to xet7 and Claude.
Thanks to above GitHub users for their contributions and translators for their translations.