Enterprise · 2026 · Full-stack developer
LendLite
Mini digital lending platform: customers apply for a personal loan, upload documents and track the decision; admins review, approve or decline, and approval generates the repayment schedule. Built to fintech standards: integer-cent money, an audited status machine, atomic approvals, idempotent submits and private document storage.

01
Context
- Role
- Full-stack developer
- Year
- 2026
- Category
- Enterprise
02
The problem
Lending software fails in the details: floating-point money that drifts by a cent, two reviewers approving the same loan, a mobile retry that submits an application twice, or identity documents left on a public URL. A demo-grade CRUD app ignores all of these.
03
The approach
A layered Express API (routes, thin controllers, services, Prisma) with Zod on every input. Money is integer cents, the loan lifecycle is a status machine with an audit trail, approvals and their repayment schedules commit in one transaction, submits are idempotent, and documents are stored privately and streamed through the API after an ownership check. A Next.js front end adds a live repayment calculator, a four-step application wizard, CSV schedule export and an admin dashboard. 89 tests run against a real Postgres, and CI gates every Railway deploy.
Architecture
- FrontendNext.js 16React 19Tailwind CSS 4URL-driven wizard and filters
- APIExpressZodJWT + bcrypthelmetrate limiting
- DomainStatus machineAmortization engineAudit logIdempotency
- DataPostgreSQLPrismaraw SQL stats
- FilesMulterCloudinary (private)magic-byte checks
- DeliveryJest + SupertestDockerGitHub ActionsRailway
Highlights
- Money stored as integer cents and rates as basis points (12.50% is 1250), so no amount is ever off by a floating-point fraction.
- Loan status machine (draft, submitted, under review, approved or rejected) enforced in the service layer; invalid moves return 409 and every transition writes an audit row.
- Approval is one database transaction: status, every repayment row and the audit entry commit together, and a conditional update means two admins deciding at once cannot both win.
- Idempotent submit with an Idempotency-Key header: a retried request returns the original result, and reusing a key on another application is rejected.
- Pure amortization engine where the last instalment absorbs rounding, so the final balance is exactly $0.00.
- Private documents on Cloudinary behind the API: ownership checked, 60-second signed links, and uploads verified by MIME type, extension and magic bytes.
- 404 instead of 403 for other users' applications, so IDs cannot be probed; admin stats use a parameterized raw-SQL GROUP BY.
- 89 Jest + Supertest tests against a real Postgres; CI runs typecheck, tests, build, npm audit and a fresh-clone Docker Compose smoke test, and Railway deploys only after CI passes.
04
Results
- Backend tests on a real database
- 89
- Final balance after rounding
- $0.00
- CI jobs gating each deploy
- 3
- Loan statuses, all audited
- 5
05
Tech stack
- Next.js 16
- React 19
- TypeScript
- Tailwind CSS 4
- Node.js
- Express
- PostgreSQL
- Prisma
- Zod
- JWT
- bcrypt
- Multer
- Cloudinary
- pino
- Jest
- Supertest
- Docker
- GitHub Actions
- Railway
Select a technology to see every project that uses it.
06
Screenshots

Landing page with the live repayment calculator 
Approved loan: rate, monthly payment and the full repayment schedule, with the application timeline (demo data) 
Admin review: affordability snapshot, decision and repayment schedule (demo data) 
Admin review queue with pipeline stats and filters (demo data) 
Customer dashboard with application status (demo data) 
Four-step loan application wizard