GitHub - Sraman01-code/ledgerguard-backend: Finance data processing and access control backend with RBAC, JWT auth, financial records CRUD, dashboard analytics, Prisma, SQLite, and Swagger.

LedgerGuard is a backend engineering assignment for a finance data processing and access control system. The project is intentionally scoped for assessment quality: correct RBAC, clean module boundaries, predictable APIs, and a small stack that is easy to explain.

Tech Stack

  • TypeScript
  • NestJS
  • Prisma
  • SQLite
  • JWT authentication
  • Swagger
  • class-validator

Architecture Overview

The API is split into four business modules plus shared infrastructure:

  • AuthModule: seeded-user login and JWT issuance
  • UsersModule: admin-only user, role, and status management
  • FinancialRecordsModule: record CRUD and filtering
  • DashboardModule: summary, trends, and recent activity
  • Shared infrastructure: Prisma service, JWT/role guards, validation, and Prisma error mapping

This keeps responsibilities clear without overengineering the project.

Role Matrix

Capability Viewer Analyst Admin
Login Yes Yes Yes
Login if inactive No No No
Read dashboard summary/trends/activity Yes Yes Yes
Read financial records No Yes Yes
Create/update/delete financial records No No Yes
Manage users, roles, and active status No No Yes

Core Entities

User

  • id
  • email
  • passwordHash
  • fullName
  • role
  • isActive
  • createdAt
  • updatedAt

FinancialRecord

  • id
  • type (income or expense)
  • category
  • amount
  • description
  • transactionDate
  • createdById
  • createdAt
  • updatedAt

API Summary

Auth

  • POST /api/auth/login

Users

  • GET /api/users
  • GET /api/users/:id
  • POST /api/users
  • PATCH /api/users/:id
  • DELETE /api/users/:id

Financial Records

  • GET /api/financial-records
  • GET /api/financial-records/:id
  • POST /api/financial-records
  • PATCH /api/financial-records/:id
  • DELETE /api/financial-records/:id

Supported filters:

  • type
  • category
  • startDate
  • endDate

Dashboard

  • GET /api/dashboard/summary
  • GET /api/dashboard/monthly-trends
  • GET /api/dashboard/recent-activity

Dashboard query parameters:

  • startDate
  • endDate
  • limit on recent activity only

Sample Credentials

  • Admin: admin@ledgerguard.local / Admin123!
  • Analyst: analyst@ledgerguard.local / Analyst123!
  • Viewer: viewer@ledgerguard.local / Viewer123!
  • Inactive user: inactive.viewer@ledgerguard.local / Viewer123!

Setup

  1. Install dependencies.
  1. Create the environment file.
Copy-Item .env.example .env
  1. Generate the Prisma client.
  1. Run migrations and seed the database.
npm run prisma:migrate -- --name init

If migrations already exist and you only want fresh seed data:

  1. Start the API.
  1. Open Swagger.
http://localhost:3000/docs

Scripts

  • npm run start:dev: start the app in development
  • npm run build: compile TypeScript
  • npm test: run unit and integration tests
  • npm run prisma:generate: generate Prisma client
  • npm run prisma:migrate -- --name <name>: create and apply a migration
  • npm run prisma:seed: seed sample data

Sample API Usage

1. Login

curl -X POST http://localhost:3000/api/auth/login ^
  -H "Content-Type: application/json" ^
  -d "{\"email\":\"admin@ledgerguard.local\",\"password\":\"Admin123!\"}"

Response:

{
  "accessToken": "JWT_TOKEN",
  "user": {
    "id": 1,
    "email": "admin@ledgerguard.local",
    "fullName": "System Admin",
    "role": "admin",
    "isActive": true
  }
}

2. List financial records as analyst

curl "http://localhost:3000/api/financial-records?type=income&startDate=2026-01-01T00:00:00.000Z&endDate=2026-03-31T23:59:59.999Z" ^
  -H "Authorization: Bearer JWT_TOKEN"

3. Create a financial record as admin

curl -X POST http://localhost:3000/api/financial-records ^
  -H "Authorization: Bearer JWT_TOKEN" ^
  -H "Content-Type: application/json" ^
  -d "{\"type\":\"income\",\"category\":\"bonus\",\"amount\":250.50,\"description\":\"Quarterly bonus\",\"transactionDate\":\"2026-03-29T10:00:00.000Z\"}"

4. Get dashboard summary as viewer

curl "http://localhost:3000/api/dashboard/summary?startDate=2026-01-01T00:00:00.000Z&endDate=2026-03-31T23:59:59.999Z" ^
  -H "Authorization: Bearer JWT_TOKEN"

5. Deactivate a user as admin

curl -X PATCH http://localhost:3000/api/users/3 ^
  -H "Authorization: Bearer JWT_TOKEN" ^
  -H "Content-Type: application/json" ^
  -d "{\"isActive\":false}"

Additional Verification

As a final validation step, I also exercised the backend APIs using my own API testing tool, ReqFlow. I used it as an additional verification layer alongside the automated test suite to confirm the seeded login flows and role-based behavior manually.

API verification screenshots for the submission are available in:

Validation and Error Handling

  • Global DTO validation with whitelist and rejection of unknown fields
  • Standard Nest status codes for auth, access control, validation, and missing resources
  • Prisma exception filter for useful conflict and not-found responses
  • Inactive users are blocked both at login and on protected routes
  • Invalid date ranges are rejected with 400 Bad Request
  • Admin cannot delete, deactivate, or demote their own account

Assumptions and Tradeoffs

  • Seeded login is sufficient; there is no signup or refresh token flow
  • SQLite is used for simplicity and local setup speed
  • Amounts are stored as decimals and returned as strings to avoid float ambiguity
  • Pagination is intentionally omitted because it is not part of the assignment brief
  • Dashboard values are computed from records directly instead of maintaining derived tables

Short Project Walkthrough

  1. AuthModule issues JWTs for seeded users.
  2. UsersModule lets admin manage users, roles, and active status.
  3. FinancialRecordsModule provides CRUD plus filters by type, category, and date range.
  4. DashboardModule exposes read-only derived views for totals, trends, and recent activity.
  5. Shared guards enforce JWT auth and role checks across all protected routes.