# Project pack: Spliit @ 73478ed

Facts about **Spliit** for an AI following the [BespokeAI handover guide](https://handoff.bespokeai.software/guide/v2.md). This pack is pinned to one version and never changes after publication.

> Spliit is a free, simple way to share expenses, like Splitwise without ads or limits. Make a group for a holiday, a shared flat or a family, add who paid for what, and Spliit works out the balances and the fewest payments to settle up. Nobody needs an account: you share the group's link. Use the free spliit.app site, or run your own copy.

## Version and source
- Repository: https://github.com/spliit-app/spliit
- Pinned commit: `73478ed2f67a59e83866948caeece6bf2ecb985e`. Use exactly this version.
- Fresh checkout: use the setup below in an empty folder. If you already have this exact source checked out, keep your branch and use the development command instead; do not clone again or reset local changes.
- Or download a zip: https://github.com/spliit-app/spliit/archive/73478ed2f67a59e83866948caeece6bf2ecb985e.zip
- Live demo: https://spliit.app. The official free instance run by the project, not a throwaway demo. Groups you create there are real and stay until deleted. Anyone with a group's link can see and change it.
- Licence: **MIT**. Free to use, change and share for any purpose, including commercially. Just keep the copyright notice and licence text with the code. You don't have to publish your changes.

## Running the pinned source
- Fresh pinned-source setup (skip clone and checkout in an existing worktree):

  ```sh
  git clone https://github.com/spliit-app/spliit bespoke-spliit
  cd bespoke-spliit
  git checkout --detach 73478ed2f67a59e83866948caeece6bf2ecb985e
  # Prepare development requirements and local configuration first.
  # Setup notes: http://localhost:3000; npm install also applies migrations
  cp .env.example .env && ./scripts/start-local-db.sh && npm install && npm run dev
  ```

The commands below are a starting point from the reviewed source. Prepare the listed tools, local configuration and companion services before starting the app. These instructions have not yet been validated in participant sessions.

### Separate trial of the current release
This tries an upstream release, which may differ from the pinned source above. It does not run your source changes. Use only sample data and a separate data directory or volume. Check the upstream documentation before running it.

  ```sh
  Copy the sample docker-compose.yml from the README (the Spliit image ghcr.io/spliit-app/spliit:latest plus PostgreSQL), change the database password in both places, then run: docker compose up -d # then open http://localhost:8080
  ```

- Needs: Docker, or for development Node.js + npm + PostgreSQL (scripts/start-local-db.sh starts one in Docker)
- Develop: `cp .env.example .env && ./scripts/start-local-db.sh && npm install && npm run dev   # http://localhost:3000; npm install also applies migrations`
- Test: `npm test`
- Check/lint: `npm run lint && npm run check-types && npm run check-formatting`
- Stack: typescript (Next.js 16, React 19, tRPC, Prisma, Tailwind CSS, shadcn/ui, next-intl). Difficulty for a non-developer with an AI: **easy**. One Next.js app in TypeScript with a small Prisma schema. Most changes are a page under src/app/groups/[groupId]/, a component, a tRPC router or a translation file. Database changes need a Prisma migration.

## Customisation points (settings → extend → code)
- **currency-and-language** [settings]: Your currency and the interface language. → `DEFAULT_CURRENCY_CODE; group currency on the group form; language switcher (38 languages in messages/)`
- **split-modes-and-recurring** [settings]: Split evenly, by shares, by percentage or by amount; repeat an expense daily, weekly or monthly. → `Expense form (src/app/groups/[groupId]/expenses/expense-form.tsx)`
- **opt-in-features** [settings]: Receipt photos, AI receipt scanning, AI category guessing, group deletion and privacy-friendly analytics. → `Environment variables read in src/lib/env.ts (see .env.example)`
- **export** [extend]: Take a group's expenses into a spreadsheet or another app. → `Export button; CSV and JSON routes in src/app/groups/[groupId]/expenses/export/`
- **group-pages** [code]: New tabs or changes to existing ones, such as a monthly summary for a shared flat. → `src/app/groups/[groupId]/ (expenses, balances, stats, activity, information, edit)`
- **logic-and-data** [code]: New fields, categories or rules for who owes what. Database changes need a Prisma migration. → `src/lib/balances.ts and src/lib/totals.ts (sums), src/trpc/routers/ (API), prisma/schema.prisma + prisma/migrations/`
- **look-and-text** [code]: Colours, wording and logo. → `src/app/globals.css, src/components/ui/ (shadcn/ui), messages/en-US.json`

## Must keep working
- Existing groups, expenses and balances. Back up the database first.
- Balance and settle-up maths in src/lib/balances.ts; run npm test after any change to it.
- Database changes need a new Prisma migration; never edit old ones in prisma/migrations/.
- Group links are the only key to a group. Never log or expose group IDs (see src/lib/analytics/).

## Staying updatable
Currency, split modes, recurring expenses, opt-in features and export cover most needs without a fork. Spliit is small and open to pull requests, so general improvements are worth offering upstream.

## Data, costs and safety
- Personal data: **yes**. Stored in: PostgreSQL database (the database volume in docker compose); receipt photos in S3 if enabled. Groups hold names and spending. Back up the database before upgrades or code changes. Each group can also be exported as CSV or JSON.
- Service: PostgreSQL (required, free (self-hosted)): Stores groups, participants and expenses.
- Service: S3-compatible storage (AWS S3, MinIO and others) (optional, pay-per-use, or free if self-hosted): Attach photos of receipts to expenses.
- Service: OpenAI or another OpenAI-compatible AI provider (optional, pay-per-use (or free with a local model)): Create an expense by scanning a receipt; guess the category from the title.
- Setting `POSTGRES_PRISMA_URL` (**secret**: the person enters it themselves, never in chat): Database connection address, including its password. Never paste it into an AI chat.
- Setting `POSTGRES_URL_NON_POOLING` (**secret**: the person enters it themselves, never in chat): Usually the same database address as above.
- Setting `BASE_URL`: The public address of your instance (default http://localhost:3000).
- Setting `DEFAULT_CURRENCY_CODE`: Currency pre-selected for new groups (default USD), e.g. GBP.
- Setting `ENABLE_EXPENSE_DOCUMENTS`: Set to true to attach receipt photos. Needs the S3_UPLOAD_* settings.
- Setting `ENABLE_RECEIPT_EXTRACT`: Set to true to scan receipts with AI. Needs expense documents and OPENAI_API_KEY.
- Setting `OPENAI_API_KEY` (**secret**: the person enters it themselves, never in chat): Only for the AI features. Never paste it into an AI chat.
- Setting `ENABLE_GROUP_DELETION`: Let people delete groups. Needs CRON_SECRET and a daily scheduled call (see README).
- Anyone with a group's link can see and change it. Only share links with people in the group.
- On your own instance, use a strong database password and HTTPS.
- AI receipt scanning sends receipt photos to the chosen AI provider. Point OPENAI_BASE_URL at a local model to keep them private.

---

# Customising Spliit

Spliit is a small Next.js app, so it is one of the **easiest projects to change in code**. Still, try levels 1 and 2 first.

## Level 1: Settings (no code)
- **Currency:** each group has its own currency; `DEFAULT_CURRENCY_CODE` sets the one pre-selected for new groups (e.g. `GBP`). Expenses can be entered in another currency and converted.
- **How costs are split:** evenly, by shares, by percentage or by amount, per expense.
- **Repeating expenses:** daily, weekly or monthly, for rent and bills.
- **Categories:** pick one per expense; the Stats tab shows spending by category and month.
- **Language and theme:** language switcher (38 languages) and light/dark toggle.
- **Opt-in features** (environment variables, see `.env.example` and the README): `ENABLE_EXPENSE_DOCUMENTS` (receipt photos, needs S3), `ENABLE_RECEIPT_EXTRACT` and `ENABLE_CATEGORY_EXTRACT` (AI, needs `OPENAI_API_KEY`; `OPENAI_BASE_URL` for a local model), `ENABLE_GROUP_DELETION` (needs `CRON_SECRET`), `ANALYTICS_PROVIDER`.

## Level 2: Extend (no fork)
- **Export** a group's expenses as CSV or JSON from the group page (routes in `src/app/groups/[groupId]/expenses/export/`), for spreadsheets or other apps.
- **Install as a phone app:** Spliit is a PWA. "Add to Home Screen" from the browser.
- **Analytics providers:** add your own in `src/lib/analytics/providers/` (the README explains the three files to register it in).

## Level 3: Code
| Change | Where |
|---|---|
| Group tabs and pages | `src/app/groups/[groupId]/` (`expenses/`, `balances/`, `stats/`, `activity/`, `information/`, `edit/`) |
| Expense form | `src/app/groups/[groupId]/expenses/expense-form.tsx` |
| Who owes whom | `src/lib/balances.ts`, totals in `src/lib/totals.ts` (both have tests) |
| API | tRPC routers in `src/trpc/routers/` |
| New data | `prisma/schema.prisma` + a new migration in `prisma/migrations/` |
| Look | `src/app/globals.css`, shadcn/ui parts in `src/components/ui/` |
| Text | `messages/en-US.json` (other languages come from Weblate) |

## Running locally
- **Just use it:** the free instance at https://spliit.app.
- **Your own copy:** save the sample `docker-compose.yml` from the README, change the database password, run `docker compose up -d`, then open http://localhost:8080.
- **Develop:**
  1. Install Node.js and Docker.
  2. Start a database with `./scripts/start-local-db.sh`.
  3. `cp .env.example .env`
  4. `npm install` (also applies migrations).
  5. `npm run dev` and open http://localhost:3000.
- **Check:** `npm test`, `npm run lint`, `npm run check-types`, `npm run check-formatting`. End-to-end tests: `npm run e2e` (needs Docker).

## Pitfalls
- Back up the database before changing code. Balances are built from every expense ever entered.
- Change the balance maths only with tests (`src/lib/balances.test.ts`).
- Groups have no passwords: the link is the key. Don't log group IDs or add pages that list all groups.
- Old `NEXT_PUBLIC_*` variables are baked in at build time; use the runtime names in the README instead.

---
Machine-readable: [bespoke.yaml](https://handoff.bespokeai.software/p/spliit/73478ed/r2/bespoke.yaml) · Hosting options: [hosting.md](https://handoff.bespokeai.software/p/spliit/73478ed/r2/hosting.md) · Agent skill: [SKILL.md](https://handoff.bespokeai.software/p/spliit/73478ed/r2/SKILL.md)
