Skip to content
All projects

Case study

Village Finance

Multi-tenant lending and collections platform for village finance lines

Role
Full Stack Developer
Status
In testing · backend live on Google Cloud
Year
2026
Category
Web platform
Private product in internal testing ahead of its Play Store release. Source code is private.

01

Overview

Village Finance runs the daily and weekly collections of small lending businesses. An owner sets up collection lines, slots and villages, issues loans to customers and closes the books every week. Field collectors work their assigned slots from a phone. A platform console onboards each client business as an isolated tenant. The backend is live on Google Cloud Run; the Android app is at version 1.2.10 in internal testing.

3
applications: mobile, API, console
20+
tenant-scoped tables
460+
automated frontend tests

02

Problem

Village finance lines involve many customers, collectors and villages, with money moving every day. Owners need books that close cleanly every week and can be corrected when they do not. Collectors need a phone-first tool that stays fast on a weak mobile connection and cannot be shared between phones. And because one platform serves many businesses, a mistake in isolation would expose one client's customers to another.

03

Product

  • Collection lines with recurring slots and cities, plus a 30-day trash with restore and scheduled purge
  • Customers with photos, location and guarantor details; loans with installment schedules, payments, voids and carry-forward
  • Weekly close and reopen with an older-history boundary, per-slot breakdowns and a printable A4 ledger PDF
  • Capital investments and withdrawals, partner contributions, expenses, chit-fund schedules, quick-loan presets and leave logs
  • Team management with one-phone-per-collector device binding, device reset and a member home with today's summary and dues
  • Passwordless setup: accounts receive an emailed one-time code with rate limits, and passwords are only ever set through it
  • Platform console to onboard, rename, suspend, restore and soft-delete tenants and manage their admin logins

04

My role

  • Sole developer across the Expo mobile app, the Spring Boot API, the React console, the data model and the cloud deployment
  • Designed the multi-tenant security model and the admin, member and platform role boundaries
  • Built the collections, loan, weekly-close and capital domains and the ledger PDF export
  • Set up Docker packaging, Cloud Run deployment with Secret Manager, Neon PostgreSQL and Cloudflare R2 storage

05

Architecture

  1. Clients

    • Expo mobile app

      React Native with Expo Router, React Query and Zustand. Admin and collector route groups, FlashList and Reanimated collections grid.

    • Platform console

      React and Vite, no extra dependencies. Passwordless sign-in for platform operators.

  2. API

    • Spring Boot 3 REST API

      Java 17. Stateless JWT with BCrypt, admin and member roles per endpoint, separate platform token type.

    • Domain services

      Lines, slots, customers, loans, installments, weekly close, capital, partners, chitty, leaves, quick loans.

  3. Data & storage

    • Neon PostgreSQL

      Serverless Postgres via JPA and Hibernate. Connection pool sized for Neon auto-suspend.

    • Cloudflare R2

      Private bucket for customer photos. Presigned upload and download URLs; bytes never pass through the API.

  4. Services

    • Email (Resend)

      One-time codes and password-changed notices through a pluggable mail sender.

    • Scheduled jobs

      Trash purge after the 30-day retention window.

  5. Delivery

    • Docker + Cloud Run

      Two-stage image, non-root runtime, secrets from Google Secret Manager, revision-based rollback.

    • EAS builds

      Internal APK previews and production AAB for the Play internal track.

06

Technical implementation

  • Every tenant-scoped query filters on the tenant id carried in the signed JWT; the request body and parameters can never name a tenant
  • Device binding service with distinct wire codes for a refused device versus a released one, so the app shows the right recovery panel
  • Device and OTP audit events written in their own transaction so a refused sign-in still leaves an audit row
  • Installments for a screen loaded in a single query instead of one per loan; large ledger responses gzip-compressed
  • Ledger PDF built as A4 landscape HTML with pure, unit-tested pagination and native rendering isolated in a hook
  • Production safety check that refuses to boot outside development with the committed JWT secret or without a real mail sender
  • Frontend layered one way, app to features to services to storage, with a single HTTP client translating server errors into typed app errors

07

Key engineering challenges & solutions

  1. 01

    Keeping clients isolated on one database

    Challenge
    Many businesses share one schema, so any endpoint that trusted a tenant id from the request could leak another client's customers.
    Solution
    Tenant identity comes only from the signed token and is applied in every tenant-scoped query. Creating a tenant requires a separate platform token type that no regular account can hold.
  2. 02

    Collectors sharing phones

    Challenge
    A collector's login on a second phone breaks accountability for cash collected in the field.
    Solution
    Bound each account to one device with an admin-side reset and a break-glass switch, and recorded every bind, refusal and reset in an audit trail that survives the failed sign-in's rollback.
  3. 03

    Photos over a village mobile connection

    Challenge
    A pull-to-refresh on a slot with hundreds of customers re-downloaded every photo through the API.
    Solution
    Moved photos to a private R2 bucket with presigned URLs and cached signed URLs so unchanged photos stay cached on the device.
  4. 04

    A serverless database behind a serverless API

    Challenge
    Neon suspends idle databases and Cloud Run cold-starts, so naive connection settings produced timeouts on the first request.
    Solution
    Capped the connection pool, set a 30-second connection timeout, and trimmed the container image and SDK clients to cut cold-start time.
  5. 05

    Weekly books that can be corrected

    Challenge
    Closing a week is irreversible on paper, but real collections get corrected after the fact.
    Solution
    Weekly close stores opening balance, given, collected, expenses and capital per slot, and the latest week can be reopened, with an older-history boundary protecting settled books.

08

Quality & evaluation

  • 460+ frontend tests that drive screens through real repositories over in-memory storage, so a tap is verified from hook to persisted state
  • Type checking and the test suite run on every push through Git hooks
  • Idempotent schema maintenance at startup for changes Hibernate cannot apply, mirrored as a reviewed SQL migration
  • Reversible destructive actions throughout: trash and restore for lines, reopen for weeks, suspend and restore for tenants

09

Technology stack

  • React Native (Expo)
  • TypeScript
  • Expo Router
  • React Query
  • Zustand
  • Java 17
  • Spring Boot 3
  • Spring Security (JWT)
  • PostgreSQL (Neon)
  • Hibernate / JPA
  • Cloudflare R2
  • Docker
  • Google Cloud Run
  • React + Vite
  • Jest

10

Outcome

The API is live on Google Cloud Run with Neon PostgreSQL and Cloudflare R2, and the Android app is in internal testing at version 1.2.10 ahead of its Play Store release.