splitwise / README.md
assafvayner's picture
assafvayner HF Staff
fix(deploy): trust x-forwarded-for for per-IP rate limiting
d0c44b2
|
Raw History Blame Contribute Delete
2.43 kB
metadata
title: Splitwise
emoji: 💸
colorFrom: green
colorTo: blue
sdk: docker
app_port: 7860
pinned: false

Splitwise-style expense splitter

Shared expenses for a small group of friends: equal / percent / exact splits, receipt photos, balances with simplified debts, settlements, and an admin who manages users.

Data lives in a private Hugging Face Storage Bucket as an append-only event log (events/*.json → hourly compaction into ledger.jsonl) plus users.json. There is no database. See docs/superpowers/specs/2026-08-29-splitwise-clone-design.md.

Space configuration

Set these in the Space Settings → Variables and secrets:

Name Kind Value
HF_TOKEN secret fine-grained token with write access to the bucket below
HF_BUCKET variable buckets/assafvayner/splitwise-data
HF_PREFIX variable directory inside the bucket for this deployment, e.g. prod (integration tests use test/<id>/); empty = bucket root
SESSION_SECRET secret openssl rand -base64 32 — must be at least 32 characters
ORIGIN variable the public URL of the Space, e.g. https://assafvayner-splitwise.hf.space (required for form submissions)
CURRENCY variable 3-letter uppercase ISO 4217 code, default USD
COMPACTION_INTERVAL_MS variable default 3600000 (1 hour)

BODY_SIZE_LIMIT=8M, STORAGE=hf, PORT, HOST and NODE_ENV are baked into the Dockerfile; there is no need to set them in the Space. ADDRESS_HEADER=x-forwarded-for and XFF_DEPTH=1 are baked in too, so the per-IP login rate limiter sees the real client address through the Spaces proxy rather than the proxy's own.

First boot creates the admin user with password 1234; the first admin login forces a password change. Then create your friends' accounts on /admin.

Local development

cp .env.example .env      # STORAGE=local writes to .data/
npm install
npm run dev

npm test runs the unit tests only — it never touches the bucket. npm run test:e2e runs the Playwright smoke test against a production build. npm run test:integration (a separate vitest.integration.config.ts) runs the real-bucket tests under a throwaway test/<id>/ prefix (needs HF_TOKEN/HF_BUCKET in .env; skipped otherwise).

Deploy

git remote add space https://huggingface.co/spaces/assafvayner/splitwise
git push space main