# Wellformed Version 1.0.0. Private software, owned outright by Bram Luiken — see [`LICENSE`](LICENSE). Running it requires a licence granted in writing; possession of these files is not one, and neither is anything you can set in a config file. A licence, once granted, is broad: use it however you like, commercially, modified, on as many machines as you run. The one boundary is that Wellformed itself is never what you sell or host for others. ## What it needs - Node 20.11 or newer - `build-essential` (or equivalent). `better-sqlite3` is a native module. npm usually finds a prebuilt binary, and when it does not it compiles — so install the toolchain **before** the first `npm ci`, not while debugging one. ## Install ```sh npm ci npm run build npm prune --omit=dev ``` Copy `.env.example` to `.env` and set at least: ``` NODE_ENV=production HOST=127.0.0.1 PORT=4000 WELLFORMED_SECRET= # node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" WELLFORMED_DATA_DIR=/opt/wellformed/data WELLFORMED_PUBLIC_URL=https://your.domain WELLFORMED_LICENSE= # the signed licence line, from your licence package WELLFORMED_SIGNUPS=closed ``` `WELLFORMED_SECRET` is mandatory in production; the server refuses to start without it. `WELLFORMED_LICENSE` holds the licence line issued with your licence — one signed line naming the party it was granted to, found in `license.env` in the package you were handed. It is what makes this installation unmetered; leave it empty and workspaces run into the hosted plan's limits. On start the server prints whose licence it is running under: ``` [wellformed] licensed to Acme B.V. · WF-2026-001 · since 3 March 2026 · perpetual ``` `WELLFORMED_SIGNUPS=closed` means accounts are made by invitation instead of by anyone who finds the address. ## First account ```sh node packages/server/dist/tenancy/provision-cli.js \ --email you@your.domain --workspace "Your workspace" --slug work ``` It prints a generated password once. Call the compiled file directly: `npm run provision` needs a dev dependency that `npm prune` has removed. ## Run Behind nginx or another reverse proxy, with the service bound to `127.0.0.1` and TLS terminated in front of it. `deploy/` holds a systemd unit to start from. ## Updating **Take a copy of the data directory first, every time.** Database migrations run forward only: putting the old code back does not put the old database back, so that copy is the only way back. ```sh cp -a /opt/wellformed/data /opt/wellformed/data.before-update git pull npm ci && npm run build && npm prune --omit=dev systemctl restart wellformed-server ``` The databases migrate themselves when the server next opens them. ## Languages Wellformed speaks English and Dutch. The language is a property of the workspace, like its currency: a workspace is full of names in one language, and everyone who opens it reads the same page — the same words, the same way of writing numbers and dates. Admins change it in workspace settings; a new workspace starts in the language of the browser that created it. Outside a workspace — the login page, the marketing page — the browser decides. Adding a language means adding a column to the message catalogue in `packages/web/src/i18n/messages/` and a value in `packages/shared/src/locale.ts` — the compiler then points at every message still missing. ## Your data One SQLite file per workspace, under `WELLFORMED_DATA_DIR`. Back that directory up somewhere that is not this machine. Any workspace can also be exported whole from inside the product, at any time, on any plan.