Receipts docs
v1.0.0
Live demo 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 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

  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
    The start script uses tsx, listed under devDependencies, so do not install with production-only flags.
  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_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. 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 by No operator yet. Use the setup code printed above twice…. A new code is printed on every restart until it is used.
  2. 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
  3. 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.

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