split turns a receipt photo into an exact, participant-by-participant bill split. An authenticated organizer reviews the extraction, assigns individual and shared items, publishes private guest links, resolves disputes, and tracks simulated payments. No real payment rail or banking system is connected.
The repository includes two complementary experiences:
- A deterministic, public North Market walkthrough that works without external services.
- A live organizer workflow backed by Auth0, MongoDB Atlas, Gemini, and Backboard.
- Mobile camera capture and device upload for JPEG, PNG, WebP, HEIC, and HEIF receipts up to 10 MB.
- Gemini vision extraction into a strict server-validated receipt schema.
- Editable merchant, date, category, currency, receipt rows, signed discounts/fees/adjustments, tax, tip, and total.
- One-person, equal, custom-weight/quantity, and whole-group assignments.
- Server-authoritative integer-cent calculations with deterministic largest-remainder allocation and visible rounding traces.
- Auth0 organizer sessions and owner-scoped APIs.
- Opaque, hashed, expiring, revocable guest tokens exchanged for
HttpOnlyparticipant sessions. - Participant-scoped itemization, payment explanation, dispute submission, and simulated payment transitions.
- Transactional dispute reassignment, recalculation, payment-request supersession, and audit history.
- MongoDB collections for users, bills, participants, receipt items, assignments, payment requests/events, disputes, audit logs, and rate limits; receipt images use GridFS.
- Four Backboard advisory workflows: Receipt Review, Split Verification, Payment Explanation, and Dispute Resolution.
- Deterministic fallback behavior that is explicitly labeled and never invents values for an unknown receipt.
- Next.js 16, React 19, TypeScript, and Tailwind CSS 4
- MongoDB Atlas and the MongoDB Node driver
- Auth0 Next.js SDK
- Google Gen AI SDK using
gemini-3.5-flashby default - Backboard HTTPS API through a server-only adapter
- Vitest and Playwright
All secrets are read only by server modules. Do not prefix any secret with NEXT_PUBLIC_.
- Node.js
20.19+,22.13+, or24+(odd-numbered Node releases are intentionally excluded) - npm
- A MongoDB Atlas cluster and database user
- An Auth0 Regular Web Application
- Gemini and Backboard API keys for the live AI path
-
Install dependencies:
npm install
-
Copy the environment template and fill in the values locally. The repository ignores
.envfiles.cp .env.example .env
-
Configure MongoDB Atlas:
- Create a database user with read/write access to the
splitaidatabase. - Add the public IP of the network running split under Network Access. If Wi-Fi changes, Atlas may require the new IP.
- Use the Atlas SRV connection string as
MONGODB_URI. - Atlas must support transactions; a normal Atlas replica-set cluster does.
- Create a database user with read/write access to the
-
Configure Auth0:
- Application type: Regular Web Application.
- Allowed Callback URL:
http://localhost:3000/auth/callback - Allowed Logout URL:
http://localhost:3000 - Allowed Web Origin:
http://localhost:3000 - Set
APP_BASE_URL=http://localhost:3000andAUTH0_DOMAIN=<tenant>.auth0.com. - Generate
AUTH0_SECRETwithopenssl rand -hex 32.
AUTH0_BASE_URLandAUTH0_ISSUER_BASE_URLare accepted as legacy aliases for the currentAPP_BASE_URLandAUTH0_DOMAINnames. -
Start the app:
npm run dev
-
Open http://localhost:3000.
| Variable | Required for live flow | Purpose |
|---|---|---|
MONGODB_URI |
Yes | Atlas SRV connection string |
MONGODB_DB_NAME |
No | Database name; defaults to splitai |
AUTH0_SECRET |
Yes | Auth0 session encryption secret |
APP_BASE_URL |
Yes | Current SDK application URL |
AUTH0_DOMAIN |
Yes | Auth0 tenant domain, without a path |
AUTH0_CLIENT_ID |
Yes | Auth0 application client ID |
AUTH0_CLIENT_SECRET |
Yes | Auth0 application client secret |
AUTH0_BASE_URL |
Alias | Legacy alias for APP_BASE_URL |
AUTH0_ISSUER_BASE_URL |
Alias | Legacy issuer URL alias for AUTH0_DOMAIN |
GEMINI_API_KEY |
Yes | Server-side Gemini receipt extraction |
GEMINI_MODEL |
No | Defaults to gemini-3.5-flash |
BACKBOARD_API_KEY |
Yes | Server-side workflow advisories |
BACKBOARD_BASE_URL |
No | Defaults to https://app.backboard.io/api |
DEMO_MODE |
No | Allows the seed route in production only when explicitly true |
DEMO_FALLBACK_ENABLED |
No | Allows the exact known fixture fallback; defaults to true |
RECEIPT_MAX_BYTES |
No | Upload limit; defaults to 10 MiB |
GET /api/health reports only whether integrations are configured; it never returns secret values.
Choose Explore the demo on the landing page. The prepared North Market flow demonstrates:
- Nine editable grocery receipt items for Alex, Priya, Jordan, and Sam.
- Individual, shared, quantity-based, and everyone assignments.
- Exact CAD totals of $37.48, $16.68, $9.59, and $25.38, totaling $89.13.
- Participant-only payment pages with Interac e-Transfer-style instructions.
- A resolved salsa dispute, two simulated paid participants, one pending participant, and one unopened link.
This is clearly marked sample data and never writes payment activity or moves money.
- Sign in through Auth0 and choose New split.
- Upload a receipt or use the mobile camera input.
- Review Gemini fields, confidence, reconciliation, and the Receipt Review advisory.
- Correct any uncertain rows and add participants.
- Assign every item, then run the server calculation and Split Verification advisory.
- Publish the bill and save the one-time private guest URLs.
- Open a guest URL, review the participant-scoped calculation, and simulate pending/paid/failed status.
- Submit a dispute for an eligible whole item, approve a reassignment as organizer, and save the replacement links.
- Track link views, disputes, simulated payments, and outstanding totals on the live status screen.
In development, POST /api/demo/seed can create the complete persistent demo against the configured Atlas database. Its response contains temporary plaintext guest URLs, so treat the response as sensitive and do not paste it into logs or tickets. Reusing the seed rotates those URLs.
Install the Playwright browser once before the end-to-end suite:
npx playwright install chromiumnpm run lint
npm run typecheck
npm test
npm run build
npm run test:e2eThe unit suite covers, among other cases:
- residual-cent allocation across four participants;
- signed discounts and double-entry manual adjustments;
- forged client totals and reconciliation mismatches;
- missing, duplicate, or stale assignments;
- invalid payment-state transitions and dispute blocking;
- concurrent/stale dispute reassignment policy;
- client API error, upload, guest-session, and idempotency contracts;
- best-effort removal of ephemeral Backboard threads.
| Area | Location |
|---|---|
| App Router pages and API routes | src/app |
| Live and deterministic UI screens | src/components |
| Exact allocation and payment state machines | src/domain |
| Server orchestration services | src/services |
| MongoDB repositories and document contracts | src/repositories |
| Gemini, image, fallback, and Backboard adapters | src/adapters |
| Auth0, MongoDB, request, transaction, and error utilities | src/lib/server |
| Typed browser client | src/lib/client |
| API/domain validation | src/schemas |
| Canonical demo fixture | public/demo and src/data/demo |
The server is the source of truth. Clients submit revisions, assignments, and requested transitions, not final totals. Financial mutations use optimistic revision checks, MongoDB transactions where multiple records change, and append-only audit entries.
- Payments are simulation-only. split never requests passwords, card numbers, account numbers, or banking credentials.
- Guest tokens use 32 random bytes; only token hashes are stored. Exchange produces a scoped
HttpOnly,Securein production, same-site session cookie. - Guest responses are allow-listed to one participant's merchant/date, assigned rows, calculation, instructions, disputes, and status.
- Guest mutations are same-origin checked, rate-limited, lifecycle validated, and idempotent.
- Receipt bytes are type-sniffed, pixel-limited, normalized server-side, stored privately, and served only to the bill owner.
- Backboard receives minimized workflow context with sensitive keys removed. Provider-created ephemeral threads are deleted best-effort after each advisory.
- Security headers deny framing, MIME sniffing, and unrelated browser permissions.
- There is no real Interac, bank, card, email, or SMS integration. Organizers copy and distribute guest links themselves.
- Automated financial dispute acceptance is intentionally limited to one standard item assigned wholly to the disputing participant. Shared-item or overall-total questions require the organizer to correct the underlying receipt/assignments separately.
- Plaintext guest URLs are shown only on publish, dispute-recalculation, or explicit rotation responses; the database stores hashes only.
- The exact known demo receipt can use a deterministic extraction fallback. An unfamiliar failed extraction opens a blank manual-review path rather than invented receipt data.
- Backboard suggestions are advisory and may fall back to explicitly labeled deterministic local guidance. They never change totals or authorize a payment.
- The current build does not deliver notifications or automatically close a fully settled bill.
- MongoDB Atlas: persistent application state, transactions, indexes, rate limits, and private GridFS receipt storage.
- Auth0: organizer identity and encrypted server sessions.
- Gemini: vision receipt extraction with JSON-schema-constrained output and server-side semantic validation.
- Backboard: four limited, advisory workflow agents with deterministic fallbacks.
- Interac-style demo: familiar Canadian transfer instructions with no real payment connection.
- Receipt references: local
data/groceriesimages plus schema/OCR variation research from Goodspot EU/NA Receipts and docjay131 Receipts OCR. The full datasets are not bundled or downloaded.
For production deployment, use production callback URLs, a narrowly scoped Atlas access list, managed secrets, HTTPS, monitoring, backups, and a deliberate retention/deletion policy for receipts and audit data.