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
---
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
```bash
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
```bash
git remote add space https://huggingface.co/spaces/assafvayner/splitwise
git push space main
```