Skip to content

Conversation

ajaykuraparthi
Copy link

@ajaykuraparthi ajaykuraparthi commented Sep 5, 2025

Summary

This PR fixes the "Login as Vigy" button which previously redirected to a 404 page.

Changes

  • Corrected routing configuration for Vigy login.
  • Added Vigy login page component and ensured deployment compatibility.
  • Verified that clicking "Login as Vigy" now correctly opens the Vigy login form.

Related Issue

Fixes #2638

Screenshots

(Before: 404 error, After: working Vigy login form)

Notes

Tested on Chrome and Edge (Windows 11). Working as expected.

Summary by CodeRabbit

  • New Features

    • Public Vigy registration/login API and client flows; added Vigy Login and Dashboard pages and top-level routes (/vigy-login, /vigy-form, /vigy-dashboard).
    • Added root status endpoint, Vigy test endpoint, and Google OAuth test route.
  • Improvements

    • Hardened CORS and session cookie settings; default backend port now 5000.
    • App no longer exits if DB is unreachable in development.
    • Updated subscribe flow to no longer emit an explicit success response; improved Google OAuth validation and redirects.
    • Updated “Login as Vigy” link to /vigy-login.
  • Chores

    • Environment setup script and test-user creation script; minor packaging script formatting.

Copy link
Contributor

coderabbitai bot commented Sep 5, 2025

Walkthrough

Adds a Vigy feature (model, controllers, routes, frontend pages), updates server configuration (CORS, sessions, port, DB error handling), introduces env/setup and test-user scripts, adjusts OAuth checks and redirects, and contains several unresolved merge-conflict markers in middleware/routes.

Changes

Cohort / File(s) Summary
Server bootstrap & config
backend/app.js, backend/config/config.js, backend/config/db.js
Mounts /api/vigy, adds root and vigy test endpoints, configures CORS from FRONTEND_URL with credentials, strengthens session cookie options and SESSION_SECRET default, changes default PORT to 5000, and replaces process.exit on Mongo connection failure with a warning. Merge-conflict markers present in app.js.
Google OAuth / Passport
backend/middlewares/Passport.js, backend/routes/authRoutes.js
Adds runtime checks for GOOGLE_CLIENT_ID/SECRET, computes a resolved callback URL (dev default to localhost:5000), switches OAuth redirects to use FRONTEND_URL, and updates failure/success redirects. Merge-conflict markers remain around callbackURL.
Vigy backend feature
backend/models/Vigy.js, backend/controllers/vigyController.js, backend/routes/vigyRoutes.js, backend/createTestUser.js
Adds Mongoose Vigy model (hashed passwords, comparePassword, getPublicProfile), controller handlers for register/login/profile/update with JWT token generation, an in-memory dev vigyRoutes router (register/login/profile stubs), and a test-user seeder script.
Subscribe API
backend/routes/subscribe.js
Minor reordering and formatting; input validation persists. Success response behavior changed (no explicit success response emitted in try block). Error handling preserved.
Env & tooling scripts
backend/setup-env.js, backend/package.json
Adds setup-env.js to write a .env template with generated JWT/SESSION secrets; package.json only whitespace adjustments.
Frontend routing & auth links
src/App.jsx, src/User/pages/UserAuth/UserAuth.jsx
Registers routes /vigy-login, /vigy-form, /vigy-dashboard and updates the "Login as Vigy" link to point to /vigy-login.
Vigy frontend pages
src/Admin/Pages/VigyLogin.jsx, src/Admin/Pages/VigyDashboard.jsx, src/Admin/Pages/VigyForm.jsx
Adds VigyLogin (API auth, localStorage token/user, Google OAuth redirect), VigyDashboard (client-side protected view, static stats), and updates VigyForm to POST JSON registration to /api/vigy/register (includes password field).
Other
backend/middlewares/*, backend/routes/*
Miscellaneous middleware/route wiring updates across auth and subscribe files; several files contain unresolved merge conflict markers requiring manual resolution.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User (Browser)
  participant FE as Frontend (VigyLogin/VigyForm)
  participant BE as Backend (/api/vigy)
  participant DB as MongoDB

  rect rgba(224,240,255,0.35)
    note over U,FE: Login flow
    U->>FE: submit credentials
    FE->>BE: POST /api/vigy/login {email,password}
    BE->>DB: find user, verify password
    DB-->>BE: user doc / not found
    BE-->>FE: 200 {token, publicProfile} or 401/403
    FE-->>U: store token, redirect /vigy-dashboard
  end

  rect rgba(230,255,230,0.35)
    note over U,FE: Registration flow
    U->>FE: submit registration form
    FE->>BE: POST /api/vigy/register {profile + password}
    BE->>DB: validate uniqueness, create user
    DB-->>BE: saved doc or duplicate/error
    BE-->>FE: 201 or 400/500
    FE-->>U: show success / error
  end
Loading
sequenceDiagram
  autonumber
  actor U as User (Browser)
  participant FE as Frontend
  participant BE as Backend (/auth/google)
  participant G as Google OAuth

  rect rgba(255,245,230,0.35)
    U->>FE: click "Continue with Google"
    FE->>BE: GET /auth/google
    BE->>BE: validate GOOGLE_CLIENT_ID/SECRET & resolved callback URL
    BE-->>U: redirect to Google or 500 if misconfigured
    U->>G: consent
    G-->>BE: callback -> /auth/google/callback
    BE-->>FE: redirect to FRONTEND_URL with success/error query
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • codervivek5

Poem

Hop hop, I wired the burrow tight,
New routes and tokens snug tonight.
From 404 to dashboard glow,
OAuth and seeds now help you grow.
Thump—Vigy hops, the pathways flow. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The PR includes multiple substantive changes beyond the routing/UI fix that appear out of scope for issue #2638: new backend Vigy model/controllers/routes and an in-memory API, session/CORS and default port changes, removal of process.exit(1) in db.js, a setup-env script that writes a .env with generated secrets, a createTestUser script, and a behavioral change in subscribe.js (removed success response); additionally backend/middlewares/Passport.js still contains unresolved merge conflict markers which is a blocker. These additions expand the review surface and introduce risk unrelated to the single UI routing bugfix. Resolve the merge conflict markers in backend/middlewares/Passport.js immediately, and split or remove unrelated backend/tooling changes (Vigy model/controllers/routes, setup-env, createTestUser, config port/DB behavior changes, subscribe.js behavioral change) into separate focused PRs so this branch only contains the routing/UI fix; then run CI/tests, verify the Vercel deployment, and ensure no sensitive secrets are committed before merging.
✅ Passed checks (4 passed)
Check name Status Explanation
Title Check ✅ Passed The title is concise and accurately summarizes the primary user-facing change: correcting the "Login as Vigy" routing to address issue #2638. It clearly signals the intent and is specific enough for a reviewer scanning PR history, even though the changeset also includes additional Vigy-related pages and backend additions that the title does not enumerate. Overall the title matches the main fix described in the PR.
Linked Issues Check ✅ Passed The changes directly address linked issue #2638: the "Login as Vigy" link now points to a dedicated /vigy-login route, the VigyLogin component was added, and App.jsx registers the new route so the login flow is restored; screenshots and manual test notes were provided. The PR therefore fulfills the primary objectives of confirming the 404, correcting the route, ensuring the login component exists, and restoring the user flow. Based on the provided summaries, coding requirements in issue #2638 are met.
Description Check ✅ Passed The PR description follows the repository template by summarizing the fix, listing the core changes, referencing the related issue (Fixes #2638), and noting screenshots and test environments; this gives reviewers sufficient context to validate the routing fix. It could be improved slightly by using the exact "Closes #2638" syntax to auto-link the issue and by adding brief verification steps and the exact route(s) changed (e.g., /vigy-login). Overall the description is mostly complete and usable for review.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

vercel bot commented Sep 5, 2025

@ajaykuraparthi is attempting to deploy a commit to the Vivek Prajapati's projects Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 32

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
src/Admin/Pages/VigyForm.jsx (4)

141-143: JSX pattern escapes are broken; use [0-9] or escape backslashes.

Current "\d{12}" becomes "d{12}" in JSX.

-             pattern="\d{12}"
+             pattern="[0-9]{12}"

169-171: Fix phone pattern escape.

-             pattern="\d{10}"
+             pattern="[0-9]{10}"

201-205: Fix bank account number pattern escape.

-             pattern="\d{8,18}"
+             pattern="[0-9]{8,18}"

245-251: Remove required from file inputs or support multipart uploads
The panCard (and the other file input at lines 253–260) aren’t included in the JSON payload you currently send, so they’re never uploaded. Either switch your submission to use FormData (and a backend endpoint that accepts multipart) or drop the required prop:

-            required
backend/createTestUser.js (1)

1-62: Prevent accidental prod seeding; ensure clean connect/disconnect flow.

  • Add a production guard to avoid creating approved test users in live data.
  • Prefer await mongoose.connect(...) and await mongoose.disconnect() to ensure deterministic teardown.
-const mongoose = require('mongoose');
-const Vigy = require('./models/Vigy');
-const config = require('./config/config');
+const mongoose = require('mongoose');
+const Vigy = require('./models/Vigy');
+const config = require('./config/config');

 // Connect to MongoDB
-mongoose.connect(config.mongoURI)
-  .then(() => console.log('Connected to MongoDB'))
-  .catch(err => console.error('MongoDB connection error:', err));
+async function connect() {
+  await mongoose.connect(config.mongoURI);
+  console.log('Connected to MongoDB');
+}

 // Test user data
 const testUser = {
@@
   isVerified: true
 };

 async function createTestUser() {
   try {
+    if (process.env.NODE_ENV === 'production') {
+      console.error('Refusing to seed test user in production.');
+      return;
+    }
+    await connect();
     // Check if user already exists
     const existingUser = await Vigy.findOne({ email: testUser.email });
@@
   } catch (error) {
     console.error('Error creating test user:', error);
   } finally {
-    mongoose.connection.close();
+    await mongoose.disconnect();
   }
 }

 createTestUser();
🧹 Nitpick comments (21)
src/Admin/Pages/VigyDashboard.jsx (2)

15-16: Use history-replacing redirects to avoid back-stack loops.

Replace pushes to /vigy-login with replace: true.

-      navigate('/vigy-login');
+      navigate('/vigy-login', { replace: true });
@@
-      navigate('/vigy-login');
+      navigate('/vigy-login', { replace: true });
@@
-    navigate('/vigy-login');
+    navigate('/vigy-login', { replace: true });

Also applies to: 23-24, 30-31


9-25: Optionally validate token on mount.

Consider a lightweight /api/vigy/profile ping; if 401, logout and redirect.

src/Admin/Pages/VigyForm.jsx (4)

299-312: Dead code: FormData is built but not used.

Remove to avoid confusion, or switch to multipart and use it.

-  const formDataToSend = new FormData();
-
-  // Append all form fields to formDataToSend
-  Object.keys(formData).forEach(tab => {
-    Object.keys(formData[tab]).forEach(field => {
-      if (field === 'panCard' || field === 'addressProof' || field === 'profilePicture') {
-        formDataToSend.append(field, formData[tab][field], formData[tab][field].name);
-      } else {
-        formDataToSend.append(field, formData[tab][field]);
-      }
-    });
-  });

334-339: Centralize API base and avoid hardcoding env switch in components.

Use a single config (e.g., import { API_BASE } from config) and append /api/vigy/register.


341-345: Redirect after successful registration.

Provide a clear next step.

        alert('Registration submitted successfully! Please wait for approval.');
-       // You can redirect to login page or show success message
+       // Redirect to Vigy login
+       window.location.replace('/vigy-login');

240-268: 50KB limit for documents may be too strict.

Confirm backend constraints; typical KYC scans exceed 50KB.

backend/models/Vigy.js (5)

10-16: Tighten input validation (email/phone/IFSC/DOB).

Add format checks and a simple age gate.

   email: {
     type: String,
     required: true,
     unique: true,
     trim: true,
-    lowercase: true
+    lowercase: true,
+    match: [/^\S+@\S+\.\S+$/, 'Invalid email'],
   },
 
   phoneNumber: {
     type: String,
     required: true,
-    trim: true
+    trim: true,
+    match: [/^\d{10}$/, 'Phone number must be 10 digits'],
   },
 
   ifscCode: {
     type: String,
     required: true,
-    trim: true
+    trim: true,
+    match: [/^[A-Z]{4}0[A-Z0-9]{6}$/, 'Invalid IFSC code'],
   }
 
   dob: {
     type: Date,
-    required: true
+    required: true,
+    validate: {
+      validator: v => {
+        const now = new Date();
+        const min = new Date(now.getFullYear() - 18, now.getMonth(), now.getDate());
+        return v <= min;
+      },
+      message: 'User must be at least 18 years old',
+    }
   },

Also applies to: 22-26, 69-73, 44-47


109-116: Prefer Mongoose-managed timestamps.

updatedAt won’t auto-update as written. Use timestamps: true and drop manual date fields.

-const vigySchema = new mongoose.Schema({
+const vigySchema = new mongoose.Schema({
   ...
-  createdAt: {
-    type: Date,
-    default: Date.now
-  },
-  updatedAt: {
-    type: Date,
-    default: Date.now
-  }
-});
+}, { timestamps: true });

Also applies to: 4-4, 117-117


120-130: Hash on updates, not just creates.

If passwords can be updated via findOneAndUpdate, add a hook to hash the new value.

// Add alongside the pre('save') hook
vigySchema.pre('findOneAndUpdate', async function (next) {
  const update = this.getUpdate() || {};
  const pwd = update.password || (update.$set && update.$set.password);
  if (!pwd) return next();
  try {
    const salt = await bcrypt.genSalt(10);
    const hashed = await bcrypt.hash(pwd, salt);
    if (update.$set && update.$set.password) update.$set.password = hashed;
    else update.password = hashed;
    this.setUpdate(update);
    next();
  } catch (err) {
    next(err);
  }
});

138-145: Enforce safe serialization by default.

Add a toJSON/toObject transform so sensitive fields are never leaked even if callers forget getPublicProfile().

vigySchema.set('toJSON', {
  transform: (_doc, ret) => {
    delete ret.password;
    delete ret.aadhaarNumber;
    delete ret.bankDetails;
    delete ret.documents;
    delete ret.__v;
    return ret;
  }
});
vigySchema.set('toObject', { transform: vigySchema.get('toJSON').transform });

10-16: Ensure unique indexes exist in the database.

unique: true adds a unique index; confirm indexes are built in prod and backfill duplicates before enabling.

You can run a one-time migration to create indexes and resolve duplicates on email and aadhaarNumber.

Also applies to: 32-38

src/User/pages/UserAuth/UserAuth.jsx (1)

338-344: Expose “Login as Vigy” on mobile too.

Left panel is hidden on small screens; add a mobile-visible Vigy link next to the Admin one to keep parity.

   <p className="sm:hidden text-sm text-center  pb-0 mt-2">
     <Link
       to="/admin-verification"
       className="bg-[#2d3e40] text-green-500 px-6 rounded-full hover:bg-opacity-90 transition duration-300"
     >
       Login as Admin
     </Link>
   </p>
+  <p className="sm:hidden text-sm text-center mt-2">
+    <Link
+      to="/vigy-login"
+      className="bg-[#f9efe4] text-[#2d3e40] px-6 rounded-full border border-[#2d3e40] hover:bg-[#2d3e40] hover:text-white transition duration-300"
+    >
+      Login as Vigy
+    </Link>
+  </p>

(Repeat for the signup side if desired.)

Also applies to: 481-488

backend/app.js (2)

17-20: CORS: allowlist and previews.

Consider a dynamic origin function to allow the configured FRONTEND_URL, localhost, and Vercel preview URLs. Keeps credentials working without overexposing.

-app.use(cors({
-  origin: process.env.FRONTEND_URL || "http://localhost:3000",
-  credentials: true
-}));
+const allowlist = [
+  process.env.FRONTEND_URL,
+  'http://localhost:3000',
+  'https://vigy-bag.vercel.app'
+].filter(Boolean);
+app.use(cors({
+  origin(origin, cb) {
+    if (!origin || allowlist.some(o => (o instanceof RegExp ? o.test(origin) : o === origin))) return cb(null, true);
+    cb(new Error(`CORS blocked: ${origin}`));
+  },
+  credentials: true
+}));

37-49: Test endpoints are helpful; minor consistency nit.

Expose resolvedCallbackUrl via the test route to mirror middleware calculations and avoid confusion with a hardcoded fallback.

 app.get("/auth/google/test", (req, res) => {
   const hasClientId = !!process.env.GOOGLE_CLIENT_ID;
   const hasClientSecret = !!process.env.GOOGLE_CLIENT_SECRET;
-  const callbackUrl = process.env.GOOGLE_CALLBACK_URL || "http://localhost:5000/auth/google/callback";
+  const callbackUrl = process.env.GOOGLE_CALLBACK_URL || "http://localhost:5000/auth/google/callback"; // mirror middleware resolution

   res.json({
     message: "Google OAuth Configuration Test",
     status: hasClientId && hasClientSecret ? "configured" : "missing_credentials",
     configuration: {
       hasClientId,
       hasClientSecret,
       callbackUrl,
       frontendUrl: process.env.FRONTEND_URL || "http://localhost:3000"
     }
   });
 });

Also applies to: 60-66, 69-84

src/Admin/Pages/VigyLogin.jsx (2)

35-38: Avoid hard-coded backend URLs; centralize via env-driven base URL.

This eases deploys across environments and prevents surprises in previews.

Apply:

-      const apiUrl = process.env.NODE_ENV === 'production' 
-        ? 'https://vigybag-backend.onrender.com/api/vigy/login'
-        : 'http://localhost:5000/api/vigy/login';
+      const apiBase =
+        (typeof import.meta !== 'undefined' && import.meta.env?.VITE_API_BASE_URL) ||
+        process.env.REACT_APP_API_BASE_URL ||
+        (process.env.NODE_ENV === 'production'
+          ? 'https://vigybag-backend.onrender.com'
+          : 'http://localhost:5000');
+      const apiUrl = `${apiBase}/api/vigy/login`;

28-69: Add request timeout and (optional) credential mode for cookie-based auth.

Prevents hanging UIs and prepares for HttpOnly-cookie auth.

-      const response = await axios.post(apiUrl, formData);
+      const response = await axios.post(apiUrl, formData, {
+        timeout: 10000,
+        withCredentials: true
+      });
backend/routes/vigyRoutes.js (2)

126-141: Protected routes aren’t protected.

Add auth middleware (JWT verify) or remove these endpoints from the dev router.

I can wire a minimal authenticateJWT middleware if desired.


1-144: Mount correct implementation per environment.

To avoid conflicts with DB-backed routes, mount conditionally in app.js.

Add in backend/app.js:

// Pseudocode
if (process.env.NODE_ENV === 'production') {
  app.use('/api/vigy', require('./routes/vigyDbRoutes')); // real DB-backed routes
} else {
  app.use('/api/vigy', require('./routes/vigyRoutes')); // in-memory dev routes
}
backend/routes/authRoutes.js (1)

23-26: Propagate flow context to Google (state) so callback can branch.

Wrap authenticate to pass a dynamic “state” from the query (default to “user”).

-  passport.authenticate("google", {
-    scope: ["profile", "email"],
-  })
+  (req, res, next) => {
+    const state = req.query.flow || 'user';
+    return passport.authenticate("google", {
+      scope: ["profile", "email"],
+      state
+    })(req, res, next);
+  }

Note: If your Google strategy isn’t already set with state: true, enable it.

backend/controllers/vigyController.js (2)

126-132: Prefer status constants/enums

Replace string literals with a shared enum to avoid typos and allow centralized changes.


1-227: Operational hardening recommendations

  • Add rate limiting and incremental lockouts on /login.
  • Store Aadhaar/bank details encrypted at rest; consider field-level encryption.
  • Consider issuing JWT in an HttpOnly, Secure, SameSite=Strict cookie for web flows.
  • Centralize validation (e.g., celebrate/express-validator) and reuse schemas for register/update.
  • Ensure CORS and cookie settings are strict in production.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2cf10f9 and b4f6540.

⛔ Files ignored due to path filters (1)
  • backend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (16)
  • backend/app.js (1 hunks)
  • backend/config/config.js (1 hunks)
  • backend/config/db.js (1 hunks)
  • backend/controllers/vigyController.js (1 hunks)
  • backend/createTestUser.js (1 hunks)
  • backend/middlewares/Passport.js (1 hunks)
  • backend/models/Vigy.js (1 hunks)
  • backend/package.json (3 hunks)
  • backend/routes/authRoutes.js (1 hunks)
  • backend/routes/vigyRoutes.js (1 hunks)
  • backend/setup-env.js (1 hunks)
  • src/Admin/Pages/VigyDashboard.jsx (1 hunks)
  • src/Admin/Pages/VigyForm.jsx (1 hunks)
  • src/Admin/Pages/VigyLogin.jsx (1 hunks)
  • src/App.jsx (2 hunks)
  • src/User/pages/UserAuth/UserAuth.jsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (11)
src/Admin/Pages/VigyLogin.jsx (2)
src/Admin/Pages/VigyForm.jsx (3)
  • formData (11-17)
  • handleInputChange (47-74)
  • handleSubmit (295-350)
src/Admin/Pages/AdminLogin.jsx (2)
  • email (6-86)
  • event (13-28)
backend/config/config.js (1)
backend/server.js (1)
  • console (11-13)
backend/controllers/vigyController.js (2)
backend/createTestUser.js (1)
  • Vigy (2-2)
backend/routes/adminRegistrationRoutes.js (1)
  • req (14-82)
backend/createTestUser.js (3)
backend/models/Vigy.js (1)
  • mongoose (1-1)
backend/controllers/vigyController.js (5)
  • Vigy (1-1)
  • vigy (49-67)
  • vigy (107-107)
  • vigy (159-159)
  • vigy (193-197)
backend/config/config.js (1)
  • config (6-14)
src/Admin/Pages/VigyForm.jsx (2)
src/User/pages/AdditionalDetails.jsx (2)
  • email (5-83)
  • e (10-36)
backend/routes/adminRegistrationRoutes.js (1)
  • req (14-82)
src/App.jsx (3)
src/Admin/Pages/VigyLogin.jsx (1)
  • VigyLogin (8-207)
src/Admin/Pages/VigyForm.jsx (1)
  • VigyForm (9-432)
src/Admin/Pages/VigyDashboard.jsx (1)
  • VigyDashboard (5-174)
backend/middlewares/Passport.js (2)
backend/app.js (1)
  • passport (5-5)
backend/routes/authRoutes.js (1)
  • passport (3-3)
backend/app.js (3)
backend/server.js (1)
  • app (2-2)
backend/routes/vigyRoutes.js (2)
  • express (1-1)
  • req (78-78)
backend/controllers/vigyController.js (2)
  • req (16-32)
  • req (96-96)
backend/models/Vigy.js (2)
backend/controllers/authController.js (1)
  • req (10-59)
backend/routes/adminRegistrationRoutes.js (1)
  • req (14-82)
backend/routes/authRoutes.js (2)
backend/app.js (1)
  • passport (5-5)
backend/middlewares/Passport.js (1)
  • passport (1-1)
backend/routes/vigyRoutes.js (2)
backend/controllers/vigyController.js (2)
  • req (16-32)
  • req (96-96)
backend/routes/adminRegistrationRoutes.js (1)
  • req (14-82)
🔇 Additional comments (10)
backend/package.json (1)

37-37: Retain mongoose-findorcreate dependency
Used in backend/models/User.js via userSchema.plugin(findOrCreate).

Likely an incorrect or invalid review comment.

src/Admin/Pages/VigyDashboard.jsx (1)

14-16: Verified /vigy-login route and its usage
The route is registered in App.jsx and the “Login as Vigy” link in UserAuth.jsx correctly points to /vigy-login.

backend/models/Vigy.js (1)

133-135: LGTM: password comparison method is correct.

src/User/pages/UserAuth/UserAuth.jsx (2)

212-216: Correct route: /vigy-login fixes the 404.

Change aligns the button with the new Vigy login route.


212-212: /vigy-login route exists and is accessible. App.jsx defines <Route path="/vigy-login" element={<VigyLogin/>}/> (line 273) at root level outside any auth guards, so casing and availability are correct; no redirect-loop risk.

src/App.jsx (1)

51-52: Imports for Vigy pages look correct.

These resolve to existing components and enable the new routes.

backend/app.js (1)

57-57: Mounting Vigy routes looks good.

This aligns frontend calls (e.g., /api/vigy/login and /api/vigy/register) with the router.

src/Admin/Pages/VigyLogin.jsx (1)

78-206: LGTM on UX and routing intent.

Form UX, loading state, error surfacing, and navigate('/vigy-dashboard') align with the PR goal.

backend/routes/authRoutes.js (2)

8-22: Preflight config check is good.

Helpful errors for misconfiguration.


1-46: End-to-end verification complete. FRONTEND_URL is configured in CORS and auth redirects, and the Google OAuth flow now lands on /vigy-dashboard as expected.

Comment on lines +23 to 36
secret: process.env.SESSION_SECRET || "Our little secret.",
resave: false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Sessions over cross-site: set trust proxy and sameSite.

Without app.set('trust proxy', 1) and sameSite: 'none' in production, secure cookies may be dropped in cross-site flows (e.g., OAuth).

 const app = express();
@@
 app.use(
   session({
     secret: process.env.SESSION_SECRET || "Our little secret.",
     resave: false,
     saveUninitialized: false,
     cookie: {
       secure: process.env.NODE_ENV === 'production',
       httpOnly: true,
-      maxAge: 24 * 60 * 60 * 1000 // 24 hours
+      sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax',
+      maxAge: 24 * 60 * 60 * 1000 // 24 hours
     }
   })
 );
+if (process.env.NODE_ENV === 'production') {
+  app.set('trust proxy', 1);
+}

Also applies to: 26-30

🤖 Prompt for AI Agents
In backend/app.js around lines 23-24 (and similarly lines 26-30) the Express app
is not configured to trust a proxy nor are session cookie options set for
cross-site flows; in production add app.set('trust proxy', 1) before mounting
the session middleware and update the session cookie options to include secure:
true and sameSite: 'none' (guard these settings behind NODE_ENV === 'production'
or equivalent so local/dev stays unchanged), ensuring the session secret remains
used from process.env.SESSION_SECRET.


const config = {
port: process.env.PORT || 3000,
port: process.env.PORT || 5000,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Port default changed to 5000 — verify server wiring and callbacks.

Ensure the HTTP server actually uses this config value and update any hardcoded localhost ports (OAuth callbacks, CORS, frontend API base URLs).


🏁 Script executed:

#!/bin/bash
# Is config.port used by the server?
rg -nP --glob '!**/node_modules/**' '\b(config\.port|process\.env\.PORT)\b' backend -C2

# Find hardcoded localhost ports (3000/5000) across repo
rg -nP --glob '!**/node_modules/**' 'localhost:(3000|5000)' -C2

# Common Google OAuth callback strings to verify
rg -nP --glob '!**/node_modules/**' 'google.*callback|/auth/google/callback' backend -C3

Length of output: 5660


Unify port defaults—remove hardcoded localhost URLs

• backend/routes/ContactRoute.js (line 7): import config and use config.port instead of process.env.PORT || 3001
• backend/app.js (lines 18 & 81): replace "http://localhost:3000" with process.env.FRONTEND_URL
• backend/app.js (line 72): replace default "http://localhost:5000/auth/google/callback" with process.env.GOOGLE_CALLBACK_URL or build from config.port
• backend/middlewares/Passport.js (line 18): use process.env.GOOGLE_CALLBACK_URL instead of hardcoded
• Frontend (src/Admin/Pages/VigyLogin.jsx lines 37 & 74; src/Admin/Pages/VigyForm.jsx line 337): use an env-based API base URL instead of http://localhost:5000

🤖 Prompt for AI Agents
In backend/config/config.js around line 7, the config currently uses a hardcoded
port fallback and other parts of the app expect env-driven URLs; update this
file to centralize env defaults by exporting port (process.env.PORT || 5000),
frontendUrl (process.env.FRONTEND_URL || 'http://localhost:3000'),
googleCallbackUrl (process.env.GOOGLE_CALLBACK_URL ||
`http://localhost:${port}/auth/google/callback`) and any API_BASE_URL if needed,
then ensure module.exports includes these values so other files
(ContactRoute.js, app.js, Passport.js, frontend callers) can import config.port,
config.frontendUrl, and config.googleCallbackUrl instead of using hardcoded
localhost strings or duplicating env logic.

Comment on lines +12 to 14
console.log("⚠️ MongoDB not available. Using in-memory fallback for development.");
// Don't exit for development - let the app continue
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Confirm an actual in-memory fallback exists and is wired.

This file only logs; ensure routes use a real store in dev.


🏁 Script executed:

#!/bin/bash
# Look for any in-memory store used by Vigy routes
rg -nP "(in-?memory|memory store|fallback).*vigy" backend -C3
rg -nP "router\\.|app\\.use\\(.*/api/vigy" -C2 backend

Length of output: 4643


Implement actual in-memory MongoDB fallback in development (backend/config/db.js:12–14)
Logging the fallback alone is insufficient—no in-memory store is wired up. Integrate and initialize a real in-memory database (e.g. MongoMemoryServer) and ensure all routes (including Vigy) use it when MongoDB is unavailable.

🤖 Prompt for AI Agents
In backend/config/db.js around lines 12–14, the code only logs that MongoDB is
unavailable but does not wire up a real in-memory fallback; implement a
MongoMemoryServer-based fallback for development: start MongoMemoryServer when
the real Mongo URI fails to connect (only in NODE_ENV !== 'production'), obtain
its URI and reconnect mongoose to that URI, ensure the returned connection
promise resolves before the app continues so all routes (including Vigy) use the
in-memory DB, surface the original connection error in the log, and add
shutdown/cleanup handlers to stop the MongoMemoryServer on process exit.

🛠️ Refactor suggestion

Don't silently continue on DB failure in non-dev. Gate by NODE_ENV.

Exiting in prod prevents partial-start bugs.

   } catch (err) {
     console.error("Error connecting to MongoDB:", err.message);
-    console.log("⚠️  MongoDB not available. Using in-memory fallback for development.");
-    // Don't exit for development - let the app continue
+    if (process.env.NODE_ENV !== "development" && process.env.NODE_ENV !== "test") {
+      console.error("MongoDB unavailable. Exiting (non-dev).");
+      process.exit(1);
+    }
+    console.warn("⚠️  MongoDB not available. Using in-memory fallback for development.");
+    // Keep the app running only in dev/test
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log("⚠️ MongoDB not available. Using in-memory fallback for development.");
// Don't exit for development - let the app continue
}
} catch (err) {
console.error("Error connecting to MongoDB:", err.message);
if (process.env.NODE_ENV !== "development" && process.env.NODE_ENV !== "test") {
console.error("MongoDB unavailable. Exiting (non-dev).");
process.exit(1);
}
console.warn("⚠️ MongoDB not available. Using in-memory fallback for development.");
// Keep the app running only in dev/test
}
🤖 Prompt for AI Agents
In backend/config/db.js around lines 12 to 14, the code currently logs a warning
and silently continues when MongoDB is unavailable; change this so the fallback
is only used in development by checking process.env.NODE_ENV === 'development',
and if NODE_ENV is anything else log the error (including any caught error
details) and exit the process with a non-zero code (e.g., process.exit(1));
ensure the fallback branch is guarded by the dev check so production/staging
never continues silently on DB failure.

Comment on lines +5 to +9
const generateToken = (vigyId) => {
return jwt.sign({ vigyId }, process.env.JWT_SECRET || 'mysecretkey', {
expiresIn: '7d'
});
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Eliminate insecure JWT secret fallback

Hard-coding a default ('mysecretkey') is unsafe; fail fast if JWT_SECRET is missing.

-const generateToken = (vigyId) => {
-  return jwt.sign({ vigyId }, process.env.JWT_SECRET || 'mysecretkey', {
-    expiresIn: '7d'
-  });
-};
+const generateToken = (vigyId) => {
+  const secret = process.env.JWT_SECRET;
+  if (!secret) {
+    throw new Error('JWT_SECRET is not configured');
+  }
+  return jwt.sign({ vigyId }, secret, { expiresIn: '7d' });
+};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const generateToken = (vigyId) => {
return jwt.sign({ vigyId }, process.env.JWT_SECRET || 'mysecretkey', {
expiresIn: '7d'
});
};
const generateToken = (vigyId) => {
const secret = process.env.JWT_SECRET;
if (!secret) {
throw new Error('JWT_SECRET is not configured');
}
return jwt.sign({ vigyId }, secret, { expiresIn: '7d' });
};
🤖 Prompt for AI Agents
In backend/controllers/vigyController.js around lines 5 to 9, the generateToken
function currently falls back to a hard-coded JWT secret which is insecure;
change it to require a configured secret by reading process.env.JWT_SECRET once
and throwing an explicit error (or returning a rejected promise) if it's
undefined/empty, then use that secret in jwt.sign so the app fails fast during
startup or token generation rather than using 'mysecretkey'.

Comment on lines +16 to +33
const {
fullname,
email,
password,
phoneNumber,
address,
aadhaarNumber,
gender,
dob,
bankAccountName,
bankAccountNumber,
bankName,
bankBranch,
ifscCode,
referralCode,
promotionalCode
} = req.body;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Validate and normalize registration input up-front

Add presence/type checks and sanitize to prevent malformed data and operator payloads.

 const registerVigy = async (req, res) => {
   try {
     const {
       fullname,
       email,
       password,
       phoneNumber,
       address,
       aadhaarNumber,
       gender,
       dob,
       bankAccountName,
       bankAccountNumber,
       bankName,
       bankBranch,
       ifscCode,
       referralCode,
       promotionalCode
     } = req.body;
+
+    // Basic type/format validation + normalization
+    const emailNorm = typeof email === 'string' ? email.trim().toLowerCase() : '';
+    const aadhaarNorm = typeof aadhaarNumber === 'string' ? aadhaarNumber.trim() : '';
+    if ([fullname, emailNorm, password, phoneNumber, address, aadhaarNorm, gender, dob].some(v => !v)) {
+      return res.status(400).json({ success: false, message: 'Missing required fields' });
+    }
+    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailNorm)) {
+      return res.status(400).json({ success: false, message: 'Invalid email' });
+    }
+    if (!/^\d{12}$/.test(aadhaarNorm)) {
+      return res.status(400).json({ success: false, message: 'Invalid Aadhaar number' });
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const {
fullname,
email,
password,
phoneNumber,
address,
aadhaarNumber,
gender,
dob,
bankAccountName,
bankAccountNumber,
bankName,
bankBranch,
ifscCode,
referralCode,
promotionalCode
} = req.body;
const {
fullname,
email,
password,
phoneNumber,
address,
aadhaarNumber,
gender,
dob,
bankAccountName,
bankAccountNumber,
bankName,
bankBranch,
ifscCode,
referralCode,
promotionalCode
} = req.body;
// Basic type/format validation + normalization
const emailNorm = typeof email === 'string' ? email.trim().toLowerCase() : '';
const aadhaarNorm = typeof aadhaarNumber === 'string' ? aadhaarNumber.trim() : '';
if ([fullname, emailNorm, password, phoneNumber, address, aadhaarNorm, gender, dob].some(v => !v)) {
return res.status(400).json({ success: false, message: 'Missing required fields' });
}
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailNorm)) {
return res.status(400).json({ success: false, message: 'Invalid email' });
}
if (!/^\d{12}$/.test(aadhaarNorm)) {
return res.status(400).json({ success: false, message: 'Invalid Aadhaar number' });
}
🤖 Prompt for AI Agents
In backend/controllers/vigyController.js around lines 16 to 33, the controller
currently destructures req.body without validating or normalizing inputs; add
upfront validation and sanitization: ensure required fields (fullname, email,
password) are present and of expected types, trim strings, lowercase and
validate email, strip non-digits from phoneNumber and validate length,
parse/validate dob, enforce Aadhaar and bankAccountNumber are numeric with
expected lengths, uppercase and validate IFSC format, normalize bankName/branch
strings, and treat referralCode/promotionalCode as optional; additionally reject
or ignore unexpected keys and return a 400 with clear messages on validation
failures (implement via a validation library like Joi/express-validator or a
small custom sanitizer before using values).

Comment on lines +319 to +320
password: 'defaultPassword123', // You might want to add a password field to the form
phoneNumber: formData.contact.phoneNumber || '',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Remove hardcoded default password from payload.

This is a security risk and creates identical credentials.

-       password: 'defaultPassword123', // You might want to add a password field to the form

Outside this hunk, either:

  • add password/confirm fields with strength rules, or
  • switch to OTP/set-password flow post-approval.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
password: 'defaultPassword123', // You might want to add a password field to the form
phoneNumber: formData.contact.phoneNumber || '',
phoneNumber: formData.contact.phoneNumber || '',
🤖 Prompt for AI Agents
In src/Admin/Pages/VigyForm.jsx around lines 319-320 the payload includes a
hardcoded password ('defaultPassword123'), which is a security risk; remove this
hardcoded value and instead either add password and confirm fields to the form
with client-side strength validation and include the user-supplied password in
the payload, or remove password from the creation payload entirely and implement
an OTP / set-password post-approval flow (send invite/OTP email and create
account only after password is set). Ensure validation is enforced and no
default or predictable password is ever sent in the request payload.

Comment on lines +39 to +48
const response = await axios.post(apiUrl, formData);

if (response.data.success) {
// Store token or user data
localStorage.setItem('vigyToken', response.data.token);
localStorage.setItem('vigyUser', JSON.stringify(response.data.user));

// Redirect to Vigy dashboard or appropriate page
navigate('/vigy-dashboard');
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Token in localStorage is vulnerable to XSS; wire “Remember me” and prefer HttpOnly cookies.

  • Best: issue an HttpOnly, Secure, SameSite=Lax cookie from the backend and remove localStorage usage.
  • If you must keep client storage, use sessionStorage by default and only persist to localStorage when “Remember me” is checked.

Minimal client-side wiring:

-        localStorage.setItem('vigyToken', response.data.token);
-        localStorage.setItem('vigyUser', JSON.stringify(response.data.user));
+        const storage = rememberMe ? localStorage : sessionStorage;
+        storage.setItem('vigyToken', response.data.token);
+        storage.setItem('vigyUser', JSON.stringify({
+          id: response.data.user.id,
+          email: response.data.user.email,
+          fullname: response.data.user.fullname
+        }));

And capture the checkbox:

-              <input
+              <input
                 type="checkbox"
                 className="mr-2 h-4 w-4 rounded border-gray-300 text-[#4a7c59] focus:ring-[#4a7c59]"
+                onChange={(e) => setRememberMe(e.target.checked)}
               />

Add state at the top:

-  const [loading, setLoading] = useState(false);
+  const [loading, setLoading] = useState(false);
+  const [rememberMe, setRememberMe] = useState(false);

Server-side (recommended): set a cookie and remove token storage; I can draft that if you want.

Also applies to: 134-142

🤖 Prompt for AI Agents
In src/Admin/Pages/VigyLogin.jsx around lines 39-48 and also apply same change
at 134-142: storing the auth token in localStorage is vulnerable to XSS; update
the login flow to stop writing tokens to localStorage and instead rely on the
backend to set an HttpOnly, Secure, SameSite=Lax cookie for authentication,
removing localStorage reads/writes; if a client-side persistence option is
required, add a "remember me" checkbox state at the top of the component and, on
successful login, store the token in sessionStorage by default and only copy it
to localStorage when the "remember me" checkbox is checked (leave server-set
HttpOnly cookie as the primary auth mechanism).

Comment on lines +71 to +76
const handleGoogleLogin = () => {
const googleAuthUrl = process.env.NODE_ENV === 'production'
? 'https://vigybag-backend.onrender.com/auth/google'
: 'http://localhost:5000/auth/google';
window.location.href = googleAuthUrl;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Google login flow may land on the wrong dashboard; pass flow context.

You redirect to “/vigy-dashboard” after form login, but Google callback currently redirects to “/dashboard”. Propagate a “vigy” flow signal and handle it in the backend.

-    const googleAuthUrl = process.env.NODE_ENV === 'production'
-      ? 'https://vigybag-backend.onrender.com/auth/google'
-      : 'http://localhost:5000/auth/google';
+    const base =
+      (typeof import.meta !== 'undefined' && import.meta.env?.VITE_API_BASE_URL) ||
+      process.env.REACT_APP_API_BASE_URL ||
+      (process.env.NODE_ENV === 'production'
+        ? 'https://vigybag-backend.onrender.com'
+        : 'http://localhost:5000');
+    const googleAuthUrl = `${base}/auth/google?flow=vigy`;

Pair with backend changes proposed in authRoutes.js to read state/flow and redirect to “/vigy-dashboard”.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleGoogleLogin = () => {
const googleAuthUrl = process.env.NODE_ENV === 'production'
? 'https://vigybag-backend.onrender.com/auth/google'
: 'http://localhost:5000/auth/google';
window.location.href = googleAuthUrl;
};
const handleGoogleLogin = () => {
const base =
(typeof import.meta !== 'undefined' && import.meta.env?.VITE_API_BASE_URL) ||
process.env.REACT_APP_API_BASE_URL ||
(process.env.NODE_ENV === 'production'
? 'https://vigybag-backend.onrender.com'
: 'http://localhost:5000');
const googleAuthUrl = `${base}/auth/google?flow=vigy`;
window.location.href = googleAuthUrl;
};
🤖 Prompt for AI Agents
In src/Admin/Pages/VigyLogin.jsx around lines 71 to 76, the Google OAuth
redirect does not include any flow context so the callback can’t distinguish
Vigy logins and ends up sending users to the wrong dashboard; update the
googleAuthUrl construction to append a state (or flow) query parameter (e.g.
state=vigy) in both production and development URLs (URL-encode the value or use
URLSearchParams) so the backend can read req.query.state (or req.query.flow) and
redirect to /vigy-dashboard accordingly.

Comment on lines +144 to +149
to="/forgot-password"
className="text-sm text-[#4a7c59] hover:underline"
>
Forgot password?
</Link>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify target exists for “/forgot-password”.

If this route is missing, users will hit another 404.

Run:


🏁 Script executed:

#!/bin/bash
rg -nP --type=ts --type=tsx --type=js --type=jsx -C2 '\bRoute\b.*path=.*["'\'']/forgot-password' src || true

Length of output: 137


🏁 Script executed:

#!/bin/bash
# Search for any Route definitions matching /forgot-password
rg -n -C2 '<Route[^>]*path=[\"\047]/forgot-password' -g '*.js' -g '*.jsx' -g '*.ts' -g '*.tsx' src || true

# Fallback: search for all occurrences of the string
rg -n '/forgot-password' -g '*.js' -g '*.jsx' -g '*.ts' -g '*.tsx' src || true

Length of output: 481


Ensure “/forgot-password” client route is registered
The login page at src/Admin/Pages/VigyLogin.jsx links to “/forgot-password”, but no matching <Route path="/forgot-password"> was found—add a route mapping this path to the existing ForgotPasswordForm component (src/User/pages/ForgotPasswordForm.jsx) to prevent a 404.

🤖 Prompt for AI Agents
In src/Admin/Pages/VigyLogin.jsx around lines 144 to 149, the link points to
"/forgot-password" but no route exists; add a Route for path="/forgot-password"
that renders the existing ForgotPasswordForm component
(src/User/pages/ForgotPasswordForm.jsx). Update your router (e.g., in
src/App.jsx or wherever routes are declared) to import ForgotPasswordForm and
add a <Route path="/forgot-password" element={<ForgotPasswordForm/>} /> (or the
equivalent for your router version), and ensure any auth/layout wrappers match
other auth routes so the page renders instead of 404.

Comment on lines +273 to +276
<Route path="/vigy-login" element={<VigyLogin />} />
<Route path="/vigy-form" element={<VigyForm />} />
<Route path="/vigy-dashboard" element={<VigyDashboard />} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Routes added fix the 404; consider a legacy redirect and confirm intentional duplicate for /vigy-form.

  • Good: adding /vigy-login addresses Issue [Bug] "Login as Vigy" button redirects to 404 page #2638.
  • Add a redirect for stale links pointing to /vigy to harden UX.
  • You now expose VigyForm both at /admin/vigy-form (guarded area) and /vigy-form (public). If that’s intentional, ignore; otherwise, dedupe.

Apply this minimal redirect:

   <Route path="/vigy-login" element={<VigyLogin />} />
   <Route path="/vigy-form" element={<VigyForm />} />
   <Route path="/vigy-dashboard" element={<VigyDashboard />} />
+  <Route path="/vigy" element={<Navigate to="/vigy-login" replace />} />

Run to verify no stale links remain:


🏁 Script executed:

#!/bin/bash
# Find any remaining references to old Vigy URLs
rg -nP -C2 '(vigy[-_/ ]?login|vigy[-_/ ]?form|/vigy\b)' --glob '!dist/**' --glob '!build/**' src

Length of output: 5820


Add missing redirect, fix stale AdminPanel link, and confirm duplicate route

  • Insert legacy redirect in src/App.jsx below the dashboard route:
         <Route path="/vigy-dashboard" element={<VigyDashboard />} />
    +    <Route path="/vigy" element={<Navigate to="/vigy-login" replace />} />
  • Correct broken link in src/Admin/Pages/AdminPanel.jsx (line 58):
    -  <Link to="/admin/vigy_form" >
    +  <Link to="/admin/vigy-form" >
  • Confirm whether exposing VigyForm at both /admin/vigy-form and /vigy-form is intentional; if not, remove or guard the public route.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Route path="/vigy-login" element={<VigyLogin />} />
<Route path="/vigy-form" element={<VigyForm />} />
<Route path="/vigy-dashboard" element={<VigyDashboard />} />
// File: src/App.jsx (around lines 273–275)
<Route path="/vigy-login" element={<VigyLogin />} />
<Route path="/vigy-form" element={<VigyForm />} />
<Route path="/vigy-dashboard" element={<VigyDashboard />} />
<Route path="/vigy" element={<Navigate to="/vigy-login" replace />} />
Suggested change
<Route path="/vigy-login" element={<VigyLogin />} />
<Route path="/vigy-form" element={<VigyForm />} />
<Route path="/vigy-dashboard" element={<VigyDashboard />} />
// File: src/Admin/Pages/AdminPanel.jsx (around line 58)
<Link to="/admin/vigy-form" >
🤖 Prompt for AI Agents
In src/App.jsx around lines 273-275, add the legacy redirect route immediately
after the /vigy-dashboard Route so users hitting the old path are forwarded to
the new dashboard; update src/Admin/Pages/AdminPanel.jsx at line 58 to correct
the broken link (replace the stale href/import with the current route path or
component reference used by routing); and verify whether VigyForm is
intentionally exposed both at /admin/vigy-form and /vigy-form — if not, remove
the public /vigy-form Route or wrap it with an auth guard so only authorized
users can access it.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (1)
backend/app.js (1)

25-33: Cross-site sessions: set trust proxy and sameSite, and use a production session store.

Without these, cookies may be dropped behind proxies and MemoryStore is not production-safe.

+if (process.env.NODE_ENV === 'production') {
+  app.set('trust proxy', 1);
+}
 app.use(
   session({
     secret: process.env.SESSION_SECRET || "Our little secret.",
     resave: false,
     saveUninitialized: false,
     cookie: {
       secure: process.env.NODE_ENV === 'production',
       httpOnly: true,
+      sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax',
       maxAge: 24 * 60 * 60 * 1000 // 24 hours
     }
   })
 );

If possible, switch to a persistent store (e.g., connect-mongo/redis):

+const MongoStore = require("connect-mongo");
@@
   session({
@@
+    store: process.env.MONGODB_URI
+      ? MongoStore.create({ mongoUrl: process.env.MONGODB_URI })
+      : undefined,
🧹 Nitpick comments (6)
backend/routes/subscribe.js (3)

24-26: Plan for idempotency and duplicates.

When you persist, enforce a unique constraint on email and treat duplicate subscriptions as 200 OK (idempotent), avoiding user enumeration.


27-31: Avoid echoing PII in success response.

No need to return the subscriber’s email; reduces exposure and log surface.

-    res.status(200).json({
+    return res.status(200).json({
       success: true,
-      message: "Successfully subscribed to newsletter",
-      email: email
+      message: "Successfully subscribed to newsletter"
     });

33-39: Return after sending the error response.

Make control flow explicit.

-    res.status(500).json({
+    return res.status(500).json({
       success: false,
       message: "Internal server error"
     });
backend/app.js (3)

19-22: Harden CORS with an allowlist and support multiple origins (local + prod + previews).

Current single-origin string can break previews and is easier to misconfigure.

-app.use(cors({
-  origin: process.env.FRONTEND_URL || "http://localhost:3000",
-  credentials: true
-}));
+const allowedOrigins = [
+  process.env.FRONTEND_URL,
+  "http://localhost:3000",
+  "http://localhost:5173"
+].filter(Boolean);
+app.use(cors({
+  origin(origin, cb) {
+    if (!origin || allowedOrigins.includes(origin)) return cb(null, true);
+    return cb(new Error("CORS: Origin not allowed"));
+  },
+  credentials: true
+}));
+app.options("*", cors());

62-69: Gate test routes in non-production.

Avoid exposing internal diagnostics.

-app.get("/api/vigy/test", (req, res) => {
+if (process.env.NODE_ENV !== "production") app.get("/api/vigy/test", (req, res) => {
   res.json({ 
     message: "Vigy API is working! ✅",
     status: "success",
     endpoint: "/api/vigy/test"
   });
-});
+});

17-22: Optional: set JSON body size limit.

Prevents large payloads hitting all routes.

-app.use(express.json());
+app.use(express.json({ limit: "100kb" }));
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b4f6540 and 0163c43.

⛔ Files ignored due to path filters (1)
  • backend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • backend/app.js (1 hunks)
  • backend/package.json (2 hunks)
  • backend/routes/subscribe.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/package.json
🧰 Additional context used
🧬 Code graph analysis (2)
backend/routes/subscribe.js (1)
src/User/pages/Home/Home.jsx (1)
  • e (80-134)
backend/app.js (6)
backend/server.js (1)
  • app (2-2)
backend/routes/subscribe.js (2)
  • express (1-1)
  • req (8-8)
backend/routes/authRoutes.js (3)
  • express (1-1)
  • passport (3-3)
  • req (16-22)
backend/routes/vigyRoutes.js (2)
  • express (1-1)
  • req (78-78)
backend/middlewares/Passport.js (1)
  • passport (1-1)
backend/controllers/vigyController.js (2)
  • req (16-32)
  • req (96-96)

Comment on lines 53 to 74
// Route setup
app.use("/api/subscribe", subscribeRoute); // POST /api/subscribe
app.use("/auth", authRoutes);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Rate-limit the public subscribe endpoint.

Prevents abuse and mail-bombing.

+const rateLimit = require("express-rate-limit");
+const subscribeLimiter = rateLimit({
+  windowMs: 60 * 1000,
+  max: 10,
+  standardHeaders: true,
+  legacyHeaders: false
+});
-app.use("/api/subscribe", subscribeRoute); // POST /api/subscribe
+app.use("/api/subscribe", subscribeLimiter, subscribeRoute); // POST /api/subscribe
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Route setup
app.use("/api/subscribe", subscribeRoute); // POST /api/subscribe
app.use("/auth", authRoutes);
// At the top of backend/app.js, alongside your other requires:
const express = require("express");
const rateLimit = require("express-rate-limit");
const subscribeRoute = require("./routes/subscribe");
const authRoutes = require("./routes/auth");
// … any other requires
// Define a rate limiter specifically for the public subscribe endpoint
const subscribeLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 10, // limit each IP to 10 requests per window
standardHeaders: true, // return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // disable the `X-RateLimit-*` headers
});
// … your app setup (middleware, etc.)
// Route setup
app.use("/api/subscribe", subscribeLimiter, subscribeRoute); // POST /api/subscribe
app.use("/auth", authRoutes);
🤖 Prompt for AI Agents
In backend/app.js around lines 53 to 55, the public POST /api/subscribe endpoint
is not rate-limited which allows abuse; add a rate-limiting middleware (e.g.,
express-rate-limit) and apply it specifically to the /api/subscribe route:
import/configure an Express rateLimit instance with a sensible window and max
(for example short window and low max per IP), attach any needed headers or
handlers for blocked requests, and use app.use("/api/subscribe",
rateLimitMiddleware, subscribeRoute) so the limiter protects only that endpoint.

backend/app.js Outdated
Comment on lines 53 to 80
// Route setup
app.use("/api/subscribe", subscribeRoute); // POST /api/subscribe
app.use("/auth", authRoutes);
app.use("/api", routes);
app.use("/api", passwordResetRoutes);
app.use("/vpi", userRoutes);
app.use("/api/v1", adminRegistrationRoutes);
app.use("/api/vigy", vigyRoutes);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Likely typo: '/vpi' should be '/api' for user routes.

This would orphan user routes and cause 404s.

-app.use("/vpi", userRoutes);
+app.use("/api", userRoutes);

Run to confirm no other '/vpi' mounts exist:


🏁 Script executed:

#!/bin/bash
rg -n -C2 -P 'app\.use\(\s*["\']/vpi["\']' backend

Length of output: 116


🏁 Script executed:

#!/bin/bash
# Verify no other mounts of "/vpi" exist
rg -n -C2 -e "app.use('/vpi'" -e 'app.use("/vpi"' backend

Length of output: 168


🏁 Script executed:

#!/bin/bash
# Search for any occurrences of "/vpi" in the backend directory
rg -n "/vpi" -C2 backend

Length of output: 285


Fix mount path for userRoutes in backend/app.js
Change at line 58 to avoid orphaning endpoints:

-app.use("/vpi", userRoutes);
+app.use("/api", userRoutes);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Route setup
app.use("/api/subscribe", subscribeRoute); // POST /api/subscribe
app.use("/auth", authRoutes);
app.use("/api", routes);
app.use("/api", passwordResetRoutes);
app.use("/vpi", userRoutes);
app.use("/api/v1", adminRegistrationRoutes);
app.use("/api/vigy", vigyRoutes);
// Route setup
app.use("/api/subscribe", subscribeRoute); // POST /api/subscribe
app.use("/auth", authRoutes);
app.use("/api", routes);
app.use("/api", passwordResetRoutes);
app.use("/api", userRoutes);
app.use("/api/v1", adminRegistrationRoutes);
app.use("/api/vigy", vigyRoutes);
🤖 Prompt for AI Agents
In backend/app.js around lines 53 to 61, the userRoutes are mounted at "/vpi"
which orphaned those endpoints; change the mount path to "/api/vpi" so they live
under the API namespace (replace app.use("/vpi", userRoutes) with
app.use("/api/vpi", userRoutes)); ensure this line remains before any catch-all
or conflicting middleware so the routes are reachable.

Comment on lines +60 to +80
app.use("/api/vigy", vigyRoutes);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Quick sanity check for the PR goal (frontend route).

Ensure the “Login as Vigy” link points to the intended path (e.g., /vigy-login) and no stale /vigy-form links remain.


🏁 Script executed:

#!/bin/bash
# Search frontend for Vigy login routes/links
rg -n -C2 -S --glob '!**/node_modules/**' --type-add 'jsx:*.{js,jsx,ts,tsx}' --type jsx \
  -e 'vigy[-_/ ]login' -e 'vigy-login' -e '/vigy-login' -e '/vigy-form' -e 'Login as Vigy'

Length of output: 3362


Login link correct; remove stale “/vigy-form” references

  • The “Login as Vigy” link correctly points to /vigy-login (UserAuth.jsx:212–216).
  • Remove or rename all remaining /vigy-form routes and links, e.g.:
    • src/App.jsx:273–274
    • src/User/pages/UserAuth/UserAuth.jsx:212–216
    • src/Admin/Pages/VigyLogin.jsx:186–188
🤖 Prompt for AI Agents
In backend/app.js around lines 60 to 61, the app is mounting vigy routes at
/api/vigy but there are stale references to the old /vigy-form path elsewhere;
find and remove or rename any routes, route handlers, or exported endpoints that
still expose or reference /vigy-form so all server-side routes match the new
/vigy-login or /api/vigy conventions. Update any Express route declarations,
middleware mounts, and route exports to use the new path names, and search the
repo for literal "/vigy-form" occurrences to either delete or replace with the
correct route, ensuring route handlers and client-side links remain consistent.

Comment on lines +72 to +106
app.get("/auth/google/test", (req, res) => {
const hasClientId = !!process.env.GOOGLE_CLIENT_ID;
const hasClientSecret = !!process.env.GOOGLE_CLIENT_SECRET;
const callbackUrl = process.env.GOOGLE_CALLBACK_URL || "http://localhost:5000/auth/google/callback";

res.json({
message: "Google OAuth Configuration Test",
status: hasClientId && hasClientSecret ? "configured" : "missing_credentials",
configuration: {
hasClientId,
hasClientSecret,
callbackUrl,
frontendUrl: process.env.FRONTEND_URL || "http://localhost:3000"
}
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Info disclosure risk: Google OAuth config test should not be public in prod.

Leaking presence/URLs of OAuth config aids reconnaissance.

-app.get("/auth/google/test", (req, res) => {
+if (process.env.NODE_ENV !== "production") app.get("/auth/google/test", (req, res) => {
   const hasClientId = !!process.env.GOOGLE_CLIENT_ID;
   const hasClientSecret = !!process.env.GOOGLE_CLIENT_SECRET;
   const callbackUrl = process.env.GOOGLE_CALLBACK_URL || "http://localhost:5000/auth/google/callback";
   
   res.json({
     message: "Google OAuth Configuration Test",
     status: hasClientId && hasClientSecret ? "configured" : "missing_credentials",
     configuration: {
       hasClientId,
       hasClientSecret,
       callbackUrl,
       frontendUrl: process.env.FRONTEND_URL || "http://localhost:3000"
     }
   });
-});
+});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
app.get("/auth/google/test", (req, res) => {
const hasClientId = !!process.env.GOOGLE_CLIENT_ID;
const hasClientSecret = !!process.env.GOOGLE_CLIENT_SECRET;
const callbackUrl = process.env.GOOGLE_CALLBACK_URL || "http://localhost:5000/auth/google/callback";
res.json({
message: "Google OAuth Configuration Test",
status: hasClientId && hasClientSecret ? "configured" : "missing_credentials",
configuration: {
hasClientId,
hasClientSecret,
callbackUrl,
frontendUrl: process.env.FRONTEND_URL || "http://localhost:3000"
}
});
});
// Only enable the Google OAuth configuration test endpoint in non-production environments
if (process.env.NODE_ENV !== "production") app.get("/auth/google/test", (req, res) => {
const hasClientId = !!process.env.GOOGLE_CLIENT_ID;
const hasClientSecret = !!process.env.GOOGLE_CLIENT_SECRET;
const callbackUrl = process.env.GOOGLE_CALLBACK_URL || "http://localhost:5000/auth/google/callback";
res.json({
message: "Google OAuth Configuration Test",
status: hasClientId && hasClientSecret ? "configured" : "missing_credentials",
configuration: {
hasClientId,
hasClientSecret,
callbackUrl,
frontendUrl: process.env.FRONTEND_URL || "http://localhost:3000"
}
});
});
🤖 Prompt for AI Agents
In backend/app.js around lines 72-87, the public /auth/google/test endpoint
discloses OAuth presence and URLs which is sensitive in production; remove or
gate it so it cannot be hit in prod: either register the route only when
NODE_ENV !== 'production' (or another explicit dev flag) or protect it with an
authenticated/admin-only middleware, and change the response in production to a
generic non-revealing success/failure message (no client IDs, secrets, or
callback/frontend URLs). Ensure the fix prevents any sensitive configuration
from being returned in production while keeping the endpoint available for
local/dev testing.

Comment on lines 8 to 66
const { email } = req.body;

if (!email) {
return res.status(400).json({
success: false,
message: "Email is required"
});
}

// Validate email format
if (!validator.isEmail(email)) {
return res.status(400).json({
success: false,
message: "Please provide a valid email address"
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Normalize and validate email on the server (don’t trust client-side).

Guard type, trim, and canonicalize before validation to prevent bypasses and ensure consistent storage.

-    const { email } = req.body;
-    
-    if (!email) {
+    const rawEmail = req.body?.email;
+    if (typeof rawEmail !== "string" || !rawEmail.trim()) {
       return res.status(400).json({
         success: false,
         message: "Email is required"
       });
     }
 
-    // Validate email format
-    if (!validator.isEmail(email)) {
+    // Normalize and validate email format
+    const email = validator.normalizeEmail(rawEmail) || rawEmail.trim().toLowerCase();
+    if (!validator.isEmail(email)) {
       return res.status(400).json({
         success: false,
         message: "Please provide a valid email address"
       });
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { email } = req.body;
if (!email) {
return res.status(400).json({
success: false,
message: "Email is required"
});
}
// Validate email format
if (!validator.isEmail(email)) {
return res.status(400).json({
success: false,
message: "Please provide a valid email address"
});
}
const rawEmail = req.body?.email;
if (typeof rawEmail !== "string" || !rawEmail.trim()) {
return res.status(400).json({
success: false,
message: "Email is required"
});
}
// Normalize and validate email format
const email = validator.normalizeEmail(rawEmail) || rawEmail.trim().toLowerCase();
if (!validator.isEmail(email)) {
return res.status(400).json({
success: false,
message: "Please provide a valid email address"
});
}
🤖 Prompt for AI Agents
In backend/routes/subscribe.js around lines 8 to 23, the server currently trusts
req.body.email as-is; you must first guard the type and canonicalize the value
before validating. Ensure you check that req.body.email is a string, then trim
whitespace and convert to lowercase (and optionally apply provider-specific
canonicalization like removing dots/plus for Gmail) before calling
validator.isEmail; use the normalized value for both validation and
storage/response so validation cannot be bypassed and emails are stored
consistently.

@codervivek5
Copy link
Owner

kindly fix the merge conflict

@codervivek5 codervivek5 added good first issue Good for newcomers OSCI 1⭐ Easy task for beginners, requires basic understanding. labels Sep 7, 2025
@codervivek5
Copy link
Owner

kindly fix the merge conflict then commit it again

@ajaykuraparthi
Copy link
Author

Merge conflicts resolved. Ready for review/merge.

- Resolved merge conflicts in app.js by combining both branches' routes
- Added missing subscribe route from main branch
- Added body-parser and validator dependencies
- Updated package-lock.json with new dependencies
- Created routes/subscribe.js with email validation
- Preserved all vigy functionality from fix-vigy-login branch
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/App.jsx (1)

207-209: Duplicate exposure of VigyForm — remove or guard the public route

VigyForm is mounted multiple times in src/App.jsx (lines 207, 265, 275 — line 275 is a top-level "/vigy-form") and there’s a link to "/vigy-form" in src/Admin/Pages/VigyLogin.jsx:186. Confirm intent; if unintended remove the public "/vigy-form" route or protect it with the appropriate PrivateRoute/AdminRoute and update links.

♻️ Duplicate comments (31)
backend/setup-env.js (3)

15-20: Don’t overwrite an existing .env; set restrictive perms when writing.

Skip creation if the file exists, and write with mode 600.

-try {
-  fs.writeFileSync(envPath, envContent);
+try {
+  if (fs.existsSync(envPath)) {
+    console.log('ℹ️  .env already exists, not overwriting.');
+    console.log('📁 Location:', envPath);
+    process.exit(0);
+  }
+  fs.writeFileSync(envPath, envContent, { mode: 0o600 });
   console.log('✅ .env file created successfully!');
   console.log('📁 Location:', envPath);
   console.log('\n⚠️  IMPORTANT: Update GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET with your actual values');

13-13: Ensure backend/.env is ignored and loaded via dotenv with the same path.

Add .env (or backend/.env) to .gitignore and configure dotenv.config({ path: <backend>/.env }) where env is consumed.

#!/bin/bash
# Verify .env is gitignored
rg -nP '(^|/)\\.env(\\b|$)' .gitignore || echo "No .env ignore rule found"

# Verify dotenv loads the backend env path
rg -nP "dotenv\\.config\\(([^)]*)\\)" backend -C2 || true

4-4: Port mismatch: use 5000 to align with frontend/dev config.

Frontend and OAuth dev callback target 5000; keep .env in sync.

-const envContent = `PORT=3001
+const envContent = `PORT=5000
 MONGO_URI=mongodb://localhost:27017/vigybag
 JWT_SECRET=vigybag_jwt_secret_key_2024
 SESSION_SECRET=vigybag_session_secret_2024
 GOOGLE_CLIENT_ID=your_google_client_id_here
 GOOGLE_CLIENT_SECRET=your_google_client_secret_here
 NODE_ENV=development
 `;
backend/middlewares/Passport.js (1)

5-5: Load the same .env that setup script generates.

Point dotenv to backend/.env so local runs pick up the generated file.

-const dotenv = require("dotenv");
-dotenv.config();
+const dotenv = require("dotenv");
+const path = require("path");
+dotenv.config({ path: path.join(__dirname, "../.env") });
backend/routes/subscribe.js (1)

10-12: Normalize email safely before validate/store.

Use validator.normalizeEmail and guard type; your current toString()+lowercase is okay but not canonical.

-  try {
-    const emailRaw = (req.body?.email ?? "").toString();
-    const email = emailRaw.trim().toLowerCase();
+  try {
+    const rawEmail = req.body?.email;
+    if (typeof rawEmail !== "string" || !rawEmail.trim()) {
+      return res.status(400).json({ success: false, message: "⚠️ A valid email is required." });
+    }
+    const email = validator.normalizeEmail(rawEmail) || rawEmail.trim().toLowerCase();
backend/models/Vigy.js (3)

48-74: Make bankDetails/documents required via sub-schemas + IFSC validation

Prevents bypassing nested requireds and validates IFSC.

-  bankDetails: {
-    accountName: { type: String, required: true, trim: true },
-    accountNumber:{ type: String, required: true, trim: true },
-    bankName:     { type: String, required: true, trim: true },
-    branch:       { type: String, required: true, trim: true },
-    ifscCode:     { type: String, required: true, trim: true }
-  },
+  bankDetails: {
+    type: new mongoose.Schema({
+      accountName:  { type: String, required: true, trim: true },
+      accountNumber:{ type: String, required: true, trim: true },
+      bankName:     { type: String, required: true, trim: true },
+      branch:       { type: String, required: true, trim: true },
+      ifscCode:     { type: String, required: true, trim: true, match: [/^[A-Z]{4}0[A-Z0-9]{6}$/, 'Invalid IFSC code'] }
+    }, { _id: false }),
+    required: true,
+  },
-  documents: {
-    panCard:      { type: String, required: true },
-    addressProof: { type: String, required: true },
-    profilePicture:{ type: String, required: false }
-  },
+  documents: {
+    type: new mongoose.Schema({
+      panCard:       { type: String, required: true },
+      addressProof:  { type: String, required: true },
+      profilePicture:{ type: String }
+    }, { _id: false }),
+    required: true,
+  },

Also applies to: 75-88


32-38: Encrypt high‑risk PII at rest (Aadhaar, bank details, docs)

Store ciphertext and a deterministic hash for lookups/uniqueness.

I can add AES‑GCM field‑level encryption hooks and a hashed lookup field (HMAC) for Aadhaar; say the word.

Also applies to: 48-74, 75-88


32-38: Fix invalid Mongoose option; enforce Aadhaar format

Replace ineffective length with a regex validator.

   aadhaarNumber: {
     type: String,
     required: true,
     unique: true,
     trim: true,
-    length: 12
+    match: [/^\d{12}$/, 'Aadhaar number must be exactly 12 digits'],
   },
src/Admin/Pages/VigyLogin.jsx (2)

35-39: Avoid localStorage; wire “Remember me” and prefer HttpOnly cookies

Default to sessionStorage; only persist when “Remember me” is checked. If the backend sets HttpOnly cookies, switch axios to withCredentials and remove token storage entirely.

-      const apiUrl = process.env.NODE_ENV === 'production' 
-        ? 'https://vigybag-backend.onrender.com/api/vigy/login'
-        : 'http://localhost:5000/api/vigy/login';
+      const base =
+        (typeof import.meta !== 'undefined' && import.meta.env?.VITE_API_BASE_URL) ||
+        process.env.REACT_APP_API_BASE_URL ||
+        (process.env.NODE_ENV === 'production'
+          ? 'https://vigybag-backend.onrender.com'
+          : 'http://localhost:5000');
+      const apiUrl = `${base}/api/vigy/login`;
       
-      const response = await axios.post(apiUrl, formData);
+      const response = await axios.post(apiUrl, formData/*, { withCredentials: true }*/);
 
       if (response.data.success) {
-        // Store token or user data
-        localStorage.setItem('vigyToken', response.data.token);
-        localStorage.setItem('vigyUser', JSON.stringify(response.data.user));
+        const storage = rememberMe ? localStorage : sessionStorage;
+        storage.setItem('vigyToken', response.data.token);
+        storage.setItem('vigyUser', JSON.stringify({
+          id: response.data.user.id,
+          email: response.data.user.email,
+          fullname: response.data.user.fullname
+        }));

Add state + checkbox wiring (outside this hunk):

-  const [loading, setLoading] = useState(false);
+  const [loading, setLoading] = useState(false);
+  const [rememberMe, setRememberMe] = useState(false);
-              <input
+              <input
                 type="checkbox"
                 className="mr-2 h-4 w-4 rounded border-gray-300 text-[#4a7c59] focus:ring-[#4a7c59]"
+                onChange={(e) => setRememberMe(e.target.checked)}
               />

Also applies to: 41-48


71-76: Ensure Google OAuth redirects to the Vigy dashboard

Pass a flow hint so the backend can route back to “/vigy-dashboard”.

-  const handleGoogleLogin = () => {
-    const googleAuthUrl = process.env.NODE_ENV === 'production'
-      ? 'https://vigybag-backend.onrender.com/auth/google'
-      : 'http://localhost:5000/auth/google';
-    window.location.href = googleAuthUrl;
-  };
+  const handleGoogleLogin = () => {
+    const base =
+      (typeof import.meta !== 'undefined' && import.meta.env?.VITE_API_BASE_URL) ||
+      process.env.REACT_APP_API_BASE_URL ||
+      (process.env.NODE_ENV === 'production'
+        ? 'https://vigybag-backend.onrender.com'
+        : 'http://localhost:5000');
+    const googleAuthUrl = `${base}/auth/google?flow=vigy`;
+    window.location.href = googleAuthUrl;
+  };
src/Admin/Pages/VigyForm.jsx (1)

315-320: Remove hardcoded default password; collect from user with confirm + strength

Hardcoding a default password is a security risk and will create identical credentials.

-      password: 'defaultPassword123', // You might want to add a password field to the form

Add password + confirm inputs (example in the “contact” tab) and reference them here:

+      password: formData.contact.password || '',

Example inputs to add under the “contact” case (outside this hunk):

<InputField label="Password" name="password" type="password" required minLength={8} onChange={handleInputChange}/>
<InputField label="Confirm Password" name="confirmPassword" type="password" required onChange={handleInputChange}/>
backend/config/config.js (1)

7-7: Centralize derived URLs to kill hardcoded localhost elsewhere.

Export frontendUrl and googleCallbackUrl here so routes can consume consistent values.

 const config = {
-  port: process.env.PORT || 5000,
+  port: process.env.PORT || 5000,
+  frontendUrl: process.env.FRONTEND_URL || 'http://localhost:3000',
+  googleCallbackUrl:
+    process.env.GOOGLE_CALLBACK_URL ||
+    `http://localhost:${process.env.PORT || 5000}/auth/google/callback`,
   mongoURI: process.env.MONGO_URI || 'mongodb://localhost:27017/myapp',
   jwtSecret: process.env.JWT_SECRET || 'mysecretkey',
   sessionSecret: process.env.SESSION_SECRET || 'defaultsessionsecret',
   googleClientID: process.env.GOOGLE_CLIENT_ID || '',
   googleClientSecret: process.env.GOOGLE_CLIENT_SECRET || '',
 };
backend/routes/authRoutes.js (2)

30-31: Avoid “undefined/auth…” when FRONTEND_URL is unset.

Define a single FRONTEND_URL fallback and reuse for both success and failure redirects.

-router.get(
-  "/google/callback",
-  passport.authenticate("google", { failureRedirect: process.env.FRONTEND_URL + "/auth?error=google_auth_failed" }),
+const FRONTEND_URL = process.env.FRONTEND_URL || "http://localhost:3000";
+router.get(
+  "/google/callback",
+  passport.authenticate("google", { failureRedirect: `${FRONTEND_URL}/auth?error=google_auth_failed` }),

31-37: Stop leaking PII in redirect; support Vigy flow via state.

Don’t put email/username in query params; redirect using state to select destination.

-  (req, res) => {
-    const email = req.user.email;
-    const username = req.user.username;
-    const frontendUrl = process.env.FRONTEND_URL || "http://localhost:3000";
-    res.redirect(
-      `${frontendUrl}/dashboard?email=${encodeURIComponent(email)}&username=${encodeURIComponent(username)}`
-    );
-  }
+  (req, res) => {
+    const flow = req.query.state; // e.g., 'vigy'
+    const targetPath = flow === 'vigy' ? '/vigy-dashboard' : '/dashboard';
+    res.redirect(`${FRONTEND_URL}${targetPath}`);
+  }
backend/app.js (4)

26-37: Sessions: set trust proxy and sameSite for cross-site auth.

Without these, cookies may be dropped behind proxies or in OAuth flows.

-const app = express();
+const app = express();
+if (process.env.NODE_ENV === 'production') {
+  app.set('trust proxy', 1);
+}
@@
   session({
     secret: process.env.SESSION_SECRET || "Our little secret.",
     resave: false,
     saveUninitialized: false,
     cookie: {
-      secure: process.env.NODE_ENV === "production",
-      httpOnly: true,
-      maxAge: 24 * 60 * 60 * 1000, // 24 hours
+      secure: process.env.NODE_ENV === "production",
+      httpOnly: true,
+      sameSite: process.env.NODE_ENV === "production" ? "none" : "lax",
+      maxAge: 24 * 60 * 60 * 1000, // 24 hours
     },
   })
 );

55-57: Rate‑limit public subscribe endpoint.

Add a small limiter to reduce abuse.

+const rateLimit = require("express-rate-limit");
+const subscribeLimiter = rateLimit({ windowMs: 60 * 1000, max: 10, standardHeaders: true, legacyHeaders: false });
@@
-app.use("/api/subscribe", subscribeRoute); // POST /api/subscribe
+app.use("/api/subscribe", subscribeLimiter, subscribeRoute); // POST /api/subscribe

60-60: Typo: mount user routes under /api, not /vpi.

This causes 404s for user endpoints.

-app.use("/vpi", userRoutes);               // /vpi
+app.use("/api", userRoutes);               // /api

74-91: Gate the Google OAuth config test route in non‑prod.

Avoid leaking config in production.

-app.get("/auth/google/test", (req, res) => {
+if (process.env.NODE_ENV !== "production") app.get("/auth/google/test", (req, res) => {
@@
-});
+});
backend/routes/vigyRoutes.js (3)

33-74: Add basic request validation to /register.

Validate required fields and normalize email before storing.

+const { body, validationResult } = require('express-validator');
-router.post('/register', (req, res) => {
+router.post(
+  '/register',
+  [
+    body('email').isEmail().normalizeEmail(),
+    body('password').isLength({ min: 8, max: 128 }),
+    body('fullname').isLength({ min: 2, max: 100 }).trim(),
+  ],
+  (req, res) => {
     try {
+      const errors = validationResult(req);
+      if (!errors.isEmpty()) {
+        return res.status(400).json({ success: false, errors: errors.array() });
+      }
       const userData = req.body;
@@
-    res.json({
+    res.json({
       success: true,
       message: "Registration successful! Please wait for approval.",
       user: {
         id: newUser.id,
         email: newUser.email,
         status: newUser.status
       }
     });
   } catch (error) {
@@
-  }
-});
+  }
+});

4-30: In‑memory users and plaintext passwords must be dev‑only.

Block this router in production to avoid accidental exposure.

-// In-memory storage for development
+// In-memory storage for development only
+router.use((req, res, next) => {
+  if (process.env.NODE_ENV === 'production') {
+    return res.status(503).json({ success: false, message: 'Vigy dev routes disabled in production' });
+  }
+  next();
+});

76-117: Use hashed passwords and real JWTs or delegate to DB‑backed controllers.

Plaintext compare and “test_token_…” aren’t acceptable beyond mock dev flows.

Consider replacing this router with the DB‑backed handlers in controllers/vigyController.js to avoid duplication and security drift.

backend/controllers/vigyController.js (9)

16-33: Validate and normalize registration input up‑front.

Add basic presence/format checks and normalization to reduce bad data and operator payloads.

   try {
-    const {
+    const {
       fullname,
       email,
       password,
       phoneNumber,
       address,
       aadhaarNumber,
       gender,
       dob,
       bankAccountName,
       bankAccountNumber,
       bankName,
       bankBranch,
       ifscCode,
       referralCode,
       promotionalCode
     } = req.body;
+    const emailNorm = typeof email === 'string' ? email.trim().toLowerCase() : '';
+    const aadhaarNorm = typeof aadhaarNumber === 'string' ? aadhaarNumber.trim() : '';
+    if (!fullname || !emailNorm || !password) {
+      return res.status(400).json({ success: false, message: 'Missing required fields' });
+    }
+    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailNorm)) {
+      return res.status(400).json({ success: false, message: 'Invalid email' });
+    }
+    if (!/^\d{12}$/.test(aadhaarNorm)) {
+      return res.status(400).json({ success: false, message: 'Invalid Aadhaar number' });
+    }

35-37: Harden uniqueness query against NoSQL operators.

Use normalized strings in the query.

-    const existingVigy = await Vigy.findOne({ 
-      $or: [{ email }, { aadhaarNumber }] 
-    });
+    const existingVigy = await Vigy.findOne({
+      $or: [{ email: emailNorm }, { aadhaarNumber: aadhaarNorm }]
+    });

49-67: Persist normalized values.

Store canonical email/aadhaar to match lookups/indexes.

     const vigy = new Vigy({
       fullname,
-      email,
+      email: emailNorm,
       password,
       phoneNumber,
       address,
-      aadhaarNumber,
+      aadhaarNumber: aadhaarNorm,
       gender,
       dob,

81-88: Handle duplicate key (E11000) explicitly; avoid echoing internals.

Return deterministic 400 without leaking error.message.

-  } catch (error) {
-    console.error('Vigy registration error:', error);
-    res.status(500).json({
-      success: false,
-      message: 'Server error during registration',
-      error: error.message
-    });
+  } catch (error) {
+    if (error && error.code === 11000) {
+      const key = Object.keys(error.keyPattern || {})[0] || 'field';
+      const message = key === 'email'
+        ? 'Email already registered'
+        : key === 'aadhaarNumber'
+        ? 'Aadhaar number already registered'
+        : 'Duplicate value';
+      return res.status(400).json({ success: false, message });
+    }
+    console.error('Vigy registration error:', error);
+    res.status(500).json({ success: false, message: 'Server error during registration' });

98-104: Type‑check and normalize login inputs.

Prevents operator payloads and case mismatches.

-    // Validate input
-    if (!email || !password) {
+    // Validate input
+    if (typeof email !== 'string' || typeof password !== 'string') {
       return res.status(400).json({
         success: false,
-        message: 'Please provide both email and password'
+        message: 'Invalid payload'
       });
     }
+    const emailNorm = email.trim().toLowerCase();
+    if (!emailNorm || !password) {
+      return res.status(400).json({ success: false, message: 'Please provide both email and password' });
+    }

106-108: Use normalized email in the lookup.

-    const vigy = await Vigy.findOne({ email });
+    const vigy = await Vigy.findOne({ email: emailNorm });

5-9: No default JWT secret; fail fast if unset.

Remove insecure fallback to 'mysecretkey'.

-const generateToken = (vigyId) => {
-  return jwt.sign({ vigyId }, process.env.JWT_SECRET || 'mysecretkey', {
-    expiresIn: '7d'
-  });
-};
+const generateToken = (vigyId) => {
+  const secret = process.env.JWT_SECRET;
+  if (!secret) throw new Error('JWT_SECRET is not configured');
+  return jwt.sign({ vigyId }, secret, { expiresIn: '7d' });
+};

154-172: JWT auth middleware is missing for req.vigyId.

Implement middleware that verifies token and sets req.vigyId; apply on protected routes.

#!/bin/bash
# Verify presence of Vigy auth middleware and its usage on /api/vigy/profile
rg -nP -C2 'authenticateVigy|verifyVigy|req\.vigyId' backend

186-197: Prevent mass‑assignment on profile update.

Whitelist allowed fields instead of spreading req.body.

-    const updates = req.body;
-    delete updates.password; // Don't allow password update through this route
-    delete updates.email; // Don't allow email update through this route
-    delete updates.aadhaarNumber; // Don't allow Aadhaar update through this route
-
-    const vigy = await Vigy.findByIdAndUpdate(
-      req.vigyId,
-      { ...updates, updatedAt: Date.now() },
-      { new: true, runValidators: true }
-    );
+    const { password, email, aadhaarNumber, ...rest } = req.body;
+    const allowed = ['fullname', 'phoneNumber', 'address', 'gender', 'dob', 'bankDetails', 'referralCode', 'promotionalCode'];
+    const safeUpdates = {};
+    for (const key of allowed) {
+      if (Object.prototype.hasOwnProperty.call(rest, key)) safeUpdates[key] = rest[key];
+    }
+    const vigy = await Vigy.findByIdAndUpdate(
+      req.vigyId,
+      { $set: safeUpdates },
+      { new: true, runValidators: true }
+    );
backend/config/db.js (1)

12-13: Don’t continue without a DB in non‑dev; implement a real dev fallback.

Right now we only log and keep going. Gate by NODE_ENV and wire an actual in‑memory Mongo for development; exit in prod/stage to avoid partial-start bugs.

Apply:

+const { MongoMemoryServer } = require("mongodb-memory-server");
 const connectDB = async () => {
   try {
     await mongoose.connect(config.mongoURI);
     console.log("Connected to MongoDB");
   } catch (err) {
     console.error("Error connecting to MongoDB:", err.message);
-    console.log("⚠️  MongoDB not available. Using in-memory fallback for development.");
-    // Don't exit for development - let the app continue
+    const env = process.env.NODE_ENV || "development";
+    if (env !== "development" && env !== "test") {
+      console.error("MongoDB unavailable. Exiting (non-dev).");
+      process.exit(1);
+    }
+    console.warn("⚠️  MongoDB not available. Falling back to in-memory MongoDB for dev.");
+    const mem = await MongoMemoryServer.create();
+    const uri = mem.getUri();
+    await mongoose.connect(uri);
+    console.log("Connected to in-memory MongoDB");
+    const shutdown = async () => {
+      await mongoose.disconnect().catch(() => {});
+      await mem.stop().catch(() => {});
+      process.exit(0);
+    };
+    process.on("SIGINT", shutdown);
+    process.on("SIGTERM", shutdown);
   }
 };
🧹 Nitpick comments (14)
src/User/pages/UserAuth/UserAuth.jsx (1)

337-345: Mobile parity: expose “Login as Vigy” on small screens.

On mobile the left column is hidden (md:block), so the Vigy login button is inaccessible. Add a mobile-visible link next to the existing Admin links.

@@
   <p className="sm:hidden text-sm text-center  pb-0 mt-2">
     <Link
       to="/admin-verification"
       className="bg-[#2d3e40] text-green-500 px-6 rounded-full hover:bg-opacity-90 transition duration-300"
     >
       Login as Admin
     </Link>
   </p>
+  <p className="sm:hidden text-sm text-center mt-2">
+    <Link
+      to="/vigy-login"
+      className="bg-[#f9efe4] text-[#2d3e40] px-6 rounded-full border border-[#2d3e40] hover:bg-[#2d3e40] hover:text-white transition duration-300"
+    >
+      Login as Vigy
+    </Link>
+  </p>
@@
   <p className="sm:hidden text-sm text-center  pb-0 mt-2">
     <Link
       to="/admin-verification"
       className="bg-[#2d3e40] text-green-500 px-6 rounded-full hover:bg-opacity-90 transition duration-300"
     >
       Login as Admin
     </Link>
   </p>
+  <p className="sm:hidden text-sm text-center mt-2">
+    <Link
+      to="/vigy-login"
+      className="bg-[#f9efe4] text-[#2d3e40] px-6 rounded-full border border-[#2d3e40] hover:bg-[#2d3e40] hover:text-white transition duration-300"
+    >
+      Login as Vigy
+    </Link>
+  </p>

Also applies to: 481-488

backend/setup-env.js (1)

6-7: Generate non‑guessable secrets instead of hardcoded defaults.

Avoid shipping fixed JWT/session secrets; create strong random values at generation time.

+const crypto = require('crypto');
-const envContent = `PORT=5000
-MONGO_URI=mongodb://localhost:27017/vigybag
-JWT_SECRET=vigybag_jwt_secret_key_2024
-SESSION_SECRET=vigybag_session_secret_2024
-GOOGLE_CLIENT_ID=your_google_client_id_here
-GOOGLE_CLIENT_SECRET=your_google_client_secret_here
-NODE_ENV=development
-`;
+const jwtSecret = crypto.randomBytes(32).toString('hex');
+const sessionSecret = crypto.randomBytes(32).toString('hex');
+const envContent = `PORT=5000
+MONGO_URI=mongodb://localhost:27017/vigybag
+JWT_SECRET=${jwtSecret}
+SESSION_SECRET=${sessionSecret}
+GOOGLE_CLIENT_ID=your_google_client_id_here
+GOOGLE_CLIENT_SECRET=your_google_client_secret_here
+# Optional but recommended for OAuth:
+# GOOGLE_CALLBACK_URL=http://localhost:5000/auth/google/callback
+NODE_ENV=development
+`;
backend/routes/subscribe.js (2)

33-37: API message style: consider dropping emojis for machine consumers.

If this endpoint feeds non-UI clients, remove emojis from messages.

-      message: "🎉 Subscribed successfully!",
+      message: "Subscribed successfully.",

1-6: Minor: remove redundant import/line.

Line 1 already imports express; delete line 2 redeclaration.

-const express = require("express");
src/Admin/Pages/VigyDashboard.jsx (1)

11-16: Prefer sessionStorage/HttpOnly cookies; clear both stores on logout

Use sessionStorage by default (mitigates XSS persistence) and clear both storages on logout. If you later move to HttpOnly cookies, this guard can fall back to a profile ping.

-    const token = localStorage.getItem('vigyToken');
-    const user = localStorage.getItem('vigyUser');
+    const token = sessionStorage.getItem('vigyToken') ?? localStorage.getItem('vigyToken');
+    const user  = sessionStorage.getItem('vigyUser')  ?? localStorage.getItem('vigyUser');
   const handleLogout = () => {
-    localStorage.removeItem('vigyToken');
-    localStorage.removeItem('vigyUser');
+    sessionStorage.removeItem('vigyToken');
+    sessionStorage.removeItem('vigyUser');
+    localStorage.removeItem('vigyToken');
+    localStorage.removeItem('vigyUser');
     navigate('/vigy-login');
   };

Also applies to: 27-31

src/Admin/Pages/VigyForm.jsx (4)

299-311: Dead code: formDataToSend is built but never used

Either remove the block or actually submit multipart if files are required.

-  const formDataToSend = new FormData();
-  // Append all form fields to formDataToSend
-  Object.keys(formData).forEach(tab => {
-    Object.keys(formData[tab]).forEach(field => {
-      if (field === 'panCard' || field === 'addressProof' || field === 'profilePicture') {
-        formDataToSend.append(field, formData[tab][field], formData[tab][field].name);
-      } else {
-        formDataToSend.append(field, formData[tab][field]);
-      }
-    });
-  });
+  // NOTE: Files are collected but not submitted in this JSON flow.
+  // If backend requires documents here, switch to FormData and submit multipart.

141-143: Tighten client-side patterns (anchor regex)

Anchor patterns so partial matches don’t pass.

-             pattern="\d{12}"
+             pattern="^\d{12}$"
-             pattern="\d{10}"
+             pattern="^\d{10}$"
-             pattern="\d{8,18}"
+             pattern="^\d{8,18}$"

(IFSC is already anchored.)

Also applies to: 169-171, 201-205, 231-233


339-349: Navigate to login on successful registration

Closes the loop for users and aligns with new route.

-    if (response.data.success) {
-      console.log('Registration successful!');
-      alert('Registration submitted successfully! Please wait for approval.');
-      // You can redirect to login page or show success message
-    }
+    if (response.data.success) {
+      alert('Registration submitted! Please wait for approval.');
+      navigate('/vigy-login');
+    }

295-299: Centralize API base URL

Avoid duplicating env logic across files.

-  // Use local backend for development, change to production URL when deploying
-  const apiUrl = process.env.NODE_ENV === 'production' 
-    ? 'https://vigybag-backend.onrender.com/api/vigy/register'
-    : 'http://localhost:5000/api/vigy/register';
+  const base =
+    (typeof import.meta !== 'undefined' && import.meta.env?.VITE_API_BASE_URL) ||
+    process.env.REACT_APP_API_BASE_URL ||
+    (process.env.NODE_ENV === 'production'
+      ? 'https://vigybag-backend.onrender.com'
+      : 'http://localhost:5000');
+  const apiUrl = `${base}/api/vigy/register`;
backend/models/Vigy.js (1)

4-4: Use Mongoose timestamps instead of manual createdAt/updatedAt

Manual timestamps won’t auto-update on writes; use timestamps: true and drop fields.

-const vigySchema = new mongoose.Schema({
+const vigySchema = new mongoose.Schema({
   // fields...
-  createdAt: { type: Date, default: Date.now },
-  updatedAt: { type: Date, default: Date.now }
-});
+}, { timestamps: true });

Also applies to: 109-116

src/App.jsx (2)

274-277: Add legacy redirect for stale “/vigy” links

Prevents 404s from old bookmarks and fixes Issue #2638 hard.

   <Route path="/vigy-login" element={<VigyLogin />} />
   <Route path="/vigy-form" element={<VigyForm />} />
-  <Route path="/vigy-dashboard" element={<VigyDashboard />} />
+  <Route path="/vigy-dashboard" element={<VigyDashboard />} />
+  <Route path="/vigy" element={<Navigate to="/vigy-login" replace />} />

274-276: Consider guarding /vigy-dashboard

If Vigy isn’t authenticated, redirect to /vigy-login.

-  <Route path="/vigy-dashboard" element={<VigyDashboard />} />
+  <Route
+    path="/vigy-dashboard"
+    element={
+      (sessionStorage.getItem('vigyToken') || localStorage.getItem('vigyToken'))
+        ? <VigyDashboard />
+        : <Navigate to="/vigy-login" replace />
+    }
+  />
backend/createTestUser.js (2)

5-8: Await DB connection; guard against prod execution.

Use await for connection and bail out in production to avoid accidental seeding.

-// Connect to MongoDB
-mongoose.connect(config.mongoURI)
-  .then(() => console.log('Connected to MongoDB'))
-  .catch(err => console.error('MongoDB connection error:', err));
+// Connect to MongoDB
+if (process.env.NODE_ENV === 'production') {
+  console.error('Refusing to run seeder in production.');
+  process.exit(1);
+}
+async function connect() {
+  try {
+    await mongoose.connect(config.mongoURI);
+    console.log('Connected to MongoDB');
+  } catch (err) {
+    console.error('MongoDB connection error:', err);
+    process.exit(1);
+  }
+}

61-61: Ensure connection before seeding and avoid logging passwords.

Call connect() first; don’t print plaintext passwords even in dev logs.

-createTestUser();
+(async () => {
+  await connect();
+  await createTestUser();
+})();
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 94e346a and 3226bb1.

⛔ Files ignored due to path filters (1)
  • backend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (17)
  • backend/app.js (1 hunks)
  • backend/config/config.js (1 hunks)
  • backend/config/db.js (1 hunks)
  • backend/controllers/vigyController.js (1 hunks)
  • backend/createTestUser.js (1 hunks)
  • backend/middlewares/Passport.js (1 hunks)
  • backend/models/Vigy.js (1 hunks)
  • backend/package.json (3 hunks)
  • backend/routes/authRoutes.js (1 hunks)
  • backend/routes/subscribe.js (1 hunks)
  • backend/routes/vigyRoutes.js (1 hunks)
  • backend/setup-env.js (1 hunks)
  • src/Admin/Pages/VigyDashboard.jsx (1 hunks)
  • src/Admin/Pages/VigyForm.jsx (1 hunks)
  • src/Admin/Pages/VigyLogin.jsx (1 hunks)
  • src/App.jsx (2 hunks)
  • src/User/pages/UserAuth/UserAuth.jsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (11)
src/Admin/Pages/VigyDashboard.jsx (2)
src/Admin/Pages/VigyLogin.jsx (2)
  • navigate (16-16)
  • error (15-15)
src/User/pages/UserAuth/UserAuth.jsx (1)
  • navigate (24-24)
backend/createTestUser.js (3)
backend/models/Vigy.js (1)
  • mongoose (1-1)
backend/controllers/vigyController.js (5)
  • Vigy (1-1)
  • vigy (49-67)
  • vigy (107-107)
  • vigy (159-159)
  • vigy (193-197)
backend/config/config.js (1)
  • config (6-14)
backend/routes/authRoutes.js (2)
backend/app.js (1)
  • passport (5-5)
backend/middlewares/Passport.js (1)
  • passport (1-1)
src/Admin/Pages/VigyLogin.jsx (2)
src/Admin/Pages/VigyForm.jsx (3)
  • formData (11-17)
  • handleInputChange (47-74)
  • handleSubmit (295-350)
src/User/pages/UserAuth/UserAuth.jsx (2)
  • loading (23-23)
  • navigate (24-24)
backend/app.js (4)
backend/routes/authRoutes.js (2)
  • express (1-1)
  • passport (3-3)
backend/routes/vigyRoutes.js (2)
  • express (1-1)
  • req (78-78)
backend/middlewares/Passport.js (1)
  • passport (1-1)
backend/controllers/vigyController.js (2)
  • req (16-32)
  • req (96-96)
src/App.jsx (3)
src/Admin/Pages/VigyLogin.jsx (1)
  • VigyLogin (8-207)
src/Admin/Pages/VigyForm.jsx (1)
  • VigyForm (9-432)
src/Admin/Pages/VigyDashboard.jsx (1)
  • VigyDashboard (5-174)
backend/routes/vigyRoutes.js (3)
backend/routes/authRoutes.js (3)
  • express (1-1)
  • router (2-2)
  • email (32-32)
backend/controllers/vigyController.js (2)
  • req (16-32)
  • req (96-96)
backend/createTestUser.js (1)
  • existingUser (36-36)
backend/controllers/vigyController.js (2)
backend/createTestUser.js (2)
  • Vigy (2-2)
  • vigy (46-46)
backend/routes/vigyRoutes.js (1)
  • req (78-78)
backend/routes/subscribe.js (2)
backend/app.js (1)
  • express (2-2)
backend/routes/index.js (3)
  • express (1-1)
  • require (2-2)
  • router (3-3)
backend/middlewares/Passport.js (2)
backend/app.js (1)
  • passport (5-5)
backend/routes/authRoutes.js (1)
  • passport (3-3)
src/Admin/Pages/VigyForm.jsx (1)
src/Admin/Pages/VigyLogin.jsx (2)
  • formData (9-12)
  • error (15-15)
🪛 Gitleaks (8.27.2)
backend/setup-env.js

[high] 6-6: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 Biome (2.1.2)
backend/routes/subscribe.js

[error] 2-2: Shouldn't redeclare 'express'. Consider to delete it or rename it.

'express' is defined here:

(lint/suspicious/noRedeclare)

🔇 Additional comments (5)
backend/package.json (1)

6-16: No action required — backend/package.json scripts are valid (no nested "scripts").
backend/package.json contains a top-level "scripts" object with start, dev, prod, lint, lint:fix, and test; the nested "scripts" issue reported earlier is not present.

Likely an incorrect or invalid review comment.

src/User/pages/UserAuth/UserAuth.jsx (1)

212-216: Verify /vigy-login route exists and deployment rewrites

Automated search returned no results — confirm <Route path="/vigy-login" ... /> is registered (likely in src/App.jsx) and that hosting deploy rewrites allow deep-linking.

src/Admin/Pages/VigyLogin.jsx (1)

143-149: Forgot-password route: confirmed

Link in src/Admin/Pages/VigyLogin.jsx (line 144) points to "/forgot-password" and matches the Route in src/App.jsx (line 179): <Route path="forgot-password" element={} />. No action needed.

backend/routes/authRoutes.js (1)

8-22: Precheck for Google OAuth config is good.

Validation before invoking passport is a solid safeguard.

backend/app.js (1)

58-63: No change required — vigy routes are correct.
Login links point to /vigy-login and /vigy-form is the registration route; no stale /vigy-form references need replacing.

Comment on lines 26 to 36
app.use(
session({
secret: "Our little secret.",
secret: process.env.SESSION_SECRET || "Our little secret.",
resave: false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Require SESSION_SECRET in production.

Avoid weak default secrets in prod.

 app.use(
   session({
-    secret: process.env.SESSION_SECRET || "Our little secret.",
+    secret: (() => {
+      if (process.env.NODE_ENV === "production" && !process.env.SESSION_SECRET) {
+        throw new Error("SESSION_SECRET must be set in production");
+      }
+      return process.env.SESSION_SECRET || "Our little secret.";
+    })(),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
app.use(
session({
secret: "Our little secret.",
secret: process.env.SESSION_SECRET || "Our little secret.",
resave: false,
app.use(
session({
secret: (() => {
if (process.env.NODE_ENV === "production" && !process.env.SESSION_SECRET) {
throw new Error("SESSION_SECRET must be set in production");
}
return process.env.SESSION_SECRET || "Our little secret.";
})(),
resave: false,
🤖 Prompt for AI Agents
In backend/app.js around lines 26 to 29, the session middleware is falling back
to a weak default secret; update it to require process.env.SESSION_SECRET when
running in production (NODE_ENV === 'production') and refuse to start or throw a
clear error if the env var is missing, otherwise allow the current behavior in
non-production (development/test); ensure the session secret is only set from
the env and remove the hardcoded fallback.

backend/app.js Outdated
Comment on lines 62 to 80
app.use("/api/vigy", vigyRoutes); // /api/vigy

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Don’t mount dev-only in‑memory Vigy routes in production.

Guard with NODE_ENV or a feature flag.

-app.use("/api/vigy", vigyRoutes);          // /api/vigy
+if (process.env.NODE_ENV !== "production") {
+  app.use("/api/vigy", vigyRoutes);        // /api/vigy
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
app.use("/api/vigy", vigyRoutes); // /api/vigy
if (process.env.NODE_ENV !== "production") {
app.use("/api/vigy", vigyRoutes); // /api/vigy
}
🤖 Prompt for AI Agents
In backend/app.js around lines 62-63, the dev-only in-memory Vigy routes are
being mounted unconditionally; wrap the app.use("/api/vigy", vigyRoutes) call in
a runtime guard so these routes are only registered in non-production or when an
explicit feature flag is enabled (e.g., check process.env.NODE_ENV !==
'production' OR a boolean env var like process.env.ENABLE_VIGY === 'true');
ensure the condition is clear, default-off in production, and add a short log
message when the routes are mounted or skipped for observability.

Comment on lines +7 to +11
// Check if Google OAuth credentials are configured
if (!process.env.GOOGLE_CLIENT_ID || !process.env.GOOGLE_CLIENT_SECRET) {
console.warn("⚠️ Google OAuth credentials not found. Google login will not work.");
console.warn(" Please set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in your environment variables.");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Guard Google strategy init; don’t default to an incorrect prod callback URL.

Currently it can initialize with missing creds or a wrong callback (vigybag.com), breaking OAuth. In production, require GOOGLE_CALLBACK_URL and skip/fail fast if missing.

-// Check if Google OAuth credentials are configured
-if (!process.env.GOOGLE_CLIENT_ID || !process.env.GOOGLE_CLIENT_SECRET) {
-  console.warn("⚠️  Google OAuth credentials not found. Google login will not work.");
-  console.warn("   Please set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in your environment variables.");
-}
-
-// Resolve callback URL safely (never default to localhost in production)
-const resolvedCallbackUrl = (() => {
-  const fromEnv = process.env.GOOGLE_CALLBACK_URL;
-  if (fromEnv && fromEnv.trim().length > 0) return fromEnv.trim();
-
-  if (process.env.NODE_ENV === "development") {
-    return "http://localhost:5000/auth/google/callback";
-  }
-
-  // Optional: Production fallback
-  return "https://vigybag.com/auth/google/callback";
-})();
+// Resolve Google OAuth config
+const missingCreds = !process.env.GOOGLE_CLIENT_ID || !process.env.GOOGLE_CLIENT_SECRET;
+const isDev = process.env.NODE_ENV !== "production";
+const resolvedCallbackUrl = (() => {
+  const fromEnv = process.env.GOOGLE_CALLBACK_URL;
+  if (fromEnv && fromEnv.trim()) return fromEnv.trim();
+  return isDev ? "http://localhost:5000/auth/google/callback" : undefined;
+})();
+const canInitGoogle = !missingCreds && !!resolvedCallbackUrl;
+if (!canInitGoogle) {
+  const msg = "Google OAuth config incomplete. Set GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET and GOOGLE_CALLBACK_URL (in production).";
+  if (isDev) {
+    console.warn("⚠️", msg, "Skipping GoogleStrategy initialization.");
+  } else {
+    console.error("❌", msg);
+    // Fail fast or skip strategy; choose one. Here we skip init to keep server up.
+  }
+}
 
-passport.use(
-  new GoogleStrategy(
-    {
-      clientID: process.env.GOOGLE_CLIENT_ID,
-      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
-      callbackURL: resolvedCallbackUrl,
-    },
-    async (accessToken, refreshToken, profile, done) => {
+if (canInitGoogle) {
+  passport.use(new GoogleStrategy(
+    {
+      clientID: process.env.GOOGLE_CLIENT_ID,
+      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
+      callbackURL: resolvedCallbackUrl,
+    },
+    async (accessToken, refreshToken, profile, done) => {
       // existing verify logic unchanged
-    }
-  )
-);
+    }
+  ));
+}

Also applies to: 13-25, 29-31

🤖 Prompt for AI Agents
In backend/middlewares/Passport.js around lines 7-11 (also address lines 13-25
and 29-31): the code currently warns only when GOOGLE_CLIENT_ID/SECRET or
callback URL are missing and may initialize the Google strategy with incorrect
defaults (e.g., vigybag.com). Change this to require GOOGLE_CLIENT_ID,
GOOGLE_CLIENT_SECRET and in production require GOOGLE_CALLBACK_URL; if any
required value is missing, do not initialize the Google strategy and either
throw or exit fast (or explicitly skip strategy registration with a clear error
log). Ensure you remove any hardcoded/default callback URL usage and read
callback URL only from env, validating it before using.

Comment on lines +315 to +333
// Prepare data for the new API
const registrationData = {
fullname: formData.personal.fullname || '',
email: formData.contact.email || '',
password: 'defaultPassword123', // You might want to add a password field to the form
phoneNumber: formData.contact.phoneNumber || '',
address: formData.contact.address || '',
aadhaarNumber: formData.personal.aadhaarNumber || '',
gender: formData.personal.gender || '',
dob: formData.personal.dob || '',
bankAccountName: formData.banking.bankAccountName || '',
bankAccountNumber: formData.banking.bankAccountNumber || '',
bankName: formData.banking.bankName || '',
bankBranch: formData.banking.bankBranch || '',
ifscCode: formData.banking.ifscCode || '',
referralCode: formData.additional.referralCode || '',
promotionalCode: formData.additional.promotionalCode || ''
};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Repo sweep for default password remnants


🏁 Script executed:

#!/bin/bash
# Find any default password leftovers
rg -n -C2 'defaultPassword|defaultPassword123' -g '!**/dist/**' -g '!**/build/**'

Length of output: 148


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Robust search for default password patterns across the repo, excluding common large dirs.
# Use ripgrep when available; fallback to git grep.
PATTERN='defaultPassword123|defaultPassword'
PATTERN_PHRASE='default password'

if command -v rg >/dev/null 2>&1; then
  rg -n -S -C2 -uu --hidden --glob '!.git/**' --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' "$PATTERN" || true
  rg -n -S -C2 -uu --hidden --glob '!.git/**' --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' "$PATTERN_PHRASE" || true
else
  git grep -n -e "defaultPassword123" -e "defaultPassword" || true
  git grep -n -e "default password" || true
fi

Length of output: 297


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== pwd ==="
pwd
echo

echo "=== top-level listing ==="
ls -la | sed -n '1,200p'
echo

echo "=== detect git repo ==="
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
  echo "Inside git repo: yes"
  git rev-parse --abbrev-ref HEAD || true
else
  echo "Inside git repo: no"
fi
echo

echo "=== grep search for default password patterns (fallback to grep instead of rg) ==="
grep -RIn --binary-files=without-match --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=dist --exclude-dir=build -E 'defaultPassword123|defaultPassword' . || true
echo

echo "=== grep search for phrase 'default password' ==="
grep -RIn --binary-files=without-match --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=dist --exclude-dir=build -E 'default password' . || true
echo

echo "=== locate VigyForm.jsx ==="
if command -v fd >/dev/null 2>&1; then
  fd -HI --hidden -e jsx VigyForm || true
else
  find . -type f -iname 'VigyForm.jsx' -print || true
fi
echo

echo "=== show snippet of src/Admin/Pages/VigyForm.jsx (if present) ==="
if [ -f src/Admin/Pages/VigyForm.jsx ]; then
  sed -n '1,480p' src/Admin/Pages/VigyForm.jsx || true
else
  echo "src/Admin/Pages/VigyForm.jsx not found"
fi

Length of output: 17235


Remove hard-coded default password from client (critical)

Hard-coded 'defaultPassword123' exists in src/Admin/Pages/VigyForm.jsx (line ~319). Sending a plaintext default password from the client is a security vulnerability — remove it and stop including passwords in client payloads. Fix options:

  • Remove the literal and do not send password from the client.
  • Collect a user-chosen password in the form (with validation) OR delegate password creation to the backend (generate a secure password + send set-password link / OTP).
  • Rotate/invalidate any accounts created with this default.

Comment on lines +316 to +333
const registrationData = {
fullname: formData.personal.fullname || '',
email: formData.contact.email || '',
password: 'defaultPassword123', // You might want to add a password field to the form
phoneNumber: formData.contact.phoneNumber || '',
address: formData.contact.address || '',
aadhaarNumber: formData.personal.aadhaarNumber || '',
gender: formData.personal.gender || '',
dob: formData.personal.dob || '',
bankAccountName: formData.banking.bankAccountName || '',
bankAccountNumber: formData.banking.bankAccountNumber || '',
bankName: formData.banking.bankName || '',
bankBranch: formData.banking.bankBranch || '',
ifscCode: formData.banking.ifscCode || '',
referralCode: formData.additional.referralCode || '',
promotionalCode: formData.additional.promotionalCode || ''
};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Align payload with backend model: nest bankDetails (and later documents)

Current payload sends flattened bank fields; the model/controller expect bankDetails.{...}. Prevents silent data loss and mismatches.

-      bankAccountName: formData.banking.bankAccountName || '',
-      bankAccountNumber: formData.banking.bankAccountNumber || '',
-      bankName: formData.banking.bankName || '',
-      bankBranch: formData.banking.bankBranch || '',
-      ifscCode: formData.banking.ifscCode || '',
+      bankDetails: {
+        accountName:  formData.banking.bankAccountName  || '',
+        accountNumber:formData.banking.bankAccountNumber|| '',
+        bankName:     formData.banking.bankName         || '',
+        branch:       formData.banking.bankBranch       || '',
+        ifscCode:     formData.banking.ifscCode         || ''
+      },

Follow-up: if documents are required in the model, either (a) switch this submit to multipart and send files, or (b) relax model requirements and add a separate upload step. I can draft either path.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const registrationData = {
fullname: formData.personal.fullname || '',
email: formData.contact.email || '',
password: 'defaultPassword123', // You might want to add a password field to the form
phoneNumber: formData.contact.phoneNumber || '',
address: formData.contact.address || '',
aadhaarNumber: formData.personal.aadhaarNumber || '',
gender: formData.personal.gender || '',
dob: formData.personal.dob || '',
bankAccountName: formData.banking.bankAccountName || '',
bankAccountNumber: formData.banking.bankAccountNumber || '',
bankName: formData.banking.bankName || '',
bankBranch: formData.banking.bankBranch || '',
ifscCode: formData.banking.ifscCode || '',
referralCode: formData.additional.referralCode || '',
promotionalCode: formData.additional.promotionalCode || ''
};
const registrationData = {
fullname: formData.personal.fullname || '',
email: formData.contact.email || '',
password: 'defaultPassword123', // You might want to add a password field to the form
phoneNumber: formData.contact.phoneNumber || '',
address: formData.contact.address || '',
aadhaarNumber: formData.personal.aadhaarNumber || '',
gender: formData.personal.gender || '',
dob: formData.personal.dob || '',
bankDetails: {
accountName: formData.banking.bankAccountName || '',
accountNumber: formData.banking.bankAccountNumber || '',
bankName: formData.banking.bankName || '',
branch: formData.banking.bankBranch || '',
ifscCode: formData.banking.ifscCode || ''
},
referralCode: formData.additional.referralCode || '',
promotionalCode: formData.additional.promotionalCode || ''
};
🤖 Prompt for AI Agents
In src/Admin/Pages/VigyForm.jsx around lines 316 to 333, the registration
payload currently flattens banking fields which the backend expects under
bankDetails; change the payload so banking values are nested as bankDetails: {
bankAccountName, bankAccountNumber, bankName, bankBranch, ifscCode } instead of
top-level keys, and similarly prepare for documents by either converting the
submission to multipart/form-data and attaching files or removing documents from
this payload and performing a separate file-upload step; ensure keys match the
backend model exactly.

@ajaykuraparthi
Copy link
Author

Hi, I’ve rebased my branch and fixed the conflicts. The Vercel check failed due to authorization, which I believe needs maintainer access. Please let me know if any further changes are needed

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/routes/subscribe.js (1)

1-87: Unresolved merge conflict and duplicate declarations make the route unusable.
Resolve conflicts and standardize validation, dedupe imports/exports.

-const express = require("express");
-<<<<<<< HEAD
-const router = express.Router();
-const validator = require("validator");
-const Subscriber = require("../models/subscriber");
-// POST /api/subscribe
-router.post("/", async (req, res) => {
-  const emailRaw = (req.body?.email ?? "").toString();
-  const email = emailRaw.trim().toLowerCase();
-  // Check if email is provided
-  if (!email) {
-    return res.status(400).json({ message: "⚠️ A valid email is required." });
-  }
-  // Validate email format
-  if (!validator.isEmail(email)) {
-    return res
-      .status(400)
-      .json({ message: "⚠️ Please provide a valid email address." });
-  }
-  try {
-    const subscriber = new Subscriber({ email });
-    await subscriber.save();
-    return res.status(201).json({ message: "🎉 Subscribed successfully!" });
-  } catch (err) {
-    console.error("Subscribe error:", err);
-    // Duplicate email
-    if (err.code === 11000) {
-      return res.status(409).json({ message: "This email is already subscribed." });
-    }
-    // Schema validation error
-    if (err.name === "ValidationError") {
-      return res.status(400).json({ message: err.message });
-    }
-    // Server error
-    return res.status(500).json({ message: "❌ Server error. Try again later." });
-=======
-const validator = require("validator");
-const router = express.Router();
-// POST /api/subscribe
-router.post("/", async (req, res) => {
-  try {
-    const { email } = req.body;
-    if (!email) {
-      return res.status(400).json({
-        success: false,
-        message: "Email is required"
-      });
-    }
-    // Validate email format
-    if (!validator.isEmail(email)) {
-      return res.status(400).json({
-        success: false,
-        message: "Please provide a valid email address"
-      });
-    }
-    // TODO: Add email to database or mailing list service
-    // TODO: Send confirmation email
-    res.status(200).json({
-      success: true,
-      message: "Successfully subscribed to newsletter",
-      email: email
-    });
-  } catch (error) {
-    console.error("Subscribe error:", error);
-    res.status(500).json({
-      success: false,
-      message: "Internal server error"
-    });
->>>>>>> 0163c432 (resolve: merge conflicts between fix-vigy-login and main branches)
-  }
-});
-
-module.exports = router;
+const express = require("express");
+const validator = require("validator");
+const Subscriber = require("../models/subscriber");
+const router = express.Router();
+
+// POST /api/subscribe
+router.post("/", async (req, res) => {
+  try {
+    const rawEmail = req.body?.email;
+    if (typeof rawEmail !== "string" || !rawEmail.trim()) {
+      return res.status(400).json({ success: false, message: "Email is required" });
+    }
+    const email = validator.normalizeEmail(rawEmail) || rawEmail.trim().toLowerCase();
+    if (!validator.isEmail(email)) {
+      return res.status(400).json({ success: false, message: "Please provide a valid email address" });
+    }
+    const subscriber = new Subscriber({ email });
+    await subscriber.save();
+    return res.status(201).json({ success: true, message: "Successfully subscribed to newsletter", email });
+  } catch (err) {
+    console.error("Subscribe error:", err);
+    if (err?.code === 11000) {
+      return res.status(409).json({ success: false, message: "This email is already subscribed." });
+    }
+    if (err?.name === "ValidationError") {
+      return res.status(400).json({ success: false, message: err.message });
+    }
+    return res.status(500).json({ success: false, message: "Internal server error" });
+  }
+});
+
+module.exports = router;
♻️ Duplicate comments (22)
backend/setup-env.js (3)

4-4: Port mismatch with dev backend (should be 5000).
Frontend and backend configs default to 5000 elsewhere; align the generated PORT.

-const envContent = `PORT=3001
+const envContent = `PORT=5000
 MONGO_URI=mongodb://localhost:27017/vigybag
 JWT_SECRET=vigybag_jwt_secret_key_2024
 SESSION_SECRET=vigybag_session_secret_2024
 GOOGLE_CLIENT_ID=your_google_client_id_here
 GOOGLE_CLIENT_SECRET=your_google_client_secret_here
 NODE_ENV=development
 `;

15-23: Don’t overwrite existing .env; create-once with a clear message.
Prevents clobbering local secrets.

-try {
-  fs.writeFileSync(envPath, envContent);
+try {
+  if (fs.existsSync(envPath)) {
+    console.log('ℹ️  .env already exists, not overwriting.');
+    console.log('📁 Location:', envPath);
+    process.exit(0);
+  }
+  fs.writeFileSync(envPath, envContent);
   console.log('✅ .env file created successfully!');
   console.log('📁 Location:', envPath);
   console.log('\n⚠️  IMPORTANT: Update GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET with your actual values');
 } catch (error) {

13-20: Ensure .env is gitignored and loaded from backend path.
Add backend/.env to .gitignore and call dotenv.config({ path: backend/.env }) in backend entry points to ensure the generated file is used.

backend/routes/subscribe.js (1)

1-1: Normalize/validate email (server-side) — good direction.
Change keeps us safe even if client validation is bypassed.

src/Admin/Pages/VigyLogin.jsx (2)

144-149: Ensure client route exists for “/forgot-password”.
Prevent a 404 from this link.


41-48: Avoid storing tokens in localStorage; wire “Remember me” and default to sessionStorage.
Mitigates XSS token theft; best is HttpOnly cookies from backend.

-      if (response.data.success) {
-        // Store token or user data
-        localStorage.setItem('vigyToken', response.data.token);
-        localStorage.setItem('vigyUser', JSON.stringify(response.data.user));
-        
-        // Redirect to Vigy dashboard or appropriate page
-        navigate('/vigy-dashboard');
-      }
+      if (response.data.success) {
+        const storage = rememberMe ? localStorage : sessionStorage;
+        storage.setItem('vigyToken', response.data.token);
+        storage.setItem('vigyUser', JSON.stringify({
+          id: response.data.user?.id,
+          email: response.data.user?.email,
+          fullname: response.data.user?.fullname
+        }));
+        navigate('/vigy-dashboard');
+      }

And add state + checkbox handler:

-  const [loading, setLoading] = useState(false);
+  const [loading, setLoading] = useState(false);
+  const [rememberMe, setRememberMe] = useState(false);
@@
-              <input
+              <input
                 type="checkbox"
                 className="mr-2 h-4 w-4 rounded border-gray-300 text-[#4a7c59] focus:ring-[#4a7c59]"
+                onChange={(e) => setRememberMe(e.target.checked)}
               />
backend/app.js (3)

28-43: Harden session cookies for cross-site flows and require SESSION_SECRET in prod.
Prevents cookie drop and weak secrets in production.


90-106: Don’t expose OAuth config in production.
Gate the /auth/google/test route behind NODE_ENV !== 'production'.


73-79: Mount path “/vpi” likely a typo; switch to “/api”.
Prevents orphaned user routes.

-app.use("/vpi", userRoutes);
+app.use("/api", userRoutes);
backend/models/Vigy.js (4)

48-74: Make bankDetails a required sub-schema and validate IFSC.

Plain nested objects let callers omit the parent field and bypass nested requireds. Use a sub-schema and add an IFSC format check.

-  bankDetails: {
-    accountName: {
-      type: String,
-      required: true,
-      trim: true
-    },
-    accountNumber: {
-      type: String,
-      required: true,
-      trim: true
-    },
-    bankName: {
-      type: String,
-      required: true,
-      trim: true
-    },
-    branch: {
-      type: String,
-      required: true,
-      trim: true
-    },
-    ifscCode: {
-      type: String,
-      required: true,
-      trim: true
-    }
-  },
+  bankDetails: {
+    type: new mongoose.Schema(
+      {
+        accountName: { type: String, required: true, trim: true },
+        accountNumber: { type: String, required: true, trim: true },
+        bankName: { type: String, required: true, trim: true },
+        branch: { type: String, required: true, trim: true },
+        ifscCode: {
+          type: String,
+          required: true,
+          trim: true,
+          match: [/^[A-Z]{4}0[A-Z0-9]{6}$/, 'Invalid IFSC code'],
+        },
+      },
+      { _id: false }
+    ),
+    required: true,
+  },

75-88: Make documents a required sub-schema.

Ensure presence of the whole object, not only nested keys.

-  documents: {
-    panCard: {
-      type: String, // File path or URL
-      required: true
-    },
-    addressProof: {
-      type: String, // File path or URL
-      required: true
-    },
-    profilePicture: {
-      type: String, // File path or URL
-      required: false
-    }
-  },
+  documents: {
+    type: new mongoose.Schema(
+      {
+        panCard: { type: String, required: true },       // file path or URL
+        addressProof: { type: String, required: true },  // file path or URL
+        profilePicture: { type: String, required: false }
+      },
+      { _id: false }
+    ),
+    required: true,
+  },

32-38: Replace invalid length with a proper validator for Aadhaar.

length: 12 is ignored by Mongoose. Enforce exactly 12 digits with a match regex.

   aadhaarNumber: {
     type: String,
     required: true,
     unique: true,
     trim: true,
-    length: 12
+    match: [/^\d{12}$/, 'Aadhaar number must be exactly 12 digits'],
   },

32-38: Encrypt high‑risk PII at rest (aadhaar, bank account numbers, documents).

Persisting plaintext PII is a major risk. Encrypt fields with AES‑GCM and index a deterministic HMAC for Aadhaar uniqueness.

Minimal plugin-based example (illustrative):

+const { fieldEncryption } = require('mongoose-field-encryption');
+const ENC_KEY = process.env.PII_ENC_KEY; // 32-byte base64
+const HMAC_KEY = process.env.PII_HMAC_KEY; // for deterministic hash/index
 ...
 const vigySchema = new mongoose.Schema({
   ...
   aadhaarNumber: { ... },
   bankDetails: { ... },
   documents: { ... },
   ...
-});
+});
+
+vigySchema.plugin(fieldEncryption, {
+  fields: [
+    'aadhaarNumber',
+    'bankDetails.accountNumber',
+    'documents.panCard',
+    'documents.addressProof',
+  ],
+  secret: ENC_KEY,
+  // consider saltGenerator for rotation
+});
+
+// Store deterministic Aadhaar hash for uniqueness
+vigySchema.add({ aadhaarHash: { type: String, unique: true, index: true } });
+vigySchema.pre('save', function(next) {
+  if (this.isModified('aadhaarNumber')) {
+    this.aadhaarHash = require('crypto')
+      .createHmac('sha256', HMAC_KEY)
+      .update(this.aadhaarNumber)
+      .digest('hex');
+  }
+  next();
+});

Confirm library acceptance, key management, and add tests for encrypt/decrypt and uniqueness collisions.

Also applies to: 48-88

backend/controllers/vigyController.js (9)

16-33: Validate and normalize registration input up front.

Type-check, trim, and canonicalize values before use.

 const registerVigy = async (req, res) => {
   try {
-    const {
+    let {
       fullname,
       email,
       password,
       phoneNumber,
       address,
       aadhaarNumber,
       gender,
       dob,
       bankAccountName,
       bankAccountNumber,
       bankName,
       bankBranch,
       ifscCode,
       referralCode,
       promotionalCode
     } = req.body;
+
+    if (typeof email !== 'string' || typeof password !== 'string') {
+      return res.status(400).json({ success: false, message: 'Invalid payload' });
+    }
+    const emailNorm = email.trim().toLowerCase();
+    const aadhaarNorm = String(aadhaarNumber || '').trim();
+    if (!fullname || !emailNorm || !password || !phoneNumber || !address || !aadhaarNorm || !dob) {
+      return res.status(400).json({ success: false, message: 'Missing required fields' });
+    }
+    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailNorm)) {
+      return res.status(400).json({ success: false, message: 'Invalid email' });
+    }
+    if (!/^\d{12}$/.test(aadhaarNorm)) {
+      return res.status(400).json({ success: false, message: 'Invalid Aadhaar number' });
+    }

48-67: Store normalized email/Aadhaar.

Align stored values with query forms.

     const vigy = new Vigy({
       fullname,
-      email,
+      email: emailNorm,
       password,
       phoneNumber,
       address,
-      aadhaarNumber,
+      aadhaarNumber: aadhaarNorm,
       gender,
       dob,
       bankDetails: {
         accountName: bankAccountName,
         accountNumber: bankAccountNumber,
         bankName,
         branch: bankBranch,
         ifscCode
       },
       referralCode,
       promotionalCode
     });

81-88: Handle duplicate key errors deterministically (E11000).

Return 400 with a stable message; don’t leak internals.

   } catch (error) {
-    console.error('Vigy registration error:', error);
-    res.status(500).json({
-      success: false,
-      message: 'Server error during registration',
-      error: error.message
-    });
+    if (error && error.code === 11000) {
+      const key = Object.keys(error.keyPattern || {})[0] || 'field';
+      const message =
+        key === 'email' ? 'Email already registered' :
+        key === 'aadhaarNumber' ? 'Aadhaar number already registered' :
+        'Duplicate value';
+      return res.status(400).json({ success: false, message });
+    }
+    console.error('Vigy registration error:', error);
+    res.status(500).json({ success: false, message: 'Server error during registration' });
   }

5-9: Remove insecure JWT secret fallback. Fail fast if unset.

Hard-coded default weakens security.

-const generateToken = (vigyId) => {
-  return jwt.sign({ vigyId }, process.env.JWT_SECRET || 'mysecretkey', {
-    expiresIn: '7d'
-  });
-};
+const generateToken = (vigyId) => {
+  const secret = process.env.JWT_SECRET;
+  if (!secret) throw new Error('JWT_SECRET is not configured');
+  return jwt.sign({ vigyId }, secret, { expiresIn: '7d' });
+};

34-38: Harden uniqueness check against operator payloads.

Query with normalized strings.

-    const existingVigy = await Vigy.findOne({ 
-      $or: [{ email }, { aadhaarNumber }] 
-    });
+    const existingVigy = await Vigy.findOne({
+      $or: [{ email: emailNorm }, { aadhaarNumber: aadhaarNorm }]
+    });

96-105: Type-check and normalize login payload.

Block NoSQL operator payloads; trim/lowercase email.

-    const { email, password } = req.body;
+    const { email, password } = req.body;
+    if (typeof email !== 'string' || typeof password !== 'string') {
+      return res.status(400).json({ success: false, message: 'Invalid payload' });
+    }
+    const emailNorm = email.trim().toLowerCase();
 ...
-    if (!email || !password) {
+    if (!emailNorm || !password) {
       return res.status(400).json({
         success: false,
         message: 'Please provide both email and password'
       });
     }

106-118: Use normalized email and select password for comparison.

If you mark password as select: false, you must project it explicitly.

-    const vigy = await Vigy.findOne({ email });
+    const vigy = await Vigy.findOne({ email: emailNorm }).select('+password');

154-172: JWT auth middleware contract is unclear (req.vigyId).

Ensure a middleware verifies the token and sets req.vigyId; protect this route accordingly.

Quick verification script:

#!/bin/bash
# Expect an auth middleware that sets req.vigyId and is used on /api/vigy/profile
rg -nP -C2 "req\\.vigyId|authenticateVigy|Authorization|jwt\\.verify" backend/middlewares backend/routes

186-197: Prevent mass assignment on profile updates.

Whitelist fields; avoid spreading req.body into updates.

-    const updates = req.body;
-    delete updates.password; // Don't allow password update through this route
-    delete updates.email; // Don't allow email update through this route
-    delete updates.aadhaarNumber; // Don't allow Aadhaar update through this route
-
-    const vigy = await Vigy.findByIdAndUpdate(
-      req.vigyId,
-      { ...updates, updatedAt: Date.now() },
-      { new: true, runValidators: true }
-    );
+    const { password, email, aadhaarNumber, ...rest } = req.body;
+    const allowed = ['fullname', 'phoneNumber', 'address', 'gender', 'dob', 'bankDetails', 'referralCode', 'promotionalCode'];
+    const safeUpdates = {};
+    for (const key of allowed) {
+      if (Object.prototype.hasOwnProperty.call(rest, key)) safeUpdates[key] = rest[key];
+    }
+    const vigy = await Vigy.findByIdAndUpdate(
+      req.vigyId,
+      { $set: safeUpdates },
+      { new: true, runValidators: true }
+    );
🧹 Nitpick comments (8)
src/Admin/Pages/VigyLogin.jsx (1)

71-76: Pass flow context to Google OAuth to land on the correct dashboard.
Backend can read it to route Vigy logins to /vigy-dashboard.

-  const handleGoogleLogin = () => {
-    const googleAuthUrl = process.env.NODE_ENV === 'production'
-      ? 'https://vigybag-backend.onrender.com/auth/google'
-      : 'http://localhost:5000/auth/google';
-    window.location.href = googleAuthUrl;
-  };
+  const handleGoogleLogin = () => {
+    const base = process.env.NODE_ENV === 'production'
+      ? 'https://vigybag-backend.onrender.com'
+      : 'http://localhost:5000';
+    const url = new URL('/auth/google', base);
+    url.searchParams.set('flow', 'vigy');
+    window.location.href = url.toString();
+  };
backend/models/Vigy.js (4)

22-26: Validate phoneNumber format.

Add a basic E.164 check to prevent malformed data.

   phoneNumber: {
     type: String,
     required: true,
-    trim: true
+    trim: true,
+    match: [/^\+?[1-9]\d{7,14}$/, 'Invalid phone number'],
   },

4-4: Use Mongoose timestamps instead of manual createdAt/updatedAt.

Removes duplication and ensures automatic updates.

-const vigySchema = new mongoose.Schema({
+const vigySchema = new mongoose.Schema({
   ...
-  createdAt: {
-    type: Date,
-    default: Date.now
-  },
-  updatedAt: {
-    type: Date,
-    default: Date.now
-  }
-});
+}, { timestamps: true });

Also applies to: 109-116


17-21: Consider select: false for password (pair with controller .select('+password')).

Prevents accidental exposure in queries; adjust login query accordingly.

   password: {
     type: String,
     required: true,
-    minlength: 6
+    minlength: 6,
+    select: false
   },

137-145: Extend redaction or centralize via toJSON transform.

Optional: move redaction to a schema transform so all JSON responses are safe by default.

Example:

+vigySchema.set('toJSON', {
+  transform: (_doc, ret) => {
+    delete ret.password;
+    delete ret.aadhaarNumber;
+    delete ret.bankDetails;
+    delete ret.documents;
+    return ret;
+  },
+});
backend/controllers/vigyController.js (3)

71-79: Consider withholding tokens until verification/approval.

You mint tokens at registration while status defaults to 'pending'. Confirm this aligns with access policy for protected routes.

Also applies to: 137-143


144-151: Avoid echoing raw error messages to clients.

Return generic messages; keep full details in server logs.

-    res.status(500).json({
-      success: false,
-      message: 'Server error during login',
-      error: error.message
-    });
+    res.status(500).json({ success: false, message: 'Server error during login' });

1-228: Add basic abuse mitigations for auth endpoints.

Apply rate limiting and incremental backoff on login to deter brute force; add audit logs for registration and suspicious activity.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3226bb1 and 28944e3.

⛔ Files ignored due to path filters (1)
  • backend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (17)
  • backend/app.js (1 hunks)
  • backend/config/config.js (1 hunks)
  • backend/config/db.js (1 hunks)
  • backend/controllers/vigyController.js (1 hunks)
  • backend/createTestUser.js (1 hunks)
  • backend/middlewares/Passport.js (1 hunks)
  • backend/models/Vigy.js (1 hunks)
  • backend/package.json (1 hunks)
  • backend/routes/authRoutes.js (1 hunks)
  • backend/routes/subscribe.js (2 hunks)
  • backend/routes/vigyRoutes.js (1 hunks)
  • backend/setup-env.js (1 hunks)
  • src/Admin/Pages/VigyDashboard.jsx (1 hunks)
  • src/Admin/Pages/VigyForm.jsx (1 hunks)
  • src/Admin/Pages/VigyLogin.jsx (1 hunks)
  • src/App.jsx (2 hunks)
  • src/User/pages/UserAuth/UserAuth.jsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • backend/package.json
🚧 Files skipped from review as they are similar to previous changes (9)
  • backend/config/db.js
  • src/Admin/Pages/VigyDashboard.jsx
  • src/Admin/Pages/VigyForm.jsx
  • src/User/pages/UserAuth/UserAuth.jsx
  • backend/routes/authRoutes.js
  • backend/createTestUser.js
  • src/App.jsx
  • backend/routes/vigyRoutes.js
  • backend/config/config.js
🧰 Additional context used
🧬 Code graph analysis (6)
backend/models/Vigy.js (2)
backend/config/db.js (1)
  • mongoose (3-3)
backend/createTestUser.js (1)
  • mongoose (1-1)
backend/middlewares/Passport.js (2)
backend/app.js (1)
  • passport (5-5)
backend/routes/authRoutes.js (1)
  • passport (3-3)
backend/controllers/vigyController.js (2)
backend/createTestUser.js (2)
  • Vigy (2-2)
  • vigy (46-46)
backend/routes/vigyRoutes.js (1)
  • req (78-78)
src/Admin/Pages/VigyLogin.jsx (1)
src/Admin/Pages/VigyForm.jsx (2)
  • formData (11-17)
  • handleSubmit (295-350)
backend/app.js (3)
backend/routes/vigyRoutes.js (2)
  • express (1-1)
  • req (78-78)
backend/middlewares/Passport.js (1)
  • passport (1-1)
backend/controllers/vigyController.js (2)
  • req (16-32)
  • req (96-96)
backend/routes/subscribe.js (3)
backend/routes/index.js (3)
  • require (2-2)
  • router (3-3)
  • express (1-1)
backend/app.js (1)
  • express (2-2)
src/User/pages/Home/Home.jsx (1)
  • email (71-71)
🪛 Biome (2.1.2)
backend/middlewares/Passport.js

[error] 27-27: Expected a property, a shorthand property, a getter, a setter, or a method but instead found '<<'.

Expected a property, a shorthand property, a getter, a setter, or a method here.

(parse)


[error] 27-27: Expected an expression but instead found '<<'.

Expected an expression here.

(parse)


[error] 27-27: Expected an expression but instead found '<<'.

Expected an expression here.

(parse)


[error] 28-28: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 28-28: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 29-29: Expected a JSX attribute but instead found ','.

Expected a JSX attribute here.

(parse)


[error] 29-29: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 29-29: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 30-30: Expected a JSX attribute but instead found ','.

Expected a JSX attribute here.

(parse)


[error] 30-30: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 30-30: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 30-32: Expected a JSX attribute but instead found '|| "http://vigybag.com/auth/google/callback",
======='.

Expected a JSX attribute here.

(parse)


[error] 32-32: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 32-32: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 33-33: Expected a JSX attribute but instead found ','.

Expected a JSX attribute here.

(parse)


[error] 33-33: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 33-33: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 34-34: Expected a JSX attribute but instead found ','.

Expected a JSX attribute here.

(parse)


[error] 35-35: Expected a JSX attribute but instead found ','.

Expected a JSX attribute here.

(parse)


[error] 35-35: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 35-35: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 35-35: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 35-35: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 35-35: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 35-35: Unexpected token. Did you mean {'>'} or &gt;?

(parse)

backend/app.js

[error] 19-20: Expected a statement but instead found '======='.

Expected a statement here.

(parse)


[error] 31-32: Expected a statement but instead found '>>>>>>> b4f6540 (Fix: Corrected routing'.

Expected a statement here.

(parse)


[error] 32-32: expected ( but instead found 'Login as Vigy'

Remove 'Login as Vigy'

(parse)


[error] 32-32: expected ; but instead found button

Remove button

(parse)


[error] 32-32: expected , but instead found #

Remove #

(parse)


[error] 32-32: Expected an identifier but instead found '2638'.

Expected an identifier here.

(parse)


[error] 32-32: Private names are only allowed on the left side of a 'in' expression

(parse)


[error] 32-32: expected , but instead found 2638

Remove 2638

(parse)


[error] 32-32: expected ; but instead found )

Remove )

(parse)


[error] 47-50: Expected a statement but instead found '<<<<<<< HEAD
// Routes
app.use("/api/subscribe", subscribeRoute)'.

Expected a statement here.

(parse)


[error] 55-59: Expected a statement but instead found '=======

// Root route for testing
app.get("/", (req, res) =>'.

Expected a statement here.

(parse)


[error] 70-70: Expected a statement but instead found ')'.

Expected a statement here.

(parse)


[error] 109-109: Expected a statement but instead found '>>>>>>> b4f6540 (Fix: Corrected routing'.

Expected a statement here.

(parse)


[error] 109-109: expected ( but instead found 'Login as Vigy'

Remove 'Login as Vigy'

(parse)


[error] 109-109: expected ; but instead found button

Remove button

(parse)


[error] 109-109: expected , but instead found #

Remove #

(parse)


[error] 109-109: Private names are only allowed on the left side of a 'in' expression

(parse)


[error] 17-18: This variable is used before its declaration.

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


[error] 18-19: This variable is used before its declaration.

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


[error] 22-22: Shouldn't redeclare 'subscribeRoute'. Consider to delete it or rename it.

'subscribeRoute' is defined here:

(lint/suspicious/noRedeclare)


[error] 24-24: Shouldn't redeclare 'app'. Consider to delete it or rename it.

'app' is defined here:

(lint/suspicious/noRedeclare)

backend/routes/subscribe.js

[error] 1-2: Expected a statement but instead found '<<<<<<< HEAD'.

Expected a statement here.

(parse)


[error] 45-45: Expected a statement but instead found '======='.

Expected a statement here.

(parse)


[error] 82-82: numbers cannot be followed by identifiers directly after

an identifier cannot appear here

(parse)

🪛 Gitleaks (8.27.2)
backend/setup-env.js

[high] 6-6: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (3)
backend/middlewares/Passport.js (2)

5-5: Load the same env file path that setup-env.js creates.
Avoid surprises across cwd differences.

-const dotenv = require("dotenv");
-dotenv.config();
+const dotenv = require("dotenv");
+const path = require("path");
+dotenv.config({ path: path.join(__dirname, "../.env") });

13-22: Good: safe callback URL resolution in dev; keep prod strict.
No change needed once conflicts are resolved.

backend/controllers/vigyController.js (1)

126-133: Confirm allowed statuses for login.

Verify that only 'approved' and 'active' are intended; document or centralize as a constant/enumeration.

Comment on lines 24 to +35
passport.use(
new GoogleStrategy(
{
<<<<<<< HEAD
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.GOOGLE_CALLBACK_URL || "http://vigybag.com/auth/google/callback",
=======
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: resolvedCallbackUrl,
>>>>>>> b4f65404 (Fix: Corrected routing for 'Login as Vigy' button (Issue #2638))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Unresolved merge conflict breaks build; also risk of initializing GoogleStrategy with invalid callbackURL.
Clean conflict markers and guard strategy init; fail fast in prod if config is incomplete.

 passport.use(
-  new GoogleStrategy(
-    {
-<<<<<<< HEAD
-  clientID: process.env.GOOGLE_CLIENT_ID,
-  clientSecret: process.env.GOOGLE_CLIENT_SECRET,
-  callbackURL: process.env.GOOGLE_CALLBACK_URL || "http://vigybag.com/auth/google/callback",
-=======
-      clientID: process.env.GOOGLE_CLIENT_ID,
-      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
-      callbackURL: resolvedCallbackUrl,
->>>>>>> b4f65404 (Fix: Corrected routing for 'Login as Vigy' button (Issue #2638))
-    },
-    async (accessToken, refreshToken, profile, done) => {
+  // Guard config before initializing strategy
+  // In dev, allow localhost default; in prod, require explicit GOOGLE_CALLBACK_URL
+  () => {
+    const missingCreds = !process.env.GOOGLE_CLIENT_ID || !process.env.GOOGLE_CLIENT_SECRET;
+    const isProd = process.env.NODE_ENV === 'production';
+    const canInitGoogle = !missingCreds && !!resolvedCallbackUrl;
+    if (!canInitGoogle) {
+      const msg = "Google OAuth config incomplete. Set GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, and GOOGLE_CALLBACK_URL (in production).";
+      if (isProd) throw new Error(msg);
+      console.warn("⚠️", msg, "Skipping GoogleStrategy initialization in development.");
+      return;
+    }
+    passport.use(new GoogleStrategy(
+      {
+        clientID: process.env.GOOGLE_CLIENT_ID,
+        clientSecret: process.env.GOOGLE_CLIENT_SECRET,
+        callbackURL: resolvedCallbackUrl,
+      },
+      async (accessToken, refreshToken, profile, done) => {
         // existing verify logic unchanged
-    }
-  )
+      }
+    ));
+  }
 );

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 Biome (2.1.2)

[error] 27-27: Expected a property, a shorthand property, a getter, a setter, or a method but instead found '<<'.

Expected a property, a shorthand property, a getter, a setter, or a method here.

(parse)


[error] 27-27: Expected an expression but instead found '<<'.

Expected an expression here.

(parse)


[error] 27-27: Expected an expression but instead found '<<'.

Expected an expression here.

(parse)


[error] 28-28: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 28-28: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 29-29: Expected a JSX attribute but instead found ','.

Expected a JSX attribute here.

(parse)


[error] 29-29: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 29-29: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 30-30: Expected a JSX attribute but instead found ','.

Expected a JSX attribute here.

(parse)


[error] 30-30: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 30-30: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 30-32: Expected a JSX attribute but instead found '|| "http://vigybag.com/auth/google/callback",
======='.

Expected a JSX attribute here.

(parse)


[error] 32-32: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 32-32: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 33-33: Expected a JSX attribute but instead found ','.

Expected a JSX attribute here.

(parse)


[error] 33-33: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 33-33: Expected a JSX attribute but instead found '.'.

Expected a JSX attribute here.

(parse)


[error] 34-34: Expected a JSX attribute but instead found ','.

Expected a JSX attribute here.

(parse)


[error] 35-35: Expected a JSX attribute but instead found ','.

Expected a JSX attribute here.

(parse)


[error] 35-35: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 35-35: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 35-35: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 35-35: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 35-35: Unexpected token. Did you mean {'>'} or &gt;?

(parse)


[error] 35-35: Unexpected token. Did you mean {'>'} or &gt;?

(parse)

🤖 Prompt for AI Agents
In backend/middlewares/Passport.js around lines 24 to 35, remove the Git merge
conflict markers and the duplicated client config, use the resolvedCallbackUrl
value (or compute it consistently) for callbackURL, and add a guard that
validates process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET and
resolvedCallbackUrl before calling passport.use; if any are missing, log an
explicit error and exit in production (or skip initialization in non-prod) so
the GoogleStrategy is never initialized with invalid config.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (4)
backend/setup-env.js (3)

17-17: Confirm .env load path and gitignore.

This writes to backend/.env. Ensure runtime uses dotenv.config({ path: path.join(__dirname, ".env") }) (or equivalent) and that .env is gitignored.

Run:

#!/bin/bash
# .env should be ignored
rg -nP '(^|/)\\.env(\\b|$)' .gitignore -n || echo "No .env ignore rule found"

# Verify dotenv is loading backend/.env explicitly
rg -nP "dotenv\\.config\\(([^)]*)\\)" backend -C2

# Check for other hard-coded ports; ensure 5000 is consistent
rg -nP 'PORT=\\d+|process\\.env\\.PORT|:\\s*\\d{4,5}\\b' -g '!**/node_modules/**' -n -C2

8-8: Fix port: set PORT=5000 (currently 3001).

Frontend/back-end expect 5000; keep local flow consistent. The AI summary also claims 5000, but code has 3001.

Apply this diff:

-const envContent = `PORT=3001
+const envContent = `PORT=5000
 MONGO_URI=mongodb://localhost:27017/vigybag
 JWT_SECRET=${jwtSecret}
 SESSION_SECRET=${sessionSecret}
 GOOGLE_CLIENT_ID=
 GOOGLE_CLIENT_SECRET=
 NODE_ENV=development
 `;

19-23: Do not overwrite existing .env; preserve secrets/sessions and tighten perms.

Overwriting rotates secrets and invalidates sessions; write once with 0600 perms.

Apply this diff:

-  fs.writeFileSync(envPath, envContent, { encoding: 'utf8', flag: 'w' });
-  console.log('✅ .env file created successfully!');
-  console.log('📁 Location:', envPath);
+  if (fs.existsSync(envPath)) {
+    console.log('ℹ️  .env already exists, not overwriting.');
+    console.log('📁 Location:', envPath);
+    process.exit(0);
+  }
+  fs.writeFileSync(envPath, envContent, { encoding: 'utf8', flag: 'wx', mode: 0o600 });
+  console.log('✅ .env file created successfully!');
+  console.log('📁 Location:', envPath);
backend/routes/subscribe.js (1)

8-16: Normalize email with validator and add strict type guard (avoid .toString()).

Use validator.normalizeEmail and a proper string check to prevent edge-case bypasses and ensure consistent storage.

-  const emailRaw = (req.body?.email ?? "").toString();
-  const email = emailRaw.trim().toLowerCase();
-
-  if (!email) {
-    return res.status(400).json({ message: "⚠️ A valid email is required." });
-  }
-
-  if (!validator.isEmail(email)) {
-    return res.status(400).json({ message: "⚠️ Please provide a valid email address." });
-  }
+  const rawEmail = req.body?.email;
+  if (typeof rawEmail !== "string" || !rawEmail.trim()) {
+    return res.status(400).json({ message: "⚠️ A valid email is required." });
+  }
+  const email =
+    validator.normalizeEmail(rawEmail, {
+      gmail_remove_subaddress: true,
+      gmail_remove_dots: false,
+    }) || rawEmail.trim().toLowerCase();
+  if (!validator.isEmail(email)) {
+    return res.status(400).json({ message: "⚠️ Please provide a valid email address." });
+  }
🧹 Nitpick comments (1)
backend/routes/subscribe.js (1)

30-33: Avoid leaking internal validation details in API responses.

Return a generic message to clients; log the detailed err.message server-side.

-    if (err.name === "ValidationError") {
-      return res.status(400).json({ message: err.message });
-    }
+    if (err.name === "ValidationError") {
+      console.warn("Subscribe validation error:", err.message);
+      return res.status(400).json({ message: "⚠️ Please provide a valid email address." });
+    }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 28944e3 and 79a25e4.

📒 Files selected for processing (3)
  • backend/app.js (1 hunks)
  • backend/routes/subscribe.js (1 hunks)
  • backend/setup-env.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/app.js
🔇 Additional comments (2)
backend/setup-env.js (1)

5-6: LGTM: Strong random secrets (256-bit) for JWT/Session.

Good call using crypto.randomBytes(32) for both secrets.

backend/routes/subscribe.js (1)

4-4: LGTM: single router init and export look correct.

Duplicate imports/exports from earlier feedback are resolved. Thanks.

Comment on lines 20 to 28
const subscriber = new Subscriber({ email });
await subscriber.save();

return res.status(201).json({ message: "🎉 Subscribed successfully!" });
} catch (err) {
console.error("Subscribe error:", err);

// Duplicate email
if (err.code === 11000) {
return res.status(409).json({ message: "This email is already subscribed." });
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Enforce case-insensitive email uniqueness at the DB level (index + backfill).

Lowercasing at write-time helps, but without a case-insensitive unique index, legacy mixed‑case rows can allow duplicates.

  • Ensure schema sets: unique: true, lowercase: true, trim: true.
  • Add an index with collation strength 2 or backfill all existing emails to lowercase before creating a standard unique index.

Example (in the Subscriber schema file):

email: { type: String, required: true, unique: true, lowercase: true, trim: true }
// Ensure case-insensitive uniqueness (MongoDB >=3.4):
SubscriberSchema.index({ email: 1 }, { unique: true, collation: { locale: "en", strength: 2 } });

Run to verify schema/index hints:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "Locate Subscriber model file(s):"
fd -a -g "models/**/subscriber.*" backend || true

echo -e "\nScan for email schema options and indexes:"
rg -n -C2 -S 'email.*(unique|lowercase|trim|index|collation)' backend || true
rg -n -C3 -S 'Schema\\(|new Schema|index\\(\\{\\s*email' backend || true

Length of output: 542


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "Searching repo for Subscriber model, schema definitions, and email/index settings (using fixed-string searches to avoid regex errors)..."

echo -e "\n1) Occurrences of 'Subscriber':"
rg -nF --hidden 'Subscriber' || true

echo -e "\n2) Mongoose/model/schema patterns (literal):"
rg -nF --hidden 'mongoose.model' || true
rg -nF --hidden 'new Schema' || true
rg -nF --hidden 'Schema(' || true

echo -e "\n3) Email field options and index hints (literal):"
rg -nF --hidden 'email:' || true
rg -nF --hidden 'lowercase: true' || true
rg -nF --hidden 'unique: true' || true
rg -nF --hidden 'index(' || true
rg -nF --hidden 'collation' || true

echo -e "\n4) Candidate model files and paths:"
fd -a -g "*subscriber*" || true
fd -a -g "*Subscriber*" || true
fd -a -g "models/**" || true

Length of output: 3885


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "== backend/models/subscriber.js =="
sed -n '1,240p' backend/models/subscriber.js || true

echo -e "\n== Search for 'index' and 'collation' across backend/models =="
rg -n --hidden 'index' backend/models || true
rg -n --hidden 'collation' backend || true

echo -e "\n== Check for 'trim: true' and 'lowercase: true' occurrences in subscriber model =="
rg -n --hidden -n --fixed-strings 'trim: true' backend/models/subscriber.js || true
rg -n --hidden -n --fixed-strings 'lowercase: true' backend/models/subscriber.js || true

Length of output: 579


Enforce case‑insensitive email uniqueness at the DB level

backend/models/subscriber.js already has email: { unique: true, lowercase: true, trim: true } — but a plain unique index is case‑sensitive and legacy mixed‑case rows can still create duplicates.

  • Add a case‑insensitive unique index, e.g. subscriberSchema.index({ email: 1 }, { unique: true, collation: { locale: "en", strength: 2 } }); and ensure the index is created on the production DB (migration/createIndexes).
  • Alternatively, backfill existing documents to lowercase and deduplicate, then create the unique index.
🤖 Prompt for AI Agents
In backend/routes/subscribe.js around lines 20 to 28, the code relies on a plain
unique index for email which is case‑sensitive and allows legacy mixed‑case
duplicates; add a case‑insensitive unique index on the subscriber schema (e.g.
index on email with collation { locale: "en", strength: 2 }) and ensure it is
created in production by adding a migration or createIndexes routine; before
creating the index, backfill existing subscriber documents to lowercase emails
and deduplicate any conflicting entries (or remove duplicates) so the unique
index can be created without errors.

Comment on lines +24 to +27
} catch (error) {
console.error('❌ Error creating .env file:', error.message);
console.log('\n📝 Please create a .env file manually with this content:');
console.log(envContent);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Stop printing secrets on error; redact and exit non‑zero.

envContent includes real secrets; avoid leaking to CI logs.

Apply this diff:

-  console.error('❌ Error creating .env file:', error.message);
-  console.log('\n📝 Please create a .env file manually with this content:');
-  console.log(envContent);
+  console.error('❌ Error creating .env file:', error.message);
+  const redacted = envContent
+    .replace(/^JWT_SECRET=.*$/m, 'JWT_SECRET=<redacted>')
+    .replace(/^SESSION_SECRET=.*$/m, 'SESSION_SECRET=<redacted>');
+  console.log('\n📝 Please create a .env file manually. Template:');
+  console.log(redacted);
+  process.exit(1);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (error) {
console.error('❌ Error creating .env file:', error.message);
console.log('\n📝 Please create a .env file manually with this content:');
console.log(envContent);
} catch (error) {
console.error('❌ Error creating .env file:', error.message);
const redacted = envContent
.replace(/^JWT_SECRET=.*$/m, 'JWT_SECRET=<redacted>')
.replace(/^SESSION_SECRET=.*$/m, 'SESSION_SECRET=<redacted>');
console.log('\n📝 Please create a .env file manually. Template:');
console.log(redacted);
process.exit(1);
}
🤖 Prompt for AI Agents
In backend/setup-env.js around lines 24 to 27, the catch block prints the full
envContent (which contains secrets) to logs; replace that behavior so you do not
leak secrets: log a concise, non‑secret error message (e.g., "Error creating
.env file; secrets redacted"), optionally include non‑secret error context, do
NOT print envContent, and then exit with a non‑zero status (process.exit(1)) to
signal failure.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
backend/setup-env.js (3)

8-15: Align PORT and harden localhost resolution for Windows.

Switch PORT to 5000 (frontend expects 5000) and prefer 127.0.0.1 to avoid IPv6 localhost quirks on Windows.

Apply this diff:

-const envContent = `PORT=3001
-MONGO_URI=mongodb://localhost:27017/vigybag
+const envContent = `PORT=5000
+MONGO_URI=mongodb://127.0.0.1:27017/vigybag
 JWT_SECRET=${jwtSecret}
 SESSION_SECRET=${sessionSecret}
 GOOGLE_CLIENT_ID=
 GOOGLE_CLIENT_SECRET=
 NODE_ENV=development
 `;

To verify the expected dev port, run:

#!/bin/bash
# Look for frontend API base URLs/ports
rg -nP -C2 '(http://(localhost|127\.0\.0\.1|0\.0\.0\.0):\d+)' --type js --type ts --type tsx --type jsx

17-18: Ensure dotenv loads the same path and .env is ignored.

Confirm backend loads this exact file (backend/.env) and that it’s gitignored.

Run:

#!/bin/bash
# .env should be ignored
rg -nP '(^|/)(backend/)?\.env(\b|$)' .gitignore -n || echo "No .env ignore rule found"

# Verify dotenv loads backend/.env (or project root) consistently
rg -nP -C2 "dotenv\.config\(([^)]*)\)" backend || echo "No explicit dotenv.config found in backend/"

19-24: Don’t overwrite existing .env; set secure perms.

Current code will rotate secrets if re-run, breaking sessions/tokens. Guard if file exists; create with mode 0600 and fail if present.

Apply this diff:

 try {
-  fs.writeFileSync(envPath, envContent, { encoding: 'utf8', flag: 'w' });
+  if (fs.existsSync(envPath)) {
+    console.log('ℹ️  .env already exists, not overwriting.');
+    console.log('📁 Location:', envPath);
+    process.exit(0);
+  }
+  fs.writeFileSync(envPath, envContent, { encoding: 'utf8', flag: 'wx', mode: 0o600 });
   console.log('✅ .env file created successfully!');
   console.log('📁 Location:', envPath);
   console.log('\n⚠️  IMPORTANT: Update GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET with your actual values');
 } catch (error) {
🧹 Nitpick comments (1)
backend/setup-env.js (1)

1-1: Optional: make the script directly runnable.

Add shebang and strict mode.

+#!/usr/bin/env node
+'use strict';
 const fs = require('fs');
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 28944e3 and 79a25e4.

📒 Files selected for processing (3)
  • backend/app.js (1 hunks)
  • backend/routes/subscribe.js (1 hunks)
  • backend/setup-env.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/app.js
  • backend/routes/subscribe.js
🔇 Additional comments (1)
backend/setup-env.js (1)

5-6: Good: cryptographically strong secrets.

32-byte random secrets are appropriate for JWT/session keys.

Comment on lines +25 to +27
console.error('❌ Error creating .env file:', error.message);
console.log('\n📝 Please create a .env file manually with this content:');
console.log(envContent);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid printing secrets on failure.

Dumping envContent leaks JWT/SESSION secrets into logs/CI.

Apply this diff:

-  console.error('❌ Error creating .env file:', error.message);
-  console.log('\n📝 Please create a .env file manually with this content:');
-  console.log(envContent);
+  console.error('❌ Error creating .env file:', error.message);
+  console.log('\n📝 Please create a .env file manually. Example:');
+  console.log(`PORT=5000
+MONGO_URI=mongodb://127.0.0.1:27017/vigybag
+JWT_SECRET=<64-hex-secret>
+SESSION_SECRET=<64-hex-secret>
+GOOGLE_CLIENT_ID=
+GOOGLE_CLIENT_SECRET=
+NODE_ENV=development`);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.error('❌ Error creating .env file:', error.message);
console.log('\n📝 Please create a .env file manually with this content:');
console.log(envContent);
console.error('❌ Error creating .env file:', error.message);
console.log('\n📝 Please create a .env file manually. Example:');
console.log(`PORT=5000
MONGO_URI=mongodb://127.0.0.1:27017/vigybag
JWT_SECRET=<64-hex-secret>
SESSION_SECRET=<64-hex-secret>
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
NODE_ENV=development`);
🤖 Prompt for AI Agents
In backend/setup-env.js around lines 25 to 27, the failure path currently logs
the full envContent (including secrets) to stdout/CI; remove printing of raw
envContent and instead either log a safe template with secret placeholders (e.g.
JWT_SECRET=<<REDACTED>>) or instruct the user to create the .env manually and
show only non-sensitive keys/paths, or write the content to a local file with
restrictive permissions and log the filename; implement one of these approaches
so secrets are never printed to logs.

Copy link

vercel bot commented Sep 23, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
vigybag Ready Ready Preview Comment Sep 23, 2025 5:56am

@ajaykuraparthi
Copy link
Author

All checks have passed and the changes look good. Please approve deployment to Vercel. 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1⭐ Easy task for beginners, requires basic understanding. good first issue Good for newcomers OSCI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug] "Login as Vigy" button redirects to 404 page
2 participants