Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/configs/db.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,22 @@ const { Pool } = pg;

dotenv.config();

const pool = new Pool({
// local 세팅 및 접근시 SSL 은 기본 X, production 에서만 추가
const poolConfig: pg.PoolConfig = {
Copy link
Contributor

Choose a reason for hiding this comment

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

로컬에서 SSL을 사용하지 않는 구체적인 이유가 궁금합니다!

Copy link
Member Author

Choose a reason for hiding this comment

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

로컬 SSL (지금 SSL 은 3.0 버전이 마지막이고 이꼴 TLS 1.3 이라고 보시면 됨) 을 하려면 인증서를 발급하고 cert / pem 등 설정이 필요한데, 로컬에 굳이 우리 모두가 힘들어지는 길을 걷기 싫어서랄까요! :)

database: process.env.DATABASE_NAME,
user: process.env.POSTGRES_USER,
host: process.env.POSTGRES_HOST,
password: process.env.POSTGRES_PASSWORD,
port: Number(process.env.POSTGRES_PORT),
ssl: {
};

if (process.env.NODE_ENV === 'production') {
poolConfig.ssl = {
rejectUnauthorized: false,
},
});
};
}

const pool = new Pool(poolConfig);

(async () => {
const client = await pool.connect();
Expand Down
28 changes: 28 additions & 0 deletions src/controllers/noti.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { NextFunction, Request, RequestHandler, Response } from 'express';
import logger from '@/configs/logger.config';
import { NotiService } from "@/services/noti.service";
import { NotiPostsResponseDto } from "@/types/dto/responses/notiResponse.type";

export class NotiController {
constructor(private notiService: NotiService) { }

getAllNotiPosts: RequestHandler = async (
req: Request,
Copy link
Contributor

Choose a reason for hiding this comment

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

request는 DTO를 따로 사용하지 않으신건가요??

맞다면 그 이유가 궁금합니다!

Copy link
Member Author

Choose a reason for hiding this comment

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

request 가 empty 한 API, 단순 get all 이라서 그렇습니다 :)

res: Response<NotiPostsResponseDto>,
next: NextFunction,
) => {
try {
const result = await this.notiService.getAllNotiPosts();
const response = new NotiPostsResponseDto(
true,
'전체 noti post 조회에 성공하였습니다.',
{ posts: result },
null,
);
res.status(200).json(response);
} catch (error) {
logger.error('전체 조회 실패:', error);
next(error);
}
};
}
29 changes: 29 additions & 0 deletions src/repositories/noti.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Pool } from 'pg';
import logger from '@/configs/logger.config';
import { DBError } from '@/exception';

export class NotiRepository {
constructor(private pool: Pool) { }

async getAllNotiPosts(limit: number = 5) {
try {
const query = `
SELECT
n.id,
n.title,
n.content,
n.created_at
FROM noti_notipost n
WHERE n.is_active = true
ORDER BY n.id DESC
LIMIT ${limit};
`;

const result = await this.pool.query(query);
return result.rows;
} catch (error) {
logger.error('Noti Repo getAllNotiPosts Error : ', error);
throw new DBError('알림 조회 중 문제가 발생했습니다.');
}
}
}
2 changes: 2 additions & 0 deletions src/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import express, { Router } from 'express';
import UserRouter from './user.router';
import TrackingRouter from './tracking.router';
import PostRouter from './post.router';
import NotiRouter from './noti.router';

const router: Router = express.Router();

Expand All @@ -12,4 +13,5 @@ router.use('/ping', (req, res) => {
router.use('/', UserRouter);
router.use('/', TrackingRouter);
router.use('/', PostRouter);
router.use('/', NotiRouter);
export default router;
44 changes: 44 additions & 0 deletions src/routes/noti.router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import express, { Router } from 'express';
import pool from '@/configs/db.config';

import { authMiddleware } from '@/middlewares/auth.middleware';
import { NotiRepository } from '@/repositories/noti.repository';
import { NotiService } from '@/services/noti.service';
import { NotiController } from '@/controllers/noti.controller';

/**
* @swagger
* tags:
* name: Notifications
* description: 알림 관련 API
*/
const router: Router = express.Router();

const notiRepository = new NotiRepository(pool);
const notiService = new NotiService(notiRepository);
const notiController = new NotiController(notiService);

/**
* @swagger
* /notis:
* get:
* summary: 공지 게시글 목록 전체 조회
* description: 사용자의 알림 게시글 목록을 조회합니다
* tags: [Notifications]
* security:
* - bearerAuth: []
* responses:
* 200:
* description: 알림 게시글 목록 조회 성공
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/NotiPostsResponseDto'
* 401:
* description: 인증되지 않은 사용자
* 500:
* description: 서버 에러
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

public하게 open하기로 했던 스웨거 코드인건가요?!

@Swagger를 사용하는군요! 처음 알고 갑니다!!

Copy link
Member Author

Choose a reason for hiding this comment

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

맞슴니다! 이게 가이드가 안되어 있었어서! http://localhost:8080/api-docs/ 에서 확인가능!

router.get('/notis', authMiddleware.login, notiController.getAllNotiPosts);

export default router;
10 changes: 10 additions & 0 deletions src/services/noti.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { NotiRepository } from "@/repositories/noti.repository";
import { NotiPost } from "@/types/models/NotiPost.type";

export class NotiService {
constructor(private notiRepo: NotiRepository) {}

async getAllNotiPosts(): Promise<NotiPost[]> {
return await this.notiRepo.getAllNotiPosts();
}
}
33 changes: 33 additions & 0 deletions src/types/dto/responses/notiResponse.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { BaseResponseDto } from '@/types/dto/responses/baseResponse.type';
import { NotiPost } from '@/types/models/NotiPost.type';

/**
* @swagger
* components:
* schemas:
* NotiPostsResponseData:
* type: object
* properties:
* posts:
* type: array
* description: 알림 게시글 목록
* items:
* $ref: '#/components/schemas/NotiPost'
*/
interface NotiPostsResponseData {
posts: NotiPost[];
}

/**
* @swagger
* components:
* schemas:
* NotiPostsResponseDto:
* allOf:
* - $ref: '#/components/schemas/BaseResponseDto'
* - type: object
* properties:
* data:
* $ref: '#/components/schemas/NotiPostsResponseData'
*/
export class NotiPostsResponseDto extends BaseResponseDto<NotiPostsResponseData> { }
9 changes: 9 additions & 0 deletions src/types/models/NotiPost.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface NotiPost {
id: number;
title: string;
content: string;
created_at: Date;
// is_active: boolean;
Copy link
Member

Choose a reason for hiding this comment

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

이 부분은 혹시 왜 주석 처리됬을까요?
이름을 보니 이전에 건의됬던 읽힘 여부 관련 값 같긴 한데.. 정확히 무슨 값인지 예상이 안 되네요~

Copy link
Member Author

Choose a reason for hiding this comment

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

  • 노션 task 보시면 해당 query 에 쓸모없는 field 는 select 에서 제외했어요 (최적화). 그에따라 type 에서 제외했습니다!
  • 주석인 이유는 필요에 따라 살릴 필요가 있을까 싶었고, 여러분들 모델 필드 파악하기 편한 것도 있고?!

// updated_at: Date;
// author?: User | null;
Copy link
Contributor

Choose a reason for hiding this comment

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

오 저도 위 3개 라인 주석 처리하신 구체적인 이유가 궁금합니다!

Copy link
Member Author

Choose a reason for hiding this comment

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

  • 노션 task 보시면 해당 query 에 쓸모없는 field 는 select 에서 제외했어요 (최적화). 그에따라 type 에서 제외했습니다!
  • 주석인 이유는 필요에 따라 살릴 필요가 있을까 싶었고, 여러분들 모델 필드 파악하기 편한 것도 있고?!

}