Receipts docs
v1.1.0
Get help
● Start · About 45 minutes

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

Windows

The commands on this page are written for bash or zsh on macOS or Linux. On Windows, run them in WSL (Ubuntu) or Git Bash, not in PowerShell or cmd. The production server itself is Ubuntu.

corepack enable        # once; or: npm install -g pnpm
pnpm install
cp .env.example .env   # set PUBLIC_URL=http://localhost:8787
pnpm build             # compiles the TypeScript source to dist/
pnpm start             # runs dist/src/index.js with plain node

pnpm start runs the compiled JavaScript in dist/ with plain node. Run pnpm build again after you change or update the source. pnpm dev is for development: it runs the TypeScript source with tsx and 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

  1. 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
  2. A system userThe app should not run as root.
    sudo useradd --system --create-home --home-dir /opt/receipts --shell /usr/sbin/nologin receipts
  3. Upload and installCopy the unzipped release to /opt/receipts (scp or rsync), then:
    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
    sudo -u receipts npm run build        # or: sudo -u receipts pnpm build
    Install with development dependencies: the build needs TypeScript. The running app needs only the production dependencies, so after the build npm prune --omit=dev may remove the rest (run npm install again before the next build).
  4. Configure
    sudo -u receipts cp .env.example .env
    sudo -u receipts nano .env
    sudo chmod 600 .env
    Set PUBLIC_URL=https://signals.example.com, ADMIN_SETUP_TOKEN (openssl rand -hex 24), optionally ADMIN_EMAIL, ADMIN_SECRET_KEY (openssl rand -hex 32), keep PORT=8787 and DEMO_MODE=0 (all variables).
  5. Test once by hand
    sudo -u receipts npm start
    curl http://127.0.0.1:8787/healthz     # from a second SSH session: {"ok":true,...}
    Then stop it with Ctrl+C and continue with systemd and Caddy.

03First run: claim the site

  1. Have the setup secret readyOn a server, use the ADMIN_SETUP_TOKEN you put in .env (recommended; the log then says No operator yet. Use ADMIN_SETUP_TOKEN twice…). Without a token, the server prints a one-time setup code instead: read it with journalctl -u receipts, in the block after [admin] No owner account yet…. A new code is printed on every restart until both accounts exist.
  2. Sign upOpen your site and click Create account. The page says the site has no operator yet and asks for the setup code. Enter the token (or the code), a name, a password of at least 10 characters and, if you set ADMIN_EMAIL, that email. You are now the operator; the Admin console asks for the same secret to create its owner (next section).
  3. Nobody else firstUntil the operator exists, nobody can create an account without the setup secret. ADMIN_EMAIL alone is not enough.
  4. Remove the tokenOnce the operator and the console owner exist, delete ADMIN_SETUP_TOKEN from .env and restart.

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.

  1. Set the console keyADMIN_SECRET_KEY in .env: 32 random bytes that encrypt the keys you save in the console. Without it a key is generated into data/.admin-secret-key on first start, with a warning. Move it into .env and back it up with data/admin.sqlite: without it the stored secrets cannot be read.
  2. Create the console ownerOpen /admin, enter the same setup token (or printed code), your email and a password of at least 12 characters, then press Create owner and sign in. Without a token, a restart issues a new code.
  3. Walk through Get startedThe console's setup wizard refuses to finish over a blocker (Admin console).
admin-import.json

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).