60 Commits
Author SHA1 Message Date
Lauri Ojansivu 3621413d6f Speed test: where the time goes when a WeKan board is opened, on FerretDB and on MongoDB.
app/board-open.cjs seeds a board of 200, 2000 or 5000 cards, opens it in Chromium and
records the wall clock to the first card and until the DDP WebSocket is quiet, what
crossed it, the Meteor server's CPU by who spends it (Node inspector) and FerretDB's
CPU (pprof). Two runs on each database: the Meteor server's CPU is the same on both
(0.1-0.5 s) and the DDP server is 1% of it; a 5000-card board takes FerretDB (SQLite)
400-600 ms longer to open, the data sent to the browser being the same ~210 KB, a
small board 70-100 ms. FerretDB uses about 4 s of CPU for the 5000-card open: SQLite
39%, filtering in Go 34%, find/getMore/aggregate 0.7-0.8 s each. The README says what
was measured and what was not: the development build, one machine, the browser's own
time not separated, and the aggregate's source not identified.

Thanks to Raymond-Voogt and xet7 !
2026-11-04 01:21:16 +02:00
Lauri Ojansivu 2441563008 Speed test: SQLite after the membership test fix (68.3 ms, 4.1x), the Due Cards profile and what was tried.
Thanks to Raymond-Voogt and xet7 !
2026-11-04 00:13:34 +02:00
Lauri Ojansivu f3950b9adc Dependabot alerts 180 and 183-187: minimatch in the other lockfiles, and the Go modules of the embedded benchmark.
minimatch before 11.0.1 (GHSA-g3hv-75wg-m249): npm-packages/exceljs still had
10.2.6 through readdir-glob 3, and the vendored jade lockfile under
meteor-jade-loader had three copies through glob 13 and test-exclude; both get
an override to minimatch 11, as the root lockfile has. A test now reads every
package-lock.json of the repository, not only the reported ones.

The benchmark module of embedded engines pulled klauspost/compress 1.18.0,
golang.org/x/net 0.23.0 and golang/glog 1.0.0 (GHSA-259r-337f-4rfw,
GHSA-5cv4-jp36-h3mw, GHSA-qxp5-gwg8-xv66, GHSA-vvgc-356p-c3xw,
GHSA-6wxm-mpqj-6jpf). They are raised to 1.18.7, 0.62.0 and 1.2.4, and
govulncheck then found more in x/net, x/text and OpenTelemetry, which are raised
too (x/net 0.62.0, x/text 0.43.0, otel 1.42.0): it now reports none. A test
holds every go.mod of the repository at or above these floors.

Thanks to dependabot and xet7 !
2026-11-04 00:12:45 +02:00
Lauri Ojansivu 5e07b8db6c Docs: the speed test, version history and embedded engines READMEs link directories, not README.md files. 2026-11-03 23:59:03 +02:00
Lauri Ojansivu 96d56ecc6c Go databases that could be linked into FerretDB, against its SQLite: none is faster where it counts.
A benchmark of its own (docs/Databases/FerretDB/1/SpeedTest/embedded, a Go module,
no cgo) loads the speed test's cards into SQLite set up as FerretDB sets it and
into Pebble, Badger, bbolt, BuntDB, Nutsdb and Clover, and asks each the six
questions WeKan asks of cards, at 15,377 and 153,768 cards. A board's cards take
the same time on every engine that is not slower, because decoding the JSON
dominates; the key-value stores win single reads and writes by microseconds that
a FerretDB call hides; Pebble is 12x slower on fetching a board, Clover 90-190x
slower in total, and bbolt with its default fsync 100-160x slower on writes. The
README accounts for every entry of the awesome-go section.

Thanks to Raymond-Voogt and xet7 !
2026-11-03 23:47:13 +02:00
Lauri Ojansivu 1c44876beb Speed test: Dolt, and what a database with version history would give WeKan's undo and redo.
Dolt runs under the existing MySQL handler with no new handler and gives the same
answers, but is by far the slowest: 20,470 ms in total, every card query a
2.8 s whole-table scan. The VersionHistory scripts drive WeKan-shaped changes
through FerretDB onto Dolt (a commit per write, undo and redo with DOLT_REVERT,
AS OF, +0.4 ms a write, a conflict when the same document is restored again) and
through the REST API of TerminusDB (author and message per commit, field-level
restore). ClickHouse and StarRocks were tried with the MySQL handler and need a
handler of their own; the README says where each fails.

Thanks to Raymond-Voogt and xet7 !
2026-11-03 23:18:51 +02:00
Lauri Ojansivu f576a0cca9 Speed test: TiDB added, and the README says what was tried: pgrust, TiDB, Noria, YugabyteDB, CockroachDB.
TiDB (MySQL protocol, Apache-2.0) runs FerretDB after its metadata table's
generated columns became VIRTUAL, and gives the same answers as MongoDB; it is
a speed test row and opt-in for the conformance run (WEKAN_CONFORMANCE_TIDB=1).
Noria has no JSON type, triggers or generated columns, which the MySQL handler
needs; YugabyteDB refuses a CREATE INDEX on a jsonb expression, which every
FerretDB v1 PostgreSQL index is; CockroachDB is not open source. The README
also records that analyzing a PostgreSQL table after its indexes are created
took the PostgreSQL row from 454 to 145 ms, and that the same on MySQL and
MariaDB did nothing.

Thanks to Raymond-Voogt and xet7 !
2026-11-03 22:45:56 +02:00
Lauri Ojansivu 46c0ad43e8 Speed test: small-scale results ordered fastest to slowest, with times slower, and pgrust.
Results.md now opens with an At a glance table (rank, total, how many times
slower than the fastest, the same for the slowest user), every table is ordered
by its own numbers, the header says the real data size and the real operating
system, and the load table is ordered by the whole load time. pgrust
(PostgreSQL in Rust, malisper/pgrust:v0.4-beta) is one more row through the
same PostgreSQL handler; in the conformance run it is opt-in with
WEKAN_CONFORMANCE_PGRUST=1. The run is 1/20 of a production WeKan so it takes
minutes.

Thanks to Raymond-Voogt and xet7 !
2026-11-03 22:36:56 +02:00
Lauri Ojansivu 499772e4c2 Speed test README: sorting in PostgreSQL was tried and was not faster.
The ten newest of 30,116 users took 52 ms with an ORDER BY in the database and
38-49 ms decoded and sorted in Go, so the change was not kept; the README says
what was measured so it is not repeated.

Thanks to Raymond-Voogt and xet7 !
2026-11-03 21:53:31 +02:00
Lauri Ojansivu d05a42a5af Speed test README: the FerretDB v1.100-v1.105 and WeKan improvements since the last run.
SQLite sorts and stores JSONB, PostgreSQL uses a GIN index for membership and
pushes down $or, $elemMatch and $and, MySQL and MariaDB read through their
indexes with multikey side tables, and WeKan stopped scanning whole collections
every hour or at every start. Results.md still shows v1.99.0, which the README
now says, and the open items are updated to match.

Thanks to Raymond-Voogt and xet7 !
2026-11-03 21:24:03 +02:00
Lauri Ojansivu bc79de8c57 Database health: a collection scan row names the command, the operators per field and the queryHash.
A row said only which fields a slow query filtered on, which is not enough
to find the query in the code or to run explain(). It now shows the command
(for a slow getMore, the query it continues, instead of 'filter on nothing'),
the operators used on each field - never values - and MongoDB's queryHash.

Thanks to Raymond-Voogt and xet7 !

Fixes #6856,
2026-11-02 11:31:47 +02:00
Lauri Ojansivu 0b5c855820 Snap backup and restore instructions work on AlmaLinux, Rocky Linux and Fedora.
snapd keeps the snaps in /var/lib/snapd/snap on Fedora, RHEL, AlmaLinux,
Rocky Linux, CentOS Stream and Arch Linux, which have no /snap, so the
instructions that exported /snap/wekan/current/bin and its lib directory
did not find mongodump and mongorestore there. They now pick the directory
with one S= line and the CPU's library directory with $(uname -m), and the
scripts that can be run from a host shell find the snap in either place.

Thanks to Group-Deed and xet7 !
2026-10-30 23:13:50 +02:00
Lauri Ojansivu b87858baaf Problems / Database: report queries without an index and a high read rate.
The database health probe (server/lib/databaseHealth.js) saw restarts, slow
storage and a full disk, but not what made one instance slow: a 10 GB
collection scanned three times per search, and an hourly job reading all
1.1 million cards (#6824, #6825). Both were visible only in MongoDB's own
log, as "Slow query" lines with COLLSCAN, and in serverStatus: 1.6 billion
documents read in two hours.

Two more checks, every 5 minutes with the others:

- db.collection-scan: the "Slow query" lines MongoDB keeps (getLog
  'global'), newer than the last probe, where a query read a whole
  collection of at least 10,000 documents. Grouped by collection and the
  field names filtered on - never values - with count, documents read and
  time. Small tables read whole by design (settings, roles) and internal
  namespaces are left out. Needs the getLog privilege; without it, and on
  FerretDB, the check finds nothing and is skipped.
- db.scan-rate: serverStatus.metrics.queryExecutor.scannedObjects between
  two probes above 50,000 documents per second. A database restart, which
  resets the counter, is not counted.

Both are rows in Admin Panel / Problems / Database with what to do;
docs/Databases/MongoDB/Storage-Requirements.md lists them.

tests/databaseHealthScans.test.cjs drives the log parsing and the rate,
including that a filter's values never reach the row. From the reporter's
patch.

Thanks to Raymond-Voogt and xet7 !

Fixes #6826.
2026-10-27 21:19:51 +02:00
Lauri Ojansivu a90576bafa The speed test report escapes a backslash before the pipe in a table cell.
CodeQL js/incomplete-sanitization, alerts #593, #594 and #595:
docs/Databases/FerretDB/1/SpeedTest/report.cjs escaped `|` as `\|` in
Markdown table cells but left a backslash alone, so a value ending in a
backslash turned the added one into a literal backslash and its pipe
split the cell. One mdCell() helper escapes the backslash first, then the
pipe, and turns a line break into a space; it is also used for the
database's name and the query's title, which were not escaped at all.
tests/speedTestReportCells.test.cjs checks the escaping, that no value
can add a column to its row, and that nothing in the tree escapes a pipe
without the backslash. The report is generated from local speed test
results at build time, so there is no attempt to record in Admin Panel /
Problems.

Thanks to GitHub CodeQL and xet7 !
2026-10-25 04:29:05 +02:00
Lauri Ojansivu e81d17da80 Speed test results: SQLite, PostgreSQL, MySQL and MariaDB with FerretDB b6c494e9.
Rerun of the four FerretDB v1 backends at twice the production data,
with the MySQL/MariaDB index reads and VIRTUAL index columns, the
multikey side tables for MySQL/MariaDB, the PostgreSQL GIN membership
index and SQLite sorting in the database. MongoDB 6-9 and FerretDB 2
keep their rows from the same directory. Every database returned the
same data as MongoDB.

All Boards count went from 8-9 s to 159 ms on PostgreSQL and from
9.4 s to 1.1 s on MySQL; adding the 44 indexes took 172 s on MySQL and
901 s on MariaDB instead of 20 and 40 minutes. This build is before
the fixes for SQLite's People page (the database sort read its key
three times per row), MySQL/MariaDB All Boards with a starred board, and
Due Cards' $and on PostgreSQL, MySQL and MariaDB, which a rerun now in
progress measures.

Thanks to xet7 !
2026-10-25 01:53:58 +03:00
Lauri Ojansivu 70485c38df A database speed test: the common WeKan queries on every database, twice a production WeKan of data.
docs/Databases/FerretDB/1/SpeedTest/speedtest.sh (build.sh and build.bat ->
Tests -> Database speed test) is releases/db-conformance.sh with
WEKAN_DB_SUITE=speedtest: the same FerretDB built from source and the same
databases started the same way - SQLite, PostgreSQL, MySQL and MariaDB through
FerretDB v1, MongoDB 6, 7, 8 and 9, and now FerretDB 2 with PostgreSQL and
DocumentDB.

data.cjs generates, deterministically, twice the users, boards, lists,
swimlanes and cards of a production instance (615,070 cards), skewed the way
real ones are; indexes.cjs creates the indexes WeKan creates, read from its
ensureIndex calls; queries.cjs asks 18 common WeKan queries as WeKan's own code
builds them; report.cjs writes Results.md - a row per database, fastest at the
top, a column per query - and fails when a database answered or stored
anything differently from MongoDB. README.md describes it, what it found, what
was improved and what could still be.

db-conformance.sh: WEKAN_DB_BACKENDS runs only the named databases (to repeat
one into an earlier run's WEKAN_LOGDIR), containers are removed with their
volumes, SQLite's data is under .tools/tmp, and FerretDB 2 is a backend of the
speed test, and of the conformance run with WEKAN_CONFORMANCE_FERRETDB2=1. The
conformance catalogue gains a case of writes by string _id and _ids differing
only by case, which found that FerretDB on MariaDB 12.3 lost them.

tests/dbSpeedTest.test.cjs checks the data, the index list, the queries, the
report's order and that a difference fails it, the wiring and the Due Cards
board scope.

Thanks to xet7 !
2026-10-24 18:18:15 +03:00
Lauri Ojansivu 89da0e5be7 Every platform runs the prebuilt SQLite-only ferretdb-sqlite binary from wekan/FerretDB.
wekan/FerretDB now releases ferretdb-sqlite-<arch> beside ferretdb-<arch>: the
same FerretDB with only the SQLite handler, about 5 MB smaller, and SQLite is
all a WeKan bundle, image, snap or .spk runs. releases/ferretdb-asset.sh is the
one place that chooses: the newest release that has ferretdb-sqlite-<arch>,
and, until one does, the full ferretdb-<arch> of the newest release, which
has the SQLite handler too. It says in the log which one it took and why,
downloads it, verifies it against its .sha256sum, and returns FERRET_ASSET,
FERRET_TAG, FERRET_URL and FERRET_SHA for the provenance table (also through
$GITHUB_ENV, cached per job so the check and embed steps agree).

Every FerretDB download goes through it: the amd64, arm64, win64, win-arm64,
win32, mac-arm64, mac-x64 and extra-architecture jobs of release-all.yml (the
Docker images, snap, AppImage, Flatpak, single-file and macOS/Windows
packages are made from those bundles), repack-bundle-for-arch.sh for
release-all-missing.yml, bsd.yml, check-arch-binaries.sh,
build-release-bundle.sh and test-download-urls.sh. require-binaries.sh checks
the resume-login floor against the release the helper chose. The provenance
rows record that release and URL instead of /latest/.

No release workflow builds FerretDB: sandstorm-src/build-deps.sh takes the
prebuilt ferretdb-sqlite-amd64 by default (FERRETDB_SOURCE=download), and
sandstorm.yml and release-all.yml's build-sandstorm no longer set
FERRETDB_SOURCE=build; building from source stays a local option. The default
docker-compose.yml downloads ferretdb-sqlite-<arch> (FERRETDB_BINARY, falling
back to ferretdb-<arch> for a release without it); the PostgreSQL, MySQL,
MariaDB and SAP HANA compose files keep the full binary.

tests/ferretdbSqliteAsset.test.cjs drives the helper against a fake GitHub
(newest, older and no release with the SQLite-only binary, .exe names, a
pinned tag, FERRETDB_VARIANT=full, checksum match and mismatch, a missing
platform, bad names) and checks that every download site uses it, that no
workflow builds FerretDB and that only the SQLite compose file takes the
SQLite-only binary. The tests that pinned the old URLs follow the helper.

Thanks to xet7 !
2026-10-23 21:22:36 +03:00
Lauri Ojansivu 11babe27f2 Docs: snap keys, setting guide and Docker examples that match this WeKan.
- Three snap set lines named keys the snap does not have, which snapd
  stores without a word: MONGO_OPLOG_URL (the key is mongo-oplog-url),
  oauth-enabled (oauth2-enabled) and "snap set wekan set disable-mongodb".
  tests/docsSnapKeysExist.test.cjs checks every snap set in the docs
  against the KEY_ names in snap-src/bin/config.
- Adding-new-Snap-settings-to-code.md used setting names that do not
  exist (LDAP_ENABLED, LDAP_SEARCH_FILTER, a wrong KEY_ line), the edge
  branch and Travis CI. It now follows the real config and wekan-help
  entries, says that a login setting goes through the Admin Panel catalog
  and authEnv(), and lists the other platform files a setting belongs in.
- The LDAP and Traefik Docker examples ran MongoDB 3.2/4.0 with
  --smallfiles, which MongoDB 4.2 removed, and WeKan images from 2018. They
  use mongo:7 and ghcr.io/wekan/wekan:latest; Traefik stays at v1.7, since
  that guide's labels and traefik.toml are v1 syntax.
- The Windows page no longer sets RICHER_CARD_EDITOR, which WeKan does not
  read, and points to build.bat for building from source.

Thanks to xet7 !
2026-10-16 23:52:46 +03:00
Lauri Ojansivu b7589737f5 File docs/Features the way the WeKan menus are.
A feature's guide now sits under the menu it is used from, read from the
templates rather than from where somebody once put it: Header-Bar,
All-Boards, Pages, Board-Header (search and every Board View), Board-Sidebar
(Board Settings, Filter, Members, Labels, Archive), Rules, Swimlanes, Lists,
Cards, Member-Settings, Admin-Panel and Login-Page. Topics used from several
menus (editor, history, theme, translations, email, troubleshooting) are in
General.

- Each area has a README mapping its menu entries to their guides and to the
  template or server module that implements them. Board-Header/README.md
  lists all 40 Board View entries with the template boardBody.jade renders;
  five views (Table, Calendar Mode, Time, Timeline, Map) have no guide of
  their own yet and say so.
- Board-View.md listed 25 views while BOARD_VIEWS has 40; it now lists all
  of them with their English labels.
- Pages keep their file names. Where a released changelog links an old path,
  a "# Moved" page stays there and points to the new one; test-menu.sh skips
  folders holding only those.
- Undo was filed under Login; it is General/Undo now.
- Every link in docs, code comments, scripts and tests follows the move;
  docsLinksResolve checks them all.

Tests that read a doc follow it to its new place. boardViewSettings now fails
when Board-View.md or Board-Header/README.md differs from BOARD_VIEWS, or
names a template boardBody.jade does not render.

Thanks to xet7 !
2026-10-16 23:45:35 +03:00
Lauri Ojansivu 7dfd942ff6 LDAP: a sync interval in milliseconds no longer stops WeKan.
"[uncaughtException] WeKan is stopping: TypeError: string.toLowerCase is
not a function at later.parse.text ... at Object.schedule
(wekan-ldap/server/sync.js)", in a snap restart loop. The docs give
LDAP_BACKGROUND_SYNC_INTERVAL in milliseconds, settings_get() turns a
numeric value into a Number, and the schedule handed it straight to
later's text parser, which threw from a timer. Text later could not read
did not throw, but made a schedule that never ran - as a quoted
'every 1 mins' from a compose file did, the second report in #2354.

packages/wekan-ldap/server/syncSchedule.js reads the setting and never
throws: milliseconds (a Number or digits) become that interval, later.js
text is read as before, one pair of surrounding quotes is removed, unset
keeps the original default (recur().on(0).minute()), and anything
unreadable logs why and uses the default. The docs, the snap description
and the compose files say both forms work, instead of "leave this unset
so it does not crash".

Tests: tests/ldapSyncSchedule.test.cjs reproduces the crash with the real
later.js from the build, schedules 3600000 ms an hour apart and 10000 ms
ten seconds apart, reads quoted text, keeps the default, never throws on
any value a setting can hold, and fails if any server file hands a setting
to parser.text directly.

Thanks to B2RN and xet7 !

Fixes #2354.
2026-10-15 03:17:49 +03:00
Lauri Ojansivu fea58e1312 Document which databases WeKan supports, and how each is tested.
docs/Databases/Supported.md is the one list: FerretDB v1 with SQLite (the
default everywhere), PostgreSQL (works), MySQL, MariaDB and SAP HANA
(experimental), FerretDB 2 (not tested), and MongoDB 6, 7, 8 and 9 - with
what checks each: the 110-query conformance catalogue answers the same on
all of them, and WeKan's own tests run on Meteor's bundled MongoDB 8 and on
FerretDB. It also says what to know about MongoDB versions: the Linux
kernel 6.19-7.0.13 refusal and its fixes, AVX, the driver, and upgrades.

The README and the Status section of CHANGELOG.md gain a Databases list,
docs/Databases/README.md links the page, the Meteor 2.14 compatibility guide
is marked historical, and the conformance page counts 110 cases and the
MongoDB backends. CLAUDE.md and AGENTS.md describe the new Status block.

Thanks to xet7 !
2026-10-10 19:07:14 +03:00
Lauri Ojansivu ad51a03731 Log in by full-page redirect by default with OAuth2/OIDC, Google & co, SAML and CAS.
Every login that chooses between a popup and a redirect opened a popup by
default. Google's sign-in pages, and other identity providers', can send
Cross-Origin-Opener-Policy, which makes Meteor's popup look closed at
once: the login was tried before the provider answered, and the user
was back on the sign-in page with no error. Popups are also blocked in
iframes and on some phones. The full-page redirect has no popup to lose.

- OAUTH2_LOGIN_STYLE (OAuth2/OIDC): redirect unless it says popup, in the
  server, the Admin Panel catalog and the samples.
- OAUTH_PROVIDERS_LOGIN_STYLE (Google, GitHub, Facebook, X, Meteor
  Developer, Weibo, Meetup): redirect by default, in the code, Dockerfile,
  snap, Sandstorm package and samples.
- SAML: both identity-provider profiles log in by redirect;
  SAML_LOGIN_FLOW=popup still chooses the popup, and the client no longer
  falls back to a popup while the configuration loads.
- CAS: redirects unless "popup": true. Its redirect could never finish:
  nothing called Meteor.initCas, which the package now does at startup.
  The sign-in page also passed username and password as loginWithCas's
  options and callback, so its callback never ran, and the CAS redirect
  page echoed the request address into HTML unescaped.

A redirect login's error now reaches the reloaded sign-in page, from
accounts-oauth's page-load hook and the SAML and CAS events, instead of
the page coming back silently.

Verified against a freshly built and prepared bundle with the local
identity-provider suite and no login style set: OIDC, SAML, CAS and all
seven Meteor providers log in by redirect, and each refusal is shown on
the sign-in page (31 of 31 with Chromium). Its LDAP wrong-password case
expected wording that changed in 679a8b3499 and is corrected.

Thanks to xet7 !
2026-10-08 15:18:59 +03:00
Lauri Ojansivu 5ed9fc944a Remove obsolete Summernote integration and editor configuration.
Use the Markdown textarea for every editor. Remove the retired environment and Snap options from server settings, all platform launchers, build scripts and current documentation. Keep released and archived changelog entries intact.

Keep notification HTML escaping independent of editor configuration, preserve attachment metadata and mention behavior, and cover Markdown and emoji round trips in browser tests. Also import the translator used by attachment error handlers.

Thanks to xet7 !
2026-09-19 14:32:29 +03:00
Lauri Ojansivu faaa83ed09 Explain and remediate the MongoDB 8.2 crash loop that follows a full disk.
A reported test environment (mongo:8.2.2 in Kubernetes) filled its data
volume: the checkpoint's fdatasync returned ENOSPC, WiredTiger panicked and
mongod aborted - and then it kept failing on every start, with the disk long
since freed. MongoDB 8.2 keeps a throwaway WiredTiger instance under
<dbPath>/_tmp/spilldb for queries that spill to disk and empties it itself on
each start; after the abort that emptying failed ("Failed to clear dbpath of
the internal WiredTiger instance: Directory not empty"), mongod opened the
half-emptied directory, found no version file, reported "Failed to open the
spill WiredTiger instance ... database corruption detected" and fasserted.
Nothing retries, so the pod restarts forever. The data itself is intact;
deleting that one directory is the whole fix.

- snap-src/bin/mongodb-control deletes _tmp/spilldb before every mongod
  start (no mongod is running at that point, and mongod recreates it), and
  its start-failure handler recognises the log line and names the directory.
  The snap ships MongoDB 7 today, so this is a no-op until it does not.
- Admin Panel / Problems: the db.restart row now says what a "No space left
  on device" abort means for a full disk as well as for a network
  filesystem, and both it and db.disk-space name the exact spill directory
  to delete when MongoDB 8.2 will not start afterwards. The probe looks the
  data directory up once and passes it to both rows.
- docs/Databases/MongoDB/Storage-Requirements.md gets the log signature of
  both stages, why the second one never ends, the one command, what must
  not be touched, and that Docker/Kubernetes users run it themselves since
  the database container is MongoDB's own image.
- tests/databaseHealth.test.cjs pins the spill path, both rows' advice, the
  probe wiring, the snap's pre-start deletion (before the first start, after
  the running-instance check, and the only recursive delete apart from the
  existing FerretDB reset) and the documentation.

Thanks to xet7 !
2026-09-11 21:31:10 +03:00
Lauri Ojansivu 61806605fc Add the Meteor accounts login providers and passwordless login to every platform's settings.
OAUTH_GOOGLE_*, OAUTH_GITHUB_*, OAUTH_FACEBOOK_*, OAUTH_TWITTER_*,
OAUTH_METEOR_DEVELOPER_*, OAUTH_WEIBO_*, OAUTH_MEETUP_*,
OAUTH_PROVIDERS_LOGIN_STYLE, OAUTH_PROVIDERS_MERGE_EXISTING_USERS and
PASSWORDLESS_ENABLED are now documented, commented out or defaulted, in
every place the OAUTH2_* and SAML_* settings already are: docker-compose.yml
and its FerretDB v1 / v2 and MongoDB variants, the Dockerfiles' ENV block,
start-wekan.sh, start-wekan.bat, the Snap config (keys list plus
DESCRIPTION_/DEFAULT_/KEY_ triples) and wekan-help, the Sandstorm package
definition, the stacksmith Docker-secrets reader and secrets/README.md.
The comments name the callback URL to register at each provider,
<ROOT_URL>/_oauth/<service>, and say that Admin Panel / People / Login
overrides the environment.

New docs pages docs/Features/Login/OAuth-Providers.md and Passwordless.md,
linked from the docs index. tests/oauthProvidersPlatformEnv.test.cjs pins
that every variable is present on every platform and that the docs exist
and are linked.

Thanks to xet7 !
2026-09-11 11:50:30 +03:00
Lauri Ojansivu 03ffb56a5e Index card_comment_reactions, and document why MongoDB's data directory must be local.
From a reported MongoDB crash series (.tools/crash: WeKan and MongoDB in one
Kubernetes pod, the database volume on an SMB/DFS share):

- The crash itself is WiredTiger's checkpoint fsync() returning ENOSPC
  ("No space left on device" with 519 MB used and 10 GiB free) on the
  network share, followed by a fatal assertion and abort - every checkpoint,
  so a restart loop. That is the storage, not WeKan: MongoDB requires a
  local filesystem with real fsync semantics under its data directory.
  docs/Databases/MongoDB/Storage-Requirements.md now says so, shows what
  the log looks like when it is not, and what to do (local block volume;
  attachments may still live on a share; MONGO_URL over TCP is fine).
- The WeKan-side finding in the same logs: card_comment_reactions had no
  index at all, and every board open queried it by `cardId: { $in: [...] }`
  and by `boardId` as a full collection scan - 3,397 COLLSCANs of that one
  collection in the last crash log, up to 1.6 s each, the bulk of its
  "Slow query" lines. server/models/cardCommentReactions.js now ensures
  indexes on cardId, boardId and cardCommentId at startup, like every other
  per-card collection.

tests/cardCommentReactionsIndexes.test.cjs pins both.

Thanks to xet7 !
2026-09-11 11:23:53 +03:00
Lauri Ojansivu 9161c20b39 Document Admin Panel email configuration 2026-09-06 18:35:33 +03:00
Lauri Ojansivu 175eea9810 Design restart-safe durable operations 2026-09-05 23:51:02 +03:00
Lauri Ojansivu 6d5bcb4fc1 Extend verified recovery integrity design 2026-09-05 23:51:02 +03:00
Lauri Ojansivu 3980dd9fc3 Design verified recovery and low-load maintenance 2026-09-05 23:51:02 +03:00
Lauri Ojansivu f66060e44c Fix Google login to USERNAME_MAP=email.
Thanks to xet7 !
2026-08-31 11:12:18 +03:00
Lauri Ojansivu c4cb87345b Reorganize documentation and repair links.
Move feature and webserver documentation into the reorganized hierarchy, update references to their new relative paths, and extend link validation across the complete documentation tree.\n\nThanks to xet7 !
2026-08-17 00:24:38 +03:00
Lauri Ojansivu fa289e4a4d Admin Panel Problems: the route and the template say what the menu says.
The pane is called Problems in the menu, its address is /admin/problems, and
docs/Features/Admin-Panel/Problems is where it is documented. Two things still
called it Reports, from before it was renamed:

  * the route NAME was 'admin-reports', where its three siblings are 'setting',
    'people' and 'attachments' - the bare page key. So the one route whose name
    did not match its own address;
  * the template, and its three files, were adminReports.

Both are 'problems' / adminProblems now, across 41 files.

What did NOT change is `legacyBase: '/admin-reports'`. That is an address people
have bookmarked and it still redirects here - the point of the rename is that
the code agrees with the menu, not that an old link should break. The CHANGELOG
entries describing the old addresses are left alone too: a released section is a
record of what shipped.

Thanks to xet7 !
2026-08-16 15:36:04 +03:00
Lauri Ojansivu e1c6221f22 FerretDB: connect with directConnection=true, so a fresh docker compose up starts.
A new install with nothing changed but the port and ROOT_URL could not reach the
database at all:

    MongoServerSelectionError: connect ECONNREFUSED 0.0.0.0:27017
    reason: TopologyDescription { type: 'ReplicaSetNoPrimary',
            servers: Map(1) { '0.0.0.0:27017' => [ServerDescription] },
            setName: 'rs0', ... }

0.0.0.0 is in no compose file. It is FerretDB's own listen address, and the
driver was handed it by the server.

The ferretdb service runs with --repl-set-name=rs0, added in #6480/#6481 so
Meteor can tail an OpLog instead of poll-and-diff. FerretDB therefore answers the
hello handshake as a one-member replica set, and fills hosts, me and primary with
its --listen-addr, which is the wildcard 0.0.0.0:27017. A driver that is not in
direct-connection mode reads that reply as an invitation to do replica-set
DISCOVERY: it adopts the advertised member list and drops the seed it was given,
because the server reports a name other than the one that was dialled. So
mongodb://ferretdb:27017 became 0.0.0.0:27017, which inside the wekan container is
the wekan container itself, where nothing listens.

Measured against FerretDB v1.49.0 - the version reported - with the mongodb
driver the bundle ships:

    mongodb://localhost:27017/wekan
      -> ReplicaSetWithPrimary, servers: 0.0.0.0:27017   (the seed discarded)
    mongodb://localhost:27017/wekan?directConnection=true
      -> Single, servers: localhost:27017

directConnection=true keeps the driver on exactly the host it was given. It costs
nothing else: the handshake still reports setName rs0, which is the only thing
Meteor checks before it will tail an OpLog (accounts for the check in the mongo
package's oplog_replica_set_error.js), so #6480/#6481 are unaffected and the
commented MONGO_OPLOG_URL examples keep replicaSet=rs0 beside it.

All five FerretDB v1 compose files are fixed, being the ones that start FerretDB
with --repl-set-name. The MongoDB compose files are deliberately left alone: those
are real replica sets whose members are reachable under the names they advertise,
and directConnection would pin Meteor to a single node of one.

tests/ferretdbDirectConnection.test.cjs pins both halves - that a compose file
running FerretDB as a replica set carries directConnection=true on every URL
pointing at it, and that the MongoDB ones do not.

Thanks to Dandrass and xet7 !

Fixes #6582,
2026-08-11 01:51:51 +03:00
Lauri Ojansivu 5ec9f3ae5b Document the CPU platforms of the Docker image, beside the snap's.
"Which CPUs is this published for, and why not that one" was answerable for
the snap and nowhere else, so the same page now exists for the image:
docs/Platforms/FOSS/Container/Docker/CPU-platforms.md. It carries the platform
matrix with each platform's TARGETARCH, TARGETVARIANT and bundle, how the set
is decided on every release from what the base image publishes and which
bundles landed, the three names that differ between Docker, Debian and the
WeKan bundles, and one section per platform that is deliberately NOT an image:
loong64 (no base image exists at any tag), armv6 (gated on a base with
arm/v6), armv7 (the one 32-bit ARM slot must carry the armhf baseline) and the
Windows and macOS bundles. It ends with why the FerretDB image covers more
platforms than the WeKan one - FROM scratch around a static Go binary needs no
userland at all.

The snap's page gains the matching armv6 section - the Snap Store has no armv6
architecture, and its only 32-bit ARM is armhf, which an ARMv6 board cannot
run - and a table of all fifteen bundles against which six become snaps, so
"it is missing" and "it cannot be there" stop looking alike. The two pages
link each other, because the answer differs between them.

docs/Databases/FerretDB/1/README.md said the per-architecture FerretDB binary
was embedded in the bundles "for ppc64le, s390x, riscv64". Every bundle
carries one; those three are part of a longer list of platforms where it is
the DEFAULT because MongoDB publishes no server. It now lists all seventeen
built binaries and separates the three 32-bit ARM builds that are not variants
of each other: armhf is GOARM=7, armv6 is GOARM=6, armel is GOARM=5 software
floating point.

Thanks to xet7 !
2026-08-10 01:35:51 +03:00
Lauri Ojansivu f628a69889 Reorganized docs Platforms etc.
Thanks to xet7 !
2026-08-03 13:07:12 +03:00
Lauri Ojansivu 4541fa99e1 Database tests run on their own ports, and survive their first real run.
Three things the first run on arm64 found.

The FerretDB it built could not start: `panic: commit.txt value ... !=
vcs.revision value ...`. Go stamps the VCS revision into the binary and
FerretDB's build/version panics when it disagrees with the committed
commit.txt, which only the generator refreshes - so every commit made after the
last refresh built a binary that panicked. Fixed in the fork (its act_build now
regenerates them, as act_dist already did).

Ports: FerretDB listened on 27017, which is where a dev server's database lives
and where the compose files publish FerretDB - so this could not run beside
anything else and, worse, could have pointed the tests at somebody else's
database and rewritten it. It listens on 37017 now and publishes the database
server on 35432, both moved on if busy, both overridable with
WEKAN_CONFORMANCE_PORT and WEKAN_CONFORMANCE_DB_PORT, and its containers are
named per run so a compose stack is never reused or stopped.

And Ctrl-C only killed whatever was in the foreground - a registry lookup, a
sleep - after which the loop carried on and reported the interrupted lookup as
"NO linux/arm64", which is a lie about the image. An interrupt ends the run now,
and the image check has three outcomes rather than two: has it, does not have
it, could not ask. A FerretDB that will not start also prints the last lines of
its log, because the reason is usually one line.

Thanks to xet7 !
2026-07-28 01:48:45 +03:00
Lauri Ojansivu 7a3783fbe6 Tests menu: run every database this CPU can, and check they answer the same.
FerretDB v1 translates one MongoDB query into five different SQL dialects, so
"WeKan starts on MariaDB" says very little. The question that decides whether a
backend can be trusted with a board is whether {n: {$gt: 5}} returns the same
documents, in the same order, as it does on SQLite - and nothing was asking it.

./build.sh -> Tests -> "All databases (sequential)" now does, and build.bat has
the same entry (running the same script through bash rather than a second
implementation that would drift).

It builds FerretDB v1 from source first: the FerretDB subdirectory is cloned
from git@github.com:wekan/FerretDB if it is not there, updated if it is, and
built through its own build.sh, which installs the Go toolchain and the module
dependencies when they are missing. The tests run against THAT binary, not a
downloaded release, so they test the newest code.

Then, for each backend whose database image has a build for THIS CPU - asked of
the registry with docker manifest inspect, so no table here can go stale - it
starts that database, runs the freshly built FerretDB against it, runs the whole
catalogue and stops everything. Sequential, because they all use the same
FerretDB port and a database under test should not be competing with three
others; the menu entry says so.

The catalogue is 100 cases in 15 groups, taken from FerretDB v1's own handler
sources rather than from MongoDB's manual: every query, update and bitwise
operator, the aggregation stages and accumulators, projection and sorting and
paging, count and distinct, indexes and uniqueness, capped collections (which is
how the OpLog exists at all), and the commands whose answers may legitimately
differ. The seed data is deliberately awkward - a null, a missing field, a
negative number, a zero, an empty array, an array of documents - because tidy
data lets a broken translation pass.

Answers are normalised and compared byte for byte against SQLite, so document
ORDER counts. Three cases are compared loosely and say so: an explain plan
differs per engine by definition, and collStats/dbStats are sizes a different
storage engine may answer differently. Two backends failing the same way is
agreement about a limitation; one answering where another fails is a difference.

Everything lands in ../log/<datetime>/ with every other test run: a JSON of what
each backend answered, each backend's container output, the build log, a summary
and db-conformance-report.md. SAP HANA is opt-in behind WEKAN_CONFORMANCE_HANA=1
- amd64-only, ~16 GB of RAM, and SAP's licence to accept - so a menu choice
cannot start it by accident.

Thanks to xet7 !
2026-07-28 01:43:22 +03:00
Lauri Ojansivu 67991587d4 Alternatives.md: group the databases by family, and lead with the summary.
The page listed images and requirements, which left the reader to work out the
pattern themselves. There is a pattern: the databases are not fifteen separate
questions but seven families, and inside a family the answer is the same one.

Each family now says what IT is missing. PostgreSQL-wire and MySQL-wire need no
code at all, only a live run against their dialect - that is where CockroachDB's
s390x image could be won. Enterprise SQL needs a whole backend each, and the
driver is the obstacle only for Db2, whose cgo-only driver cannot be in a
nine-architecture build. Embedded databases need a pure-Go driver before
anything else. Columnar engines pass the driver gate and fail the second one:
WeKan updates single cards constantly, and they are built for the opposite.
Key-value stores would have to have indexes, filters and atomicity implemented
inside FerretDB, which is not a backend but a database. And what already speaks
MongoDB needs no FerretDB at all - the reason for this page is that on ppc64le,
s390x, riscv64 and loong64 that family has no members.

The page opens with all of it in five sentences and one table, because the
conclusion - that the most valuable work is verifying the three backends that
already exist, not writing a fourth - was previously only visible to whoever
read to the end.

Corrections while checking: Oracle DOES have a pure-Go driver (sijms/go-ora
implements the TNS protocol itself), so it is not blocked by cgo the way Db2 is;
and Cassandra belongs in the CPU table, since its image covers ppc64le and
s390x.

Thanks to xet7 !
2026-07-28 01:12:52 +03:00
Lauri Ojansivu 69f2be1161 Document which other databases run on many CPUs, and what a backend costs.
WeKan runs on every CPU Node.js runs on, and this fork of FerretDB v1 exists
because MongoDB does not publish a server for most of them. Two questions kept
coming back: which databases even have images for those CPUs, and what would be
missing in FerretDB v1 before it could store into one.

docs/Databases/FerretDB/1/Alternatives.md answers both. The architecture table
is read from each registry's own manifest, not from documentation, and it says
plainly what that data shows: PostgreSQL is the only widely-portable database
server - the only one publishing ppc64le, s390x AND riscv64 - MariaDB covers
ppc64le and s390x, MySQL neither, and MongoDB itself and upstream FerretDB 2
are amd64 + arm64 only. This fork's own image covers nine platforms.

What a new backend needs is taken from the code: a pure-Go driver, because the
binaries are built CGO_ENABLED=0 and that is what makes one build serve nine
architectures (which is why Oracle and Db2 are out, despite Db2's ppc64le and
s390x images); the three backends interfaces, none of them stubbable; a
metadata registry; the SQL features the translation actually uses - JSON path
extraction, containment and type inspection, schemas, expression indexes, a
parseable EXPLAIN, and the record-id column that capped collections and
therefore the OpLog are built on; correct MongoDB semantics on top; and a live
integration run, which is the whole difference between the confirmed and
experimental rows.

And the shortcut: a database that speaks the PostgreSQL or MySQL wire protocol
needs no new backend, only an existing one that survives its dialect -
CockroachDB brings s390x that way, for the price of a test run.

Thanks to xet7 !
2026-07-28 01:10:22 +03:00
Lauri Ojansivu fea3c432e8 Organize docs/Databases: one directory per database.
It was a flat list where the database was a filename prefix, in three spellings
- MongoDB-Driver-System.md, mongodb-avx-qemu.md, MongoDB_OpLog_Enablement.md -
plus FerretDB2-PostgreSQL.md and a ToroDB-PostgreSQL directory. Somebody asking
"how do I run WeKan on PostgreSQL" had to read the prefixes to find out which
files were even about their database.

Now: Migrations, MongoDB, FerretDB (with 1 and 2, because v1 and v2 are
different products with different backends) and ToroDB (with PostgreSQL). Each
file keeps its name minus the redundant prefix - MongoDB/Driver-System.md,
MongoDB/avx-qemu.md - and the old PostgreSQL.md, which was an index of FerretDB
and ToroDB rather than a document about PostgreSQL, becomes the directory's
README.md.

Every directory has a README.md saying what is in it and where to go next,
including FerretDB/1, which had no documentation at all until now although it
is WeKan's default database and just gained four more backends. Links to a
directory point at the DIRECTORY, not at its README.md, because README.md is
what is opened by default.

Every link that pointed into the old paths is updated - in docs, in
docker-compose-ferretdb-v2-postgresql.yml, and in the wekan.fi website - and
the relative links inside the moved files, which gained a directory level and
so needed one more "../". tests/docsDatabases.test.cjs pins the layout, the
READMEs, the directory links, that every relative link resolves, and that
nothing outside CHANGELOG.md still names an old path.

Thanks to xet7 !
2026-07-28 01:05:27 +03:00
Lauri Ojansivu c29f5c7a66 Rename the dev helper rebuild-wekan.sh/.bat -> build.sh/.bat (shorter name).
Renames rebuild-wekan.sh -> build.sh, rebuild-wekan.bat -> build.bat, and the
guard test tests/rebuildWekanDevServer.test.cjs -> tests/buildDevServer.test.cjs,
and updates every reference across the repo: the docs (Build-from-source, Windows,
Sandstorm, Raspberry Pi, virtual-appliance, Debugging, Developer-Documentation,
FerretDB, OpLog, Rclone, Emoji, Multiverse roadmap, Security remediation, Tests),
README.md, CONTRIBUTING.md, CLAUDE.md, package.json (test:unit:node), the release
scripts (release-all.sh, fix-changelog-hashes.sh, node-update.sh), the disabled
playwright workflow, playwright.config.js, the REST spec comment, tools/forge-mirror.js,
and the CHANGELOG. The menu and every option are unchanged; only the filename and
its references. The website has no references.

Thanks to xet7 !
2026-07-24 19:32:24 +03:00
Lauri Ojansivu ffecc49c92 Docs: WeKan lists are board-wide, not per-swimlane (reflect the #6521 revert).
The per-swimlane-lists model was reverted (its migrations were removed in #6521);
lists are board-wide and the same lists appear in every swimlane. Update the docs
to say so:

  * Features/Lists/Lists.md and Features/Board/Swimlanes.md now state plainly that
    lists are shared across swimlanes (a card belongs to one list and one
    swimlane), and that per-swimlane lists were an experiment that was reverted.
  * The docs/Databases/Migrations/ writeups (MIGRATION_SYSTEM_IMPROVEMENTS,
    MIGRATION_SYSTEM_REVIEW_COMPLETE, CODE_CHANGES_SUMMARY, SESSION_SUMMARY,
    verify-migrations.sh) describe the old cron-driven migration system and the
    per-swimlane-lists migration, both removed; each now carries an OBSOLETE banner
    pointing at the current board-wide model and the live repair paths
    (merge-per-swimlane-lists + repairBoardData).

The dated PerUserDataAudit2025-12-23 snapshot is left as-is: it already observed
that lists are board-wide, and it is a point-in-time record.

Thanks to xet7 !
2026-07-24 16:44:56 +03:00
Lauri Ojansivu 794346e396 cpu-exec qemu-user fallback everywhere; tests for all newest fixes.
Fix #6458 completely: the reporter's host runs inside a hypervisor that
masks AVX, and the old per-tool AVX wrappers (amd64-only, PATH-based)
were bypassed by absolute-path mongod invocations.

- New general snap-src/bin/cpu-exec: runs any binary directly when the
  CPU has the features it declares (--features x86_64=avx,aarch64=atomics
  or WEKAN_REQUIRED_CPU_FEATURES) and through same-arch qemu-user when
  not; plain zero-overhead exec with no declared features. Lookup order:
  WEKAN_QEMU_USER, qemu-<arch> next to the script (bundle/Docker),
  $SNAP/qemu-<arch>, the snap's migratemongo/avx one, then system
  qemu-user(-static). Clear error + direct run when no qemu exists, so
  the real SIGILL surfaces instead of hiding.
- Snap: mongodb-control and migration-control run every mongod 7 through
  cpu-exec, so MongoDB works without AVX (slower) and migration can READ
  modern MongoDB data on such CPUs; completed-FerretDB switch and
  migration fallbacks unchanged (switch_to_completed_ferretdb extracted).
- release-all.yml: every Linux bundle .zip ships cpu-exec + this-arch's
  static qemu-user (amd64/arm64/ppc64le/s390x/riscv64; stripped from
  win64/mac bundles), flowing into Docker and Snap automatically;
  Sandstorm .spk gets both via build-deps.sh. Bundle launcher and Docker
  entrypoint route node/ferretdb through cpu-exec.
- Docs: mongodb-avx-qemu.md and mongodb-raspi4-qemu.md document the
  built-in mechanism.

Tests, with negative cases, for the newest features and fixes at
changelog: htmljs array-vs-attributes (#6459), description draft
normalize/reset (#6455), comment draft lifecycle (#5547), attachment
delete guard (#5282), rules move actions + import normalization (#6472),
snap mongod-failure/migration recovery (#6458 #6466), FerretDB polling
defaults (#6467 #6468), UI density guards for every #6465 fix, and a
behavioral cpu-exec test against fake cpuinfo + fake qemu. All wired
into test:unit:node. Go table tests for the FerretDB SQLite filter
pushdown are in the wekan/FerretDB repo.

Updated ChangeLog.

Thanks to xet7.
2026-07-16 17:40:24 +03:00
Lauri Ojansivu 5cc9b1dcbb Docker: add "Build from source & start" menu action; remove obsolete compose version: attribute
Add a "Build from source & start (up -d --build)" action to the Docker
menus in rebuild-wekan.sh and rebuild-wekan.bat. It builds the wekan-app
image from the local Dockerfile, tags it as the image the chosen compose
file references (ghcr.io/wekan/wekan:latest), and starts that freshly
built container instead of a possibly-stale prebuilt image pulled from
the registry - useful when a source change (e.g. the FerretDB
Version-page detection) is not in the pulled image yet.

Remove the obsolete top-level "version:" attribute from all docker
compose files, which Docker Compose v2 warns about and ignores:
docker-compose.yml, docker-compose-ferretdb-v2-postgresql.yml,
docker-compose-multitenancy.yml, .devcontainer/docker-compose.yml, and
docs/Databases/ToroDB-PostgreSQL/docker-compose.yml.

Thanks to xet7 !
2026-07-11 11:52:03 +03:00
Lauri Ojansivu 4dbf99010c Docker: make FerretDB v1 + SQLite the default docker-compose.yml
Rename docker-compose-ferretdb-v1-sqlite.yml -> docker-compose.yml (the
new default) and the old MongoDB docker-compose.yml ->
docker-compose-mongodb-v7.yml, so "docker compose up -d" uses the light,
self-contained FerretDB v1 + embedded SQLite from
https://github.com/wekan/FerretDB by default.

Update rebuild-wekan.sh and rebuild-wekan.bat Docker menus to list
FerretDB v1 SQLite first (default) and point at the new filenames.
Update the compose files' own header comments (self-identification and
cross-references), note the new default at the top of docker-compose.yml,
and update the Docker docs (main Docker.md gets a compose-file/database
map; FerretDB2-PostgreSQL.md points at the v2 postgresql compose file).

Thanks to xet7 !
2026-07-11 11:35:47 +03:00
Lauri OjansivuandClaude Opus 4.8 7b66884ba3 docs: fix bare wiki-style links to relative paths of existing docs pages
Many docs still used flat GitHub-wiki page-name links like [Backup](Backup),
[OAuth2](OAuth2) or [FAQ](FAQ) that only resolved on the old wiki; in the docs/
hierarchy they were broken. Rewrite them to correct relative paths of the
existing pages (e.g. ](Backup) -> ](Backup.md), ](OAuth2) -> ](../Login/OAuth2.md),
](Sandstorm) -> ](../Platforms/FOSS/Sandstorm/Sandstorm.md)).

Mapping: page name -> docs/<...>/<Name>.md by filename, with explicit handling
for renamed pages (Caddy/Nginx-Webserver-Config, Wekan-Markdown, the Sandstorm
grain export page, Uberspace) and the REST-API-<X> family -> docs/API/<X>.md.
Ambiguous names resolved by preferring a same-directory file or the primary page.
Anchors and markdown titles preserved. 280 links across the docs tree.

Out of scope (left as-is): source-code references (models/*.js etc.) and
[Link](url) placeholders, which are not docs pages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 21:03:27 +03:00
Lauri OjansivuandClaude Opus 4.8 b912ddb6f5 docs: convert internal wiki/repo links from https URLs to relative paths
The GitHub wiki is disabled and its content was migrated into docs/, so every
https://github.com/wekan/wekan/wiki/... link now redirects to the repo home and
is broken. Rewrite all internal links in docs/ to relative paths:

- wiki/<Page> -> relative path to the corresponding docs/ file (renamed pages
  mapped explicitly: Caddy-Webserver-Config->Webserver/Caddy.md, Wekan-Markdown
  ->Features/Markdown/Markdown.md, REST-API-Role->API/Role.md, etc.)
- wiki home -> docs/README.md
- blob|tree|raw/main|master/<path> -> relative path (anchors and #Lxx line
  ranges preserved; bare URLs wrapped as [name](path) so they stay clickable)

Kept absolute (intentionally not flattened to the current ref):
- ref-pinned links (edge, devel, version tags, commit hashes)
- links whose target no longer exists in the tree

wiki/issues -> the GitHub issues tracker URL (external). 436 links across 113
files; verified no wiki links remain and no broken relative links introduced.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 20:43:36 +03:00
Lauri Ojansivu f6d8befb56 Moved website to separate repo. Moved docs2 back to docs.
Thanks to xet7 !
2026-04-28 11:59:16 +03:00
Lauri Ojansivu 1c0d8e9964 Moved docs to docs2, and wekan.fi to docs, to be able publish with GitHub Pages.
Thanks to xet7 !
2026-04-16 14:36:10 +03:00