{"info":{"_postman_id":"364b6eba-18b8-4cf0-9fd3-32200aa1986c","name":"Finance Backend API","description":"<html><head></head><body><h1 id=\"finance-data-processing-access-control-api\">Finance Data Processing &amp; Access Control API</h1>\n<p>This is the backend API for a finance management system where a team of users with different roles interact with shared financial data.</p>\n<p>The system is built around the idea that not everyone in an organization should have the same level of access. An <strong>Admin</strong> manages the system — creating users, adding financial records, and overseeing everything. An <strong>Analyst</strong> can explore and analyze the financial data but cannot modify it. A <strong>Viewer</strong> gets a high-level summary of the finances without access to the raw records.</p>\n<h2 id=\"key-highlights\">Key Highlights</h2>\n<ul>\n<li><p>JWT based stateless authentication with role enforcement at middleware level</p>\n</li>\n<li><p>Soft delete preserves financial history and audit integrity</p>\n</li>\n<li><p>Dashboard analytics computed via SQL aggregations — not in memory</p>\n</li>\n<li><p>Every critical action is logged with old and new values for full traceability</p>\n</li>\n<li><p>Consistent error handling and input validation across all endpoints</p>\n</li>\n<li><p>Clean layered architecture — Routes, Controllers, Services, Repositories</p>\n</li>\n</ul>\n</body></html>","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","toc":[{"content":"Finance Data Processing & Access Control API","slug":"finance-data-processing-access-control-api"}],"owner":"52380998","collectionId":"364b6eba-18b8-4cf0-9fd3-32200aa1986c","publishedId":"2sBXiqFUh5","public":true,"customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"},"publishDate":"2026-04-06T12:31:34.000Z"},"item":[{"name":"Auth","item":[{"name":"Login","id":"c7f70f0b-e7d5-43d4-8d70-26ae0db2b8be","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n    \"email\" : \"admin@example.com\",\r\n    \"password\" : \"Admin@123\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:4000/api/v1/auth/login","description":"<h2 id=\"login\">Login</h2>\n<p>Authenticates a user with their email and password. Returns a signed JWT token and user profile on success.</p>\n<h3 id=\"access\">Access</h3>\n<p>Public — no authentication required</p>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>200</code> Login successful — returns token and user profile</p>\n</li>\n<li><p><code>400</code> Validation failed — email or password missing or invalid format</p>\n</li>\n<li><p><code>401</code> Invalid email or password</p>\n</li>\n<li><p><code>403</code> Your account is inactive. Please contact admin</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","auth","login"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"10308b3f-defe-425f-a239-b4ddb4389eb9","name":"Response","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n    \"email\" : \"admin@example.com\",\r\n    \"password\" : \"Admin@123\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:4000/api/v1/auth/login"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"360"},{"key":"ETag","value":"W/\"168-yr/ozhetkhd8sDf640aOsnud/Xc\""},{"key":"Date","value":"Mon, 06 Apr 2026 10:48:57 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 200,\n    \"message\": \"Login successful\",\n    \"data\": {\n        \"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFETUlOIiwic3RhdHVzIjoiQUNUSVZFIiwiaWF0IjoxNzc1NDcyNTM3LCJleHAiOjE3NzU1NTg5Mzd9.tw4ARtX9OqQuSx59KqJ2OlTuLlgrLCNqq4Ffq778lh0\",\n        \"user\": {\n            \"id\": 1,\n            \"name\": \"Harsh Goel\",\n            \"email\": \"admin@example.com\",\n            \"role\": \"ADMIN\",\n            \"status\": \"ACTIVE\"\n        }\n    }\n}"}],"_postman_id":"c7f70f0b-e7d5-43d4-8d70-26ae0db2b8be"},{"name":"currentUser","id":"1aac45d3-8fea-4be2-be6e-067cd7502f98","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/auth/me","description":"<h2 id=\"get-current-user\">Get Current User</h2>\n<p>Returns the profile of the currently authenticated user based on the provided JWT token.</p>\n<h3 id=\"access\">Access</h3>\n<p>All roles — ADMIN, ANALYST, VIEWER</p>\n<h3 id=\"how-to-use\">How to use</h3>\n<p>Set the Authorization header with your JWT token:<br /><code>Authorization: Bearer</code></p>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>Does not hit the database with credentials — identity is derived from the token</p>\n</li>\n<li><p>Useful for frontend apps to fetch the logged-in user's profile on load</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>200</code> Current user fetched successfully — returns user profile</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>401</code> Invalid or expired token</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","auth","me"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"ec49d60e-20c5-4cc5-90c6-44a2108b716d","name":"currentUser","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/auth/me"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"176"},{"key":"ETag","value":"W/\"b0-NMI09VbvcVDEwNKXAlD9xUSBq1E\""},{"key":"Date","value":"Mon, 06 Apr 2026 11:01:26 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 200,\n    \"message\": \"Current user fetched successfully\",\n    \"data\": {\n        \"id\": 1,\n        \"name\": \"Harsh Goel\",\n        \"email\": \"admin@example.com\",\n        \"role\": \"ADMIN\",\n        \"status\": \"ACTIVE\"\n    }\n}"}],"_postman_id":"1aac45d3-8fea-4be2-be6e-067cd7502f98"}],"id":"100ad7c2-4d49-44f9-b21b-644082bb057c","description":"<h2 id=\"authentication--session-management\">Authentication &amp; Session Management</h2>\n<p>This module handles user authentication using <strong>JWT (JSON Web Tokens)</strong>.</p>\n<h3 id=\"how-it-works\">How it works</h3>\n<ol>\n<li><p>Call <code>POST /auth/login</code> with valid credentials</p>\n</li>\n<li><p>Receive a signed JWT token in the response</p>\n</li>\n<li><p>Include the token in every subsequent request:<br /> <code>Authorization: Bearer</code></p>\n</li>\n<li><p>Token expires based on server configuration (default: 1 day)</p>\n</li>\n</ol>\n<h3 id=\"security\">Security</h3>\n<ul>\n<li><p>Passwords are hashed using <strong>bcrypt</strong> before storage — plain text is never saved</p>\n</li>\n<li><p>Tokens are stateless — no session is stored on the server</p>\n</li>\n<li><p>Inactive accounts are blocked at login even with correct credentials</p>\n</li>\n<li><p>Expired or tampered tokens are rejected with a clear error message</p>\n</li>\n</ul>\n<h3 id=\"endpoints\">Endpoints</h3>\n<ul>\n<li><p><code>POST /auth/login</code> — Public — Login and receive JWT token</p>\n</li>\n<li><p><code>GET /auth/me</code> — All roles — Get currently authenticated user</p>\n</li>\n</ul>\n","_postman_id":"100ad7c2-4d49-44f9-b21b-644082bb057c"},{"name":"Users","item":[{"name":"createUser","id":"ca7a9630-3448-49aa-a8d6-ae50cfa7d266","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"name\": \"Harsh Goel\",\r\n  \"email\": \"harsh@zorvyn.com\",\r\n  \"password\": \"hello@123\",\r\n  \"role\": \"ANALYST\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:4000/api/v1/users/","description":"<h2 id=\"create-user\">Create User</h2>\n<p>Creates a new user in the system with the specified role. Only admins can create users.</p>\n<h3 id=\"access\">Access</h3>\n<p>ADMIN only — returns 403 for Analyst and Viewer</p>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>Default role is VIEWER if role is not provided</p>\n</li>\n<li><p>Password is hashed with bcrypt before storage — never stored as plain text</p>\n</li>\n<li><p>Email must be unique — duplicate emails are rejected with 409</p>\n</li>\n<li><p>Newly created users are ACTIVE by default</p>\n</li>\n<li><p>Creation is logged in the audit trail with the admin's ID</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>201</code> User created successfully — returns created user profile</p>\n</li>\n<li><p><code>400</code> Validation failed — missing or invalid fields</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>403</code> You do not have permission to perform this action</p>\n</li>\n<li><p><code>409</code> User with this email already exists</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","users",""],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"a887ed98-16b3-4c04-93f3-998e1d1cde19","name":"createUser","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"name\": \"Harsh Goel\",\r\n  \"email\": \"harsh@zorvyn.com\",\r\n  \"password\": \"hello@123\",\r\n  \"role\": \"ANALYST\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:4000/api/v1/users/"},"status":"Created","code":201,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"321"},{"key":"ETag","value":"W/\"141-VFBltD+IzUtQTqUmiWvnT8+hkBA\""},{"key":"Date","value":"Mon, 06 Apr 2026 11:08:35 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 201,\n    \"message\": \"User created successfully\",\n    \"data\": {\n        \"status\": \"ACTIVE\",\n        \"id\": 8,\n        \"name\": \"Harsh Goel\",\n        \"email\": \"harsh@zorvyn.com\",\n        \"password\": \"$2b$10$/pMJ6sKvC4f9zvxMRA1A0OWYIEUiOfgJ8/k20ebpHrDXtXpnVyUfK\",\n        \"role\": \"ANALYST\",\n        \"updatedAt\": \"2026-04-06T11:08:35.944Z\",\n        \"createdAt\": \"2026-04-06T11:08:35.944Z\"\n    }\n}"}],"_postman_id":"ca7a9630-3448-49aa-a8d6-ae50cfa7d266"},{"name":"getUser","id":"7c47163b-48da-4420-9b5f-edd5db015c56","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[],"description":"<h2 id=\"get-all-users\">Get All Users</h2>\n<p>Returns a list of all users registered in the system.</p>\n<h3 id=\"access\">Access</h3>\n<p>ADMIN only — returns 403 for Analyst and Viewer</p>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>Passwords are never returned in the response</p>\n</li>\n<li><p>Returns all users regardless of their status (ACTIVE or INACTIVE)</p>\n</li>\n<li><p>Useful for admin dashboard to manage and monitor all system users</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>200</code> Users fetched successfully — returns array of user profiles</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>403</code> You do not have permission to perform this action</p>\n</li>\n</ul>\n","urlObject":{"query":[],"variable":[]},"url":""},"response":[{"id":"cc329858-a7a5-4951-9767-9954499eea45","name":"getUser","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/users/"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"1450"},{"key":"ETag","value":"W/\"5aa-jalt5LtuwnUIEuZ4tIShJMO7F6w\""},{"key":"Date","value":"Mon, 06 Apr 2026 11:10:09 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 200,\n    \"message\": \"Users fetched successfully\",\n    \"data\": [\n        {\n            \"id\": 1,\n            \"name\": \"Harsh Goel\",\n            \"email\": \"admin@example.com\",\n            \"role\": \"ADMIN\",\n            \"status\": \"ACTIVE\",\n            \"createdAt\": \"2026-04-05T06:19:54.000Z\",\n            \"updatedAt\": \"2026-04-05T06:19:54.000Z\"\n        },\n        {\n            \"id\": 2,\n            \"name\": \"Riya Sharma\",\n            \"email\": \"analyst@example.com\",\n            \"role\": \"ANALYST\",\n            \"status\": \"ACTIVE\",\n            \"createdAt\": \"2026-04-05T06:19:54.000Z\",\n            \"updatedAt\": \"2026-04-06T04:02:39.000Z\"\n        },\n        {\n            \"id\": 3,\n            \"name\": \"Amit Verma\",\n            \"email\": \"viewer@example.com\",\n            \"role\": \"VIEWER\",\n            \"status\": \"ACTIVE\",\n            \"createdAt\": \"2026-04-05T06:19:54.000Z\",\n            \"updatedAt\": \"2026-04-05T06:19:54.000Z\"\n        },\n        {\n            \"id\": 4,\n            \"name\": \"Zorvyn employee\",\n            \"email\": \"zorvyn@gmail.in\",\n            \"role\": \"ANALYST\",\n            \"status\": \"ACTIVE\",\n            \"createdAt\": \"2026-04-05T12:53:53.000Z\",\n            \"updatedAt\": \"2026-04-05T12:57:31.000Z\"\n        },\n        {\n            \"id\": 5,\n            \"name\": \"iya Sharma\",\n            \"email\": \"anayst@example.com\",\n            \"role\": \"ANALYST\",\n            \"status\": \"ACTIVE\",\n            \"createdAt\": \"2026-04-05T18:17:36.000Z\",\n            \"updatedAt\": \"2026-04-05T18:17:36.000Z\"\n        },\n        {\n            \"id\": 6,\n            \"name\": \"Virat Sharma\",\n            \"email\": \"analyst@zorvyn.com\",\n            \"role\": \"ANALYST\",\n            \"status\": \"ACTIVE\",\n            \"createdAt\": \"2026-04-05T19:23:34.000Z\",\n            \"updatedAt\": \"2026-04-05T19:23:34.000Z\"\n        },\n        {\n            \"id\": 7,\n            \"name\": \"Virat Sharma\",\n            \"email\": \"anayst@zorvyn.com\",\n            \"role\": \"ANALYST\",\n            \"status\": \"ACTIVE\",\n            \"createdAt\": \"2026-04-05T19:42:36.000Z\",\n            \"updatedAt\": \"2026-04-05T19:42:36.000Z\"\n        },\n        {\n            \"id\": 8,\n            \"name\": \"Harsh Goel\",\n            \"email\": \"harsh@zorvyn.com\",\n            \"role\": \"ANALYST\",\n            \"status\": \"ACTIVE\",\n            \"createdAt\": \"2026-04-06T11:08:35.000Z\",\n            \"updatedAt\": \"2026-04-06T11:08:35.000Z\"\n        }\n    ]\n}"}],"_postman_id":"7c47163b-48da-4420-9b5f-edd5db015c56"},{"name":"getUserbyID","id":"7d922b80-5b9d-4fa3-a5a4-dc5b27a33fc4","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/users/1","description":"<h2 id=\"get-user-by-id\">Get User by ID</h2>\n<p>Returns a single user profile by their unique ID.</p>\n<h3 id=\"access\">Access</h3>\n<p>ADMIN only — returns 403 for Analyst and Viewer</p>\n<h3 id=\"path-parameter\">Path Parameter</h3>\n<ul>\n<li><code>id</code> — integer — the unique ID of the user to fetch</li>\n</ul>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>Passwords are never returned in the response</p>\n</li>\n<li><p>Returns 404 if no user exists with the provided ID</p>\n</li>\n<li><p>Useful for viewing detailed profile of a specific user before making role or status changes</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>200</code> User fetched successfully — returns user profile</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>403</code> You do not have permission to perform this action</p>\n</li>\n<li><p><code>404</code> User not found</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","users","1"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"41d2977c-cd17-4150-a6f3-befa5f9955a8","name":"getUserbyID","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/users/1"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"246"},{"key":"ETag","value":"W/\"f6-owzxSkL3p4wWPY9A9hlUHTTgOF8\""},{"key":"Date","value":"Mon, 06 Apr 2026 11:11:28 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 200,\n    \"message\": \"User fetched successfully\",\n    \"data\": {\n        \"id\": 1,\n        \"name\": \"Harsh Goel\",\n        \"email\": \"admin@example.com\",\n        \"role\": \"ADMIN\",\n        \"status\": \"ACTIVE\",\n        \"createdAt\": \"2026-04-05T06:19:54.000Z\",\n        \"updatedAt\": \"2026-04-05T06:19:54.000Z\"\n    }\n}"}],"_postman_id":"7d922b80-5b9d-4fa3-a5a4-dc5b27a33fc4"},{"name":"updateUserRole","id":"3f1fd285-72a7-44bb-b129-3793dd41fba1","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\r\n    \"role\" : \"ADMIN\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:4000/api/v1/users/2/role","description":"<h2 id=\"update-user-role\">Update User Role</h2>\n<p>Updates the role of a specific user. Role change takes effect immediately on their next request.</p>\n<h3 id=\"access\">Access</h3>\n<p>ADMIN only — returns 403 for Analyst and Viewer</p>\n<h3 id=\"path-parameter\">Path Parameter</h3>\n<ul>\n<li><code>id</code> — integer — the unique ID of the user to update</li>\n</ul>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>Valid roles are ADMIN, ANALYST, VIEWER</p>\n</li>\n<li><p>Role change is recorded in the audit log with old and new values</p>\n</li>\n<li><p>Changing a user's role immediately affects what endpoints they can access</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>200</code> User role updated successfully</p>\n</li>\n<li><p><code>400</code> Validation failed — invalid or missing role</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>403</code> You do not have permission to perform this action</p>\n</li>\n<li><p><code>404</code> User not found</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","users","2","role"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"d616991f-95b2-4fc1-a993-1ac9c31e6378","name":"updateUserRole","originalRequest":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\r\n    \"role\" : \"ADMIN\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:4000/api/v1/users/2/role"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"328"},{"key":"ETag","value":"W/\"148-nJAaXJq0j4zFqZYPRx3+rmjRa7M\""},{"key":"Date","value":"Mon, 06 Apr 2026 11:14:26 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 200,\n    \"message\": \"User role updated successfully\",\n    \"data\": {\n        \"id\": 2,\n        \"name\": \"Riya Sharma\",\n        \"email\": \"analyst@example.com\",\n        \"password\": \"$2b$10$06/yc9alw40YXcDmYUUMkehWQjeM/F.5hkVYUA/oghS6PwIDa74pi\",\n        \"role\": \"ADMIN\",\n        \"status\": \"ACTIVE\",\n        \"createdAt\": \"2026-04-05T06:19:54.000Z\",\n        \"updatedAt\": \"2026-04-06T11:14:26.307Z\"\n    }\n}"}],"_postman_id":"3f1fd285-72a7-44bb-b129-3793dd41fba1"},{"name":"updateUserStatus","id":"0aa84181-ce11-4f9d-9982-3d90aaecc735","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\r\n    \"status\" : \"INACTIVE\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:4000/api/v1/users/2/status","description":"<h2 id=\"update-user-status\">Update User Status</h2>\n<p>Activates or deactivates a user account. Deactivated users cannot login even with correct credentials.</p>\n<h3 id=\"access\">Access</h3>\n<p>ADMIN only — returns 403 for Analyst and Viewer</p>\n<h3 id=\"path-parameter\">Path Parameter</h3>\n<ul>\n<li><code>id</code> — integer — the unique ID of the user to update</li>\n</ul>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>Valid statuses are ACTIVE and INACTIVE</p>\n</li>\n<li><p>Status change is recorded in the audit log with old and new values</p>\n</li>\n<li><p>Deactivating a user does not invalidate their existing JWT token — token will still pass authentication but active user check will block them</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>200</code> User status updated successfully</p>\n</li>\n<li><p><code>400</code> Validation failed — invalid or missing status</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>403</code> You do not have permission to perform this action</p>\n</li>\n<li><p><code>404</code> User not found</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","users","2","status"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"e502fd95-6eaf-433c-8218-ab926f236423","name":"updateUserStatus","originalRequest":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\r\n    \"status\" : \"INACTIVE\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:4000/api/v1/users/2/status"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"332"},{"key":"ETag","value":"W/\"14c-T7U++NbIkLvyVEw1uU+t5zamJA0\""},{"key":"Date","value":"Mon, 06 Apr 2026 11:15:28 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 200,\n    \"message\": \"User status updated successfully\",\n    \"data\": {\n        \"id\": 2,\n        \"name\": \"Riya Sharma\",\n        \"email\": \"analyst@example.com\",\n        \"password\": \"$2b$10$06/yc9alw40YXcDmYUUMkehWQjeM/F.5hkVYUA/oghS6PwIDa74pi\",\n        \"role\": \"ADMIN\",\n        \"status\": \"INACTIVE\",\n        \"createdAt\": \"2026-04-05T06:19:54.000Z\",\n        \"updatedAt\": \"2026-04-06T11:15:28.440Z\"\n    }\n}"}],"_postman_id":"0aa84181-ce11-4f9d-9982-3d90aaecc735"}],"id":"fc43566c-97c2-4d7c-b6f3-4fdfbd283d07","description":"<h2 id=\"user-management\">User Management</h2>\n<p>This module handles all user-related operations including creation, retrieval, and role/status management.</p>\n<h3 id=\"access\">Access</h3>\n<p>All endpoints in this module are restricted to <strong>ADMIN</strong> only.</p>\n<h3 id=\"user-roles\">User Roles</h3>\n<ul>\n<li><p><strong>ADMIN</strong> — full access to users, records, and dashboard</p>\n</li>\n<li><p><strong>ANALYST</strong> — read access to records and full dashboard analytics</p>\n</li>\n<li><p><strong>VIEWER</strong> — access to summary and recent activity only</p>\n</li>\n</ul>\n<h3 id=\"user-status\">User Status</h3>\n<ul>\n<li><p><strong>ACTIVE</strong> — user can login and access the system</p>\n</li>\n<li><p><strong>INACTIVE</strong> — user is blocked from logging in even with correct credentials</p>\n</li>\n</ul>\n<h3 id=\"security\">Security</h3>\n<ul>\n<li><p>Passwords are hashed with bcrypt — never stored or returned as plain text</p>\n</li>\n<li><p>Every user mutation (create, role update, status update) is recorded in the audit log with the acting admin's ID</p>\n</li>\n<li><p>Role and status changes take effect immediately on the next request</p>\n</li>\n</ul>\n<h3 id=\"endpoints\">Endpoints</h3>\n<ul>\n<li><p><code>POST /users</code> — ADMIN — Create a new user</p>\n</li>\n<li><p><code>GET /users</code> — ADMIN — Get all users</p>\n</li>\n<li><p><code>GET /users/:id</code> — ADMIN — Get user by ID</p>\n</li>\n<li><p><code>PATCH /users/:id/role</code> — ADMIN — Update user role</p>\n</li>\n<li><p><code>PATCH /users/:id/status</code> — ADMIN — Update user status</p>\n</li>\n</ul>\n","_postman_id":"fc43566c-97c2-4d7c-b6f3-4fdfbd283d07"},{"name":"Financial Records","item":[{"name":"newRecord","id":"0e2ae13a-9abe-4fe0-a524-fda997ee39b1","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"amount\": 5000.00,\r\n  \"type\": \"EXPENSE\",\r\n  \"category\": \"Marketing\",\r\n  \"date\": \"2026-04-06\",\r\n  \"notes\": \"Ad campaign\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:4000/api/v1/records/","description":"<h2 id=\"create-financial-record\">Create Financial Record</h2>\n<p>Creates a new financial record linked to the authenticated admin user.</p>\n<h3 id=\"access\">Access</h3>\n<p>ADMIN only — returns 403 for Analyst and Viewer</p>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>Amount must be at least 0.01 and supports up to 2 decimal places</p>\n</li>\n<li><p>Amount is stored as DECIMAL(10,2) in the database for financial precision</p>\n</li>\n<li><p>Date must be a valid ISO8601 date format (YYYY-MM-DD)</p>\n</li>\n<li><p>Category must be between 2 and 50 characters</p>\n</li>\n<li><p>Notes are optional and capped at 500 characters</p>\n</li>\n<li><p>Record is automatically linked to the authenticated user via createdBy</p>\n</li>\n<li><p>Creation is recorded in the audit log</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>201</code> Financial record created successfully — returns created record</p>\n</li>\n<li><p><code>400</code> Validation failed — missing or invalid fields</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>403</code> You do not have permission to perform this action</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","records",""],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"8ebf6e29-5876-4341-988d-4f9d93c4d030","name":"newRecord","originalRequest":{"method":"POST","header":[],"body":{"mode":"raw","raw":"{\r\n  \"amount\": 5000.00,\r\n  \"type\": \"EXPENSE\",\r\n  \"category\": \"Marketing\",\r\n  \"date\": \"2026-04-06\",\r\n  \"notes\": \"Ad campaign\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:4000/api/v1/records/"},"status":"Created","code":201,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"306"},{"key":"ETag","value":"W/\"132-XFKn4mCEpKrw7IKM1YA8GdrSVZw\""},{"key":"Date","value":"Mon, 06 Apr 2026 11:39:51 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 201,\n    \"message\": \"Financial record created successfully\",\n    \"data\": {\n        \"isDeleted\": false,\n        \"id\": 56,\n        \"amount\": 5000,\n        \"type\": \"EXPENSE\",\n        \"category\": \"Marketing\",\n        \"date\": \"2026-04-06\",\n        \"notes\": \"Ad campaign\",\n        \"createdBy\": 1,\n        \"updatedAt\": \"2026-04-06T11:39:51.329Z\",\n        \"createdAt\": \"2026-04-06T11:39:51.329Z\"\n    }\n}"}],"_postman_id":"0e2ae13a-9abe-4fe0-a524-fda997ee39b1"},{"name":"getRecordbyFilter","id":"38f4f9e5-bb75-4e01-84a0-789093ee55f8","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/records/?type=INCOME&page=1&limit=5&sortBy=date&sortOrder=DESC","description":"<h2 id=\"get-all-financial-records\">Get All Financial Records</h2>\n<p>Returns a paginated list of financial records. Supports advanced filtering, searching, and sorting.</p>\n<h3 id=\"access\">Access</h3>\n<p>ANALYST and ADMIN only — returns 403 for Viewer</p>\n<h3 id=\"query-parameters\">Query Parameters</h3>\n<ul>\n<li><p><code>type</code> — filter by INCOME or EXPENSE</p>\n</li>\n<li><p><code>category</code> — filter by exact category name</p>\n</li>\n<li><p><code>startDate</code> — filter records from this date (YYYY-MM-DD, inclusive)</p>\n</li>\n<li><p><code>endDate</code> — filter records up to this date (YYYY-MM-DD, inclusive)</p>\n</li>\n<li><p><code>search</code> — partial match search across notes and category fields</p>\n</li>\n<li><p><code>page</code> — page number, default 1</p>\n</li>\n<li><p><code>limit</code> — records per page, default 10, max 100</p>\n</li>\n<li><p><code>sortBy</code> — field to sort by: date, amount, category, createdAt (default: date)</p>\n</li>\n<li><p><code>sortOrder</code> — ASC or DESC (default: DESC)</p>\n</li>\n</ul>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>Soft deleted records are never returned</p>\n</li>\n<li><p>Returns creator details with each record</p>\n</li>\n<li><p>Pagination metadata is included in every response (total, page, limit, totalPages)</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>200</code> Financial records fetched successfully — returns paginated records</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>403</code> You do not have permission to perform this action</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","records",""],"host":["localhost"],"query":[{"key":"type","value":"INCOME"},{"key":"page","value":"1"},{"key":"limit","value":"5"},{"key":"sortBy","value":"date"},{"key":"sortOrder","value":"DESC"}],"variable":[]}},"response":[{"id":"aebff38d-5e21-41ac-896a-2092dd268a98","name":"getRecordbyFilter","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":{"raw":"http://localhost:4000/api/v1/records/?type=INCOME&page=1&limit=5&sortBy=date&sortOrder=DESC","protocol":"http","host":["localhost"],"port":"4000","path":["api","v1","records",""],"query":[{"key":"type","value":"INCOME"},{"key":"page","value":"1"},{"key":"limit","value":"5"},{"key":"sortBy","value":"date"},{"key":"sortOrder","value":"DESC"}]}},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"1717"},{"key":"ETag","value":"W/\"6b5-1sC/77vWzJWrOq/zWgM6kOvvEJ4\""},{"key":"Date","value":"Mon, 06 Apr 2026 11:46:02 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 200,\n    \"message\": \"Financial records fetched successfully\",\n    \"data\": [\n        {\n            \"id\": 49,\n            \"amount\": \"32000.00\",\n            \"type\": \"INCOME\",\n            \"category\": \"Freelance\",\n            \"date\": \"2026-03-22\",\n            \"notes\": \"Freelance project - March\",\n            \"createdBy\": 1,\n            \"isDeleted\": false,\n            \"createdAt\": \"2026-04-05T06:19:54.000Z\",\n            \"updatedAt\": \"2026-04-05T06:19:54.000Z\",\n            \"records\": {\n                \"id\": 1,\n                \"name\": \"Harsh Goel\",\n                \"email\": \"admin@example.com\",\n                \"role\": \"ADMIN\"\n            }\n        },\n        {\n            \"id\": 46,\n            \"amount\": \"85000.00\",\n            \"type\": \"INCOME\",\n            \"category\": \"Salary\",\n            \"date\": \"2026-03-15\",\n            \"notes\": \"Monthly salary - March\",\n            \"createdBy\": 1,\n            \"isDeleted\": false,\n            \"createdAt\": \"2026-04-05T06:19:54.000Z\",\n            \"updatedAt\": \"2026-04-05T06:19:54.000Z\",\n            \"records\": {\n                \"id\": 1,\n                \"name\": \"Harsh Goel\",\n                \"email\": \"admin@example.com\",\n                \"role\": \"ADMIN\"\n            }\n        },\n        {\n            \"id\": 52,\n            \"amount\": \"32000.00\",\n            \"type\": \"INCOME\",\n            \"category\": \"Freelance\",\n            \"date\": \"2026-03-03\",\n            \"notes\": \"Freelance project - March\",\n            \"createdBy\": 1,\n            \"isDeleted\": false,\n            \"createdAt\": \"2026-04-05T13:01:27.000Z\",\n            \"updatedAt\": \"2026-04-05T13:01:27.000Z\",\n            \"records\": {\n                \"id\": 1,\n                \"name\": \"Harsh Goel\",\n                \"email\": \"admin@example.com\",\n                \"role\": \"ADMIN\"\n            }\n        },\n        {\n            \"id\": 44,\n            \"amount\": \"15000.00\",\n            \"type\": \"INCOME\",\n            \"category\": \"Consulting\",\n            \"date\": \"2026-02-20\",\n            \"notes\": \"Consulting fees - Q1\",\n            \"createdBy\": 1,\n            \"isDeleted\": false,\n            \"createdAt\": \"2026-04-05T06:19:54.000Z\",\n            \"updatedAt\": \"2026-04-05T06:19:54.000Z\",\n            \"records\": {\n                \"id\": 1,\n                \"name\": \"Harsh Goel\",\n                \"email\": \"admin@example.com\",\n                \"role\": \"ADMIN\"\n            }\n        },\n        {\n            \"id\": 36,\n            \"amount\": \"85000.00\",\n            \"type\": \"INCOME\",\n            \"category\": \"Salary\",\n            \"date\": \"2026-01-15\",\n            \"notes\": \"Monthly salary - January\",\n            \"createdBy\": 1,\n            \"isDeleted\": false,\n            \"createdAt\": \"2026-04-05T06:19:54.000Z\",\n            \"updatedAt\": \"2026-04-05T06:19:54.000Z\",\n            \"records\": {\n                \"id\": 1,\n                \"name\": \"Harsh Goel\",\n                \"email\": \"admin@example.com\",\n                \"role\": \"ADMIN\"\n            }\n        }\n    ],\n    \"meta\": {\n        \"total\": 5,\n        \"page\": 1,\n        \"limit\": 5,\n        \"totalPages\": 1\n    }\n}"}],"_postman_id":"38f4f9e5-bb75-4e01-84a0-789093ee55f8"},{"name":"getUserbyId","id":"7918bd99-91af-4784-9694-0d91784811a6","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/records/49","description":"<h2 id=\"get-financial-record-by-id\">Get Financial Record by ID</h2>\n<p>Returns a single financial record by its unique ID including full creator details.</p>\n<h3 id=\"access\">Access</h3>\n<p>ANALYST and ADMIN only — returns 403 for Viewer</p>\n<h3 id=\"path-parameter\">Path Parameter</h3>\n<ul>\n<li><code>id</code> — integer — the unique ID of the financial record to fetch</li>\n</ul>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>Soft deleted records return 404 — they are treated as non-existent</p>\n</li>\n<li><p>Creator details (id, name, email, role) are included in the response</p>\n</li>\n<li><p>Useful for viewing full details of a specific transaction</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>200</code> Financial record fetched successfully — returns record with creator</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>403</code> You do not have permission to perform this action</p>\n</li>\n<li><p><code>404</code> Financial record not found</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","records","49"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"8e9b2707-2646-4643-beb0-2aceea11e706","name":"getUserbyId","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/records/49"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"407"},{"key":"ETag","value":"W/\"197-qLOFMWBMQ+VO6RdM41NySJSJUXY\""},{"key":"Date","value":"Mon, 06 Apr 2026 11:47:22 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 200,\n    \"message\": \"Financial record fetched successfully\",\n    \"data\": {\n        \"id\": 49,\n        \"amount\": \"32000.00\",\n        \"type\": \"INCOME\",\n        \"category\": \"Freelance\",\n        \"date\": \"2026-03-22\",\n        \"notes\": \"Freelance project - March\",\n        \"createdBy\": 1,\n        \"isDeleted\": false,\n        \"createdAt\": \"2026-04-05T06:19:54.000Z\",\n        \"updatedAt\": \"2026-04-05T06:19:54.000Z\",\n        \"records\": {\n            \"id\": 1,\n            \"name\": \"Harsh Goel\",\n            \"email\": \"admin@example.com\",\n            \"role\": \"ADMIN\"\n        }\n    }\n}"}],"_postman_id":"7918bd99-91af-4784-9694-0d91784811a6"},{"name":"updateRecord","id":"228be5ba-d5d1-44a5-8cf7-183f8e122c36","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\r\n    \"amount\" : \"90000\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:4000/api/v1/records/49","description":"<h2 id=\"update-financial-record\">Update Financial Record</h2>\n<p>Updates one or more fields of an existing financial record.</p>\n<h3 id=\"access\">Access</h3>\n<p>ADMIN only — returns 403 for Analyst and Viewer</p>\n<h3 id=\"path-parameter\">Path Parameter</h3>\n<ul>\n<li><code>id</code> — integer — the unique ID of the financial record to update</li>\n</ul>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>At least one field must be provided</p>\n</li>\n<li><p>Submitted values must differ from existing record — identical values return 400</p>\n</li>\n<li><p>Amount must be at least 0.01 with max 2 decimal places</p>\n</li>\n<li><p>Date must be in YYYY-MM-DD format</p>\n</li>\n<li><p>Update is recorded in the audit log with oldValues and newValues</p>\n</li>\n<li><p>Soft deleted records cannot be updated — returns 404</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>200</code> Financial record updated successfully</p>\n</li>\n<li><p><code>400</code> Validation failed or no changes detected</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>403</code> You do not have permission to perform this action</p>\n</li>\n<li><p><code>404</code> Financial record not found</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","records","49"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"87ae9317-8a7c-4aa1-b27e-5ec4a566404c","name":"updateRecord","originalRequest":{"method":"PATCH","header":[],"body":{"mode":"raw","raw":"{\r\n    \"amount\" : \"90000\"\r\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:4000/api/v1/records/49"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"402"},{"key":"ETag","value":"W/\"192-qljdeHZnHTPOhI6P0Mb9SiGYNwI\""},{"key":"Date","value":"Mon, 06 Apr 2026 11:49:05 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 200,\n    \"message\": \"Financial record updated successfully\",\n    \"data\": {\n        \"id\": 49,\n        \"amount\": 90000,\n        \"type\": \"INCOME\",\n        \"category\": \"Freelance\",\n        \"date\": \"2026-03-22\",\n        \"notes\": \"Freelance project - March\",\n        \"createdBy\": 1,\n        \"isDeleted\": false,\n        \"createdAt\": \"2026-04-05T06:19:54.000Z\",\n        \"updatedAt\": \"2026-04-06T11:49:05.598Z\",\n        \"records\": {\n            \"id\": 1,\n            \"name\": \"Harsh Goel\",\n            \"email\": \"admin@example.com\",\n            \"role\": \"ADMIN\"\n        }\n    }\n}"}],"_postman_id":"228be5ba-d5d1-44a5-8cf7-183f8e122c36"},{"name":"softDeleteRecord","id":"26cf1aef-3c15-41b7-bb1a-1e7dfe52b98c","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"DELETE","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/records/49","description":"<h2 id=\"delete-financial-record\">Delete Financial Record</h2>\n<p>Soft deletes a financial record by setting isDeleted to true. Record is preserved in the database for audit and historical purposes.</p>\n<h3 id=\"access\">Access</h3>\n<p>ADMIN only — returns 403 for Analyst and Viewer</p>\n<h3 id=\"path-parameter\">Path Parameter</h3>\n<ul>\n<li><code>id</code> — integer — the unique ID of the financial record to delete</li>\n</ul>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>Record is NOT permanently removed from the database</p>\n</li>\n<li><p>Soft deleted records are excluded from all GET queries automatically</p>\n</li>\n<li><p>Deletion is recorded in the audit log with the full record snapshot as oldValues</p>\n</li>\n<li><p>This approach preserves data integrity and audit trail</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>200</code> Financial record deleted successfully</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>403</code> You do not have permission to perform this action</p>\n</li>\n<li><p><code>404</code> Financial record not found</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","records","49"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"ff222b64-0aa5-490f-a99a-e4bd5561d103","name":"softDeleteRecord","originalRequest":{"method":"DELETE","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/records/49"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"95"},{"key":"ETag","value":"W/\"5f-U0AXKGoqMZgICbF/sFtYw9Ydr9M\""},{"key":"Date","value":"Mon, 06 Apr 2026 11:50:17 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 200,\n    \"message\": \"Financial record deleted successfully\",\n    \"data\": null\n}"}],"_postman_id":"26cf1aef-3c15-41b7-bb1a-1e7dfe52b98c"}],"id":"48b1cea8-bcdf-4ee3-a236-c1e7dffc2d97","description":"<h2 id=\"financial-records\">Financial Records</h2>\n<p>This module handles all financial record operations including creation, retrieval, updating, and soft deletion.</p>\n<h3 id=\"access\">Access</h3>\n<ul>\n<li><p><strong>Create, Update, Delete</strong> — ADMIN only</p>\n</li>\n<li><p><strong>Read</strong> — ANALYST and ADMIN only</p>\n</li>\n<li><p>VIEWER has no access to any record endpoints</p>\n</li>\n</ul>\n<h3 id=\"record-types\">Record Types</h3>\n<ul>\n<li><p><strong>INCOME</strong> — money coming in (salary, freelance, consulting)</p>\n</li>\n<li><p><strong>EXPENSE</strong> — money going out (rent, utilities, marketing)</p>\n</li>\n</ul>\n<h3 id=\"soft-delete\">Soft Delete</h3>\n<p>Records are never hard deleted from the database. Instead an <code>isDeleted</code> flag is set to <code>true</code>. This preserves historical data integrity and keeps the audit trail meaningful.</p>\n<h3 id=\"filtering--pagination\">Filtering &amp; Pagination</h3>\n<p><code>GET /records</code> supports:</p>\n<ul>\n<li><p>Filter by <code>type</code>, <code>category</code>, <code>startDate</code>, <code>endDate</code></p>\n</li>\n<li><p>Full-text <code>search</code> across notes and category</p>\n</li>\n<li><p><code>pagination</code> with page and limit</p>\n</li>\n<li><p><code>sorting</code> by date, amount, category, or createdAt</p>\n</li>\n</ul>\n<h3 id=\"audit-logging\">Audit Logging</h3>\n<p>Every create, update, and delete operation is recorded in the audit log with:</p>\n<ul>\n<li><p>Who performed the action</p>\n</li>\n<li><p>What changed (oldValues and newValues)</p>\n</li>\n<li><p>When it happened</p>\n</li>\n</ul>\n<h3 id=\"endpoints\">Endpoints</h3>\n<ul>\n<li><p><code>POST /records</code> — ADMIN — Create a financial record</p>\n</li>\n<li><p><code>GET /records</code> — ANALYST, ADMIN — Get all records with filters</p>\n</li>\n<li><p><code>GET /records/:id</code> — ANALYST, ADMIN — Get record by ID</p>\n</li>\n<li><p><code>PATCH /records/:id</code> — ADMIN — Update a record</p>\n</li>\n<li><p><code>DELETE /records/:id</code> — ADMIN — Soft delete a record</p>\n</li>\n</ul>\n","_postman_id":"48b1cea8-bcdf-4ee3-a236-c1e7dffc2d97"},{"name":"Dashboard","item":[{"name":"summary","id":"4e727a94-e8ab-49ee-9970-e5b317ca9859","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/dashboard/summary","description":"<h2 id=\"dashboard-summary\">Dashboard Summary</h2>\n<p>Returns the overall financial summary including total income, total expenses, and net balance. Supports optional date range filtering for period-specific insights.</p>\n<h3 id=\"access\">Access</h3>\n<p>All roles — ADMIN, ANALYST, VIEWER</p>\n<h3 id=\"query-parameters\">Query Parameters</h3>\n<ul>\n<li><p><code>startDate</code> — filter from this date (YYYY-MM-DD, inclusive)</p>\n</li>\n<li><p><code>endDate</code> — filter up to this date (YYYY-MM-DD, inclusive)</p>\n</li>\n</ul>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>Both startDate and endDate are optional — omitting them returns all-time totals</p>\n</li>\n<li><p>Net balance is calculated as totalIncome - totalExpenses</p>\n</li>\n<li><p>Computed directly from the database using SQL SUM aggregation — efficient for large datasets</p>\n</li>\n<li><p>Soft deleted records are excluded from all calculations</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>200</code> Dashboard summary fetched successfully — returns totalIncome, totalExpenses, netBalance</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>403</code> Your account is inactive. Please contact admin</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","dashboard","summary"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"b77d7fdf-7e94-465b-86bb-5ea09bdbe8d7","name":"summary","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/dashboard/summary"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"160"},{"key":"ETag","value":"W/\"a0-jT7ApGbctLLhpOeeLo3NTF+ZuzA\""},{"key":"Date","value":"Mon, 06 Apr 2026 12:03:20 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 200,\n    \"message\": \"Dashboard summary fetched successfully\",\n    \"data\": {\n        \"totalIncome\": 217000,\n        \"totalExpenses\": 49500.5,\n        \"netBalance\": 167499.5\n    }\n}"}],"_postman_id":"4e727a94-e8ab-49ee-9970-e5b317ca9859"},{"name":"categoryBreakdown","id":"66e1d118-a22d-43d9-b656-2ffd77d3fb99","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/dashboard/category-breakdown","description":"<h2 id=\"category-breakdown\">Category Breakdown</h2>\n<p>Returns aggregated totals grouped by record type and category, ordered by highest total first.</p>\n<h3 id=\"access\">Access</h3>\n<p>ANALYST and ADMIN only — returns 403 for Viewer</p>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>Results are ordered by total amount descending — highest spending/earning categories appear first</p>\n</li>\n<li><p>Useful for visualizing where money is going and coming from</p>\n</li>\n<li><p>Computed using SQL GROUP BY and SUM — efficient and scalable</p>\n</li>\n<li><p>Soft deleted records are excluded</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>200</code> Category breakdown fetched successfully — returns array of type, category, total</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>403</code> You do not have permission to perform this action</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","dashboard","category-breakdown"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"a800cc70-76b0-4272-973b-4e04440cc718","name":"categoryBreakdown","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/dashboard/category-breakdown"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"528"},{"key":"ETag","value":"W/\"210-YjGp+yuPFIAB1HCdPHT7hkJvr1Y\""},{"key":"Date","value":"Mon, 06 Apr 2026 12:04:00 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 200,\n    \"message\": \"Category breakdown fetched successfully\",\n    \"data\": [\n        {\n            \"type\": \"INCOME\",\n            \"category\": \"Salary\",\n            \"total\": 170000\n        },\n        {\n            \"type\": \"INCOME\",\n            \"category\": \"Freelance\",\n            \"total\": 32000\n        },\n        {\n            \"type\": \"EXPENSE\",\n            \"category\": \"Marketing\",\n            \"total\": 28500\n        },\n        {\n            \"type\": \"INCOME\",\n            \"category\": \"Consulting\",\n            \"total\": 15000\n        },\n        {\n            \"type\": \"EXPENSE\",\n            \"category\": \"Travel\",\n            \"total\": 11000\n        },\n        {\n            \"type\": \"EXPENSE\",\n            \"category\": \"Software\",\n            \"total\": 5300\n        },\n        {\n            \"type\": \"EXPENSE\",\n            \"category\": \"Rent\",\n            \"total\": 3600\n        },\n        {\n            \"type\": \"EXPENSE\",\n            \"category\": \"Utilities\",\n            \"total\": 1100.5\n        }\n    ]\n}"}],"_postman_id":"66e1d118-a22d-43d9-b656-2ffd77d3fb99"},{"name":"recent-activity","id":"9a619982-17e7-4d2e-892e-6ab5c3edd3bd","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/dashboard/recent-activity?limit=4","description":"<h2 id=\"recent-activity\">Recent Activity</h2>\n<p>Returns the most recent financial records ordered by creation time. Default limit is 5.</p>\n<h3 id=\"access\">Access</h3>\n<p>All roles — ADMIN, ANALYST, VIEWER<br />Creator details (name, email, role) are hidden for VIEWER role.</p>\n<h3 id=\"query-parameters\">Query Parameters</h3>\n<ul>\n<li><code>limit</code> — number of recent records to return, default 5</li>\n</ul>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>Returns up to the requested limit — if fewer records exist, returns all available</p>\n</li>\n<li><p>Ordered by createdAt descending — most recent first</p>\n</li>\n<li><p>VIEWER sees record data but not who created it — creator field is excluded</p>\n</li>\n<li><p>Soft deleted records are excluded</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>200</code> Recent activity fetched successfully — returns array of recent records</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>403</code> Your account is inactive. Please contact admin</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","dashboard","recent-activity"],"host":["localhost"],"query":[{"key":"limit","value":"4"}],"variable":[]}},"response":[{"id":"b0f03ec6-2168-4bc8-9aa0-fe223c69eb86","name":"recent-activity","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":{"raw":"http://localhost:4000/api/v1/dashboard/recent-activity?limit=4","protocol":"http","host":["localhost"],"port":"4000","path":["api","v1","dashboard","recent-activity"],"query":[{"key":"limit","value":"4"}]}},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"1306"},{"key":"ETag","value":"W/\"51a-WAm9/t8ksVU0eRhFbq+U/0NrvcM\""},{"key":"Date","value":"Mon, 06 Apr 2026 12:05:03 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 200,\n    \"message\": \"Recent activity fetched successfully\",\n    \"data\": [\n        {\n            \"id\": 56,\n            \"amount\": \"5000.00\",\n            \"type\": \"EXPENSE\",\n            \"category\": \"Marketing\",\n            \"date\": \"2026-04-06\",\n            \"notes\": \"Ad campaign\",\n            \"createdBy\": 1,\n            \"isDeleted\": false,\n            \"createdAt\": \"2026-04-06T11:39:51.000Z\",\n            \"updatedAt\": \"2026-04-06T11:39:51.000Z\",\n            \"records\": {\n                \"id\": 1,\n                \"name\": \"Harsh Goel\",\n                \"email\": \"admin@example.com\",\n                \"role\": \"ADMIN\"\n            }\n        },\n        {\n            \"id\": 55,\n            \"amount\": \"5000.00\",\n            \"type\": \"EXPENSE\",\n            \"category\": \"Marketing\",\n            \"date\": \"2026-03-15\",\n            \"notes\": \"Social media\",\n            \"createdBy\": 1,\n            \"isDeleted\": false,\n            \"createdAt\": \"2026-04-06T03:53:29.000Z\",\n            \"updatedAt\": \"2026-04-06T03:53:29.000Z\",\n            \"records\": {\n                \"id\": 1,\n                \"name\": \"Harsh Goel\",\n                \"email\": \"admin@example.com\",\n                \"role\": \"ADMIN\"\n            }\n        },\n        {\n            \"id\": 54,\n            \"amount\": \"5000.00\",\n            \"type\": \"EXPENSE\",\n            \"category\": \"Marketing\",\n            \"date\": \"2026-03-15\",\n            \"notes\": \"Social media\",\n            \"createdBy\": 1,\n            \"isDeleted\": false,\n            \"createdAt\": \"2026-04-05T19:44:15.000Z\",\n            \"updatedAt\": \"2026-04-05T19:44:15.000Z\",\n            \"records\": {\n                \"id\": 1,\n                \"name\": \"Harsh Goel\",\n                \"email\": \"admin@example.com\",\n                \"role\": \"ADMIN\"\n            }\n        },\n        {\n            \"id\": 53,\n            \"amount\": \"5000.00\",\n            \"type\": \"EXPENSE\",\n            \"category\": \"Marketing\",\n            \"date\": \"2026-03-15\",\n            \"notes\": \"Social media\",\n            \"createdBy\": 1,\n            \"isDeleted\": false,\n            \"createdAt\": \"2026-04-05T19:26:15.000Z\",\n            \"updatedAt\": \"2026-04-05T19:26:15.000Z\",\n            \"records\": {\n                \"id\": 1,\n                \"name\": \"Harsh Goel\",\n                \"email\": \"admin@example.com\",\n                \"role\": \"ADMIN\"\n            }\n        }\n    ]\n}"}],"_postman_id":"9a619982-17e7-4d2e-892e-6ab5c3edd3bd"},{"name":"trends","id":"d4572c96-f256-41af-a83a-b39591432183","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"auth":{"type":"bearer","bearer":{"basicConfig":[{"key":"token","value":"<token>"}]},"isInherited":false},"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/dashboard/trends","description":"<h2 id=\"monthly-trends\">Monthly Trends</h2>\n<p>Returns monthly aggregated income and expense totals, useful for visualizing financial trends over time.</p>\n<h3 id=\"access\">Access</h3>\n<p>ANALYST and ADMIN only — returns 403 for Viewer</p>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>Results are grouped by month in YYYY-MM format and ordered ascending</p>\n</li>\n<li><p>Each month entry contains separate income and expense totals</p>\n</li>\n<li><p>Months with only income or only expense will show 0 for the missing type</p>\n</li>\n<li><p>Computed using SQL DATE_FORMAT and GROUP BY — efficient for large datasets</p>\n</li>\n<li><p>Soft deleted records are excluded</p>\n</li>\n</ul>\n<h3 id=\"responses\">Responses</h3>\n<ul>\n<li><p><code>200</code> Monthly trends fetched successfully — returns array of month, income, expense</p>\n</li>\n<li><p><code>401</code> Access token is missing or invalid</p>\n</li>\n<li><p><code>403</code> You do not have permission to perform this action</p>\n</li>\n</ul>\n","urlObject":{"protocol":"http","port":"4000","path":["api","v1","dashboard","trends"],"host":["localhost"],"query":[],"variable":[]}},"response":[{"id":"15e44144-d64d-4649-90c1-058c83bb13b9","name":"trends","originalRequest":{"method":"GET","header":[],"body":{"mode":"raw","raw":""},"url":"http://localhost:4000/api/v1/dashboard/trends"},"status":"OK","code":200,"_postman_previewlanguage":null,"header":[{"key":"X-Powered-By","value":"Express"},{"key":"Access-Control-Allow-Origin","value":"*"},{"key":"Content-Type","value":"application/json; charset=utf-8"},{"key":"Content-Length","value":"291"},{"key":"ETag","value":"W/\"123-dr4by516C49cUKa8PC9FCpLN76Y\""},{"key":"Date","value":"Mon, 06 Apr 2026 12:05:37 GMT"},{"key":"Connection","value":"keep-alive"},{"key":"Keep-Alive","value":"timeout=5"}],"cookie":[],"responseTime":null,"body":"{\n    \"success\": true,\n    \"statusCode\": 200,\n    \"message\": \"Monthly trends fetched successfully\",\n    \"data\": [\n        {\n            \"month\": \"2026-01\",\n            \"income\": 85000,\n            \"expense\": 4850.5\n        },\n        {\n            \"month\": \"2026-02\",\n            \"income\": 15000,\n            \"expense\": 10350\n        },\n        {\n            \"month\": \"2026-03\",\n            \"income\": 117000,\n            \"expense\": 29300\n        },\n        {\n            \"month\": \"2026-04\",\n            \"income\": 0,\n            \"expense\": 5000\n        }\n    ]\n}"}],"_postman_id":"d4572c96-f256-41af-a83a-b39591432183"}],"id":"90dd661d-6e41-45d8-9b8b-af283fd1c921","description":"<h2 id=\"dashboard-analytics\">Dashboard Analytics</h2>\n<p>This module provides aggregated financial insights and analytics for monitoring the overall financial health of the system.</p>\n<h3 id=\"access\">Access</h3>\n<ul>\n<li><p><strong>Summary &amp; Recent Activity</strong> — all roles (ADMIN, ANALYST, VIEWER)</p>\n</li>\n<li><p><strong>Category Breakdown &amp; Monthly Trends</strong> — ANALYST and ADMIN only</p>\n</li>\n<li><p>VIEWER has limited access — creator details are hidden in recent activity</p>\n</li>\n</ul>\n<h3 id=\"notes\">Notes</h3>\n<ul>\n<li><p>All analytics are computed directly from the database using SQL aggregations — no in-memory computation</p>\n</li>\n<li><p>Soft deleted records are excluded from all analytics</p>\n</li>\n<li><p>Summary supports optional date range filtering for period-specific insights</p>\n</li>\n<li><p>Monthly trends are returned in ascending order by month</p>\n</li>\n</ul>\n<h3 id=\"endpoints\">Endpoints</h3>\n<ul>\n<li><p><code>GET /dashboard/summary</code> — All roles — Total income, expenses and net balance</p>\n</li>\n<li><p><code>GET /dashboard/recent-activity</code> — All roles — Latest N financial records</p>\n</li>\n<li><p><code>GET /dashboard/category-breakdown</code> — ANALYST, ADMIN — Totals grouped by type and category</p>\n</li>\n<li><p><code>GET /dashboard/monthly-trends</code> — ANALYST, ADMIN — Monthly income vs expense trends</p>\n</li>\n</ul>\n","_postman_id":"90dd661d-6e41-45d8-9b8b-af283fd1c921"}]}