- TypeScript 87.8%
- PLpgSQL 11.3%
- JavaScript 0.9%
|
|
||
|---|---|---|
| .vscode | ||
| assets | ||
| scripts | ||
| src | ||
| supabase | ||
| .gitignore | ||
| AGENTS.md | ||
| app.json | ||
| CLAUDE.md | ||
| eslint.config.js | ||
| LICENSE | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
quickfin
A React Native / Expo app for German SMB accounting, backed by Supabase (Postgres + auth). Each user's data is row-level-security-scoped to their account. Scan a receipt, let cloud OCR read it out, and the deterministic booking engine maps each line to an account; bank transactions are reconciled against receipts.
Prerequisites
-
Node.js + npm
-
A dev build for native features (
npx expo run:ios/run:android) — the document scanner and Face ID don't run in Expo Go or web. -
A
.envfile (gitignored) with your Supabase project credentials:EXPO_PUBLIC_SUPABASE_URL=... EXPO_PUBLIC_SUPABASE_ANON_KEY=...src/lib/supabase.tsthrows on launch if either is missing.
Get started
npm install
npx expo start # dev server (Expo Go / dev client)
npx expo run:ios # build + run on iOS simulator/device
npx expo run:android # build + run on Android emulator/device
npx expo start --web # run in the browser
Cloud receipt extraction additionally needs the extract-receipt and assign-groups Supabase Edge Functions deployed (they call Claude server-side with your API key).
Scripts
npx expo lint # ESLint (eslint-config-expo)
npx tsc --noEmit # type-check
npm run test:booking # booking-engine spec tests (tsx harness)
Architecture
quickfin uses Expo Router file-based routing; all source lives under src/ (path alias @/ → src/).
- Auth & routing —
src/app/_layout.tsxgates on the Supabase session. New signups go through a 4-step onboarding wizard (onboarding.tsx); the five main tabs (home, transactions, receipts, cashier, account) live insrc/app/(tabs)/. - Data layer — the Zustand store (
src/store/useStore.ts) is a local cache that writes through to Supabase: mutations update local state optimistically, then persist viasrc/lib/db.ts(the only module that talks to PostgREST). Data slices are also cached to AsyncStorage so the app renders instantly on launch, then refreshes viahydrate(). - Receipt ↔ transaction linking — an n:m relationship kept in sync locally and in Postgres (
receipt_transaction_links). A receipt movesopen → reconciled → booked/error. - Receipt extraction & booking (
src/lib/booking/,src/lib/ocr/) — the document scanner captures the receipt, cloud OCR (Claude vision via a Supabase Edge Function) reads it out, and a deterministic engine harmonizes the read-out against printed totals and maps each line to a category → account. Same input ⇒ same booking; all money is integer cents. - Theme & i18n — design tokens in
src/theme/tokens.ts(never hard-code colors/spacing); UI locale togglesde/enviauseT(), but number/date formatting always stays German.
See CLAUDE.md for the full architecture guide (data flow, the booking pipeline, onboarding, biometric lock, and conventions).
Schema
Postgres schema lives in supabase/migrations/*.sql. supabase/apply_all.sql is a generated concatenation for applying everything to a fresh database in one shot (regenerate it — don't hand-edit).