# Project pack: Spliit @ 73478ed

Facts about **Spliit** for an AI following the [BespokeAI handover guide](https://handoff.bespokeai.software/guide/v1.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.
- Get it: `git clone https://github.com/spliit-app/spliit spliit && cd spliit && git checkout 73478ed2f67a59e83866948caeece6bf2ecb985e`
- 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 it
- Easiest: 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/bespoke.yaml) · Agent skill: [SKILL.md](https://handoff.bespokeai.software/p/spliit/73478ed/SKILL.md)
