보조금 신청서 작성

이 자습서에서는 사용자가 보조금을 신청할 수 있는 애플리케이션을 빌드하는 방법을 보여줍니다. 이 게시물에서는 MySQL 데이터베이스에 연결, SQL 연결, 암호 해싱 및 코드 기반 모듈화와 같은 개념을 보여줍니다.

사용 스택: MySQL, NodeJS, Express, Nodemailer

이 프로젝트의 폴더 구조





프로젝트 설정



npm 프로젝트를 시작하고 다음 패키지를 설치합니다.



package.json 파일에서 스크립트 설정




//...
 "scripts": {
    "dev": "nodemon index.js",
    "start": "node index.js"
  },
//...



✅ 구성 폴더 및 db.config.js 파일 생성




// config/db.config.js
const dotenv = require('dotenv');
dotenv.config();

module.exports = {
  HOST: process.env.DB_HOST,
  USER: process.env.DB_USER,
  PASSWORD: process.env.DB_PASSWORD,
  DB: process.env.DB_NAME,
  PORT: process.env.DB_PORT,
};




✅ mysql에 데이터베이스 생성




mysql -u root -p
Enter password: *******
CREATE DATABASE db_name;



💻 사용자 생성 및 모델 부여



모델/user.model.sql에서

CREATE TABLE IF NOT EXISTS users (
    id INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255) NOT NULL,
    password VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL,
    phone VARCHAR(255) NOT NULL,
    gender enum('Male', 'Female') DEFAULT 'Male'  NOT NULL,
    dob DATE NOT NULL,
    role enum('Admin', 'User') DEFAULT 'User',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    );


모델/grant.model.sql에서

CREATE TABLE IF NOT EXISTS grants (
    id INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id INT(11) UNSIGNED NOT NULL,
    grant_name VARCHAR(255) NOT NULL,
    grant_type VARCHAR(255) NOT NULL,
    grant_amount VARCHAR(255) NOT NULL,
    grant_description VARCHAR(255) NOT NULL,
    grant_status enum('Pending', 'Approved', 'Rejected') DEFAULT 'Pending',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id)
    );


📢 mysql 셸에서 두 모델을 실행하여 usergrants 테이블을 생성할 수 있습니다.


🔅 인증을 위한 애플리케이션 로직



컨트롤러 폴더에서 user.controller.js 파일을 만듭니다.


exports.createNewUser = async (req, res, next) => {
  try {
    const { email, username, phone, gender, password, dob } = req.body;

    //  check if email already exists
    const [row] = await db.query('SELECT * FROM users WHERE email = ?', [
      email,
    ]);

    if (row.length > 0) {
      return res.status(409).json({
        status: 400,
        message: 'Email already exists',
      });
    }

    // hash password
    const hashedPassword = await passwordHash(password);

    const user = await db.query(
      'INSERT INTO users (email, username, phone,password, gender, dob) VALUES (?,?,?,?,?,?)',
      [email, username, phone, hashedPassword, gender, dob]
    );

    let data = {
      id: user[0].insertId,
      email,
      username,
      phone,
    };

    const token = await jwtSign(data);

    // send email
    const subject = 'Welcome to AB Code';
    const text = `Hi ${username}, welcome to AB Code. We are glad to have you on board.`;
    await sendEmail({ email, subject, text });
    return responseHandler(res, 200, 'User created successfully', {
      token,
      data,
    });
  } catch (error) {
    next(error);
  }
};



🔅 로그인 로직




exports.loginUser = async (req, res, next) => {
  try {
    const { email, password } = req.body;

    const [user] = await db.query('SELECT * FROM users WHERE email = ?', [
      email,
    ]);

    if (user.length === 0) {
      return res.status(401).json({
        status: 401,
        message: 'Invalid email or password',
      });
    }

    const isPasswordValid = await passwordCompare(password, user[0].password);
    if (!isPasswordValid) {
      return res.status(401).json({
        status: 401,
        message: 'Invalid email or password',
      });
    }

    let data = {
      id: user[0].id,
      email: user[0].email,
      username: user[0].username,
      phone: user[0].phone,
      role: user[0].role,
    };

    const token = await jwtSign(data);
    return responseHandler(res, 200, 'Login successful', {
      token,
      data,
    });
  } catch (error) {
    next(error);
  }
};



🔐 사용자 토큰을 검증하기 위한 인증 미들웨어 생성



새 파일 미들웨어/auth.js 만들기

const { jwtVerify } = require('../lib/jwt');
const customError = require('../utils/customError');


const validateUserToken = async (req, res, next) => {
  try {
    // console.log(req.headers.authorization);
    const token = req.headers.authorization.split(' ')[1];
    if (!token) return res.status(401).json({ message: 'Unauthorized' });

    const decoded = await jwtVerify(token);
    if (!decoded) {
      throw new Error('Invalid token');
    }
    req.user = decoded;
    console.log('===req.user');
    console.log(req.user);
    console.log('===req.user');

    next();
  } catch (e) {
    return res.status(401).json({ message: 'Unauthorized...' });
  }
};

const validateAdmin = (req, res, next) => {
  try {
    if (req.user.role !== 'Admin') {
      // use custom error statusCode, message, data
      throw new customError(
        401,
        'You are not authorized to perform this action',
        []
      );
    }
    next();
  } catch (e) {
    next(e);
  }
};

module.exports = { validateUserToken, validateAdmin };



💰 이제 보조금을 신청하기 위한 애플리케이션 로직을 생성해 보겠습니다.





// Apply for grant
exports.applyForGrant = async (req, res, next) => {
  try {
    const {
      grant_name,
      grant_type,
      grant_amount,
      grant_description,
      grant_status,
    } = req.body;
    const { id } = req.user;

    // check if grant already exists
    const [row] = await db.query(
      'SELECT * FROM grants WHERE grant_name = ? AND user_id = ?',
      [grant_name, id]
    );

    if (row.length > 0) {
      return res.status(409).json({
        status: 400,
        message: 'Grant already exists',
      });
    }

    const grant = await db.query(
      'INSERT INTO grants (grant_name, grant_type, grant_amount, grant_description, grant_status, user_id) VALUES (?,?,?,?,?,?)',
      [
        grant_name,
        grant_type,
        grant_amount,
        grant_description,
        grant_status,
        id,
      ]
    );

    let data = {
      id: grant[0].insertId,
      grant_name,
      grant_type,
      grant_amount,
      grant_description,
      grant_status: 'Pending',
    };

    // send email
    const subject = 'Grant Application';
    const text = `Hi ${req.user.username}, your grant application has been received. We will get back to you shortly.`;
    await sendEmail({ email: req.user.email, subject, text });

    return responseHandler(res, 200, 'Grant created successfully', {
      data,
    });


  } catch (error) {
    next(error);
  }
};




🚪 경로 처리기




//...
const { validateUserToken, validateAdmin } = require('../middleware/auth');

const router = express.Router();

router.post('/signup', createNewUser);
router.post('/login', loginUser);
router.post('/grant', validateUserToken, applyForGrant);

//...




마지막으로 기본 항목 파일인 index.js에 경로 처리기를 마운트합니다.




const express = require('express');
const cors = require('cors');
const connection = require('./database/db');
const dotenv = require('dotenv');
dotenv.config();

const userRoutes = require('./routes/user.routes.js');

const app = express();

const corsOptions = {
  origin: 'http://localhost:7878',
  optionsSuccessStatus: 200,
};

app.use(cors(corsOptions));

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.get('/', (req, res) => {
  res.send('Hello World');
});

app.use('/api/users', userRoutes);

const port = process.env.PORT || 7878;

// 404 global error handler
app.use((req, res, next) => {
  const error = new Error('Not Found');
  error.status = 404;
  next(error);
});

// global error handler
app.use((error, req, res, next) => {
  res.status(error.status || 500);
  res.json({
    error: {
      message: error.message,
    },
  });
});

app.listen(port, async () => {
  console.log(`Server is running on port ${port}`);
});



결론



이 게시물이 MySQL 데이터베이스 연결, 다른 모델 연결, 폴더 구조 등과 같은 개념을 설명하는 데 도움이 되었기를 바랍니다.

여기에서 소스 코드를 받으세요: source code

😊 읽어주셔서 감사합니다

좋은 웹페이지 즐겨찾기