Installation
local, then production.
A local install to try it, a production install on Ubuntu, and the first run: claiming the site and the Admin console.
01Local install Tested
corepack enable # once; or: npm install -g pnpm
pnpm install
cp .env.example .env # set PUBLIC_URL=http://localhost:8787
pnpm start
pnpm start runs the TypeScript source directly with tsx; there is no build step to run the app. pnpm dev does the same but restarts when files change. Stop with Ctrl+C. Always start from the project folder: the app reads .env, public/ and the default database path data/receipts.db relative to it.
02Production install on Ubuntu Not tested here
- Node.js 22 and tools
sudo apt update sudo apt install -y curl ca-certificates build-essential python3 sqlite3 curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt install -y nodejs node -v - A system userThe app should not run as root.
sudo useradd --system --create-home --home-dir /opt/receipts --shell /usr/sbin/nologin receipts - Upload and installCopy the unzipped release to
/opt/receipts(scp or rsync), then:
The start script uses tsx, listed under devDependencies, so do not install with production-only flags.sudo chown -R receipts:receipts /opt/receipts cd /opt/receipts sudo -u receipts npm install # or: sudo corepack enable && sudo -u receipts pnpm install --frozen-lockfile - Configure
Setsudo -u receipts cp .env.example .env sudo -u receipts nano .env sudo chmod 600 .envPUBLIC_URL=https://signals.example.com,ADMIN_EMAIL,ADMIN_SECRET_KEY(openssl rand -hex 32), keepPORT=8787andDEMO_MODE=0(all variables). - Test once by hand
Then stop it with Ctrl+C and continue with systemd and Caddy.sudo -u receipts npm start curl http://127.0.0.1:8787/healthz # from a second SSH session: {"ok":true,...}
03First run: claim the site
- Choose how you claim itPut your email in
ADMIN_EMAIL(recommended), or leave it empty and use the one-time setup code in the log (journalctl -u receipts): the line after[admin] No owner account yet…, followed byNo operator yet. Use the setup code printed above twice…. A new code is printed on every restart until it is used. - Sign upOpen your site and click Create account. The page says the site has no operator yet. Sign up with that email (or the code), a name and a password of at least 10 characters. You are now the operator and are sent on to the Admin console, where the same code creates the console owner (next section). Tested
- Nobody else firstUntil the operator exists, nobody else can create an account.
04First run: the Admin console
Settings, fees, revenue, status, team and the audit log live in the Admin console at /admin (the MIKODES Admin Kit). It has its own accounts.
- Set the console key
ADMIN_SECRET_KEYin.env: 32 random bytes that encrypt the keys you save in the console. Without it a key is generated intodata/.admin-secret-keyon first start, with a warning. Move it into.envand back it up withdata/admin.sqlite: without it the stored secrets cannot be read. - Create the console ownerOpen
/admin, enter the same setup code, your email and a password of at least 12 characters, then press Create owner and sign in. Tested A restart issues a new code. - Walk through Get startedThe console's setup wizard refuses to finish over a blocker (Admin console).
Only when you upgrade an install that saved settings before the console existed: the app writes those settings to data/admin-import.json and changes nothing until you import them (Admin → Export / Import, preview first). A fresh install writes no such file.
05Publishing yourself
To publish signals yourself, open Studio (sidebar: Become a provider), enter a provider name and confirm that published signals are permanent. Any member can become a provider this way (unless you turn on provider approval).