SlowBooks Pro
Free accounting software for Windows, Mac, and Linux. Payroll, inventory, unlimited invoicing, multi-user Server Edition built into the signed installer (no Docker required). No cloud, no subscription
Free, mobile-first bill splitting for students, with UPI settle-up.
FinanceTypeScript · PLpgSQLGitHub @ShubhamMeghaniOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗Split bills. Settle up. Call it quits.
Quits is a free, mobile-first bill-splitting web app for Indian students, built as the course project for Applied Data Science & AI at IISc. It was built with spec-driven development: SPEC.md states what to build, and PLAN.md records how it was built and the evidence for every acceptance criterion.
gemini-3.5-flash-lite).| Part | Choice |
|---|---|
| App | Next.js 16 (App Router, TypeScript), Tailwind CSS 4 with design tokens for both themes, Inter self-hosted via next/font, on Vercel |
| Data | Supabase Postgres. RLS is on for every table with no policies. The database is used only from server code with the secret key, so the browser never talks to Supabase. |
| AI | Gemini structured JSON output (receipts and type-to-add), called only from the server. Receipt images are never stored. |
| Exchange rates | Frankfurter v2 (/v2/rate/{BASE}/{QUOTE}?date=), cached in fx_rates |
| Core logic | Pure, unit-tested modules in lib/: money, splits, simplify, receipt, nlparse, currency, upi, share, csv, recurring, demo-seed, recent-groups, stats, theme, avatar, category-style |
| Writes | Each multi-table write is one Postgres function, so it is atomic. The functions re-check that every id belongs to the group and that payers = splits = total. |
npm install
cp .env.example .env.local # then fill in the values (never commit .env.local)
npm run db:push # applies supabase/migrations to your database
npm run dev # http://localhost:3000
Environment variables (names only):
| Name | Where | Notes |
|---|---|---|
SUPABASE_URL | .env.local, Vercel | |
SUPABASE_SECRET_KEY | .env.local, Vercel | secret |
GEMINI_API_KEY | .env.local, Vercel | secret |
GEMINI_MODEL | .env.local, Vercel | gemini-3.5-flash-lite |
SUPABASE_DB_URL | .env.local only | Session pooler connection string (IPv4), for migrations and DB tests |
SCAN_LIMIT_PER_GROUP, SCAN_LIMIT_PER_APP | optional | daily receipt scans per group (default 30) and AI calls for the whole app (default 300) |
NL_LIMIT_PER_GROUP | optional | daily type-to-add calls per group (default 50) |
APP_URL | GitHub repository variable | used by the daily keep-alive workflow |
Deploy: push to main, and Vercel builds and deploys it. GitHub Actions does two things:
ci.yml runs lint, typecheck and unit tests on every push;keepalive.yml calls /api/health daily so the free Supabase project doesn't pause.npm run lint && npm run typecheck
npm test # unit tests (Vitest): 162 tests
npm run test:db # DB integration tests (24); needs SUPABASE_DB_URL, skipped otherwise
npm run test:db:clean # removes leftover "__test__" groups
npm run build
npm run eval # receipt eval on eval/receipts (see eval/README.md)
npm run eval:nl # type-to-add eval on eval/nl (see eval/nl/README.md)
Both evals call Gemini. Every run is kept, never overwritten, and each run's report says what changed since the previous one and which results are not blind. The results are on the About page.
Receipt eval (eval/REPORT.md): n = 5, small sample (one receipt moves a per-receipt rate by 20 points). Five real receipts with ground truth checked by hand against the paper bills. The main result is run 3:
| Overall | When answered | |
|---|---|---|
| Answer rate (read within 25 s) | 80% (4 of 5) | — |
| Item F1 | 45.2% | 100% |
| Total accuracy | 80% | 100% |
| Reconciliation (items + tax + charges = total ± ₹1) | 80% | 100% |
Run 3 is not blind for r01 and r04: run 2 revealed two prompt gaps there, which were fixed. The low overall F1 comes from one receipt that timed out (all 34 of its items count as missed), not from misreads.
Type-to-add eval (eval/nl/REPORT.md): n = 30, small sample. Twenty sentences were written by Claude and ten by the human, all reviewed by the human; seven are deliberately ambiguous. The main result is run 3:
| Overall | When answered | |
|---|---|---|
| Answer rate (within 20 s) | 80% (24 of 30) | — |
| Amount | 76.7% | 95.8% |
| Exact match | 76.7% | 95.8% |
The 6 unanswered sentences were Gemini "high demand" errors (HTTP 503) or timeouts, not wrong answers.
The eval/synthetic/ run only smoke-tests the script.
Tested on a Samsung phone against the deployed app, 2026-10-16:
| Path | GPay | PhonePe | Paytm |
|---|---|---|---|
upi://pay link from a website ("Pay via UPI app") | blocked: misleading "exceeded bank limit" error at ₹1 | blocked | blocked |
| QR shown on a laptop, scanned by the phone | works: payee and ₹1.00 filled in | — | — |
| QR screenshot scanned from the gallery | works | — | — |
As a result, settle-up is QR-first (SPEC v0.5, D-18). The link is kept only as a best-effort option, labelled "May be blocked by some UPI apps". The 2026-10-19 production check confirmed the QR also scans in the dark theme: on screen, full screen and from the saved image.
58 of 60 acceptance criteria pass, all with evidence in PLAN.md → "AC status": unit and DB tests, headless-browser checks, and live checks on production and on an Android phone. The two failures are Should-level accuracy targets:
| AC | Target | Result (n is small) | Why |
|---|---|---|---|
| AC-25 (Should) | receipt item F1 ≥ 0.80 and reconciliation ≥ 0.70 | F1 0.452, reconciliation 0.80 (run 3, n = 5) | One receipt timed out at 25 s, so all 34 of its items count as missed. When answered: F1 1.00, reconciliation 1.00. |
| AC-52 (Should) | type-to-add amount ≥ 95% and exact match ≥ 80% | 76.7% and 76.7% (run 3, n = 30) | Six sentences got no answer (Gemini 503 or timeouts). When answered: amount and exact match 95.8%. |
Both are reported as measured. Fixes driven by the evals are labelled in the reports, and the next run is marked not blind:
Nothing was tuned just to raise a score.
| File | What it is |
|---|---|
| SPEC.md | The specification, v1.7: goals and users, constraints, data model and interfaces, 73 requirements in EARS form (49 Must, 24 Should), 60 pass/fail acceptance criteria, deliverables, non-goals, risks, decisions D-1 to D-41, and a changelog from v0.1 to v1.7. When the code and the spec disagreed, the spec was changed first and logged. |
| PLAN.md | The build plan: phases 1–12 with tasks mapped to requirements and ACs (AUTO / HUMAN), the build log, SPEC change proposals, and the AC status table, with evidence for every criterion. |
| eval/README.md, eval/nl/README.md | How the two evaluations work, their ground-truth rules, and every kept run (REPORT*.md, results*.json). |
AGENTS.md, .claude/settings.json | Instructions and settings for the coding agent (Claude Code). |