DEV Community

Snow Virus
Snow Virus

Posted on

the "npm run dev" link can't open the login page i want

this is the project structure
Image description
Image description

i face a problem on my project. when i click on link. it shows error. i dont know why and what happened. anyone there please help. i request.
i expect when i click on link, the login page comes

this is app.js
`/**

  • Bugema University Vocational Training School Electronic Records Management System
  • Main application entry point */

// Import required modules
const express = require('express');
const path = require('path');
const morgan = require('morgan');
const compression = require('compression');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const MongoStore = require('connect-mongo');
const helmet = require('helmet');
const cors = require('cors');
const flash = require('connect-flash');
const mongoose = require('mongoose');
const expressLayouts = require('express-ejs-layouts');

// Import custom modules
const env = require('./config/env');
const { connectToDatabase } = require('./config/database');
const { securityHeaders } = require('./config/security');
const logger = require('./utils/logger');
const { notFoundHandler, errorHandler } = require('./utils/errorHandler');

// Create Express application
const app = express();

// Set up view engine and views directory
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));

// Set up express layouts
app.use(expressLayouts);
app.set('layout', 'layouts/main');
app.set('layout extractScripts', true);
app.set('layout extractStyles', true);

console.log('Step 1: Starting app.js execution...');

// Database connection and server startup
connectToDatabase()
.then(() => {
logger.info('MongoDB Atlas connection established successfully');

// Start server after successful database connection
const PORT = env.port || 3000;
console.log('Attempting to start the server...');

const server = app.listen(PORT, '0.0.0.0', function(err) {
  if (err) {
    console.error('ERROR STARTING SERVER:', err);
    process.exit(1);
  }
  const serverInfo = server.address();
  console.log('\n\n==========================================================');
  console.log(`*** SERVER STARTED SUCCESSFULLY ***`);
  console.log(`🌐 App URL: http://localhost:${serverInfo.port}`);
  console.log('==========================================================\n');
});
Enter fullscreen mode Exit fullscreen mode

})
.catch((err) => {
logger.error(Failed to connect to MongoDB Atlas: ${err.message});
process.exit(1);
});

// Security middleware
app.use(helmet({
contentSecurityPolicy: securityHeaders.contentSecurityPolicy,
xContentTypeOptions: true,
xFrameOptions: securityHeaders.xFrameOptions,
xXssProtection: true,
hsts: env.isProd ? securityHeaders.hsts : false,
referrerPolicy: securityHeaders.referrerPolicy,
}));
console.log('Middleware setup complete.');

// Request parsing middleware
app.use(express.json({ limit: '1mb' }));
app.use(express.urlencoded({ extended: true, limit: '1mb' }));

// Cookie parser middleware
app.use(cookieParser(env.sessionSecret));

// Server-side session configuration
app.use(session({
secret: env.sessionSecret,
resave: false,
saveUninitialized: false,
store: process.env.SKIP_DB_CONNECT === 'true' ? undefined : MongoStore.create({
mongoUrl: env.mongodbUri,
ttl: 14 * 24 * 60 * 60,
autoRemove: 'native',
collectionName: 'sessions',
crypto: {
secret: env.sessionSecret,
},
}),
cookie: {
httpOnly: true,
secure: env.isProd,
sameSite: 'strict',
maxAge: 14 * 24 * 60 * 60 * 1000,
},
}));

// Verify session is being tracked
if (!env.isProd) {
app.use((req, res, next) => {
console.log('🔐 Session Check:', req.session);
next();
});
}

// Flash messages middleware
app.use(flash());

// Cross-Origin Resource Sharing
app.use(cors({
origin: env.isProd ? 'https://erms.bugema.ac.ug' : true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true,
}));

// HTTP request logging
app.use(morgan(env.isProd ? 'combined' : 'dev', { stream: logger.stream }));

// Compression middleware
app.use(compression());

// Serve static files - MOVED BEFORE ROUTES
app.use(express.static(path.join(__dirname, 'public')));

// Custom middleware to make some variables available to all templates
app.use((req, res, next) => {
res.locals.user = req.session.user || null;
res.locals.flashMessages = req.flash();
res.locals.currentPath = req.path;
res.locals.appName = 'Bugema ERMS';
res.locals.year = new Date().getFullYear();
next();
});

// Import routes
const authRoutes = require('./routes/auth');
const authWebRoutes = require('./routes/auth-web');
const studentRoutes = require('./routes/students');
const programRoutes = require('./routes/programs');
const courseRoutes = require('./routes/courses');
const enrollmentRoutes = require('./routes/enrollments');
const assessmentRoutes = require('./routes/assessments');
const paymentRoutes = require('./routes/payments');
const documentRoutes = require('./routes/documents');
const reportRoutes = require('./routes/reports');
const adminRoutes = require('./routes/admin');
const registrarRoutes = require('./routes/registrar');
const financeRoutes = require('./routes/finance');
const userRoutes = require('./routes/users');
const dashboardRoutes = require('./routes/dashboard');

// API routes
app.use('/api/auth', authRoutes);
app.use('/api/students', studentRoutes);
app.use('/api/programs', programRoutes);
app.use('/api/courses', courseRoutes);
app.use('/api/enrollments', enrollmentRoutes);
app.use('/api/assessments', assessmentRoutes);
app.use('/api/payments', paymentRoutes);
app.use('/api/documents', documentRoutes);
app.use('/api/reports', reportRoutes);
app.use('/api/users', userRoutes);

// Web routes
app.use('/auth', authWebRoutes);
app.use('/admin', adminRoutes);
app.use('/registrar', registrarRoutes);
app.use('/finance', financeRoutes);
app.use('/dashboard', dashboardRoutes);

console.log('Routes registered.');

// Root route - redirect to login or dashboard
app.get('/', (req, res) => {
console.log('➡️ Root route hit');

if (req.session.user) {
const role = req.session.user.role;
switch (role) {
case 'admin':
return res.redirect('/admin/dashboard');
case 'registrar':
return res.redirect('/registrar/dashboard');
case 'finance':
return res.redirect('/finance/dashboard');
case 'student':
return res.redirect('/dashboard');
default:
return res.redirect('/auth/login');
}
} else {
console.log('🧑‍🚫 No session found — redirecting to /auth/login');
res.redirect('/auth/login');
}
});

// Error handling middleware
app.use(notFoundHandler);
app.use(errorHandler);

// Handle uncaught exceptions
process.on('uncaughtException', (err) => {
logger.error('UNCAUGHT EXCEPTION! 💥 Shutting down...');
logger.error(${err.name}: ${err.message}, { stack: err.stack });
process.exit(1);
});

// Handle unhandled promise rejections
process.on('unhandledRejection', (err) => {
logger.error('UNHANDLED REJECTION! 💥 Shutting down...');
logger.error(${err.name}: ${err.message}, { stack: err.stack });
process.exit(1);
});

// Check for required environment variables
if (!env.port || !env.mongodbUri || !env.jwtSecret) {
console.error('Missing required environment variables. Please check your configuration.');
process.exit(1);
}

module.exports = app;`

here is the "auth.js"
`/**

  • Authentication Middleware
  • Handles authentication and authorization for protected routes */

const { jwtHelpers } = require('../config/security');
const User = require('../models/user');
const { createError } = require('../utils/errorHandler');
const logger = require('../utils/logger');

/**

  • Authenticate user based on JWT token
  • @param {Object} req - Express request object
  • @param {Object} res - Express response object
  • @param {Function} next - Express next middleware function
    */
    exports.authenticate = async (req, res, next) => {
    try {
    // Get token from Authorization header
    let token = req.headers.authorization;

    // Check if token exists
    if (!token || !token.startsWith('Bearer ')) {
    return res.status(401).json({
    status: 'error',
    message: 'Authentication required. Please login.',
    code: 'AUTH_REQUIRED'
    });
    }

    // Extract token value (remove "Bearer " prefix)
    token = token.split(' ')[1];

    // Verify token
    const decoded = jwtHelpers.verifyToken(token);
    if (!decoded) {
    return res.status(401).json({
    status: 'error',
    message: 'Invalid or expired token. Please login again.',
    code: 'INVALID_TOKEN'
    });
    }

    // Find user by ID
    const user = await User.findById(decoded.userId);
    if (!user) {
    return res.status(401).json({
    status: 'error',
    message: 'User associated with this token no longer exists.',
    code: 'USER_NOT_FOUND'
    });
    }

    // Check if user is active
    if (user.status !== 'active') {
    return res.status(403).json({
    status: 'error',
    message: Your account is ${user.status}. Please contact an administrator.,
    code: 'ACCOUNT_INACTIVE'
    });
    }

    // Add user object to request
    req.user = {
    _id: user._id,
    username: user.username,
    email: user.email,
    role: user.role,
    permissions: user.permissions,
    firstName: user.firstName,
    lastName: user.lastName,
    studentId: user.studentId
    };

    // Proceed to next middleware
    next();
    } catch (error) {
    logger.error(Authentication error: ${error.message});
    return res.status(401).json({
    status: 'error',
    message: 'Authentication failed',
    code: 'AUTH_FAILED'
    });
    }
    };

/**

  • Authorize user based on roles
  • @param {Array} roles - Array of allowed roles
  • @returns {Function} Middleware function
    */
    exports.authorize = (roles = []) => {
    return (req, res, next) => {
    // Check if user exists and has a role
    if (!req.user || !req.user.role) {
    return res.status(401).json({
    status: 'error',
    message: 'Authentication required',
    code: 'AUTH_REQUIRED'
    });
    }

    // Superadmin has access to everything
    if (req.user.role === 'superadmin') {
    return next();
    }

    // Check if user's role is in the allowed roles
    if (roles.length > 0 && !roles.includes(req.user.role)) {
    return res.status(403).json({
    status: 'error',
    message: 'You do not have permission to perform this action',
    code: 'UNAUTHORIZED_ROLE'
    });
    }

    if (roles.length === 0) {
    return res.status(403).json({
    status: 'error',
    message: 'Access denied. No roles are allowed for this action.',
    code: 'NO_ROLES_ALLOWED'
    });
    }

    // Proceed to next middleware
    next();
    };
    };

/**

  • Check if user has specific permissions
  • @param {Array|String} permissions - Required permission(s)
  • @returns {Function} Middleware function */ exports.checkPermission = (permissions = []) => { // Convert string to array if single permission is passed if (typeof permissions === 'string') { permissions = [permissions]; }

return (req, res, next) => {
// Check if user exists
if (!req.user) {
return res.status(401).json({
status: 'error',
message: 'Authentication required',
code: 'AUTH_REQUIRED'
});
}

// Superadmin has all permissions
if (req.user.role === 'superadmin') {
  return next();
}

// Check if user has any of the required permissions
const hasPermission = permissions.some(permission => 
  req.user.permissions && req.user.permissions.includes(permission)
);

if (!hasPermission) {
  return res.status(403).json({
    status: 'error',
    message: 'You do not have the required permissions for this action',
    code: 'INSUFFICIENT_PERMISSIONS'
  });
}

if (permissions.length === 0) {
  return res.status(403).json({
    status: 'error',
    message: 'Access denied. No permissions are allowed for this action.',
    code: 'NO_PERMISSIONS_ALLOWED'
  });
}

// Proceed to next middleware
next();
Enter fullscreen mode Exit fullscreen mode

};
};

/**

  • Middleware to check if user is accessing their own data or has admin rights
  • @param {Function} getResourceUserId - Function to extract user ID from resource
  • @returns {Function} Middleware function
    */
    exports.checkResourceOwnership = (getResourceUserId) => {
    return async (req, res, next) => {
    try {
    // Get user ID associated with the resource
    const resourceUserId = await getResourceUserId(req);

    // If no resource user ID found, proceed (might be a creation operation)
    if (!resourceUserId) {
    return res.status(403).json({
    status: 'error',
    message: 'Unable to verify resource ownership.',
    code: 'RESOURCE_OWNERSHIP_FAILED'
    });
    }

    // Check if current user is the owner of the resource
    const isOwner = req.user._id.toString() === resourceUserId.toString();

    // Check if current user has admin privileges
    const isAdmin = ['superadmin', 'admin'].includes(req.user.role);

    // Allow access if user is owner or has admin rights
    if (isOwner || isAdmin) {
    return next();
    }

    // Deny access
    return res.status(403).json({
    status: 'error',
    message: 'You do not have permission to access this resource',
    code: 'NOT_RESOURCE_OWNER'
    });
    } catch (error) {
    logger.error(Resource ownership check error: ${error.message});
    return res.status(500).json({
    status: 'error',
    message: 'Failed to verify resource ownership',
    code: 'OWNERSHIP_CHECK_FAILED'
    });
    }
    };
    };`

here is "auth-web.js"

`/**

  • Authentication Web Routes
  • Routes for web authentication UI */

const express = require('express');
const router = express.Router();
const { authenticate } = require('../middleware/auth');
const authWebController = require('../controllers/authWebController');

// Login page
router.get('/login', (req, res) => {
// If user is already logged in, redirect to appropriate dashboard
if (req.session.user) {
const role = req.session.user.role;

switch (role) {
  case 'admin':
  case 'superadmin':
    return res.redirect('/admin/dashboard');
  case 'registrar':
    return res.redirect('/registrar/dashboard');
  case 'finance':
    return res.redirect('/finance/dashboard');
  case 'student':
    return res.redirect('/dashboard');
  default:
    return res.redirect('/');
}
Enter fullscreen mode Exit fullscreen mode

}

// Render login page with layout
res.render('auth/login', {
title: 'Login',
page: 'auth',
message: req.flash('error'),
success: req.flash('success'),
layout: 'layouts/main'
});
});

// Forgot password page
router.get('/forgot-password', (req, res) => {
res.render('auth/forgot-password', {
title: 'Forgot Password',
page: 'auth',
message: req.flash('error'),
success: req.flash('success')
});
});

// Process forgot password form
router.post('/forgot-password', authWebController.forgotPassword);

// Reset password page
router.get('/reset-password/:token', (req, res) => {
res.render('auth/reset-password', {
title: 'Reset Password',
page: 'auth',
token: req.params.token,
message: req.flash('error'),
success: req.flash('success')
});
});

// Process reset password form
router.post('/reset-password/:token', authWebController.resetPassword);

// Account activation page
router.get('/activate/:token', authWebController.activateAccount);

// Process login form
router.post('/login', authWebController.login);

// Logout - must be authenticated
router.get('/logout', authenticate, authWebController.logout);

module.exports = router;`

here is error.ejs
`<%- contentFor('body') %>

Bugema University

Vocational Training School

    <div class="card-body p-4 text-center">
      <div class="error-icon mb-4">
        <i class="fas fa-exclamation-circle fa-4x text-danger"></i>
      </div>

      <h3 class="error-title mb-3">
        <% if (locals.status === 404) { %>
          Page Not Found
        <% } else if (locals.status === 403) { %>
          Access Denied
        <% } else if (locals.status === 500) { %>
          Server Error
        <% } else { %>
          Error <%= locals.status %>
        <% } %>
      </h3>

      <p class="error-message mb-4">
        <% if (locals.message) { %>
          <%= message %>
        <% } else if (locals.status === 404) { %>
          The page you are looking for might have been removed, had its name changed, or is temporarily unavailable.
        <% } else if (locals.status === 403) { %>
          You don't have permission to access this resource.
        <% } else if (locals.status === 500) { %>
          Something went wrong on our end. Please try again later.
        <% } else { %>
          An unexpected error occurred. Please try again later.
        <% } %>
      </p>

      <div class="error-actions">
        <a href="javascript:history.back()" class="btn btn-outline-primary me-2">
          <i class="fas fa-arrow-left"></i> Go Back
        </a>
        <a href="/" class="btn btn-primary">
          <i class="fas fa-home"></i> Go to Homepage
        </a>
      </div>

      <% if (locals.error && !env.isProd) { %>
        <div class="error-details mt-4">
          <div class="card">
            <div class="card-header bg-light">
              <h5 class="mb-0">Error Details</h5>
            </div>
            <div class="card-body">
              <pre class="error-stack"><%= error.stack %></pre>
            </div>
          </div>
        </div>
      <% } %>
    </div>

    <div class="card-footer text-center py-3">
      <div class="small">
        Need help? Contact <a href="mailto:ict@bugema.ac.ug">ICT Support</a>
      </div>
    </div>
  </div>
</div>

<%- contentFor('styles') %>

.error-container { max-width: 800px; margin: 2rem auto; } .error-card { border: none; border-radius: 12px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); overflow: hidden; } .error-card .card-header { background-color: #0f4c81; color: white; padding: 1.5rem; text-align: center; border-bottom: none; } .error-card .card-body { padding: 2rem; } .error-icon { color: #dc3545; } .error-title { color: #2d3748; font-weight: 600; } .error-message { color: #4a5568; font-size: 1.1rem; } .error-actions { margin-top: 2rem; } .error-details { text-align: left; } .error-stack { background-color: #f8f9fa; padding: 1rem; border-radius: 6px; font-size: 0.9rem; color: #2d3748; white-space: pre-wrap; word-wrap: break-word; } @media (max-width: 576px) { .error-container { margin: 1rem; } .error-card .card-body { padding: 1.5rem; } .error-actions .btn { display: block; width: 100%; margin: 0.5rem 0; } }

<%- contentFor('scripts') %>
<br> // Add any error page specific JavaScript here<br> document.addEventListener(&#39;DOMContentLoaded&#39;, function() {<br> // Example: Log error details to console in development<br> &lt;% if (locals.error &amp;&amp; !env.isProd) { %&gt;<br> console.error(&#39;Error Details:&#39;, &lt;%= JSON.stringify(error) %&gt;);<br> &lt;% } %&gt;<br> });<br> `

this is what i suffer from
`snow@snow:~/Desktop/ERMS$ npm run dev

erms@1.0.0 dev
nodemon app.js

[nodemon] 3.1.10
[nodemon] to restart at any time, enter rs
[nodemon] watching path(s): .
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting node app.js
Step 1: Starting app.js execution...
2025-05-21 06:05:45 info: Attempting to connect to MongoDB at cluster0.wcahcli.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0
Middleware setup complete.
(node:34440) [MONGOOSE] Warning: Duplicate schema index on {"email":1} found. This is often due to declaring an index using both "index: true" and "schema.index()". Please remove the duplicate index definition.
(Use node --trace-warnings ... to show where the warning was created)
(node:34440) [MONGOOSE] Warning: Duplicate schema index on {"username":1} found. This is often due to declaring an index using both "index: true" and "schema.index()". Please remove the duplicate index definition.
(node:34440) [MONGOOSE] Warning: Duplicate schema index on {"studentId":1} found. This is often due to declaring an index using both "index: true" and "schema.index()". Please remove the duplicate index definition.
(node:34440) [MONGOOSE] Warning: Duplicate schema index on {"programCode":1} found. This is often due to declaring an index using both "index: true" and "schema.index()". Please remove the duplicate index definition.
(node:34440) [MONGOOSE] Warning: Duplicate schema index on {"courseCode":1} found. This is often due to declaring an index using both "index: true" and "schema.index()". Please remove the duplicate index definition.
2025-05-21 06:05:48 info: Successfully connected to MongoDB Atlas
2025-05-21 06:05:48 info: MongoDB Atlas connection established successfully
Attempting to start the server...

==========================================================
*** SERVER STARTED SUCCESSFULLY ***

🌐 App URL: http://localhost:3000

🔐 Session Check: Session {
cookie: {
path: '/',
_expires: 2025-05-31T07:25:36.990Z,
originalMaxAge: 1209600000,
httpOnly: true,
secure: false,
sameSite: 'strict'
},
flash: {}
}
2025-05-21 06:05:53 info: GET / 404 2.736 ms - 139
`

Top comments (0)