diff --git a/.gitignore b/.gitignore index cf7d62c..e9e8977 100644 Binary files a/.gitignore and b/.gitignore differ diff --git a/backend/package-lock.json b/backend/package-lock.json index 187b733..9b4824e 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -9,9 +9,11 @@ "version": "1.0.0", "dependencies": { "bcryptjs": "^2.4.3", + "compression": "^1.8.1", "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.19.2", + "express-rate-limit": "^8.5.2", "helmet": "^7.1.0", "jsonwebtoken": "^9.0.2", "morgan": "^1.10.0", @@ -264,6 +266,45 @@ "fsevents": "~2.3.2" } }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -539,6 +580,24 @@ "url": "https://opencollective.com/express" } }, + "node_modules/express-rate-limit": { + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz", + "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -762,6 +821,15 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", diff --git a/backend/package.json b/backend/package.json index 56e96c0..e047ecd 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,4 +1,4 @@ -{ +{ "name": "reimbursement-backend", "version": "1.0.0", "private": true, @@ -15,9 +15,11 @@ }, "dependencies": { "bcryptjs": "^2.4.3", + "compression": "^1.8.1", "cors": "^2.8.5", "dotenv": "^16.4.5", "express": "^4.19.2", + "express-rate-limit": "^8.5.2", "helmet": "^7.1.0", "jsonwebtoken": "^9.0.2", "morgan": "^1.10.0", diff --git a/backend/src/app.js b/backend/src/app.js index 570990d..05b0d58 100644 --- a/backend/src/app.js +++ b/backend/src/app.js @@ -1,6 +1,8 @@ import cors from "cors"; import express from "express"; import helmet from "helmet"; +import compression from "compression"; +import rateLimit from "express-rate-limit"; import morgan from "morgan"; import routes from "./routes/index.js"; import { errorHandler } from "./middleware/errorHandler.js"; @@ -9,6 +11,8 @@ import { env } from "./config/env.js"; const app = express(); app.use(helmet()); +app.use(compression()); +app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 })); app.use(cors({ origin: env.FRONTEND_URL })); app.use(morgan("dev")); app.use(express.json({ limit: "5mb" })); diff --git a/backend/src/db/migrations/001_init_users.sql b/backend/src/db/migrations/001_init_users.sql deleted file mode 100644 index a67fd8d..0000000 --- a/backend/src/db/migrations/001_init_users.sql +++ /dev/null @@ -1,17 +0,0 @@ -CREATE TABLE IF NOT EXISTS companies ( - id SERIAL PRIMARY KEY, - name TEXT NOT NULL, - country_code VARCHAR(4) NOT NULL, - default_currency VARCHAR(8) NOT NULL, - created_at TIMESTAMP DEFAULT NOW() -); - -CREATE TABLE IF NOT EXISTS users ( - id SERIAL PRIMARY KEY, - company_id INT REFERENCES companies(id), - full_name TEXT NOT NULL, - email TEXT UNIQUE NOT NULL, - password_hash TEXT NOT NULL, - role VARCHAR(20) NOT NULL, - created_at TIMESTAMP DEFAULT NOW() -); diff --git a/backend/src/modules/ai/ai.controller.js b/backend/src/modules/ai/ai.controller.js deleted file mode 100644 index 2ab8cfd..0000000 --- a/backend/src/modules/ai/ai.controller.js +++ /dev/null @@ -1,7 +0,0 @@ -import { asyncHandler } from "../../utils/asyncHandler.js"; -import { scoreExpenseRisk } from "../../services/riskScoring.service.js"; - -export const score = asyncHandler(async (req, res) => { - const risk = scoreExpenseRisk(req.body); - res.json({ risk }); -}); diff --git a/backend/src/modules/ai/ai.model.js b/backend/src/modules/ai/ai.model.js deleted file mode 100644 index 26f5b1f..0000000 --- a/backend/src/modules/ai/ai.model.js +++ /dev/null @@ -1,3 +0,0 @@ -export const aiModel = { - version: "mock-v1" -}; diff --git a/backend/src/modules/ai/ai.routes.js b/backend/src/modules/ai/ai.routes.js deleted file mode 100644 index b525544..0000000 --- a/backend/src/modules/ai/ai.routes.js +++ /dev/null @@ -1,9 +0,0 @@ -import { Router } from "express"; -import { authenticate } from "../../middleware/authenticate.js"; -import { score } from "./ai.controller.js"; - -const router = Router(); -router.use(authenticate); -router.post("/risk-score", score); - -export default router; diff --git a/backend/src/routes/index.js b/backend/src/routes/index.js index 2c2de1a..f6bd91e 100644 --- a/backend/src/routes/index.js +++ b/backend/src/routes/index.js @@ -7,7 +7,6 @@ import approvalRoutes from "../modules/approvals/approvals.routes.js"; import workflowRoutes from "../modules/workflows/workflows.routes.js"; import analyticsRoutes from "../modules/analytics/analytics.routes.js"; import notificationRoutes from "../modules/notifications/notifications.routes.js"; -import aiRoutes from "../modules/ai/ai.routes.js"; //these are routes @@ -20,6 +19,5 @@ router.use("/approvals", approvalRoutes); router.use("/workflows", workflowRoutes); router.use("/analytics", analyticsRoutes); router.use("/notifications", notificationRoutes); -router.use("/ai", aiRoutes); export default router; diff --git a/backend/src/services/ocr.service.js b/backend/src/services/ocr.service.js deleted file mode 100644 index e0d4edf..0000000 --- a/backend/src/services/ocr.service.js +++ /dev/null @@ -1,9 +0,0 @@ -export async function parseReceiptWithOcr(_base64Image) { - return { - merchant: "Sample Store", - amount: 1299.5, - currency: "INR", - category: "Travel", - expenseDate: new Date().toISOString().slice(0, 10) - }; -} diff --git a/backend/src/services/riskScoring.service.js b/backend/src/services/riskScoring.service.js deleted file mode 100644 index 9efeab4..0000000 --- a/backend/src/services/riskScoring.service.js +++ /dev/null @@ -1,7 +0,0 @@ -export function scoreExpenseRisk(expense) { - let score = 10; - if (Number(expense.amount_company || 0) > 50000) score += 45; - if (expense.category === "Other") score += 10; - if (!expense.receipt_url) score += 20; - return { score, label: score >= 60 ? "HIGH" : score >= 30 ? "MEDIUM" : "LOW" }; -} diff --git a/backend/src/services/smartApproval.service.js b/backend/src/services/smartApproval.service.js deleted file mode 100644 index 89a62c8..0000000 --- a/backend/src/services/smartApproval.service.js +++ /dev/null @@ -1,5 +0,0 @@ -export function suggestApprovalPath({ amountCompany, managerFirstEnabled }) { - if (managerFirstEnabled) return ["MANAGER", "FINANCE"]; - if (amountCompany > 100000) return ["MANAGER", "FINANCE", "ADMIN"]; - return ["MANAGER", "FINANCE"]; -}