For end users: see the User Guide and FAQ. Compliance docs: Privacy Policy, Account Deletion.
A receipt-first expense and tax app for self-employed drivers. Sibling app to Qbit (the weekly tax app), sharing its purpose but inverting the workflow: expenses are captured immediately at point of sale (photo + quick fields), and income is recorded separately, later, as a periodic invoice.
Evolution is intended to fully replace Qbit — same Play Console / App Store
listing (com.aplc.weeklytaxapp), same users. It shares Qbit’s production
database: the users table lives in public (shared — existing accounts
log in with their existing email/password, no re-registration), while every
table Evolution owns lives in its own evolution Postgres schema so it can
never collide with Qbit’s differently-shaped tables of the same name. See
backend/src/db.ts and backend/sql/schema.sql. Sessions do not carry
over automatically — Evolution uses its own JWT_SECRET, so an existing
Qbit user gets one fresh login on Evolution, not an instant carry-over
mid-session. An account with Qbit’s 2FA enabled is blocked from logging into
Evolution until 2FA support ships there too (routes/auth.routes.ts) —
this is a deliberate safety check, not a gap.
@react-navigationbackend — API, tax engine, rules engine, SQL schema/seedmobile — Expo app: Capture, Income, Summary, History, Export tabscd backendcp .env.example .env and fill in DATABASE_URL, JWT_SECRET, and the AWS_* S3 variablesnpm installpsql "$DATABASE_URL" -f sql/schema.sqlpsql "$DATABASE_URL" -f sql/seed_rules.sqlnpm run devnpm run check-env — verifies required env vars and DB connectivity before deployingnpm run smoke-test — exercises capture → void → summary end to end against a running backendcd mobilenpm installnpm startSet EXPO_PUBLIC_API_BASE_URL for device testing (use your machine’s LAN IP, not localhost, for a physical phone).
Deferred to a later milestone: 2FA, password reset, account deletion, admin rule-publishing UI, multi-receipt-per-expense, offline queueing, and the OCR auto-fill / one-tap-capture fast-follow (see the project’s saved plan for details).
Public:
POST /auth/register, POST /auth/loginProtected (Bearer token):
POST /expenses (multipart: receipt + fields), GET /expenses, GET /expenses/:id, POST /expenses/:id/voidGET /receipts/:receiptId/download?token=...POST /income-invoices (multipart, file optional), GET /income-invoices, GET /income-invoices/:id, POST /income-invoices/:id/void, GET /income-invoices/:id/download?token=...GET /tax-years/:taxYear/summary, GET /tax-years/:taxYear/rules-monitoring, GET /tax-years/:taxYear/export?format=json|csvnone / partial / full) rather than a bare numeric field — a fully reimbursed expense is not a deductible loss at all.receipts.expense_id), not to a week or period.backend/src/incomeAggregation.ts), not from a per-week record — a straddling invoice correctly contributes only its in-year days to each tax year it touches.