issue #63
All checks were successful
Test CI / build (push) Successful in 1m22s

- 일정 상세 조회 기능 구현 중
This commit is contained in:
geonhee-min
2025-12-15 17:35:35 +09:00
parent b7c8b0a4cf
commit 17335a26e7
7 changed files with 53 additions and 41 deletions

View File

@@ -1,4 +1,4 @@
import { pgTable, foreignKey, uuid, text, date, boolean, varchar, index, time, primaryKey, pgSequence } from "drizzle-orm/pg-core" import { pgTable, varchar, date, boolean, timestamp, uuid, foreignKey, text, index, time, primaryKey, pgSequence } from "drizzle-orm/pg-core"
import { sql } from "drizzle-orm" import { sql } from "drizzle-orm"
@@ -19,10 +19,23 @@ export const userBadgeIdSeq = pgSequence("user_badge_id_seq", { startWith: "1",
export const userBlockingIdSeq = pgSequence("user_blocking_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "9223372036854775807", cache: "1", cycle: false }) export const userBlockingIdSeq = pgSequence("user_blocking_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "9223372036854775807", cache: "1", cycle: false })
export const emailAddressIdSeq = pgSequence("email_address_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "9223372036854775807", cache: "1", cycle: false }) export const emailAddressIdSeq = pgSequence("email_address_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "9223372036854775807", cache: "1", cycle: false })
export const account = pgTable("account", {
name: varchar().notNull(),
email: varchar().notNull(),
password: varchar().notNull(),
birthday: date(),
accountId: varchar("account_id").notNull(),
nickname: varchar().notNull(),
status: varchar().default('active').notNull(),
isDeleted: boolean("is_deleted").default(false).notNull(),
createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(),
});
export const comment = pgTable("comment", { export const comment = pgTable("comment", {
id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(), id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(),
content: text(), content: text(),
createdAt: date("created_at"), createdAt: timestamp("created_at", { mode: 'string' }),
isDeleted: boolean("is_deleted").default(false), isDeleted: boolean("is_deleted").default(false),
writerId: uuid("writer_id"), writerId: uuid("writer_id"),
parentId: uuid("parent_id"), parentId: uuid("parent_id"),
@@ -39,19 +52,6 @@ export const comment = pgTable("comment", {
}), }),
]); ]);
export const account = pgTable("account", {
name: varchar().notNull(),
email: varchar().notNull(),
password: varchar().notNull(),
birthday: date(),
accountId: varchar("account_id").notNull(),
nickname: varchar().notNull(),
status: varchar().default('active').notNull(),
isDeleted: boolean("is_deleted").default(false).notNull(),
createdAt: date("created_at").defaultNow().notNull(),
id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(),
});
export const participant = pgTable("participant", { export const participant = pgTable("participant", {
participantId: uuid("participant_id").notNull(), participantId: uuid("participant_id").notNull(),
scheduleId: uuid("schedule_id").notNull(), scheduleId: uuid("schedule_id").notNull(),
@@ -80,7 +80,7 @@ export const schedule = pgTable("schedule", {
content: text(), content: text(),
isDeleted: boolean("is_deleted").default(false).notNull(), isDeleted: boolean("is_deleted").default(false).notNull(),
type: varchar().notNull(), type: varchar().notNull(),
createdAt: date("created_at"), createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
owner: uuid().notNull(), owner: uuid().notNull(),
style: varchar().notNull(), style: varchar().notNull(),
startTime: time("start_time").notNull(), startTime: time("start_time").notNull(),
@@ -122,7 +122,7 @@ export const follow = pgTable("follow", {
isDeleted: boolean("is_deleted").default(false), isDeleted: boolean("is_deleted").default(false),
isAccepted: boolean("is_accepted").default(false), isAccepted: boolean("is_accepted").default(false),
isLinked: boolean("is_linked").default(false), isLinked: boolean("is_linked").default(false),
createdAt: date("created_at"), createdAt: timestamp("created_at", { mode: 'string' }).defaultNow().notNull(),
following: uuid().notNull(), following: uuid().notNull(),
follower: uuid().notNull(), follower: uuid().notNull(),
}, (table) => [ }, (table) => [

View File

@@ -26,7 +26,7 @@
"drizzle-pull:prod": "dotenv -e .env.prod -- drizzle-kit pull" "drizzle-pull:prod": "dotenv -e .env.prod -- drizzle-kit pull"
}, },
"dependencies": { "dependencies": {
"@baekyangdan/core-utils": "^1.0.4", "@baekyangdan/core-utils": "^1.0.9",
"@fastify/cookie": "^11.0.2", "@fastify/cookie": "^11.0.2",
"@nestjs/class-transformer": "^0.4.0", "@nestjs/class-transformer": "^0.4.0",
"@nestjs/class-validator": "^0.13.4", "@nestjs/class-validator": "^0.13.4",
@@ -38,6 +38,7 @@
"@nestjs/platform-express": "^11.0.1", "@nestjs/platform-express": "^11.0.1",
"@nestjs/platform-fastify": "^11.1.9", "@nestjs/platform-fastify": "^11.1.9",
"bcrypt": "^6.0.0", "bcrypt": "^6.0.0",
"date-fns": "^4.1.0",
"dotenv": "^17.2.3", "dotenv": "^17.2.3",
"drizzle-kit": "^0.31.7", "drizzle-kit": "^0.31.7",
"drizzle-orm": "^0.44.7", "drizzle-orm": "^0.44.7",

View File

@@ -6,7 +6,7 @@ export class AuthService {
constructor(private readonly jwtService: JwtService) {} constructor(private readonly jwtService: JwtService) {}
generateTokens(id: string) { generateTokens(id: string) {
const accessToken = this.jwtService.sign({id: id}, { expiresIn: '1m' }); const accessToken = this.jwtService.sign({id: id}, { expiresIn: '5m' });
const refreshToken = this.jwtService.sign({id: id}, { expiresIn: '7d' }); const refreshToken = this.jwtService.sign({id: id}, { expiresIn: '7d' });
return { accessToken, refreshToken }; return { accessToken, refreshToken };

View File

@@ -5,67 +5,69 @@ import { Public } from "src/common/decorators/public.decorator";
import type { FastifyReply, FastifyRequest } from "fastify"; import type { FastifyReply, FastifyRequest } from "fastify";
import { AuthGuard } from "@nestjs/passport"; import { AuthGuard } from "@nestjs/passport";
import { JwtAccessAuthGuard } from "src/middleware/auth/guard/access-token.guard"; import { JwtAccessAuthGuard } from "src/middleware/auth/guard/access-token.guard";
import { HttpApiUrl } from '@baekyangdan/core-utils';
const AccountApi = HttpApiUrl.Account;
@UseGuards(JwtAccessAuthGuard) @UseGuards(JwtAccessAuthGuard)
@Controller('account') @Controller(AccountApi.base)
export class AccountController { export class AccountController {
constructor(private readonly accountService: AccountService) {} constructor(private readonly accountService: AccountService) {}
@Get('/') @Get(AccountApi.root)
async test() { async test() {
return "Test" return "Test"
} }
@Public() @Public()
@Get('check-duplication') @Get(AccountApi.checkDuplication)
async checkDuplication(@Query() query: DTO.CheckDuplicationRequest): Promise<DTO.CheckDuplicationResponse> { async checkDuplication(@Query() query: DTO.CheckDuplicationRequest): Promise<DTO.CheckDuplicationResponse> {
return await this.accountService.checkDuplication(query); return await this.accountService.checkDuplication(query);
} }
@Public() @Public()
@Post('send-email-verification-code') @Post(AccountApi.sendEmailVerificationCode)
async sendEmailVerificationCode(@Body() body: DTO.SendEmailVerificationCodeRequest): Promise<DTO.SendEmailVerificationCodeResponse> { async sendEmailVerificationCode(@Body() body: DTO.SendEmailVerificationCodeRequest): Promise<DTO.SendEmailVerificationCodeResponse> {
const result = await this.accountService.sendVerificationCode(body); const result = await this.accountService.sendVerificationCode(body);
return result; return result;
} }
@Public() @Public()
@Post('verify-email-verification-code') @Post(AccountApi.verifyEmailVerificationCode)
async verifyCode(@Body() body: DTO.VerifyEmailVerificationCodeRequest): Promise<DTO.VerifyEmailVerificationCodeResponse> { async verifyEmailVerificationCode(@Body() body: DTO.VerifyEmailVerificationCodeRequest): Promise<DTO.VerifyEmailVerificationCodeResponse> {
const result = await this.accountService.verifyCode(body); const result = await this.accountService.verifyCode(body);
return result; return result;
} }
@Public() @Public()
@Post('send-reset-password-code') @Post(AccountApi.sendResetPasswordCode)
async sendResetPasswordCode(@Body() body: DTO.SendResetPasswordCodeRequest): Promise<DTO.SendResetPasswordCodeResponse> { async sendResetPasswordCode(@Body() body: DTO.SendResetPasswordCodeRequest): Promise<DTO.SendResetPasswordCodeResponse> {
const result = await this.accountService.sendResetPasswordCode(body); const result = await this.accountService.sendResetPasswordCode(body);
return result; return result;
} }
@Public() @Public()
@Post('verify-reset-password-code') @Post(AccountApi.verifyResetPasswordCode)
async verifyResetPasswordCode(@Body() body: DTO.VerifyResetPasswordCodeRequest): Promise<DTO.VerifyResetPasswordCodeResponse> { async verifyResetPasswordCode(@Body() body: DTO.VerifyResetPasswordCodeRequest): Promise<DTO.VerifyResetPasswordCodeResponse> {
const result = await this.accountService.verifyResetPasswordCode(body); const result = await this.accountService.verifyResetPasswordCode(body);
return result; return result;
} }
@Public() @Public()
@Post('reset-password') @Post(AccountApi.resetPassword)
async resetPassword(@Body() body: DTO.ResetPasswordRequest): Promise<DTO.ResetPasswordResponse> { async resetPassword(@Body() body: DTO.ResetPasswordRequest): Promise<DTO.ResetPasswordResponse> {
const result = await this.accountService.resetPassword(body); const result = await this.accountService.resetPassword(body);
return result; return result;
} }
@Public() @Public()
@Post('signup') @Post(AccountApi.signup)
async signup(@Body() body: DTO.SignupRequest): Promise<DTO.SignupResponse> { async signup(@Body() body: DTO.SignupRequest): Promise<DTO.SignupResponse> {
const result = await this.accountService.signup(body); const result = await this.accountService.signup(body);
return result; return result;
} }
@Public() @Public()
@Post('login') @Post(AccountApi.login)
async login(@Body() body: DTO.LoginRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<DTO.LoginResponse> { async login(@Body() body: DTO.LoginRequest, @Res({ passthrough: true }) res: FastifyReply): Promise<DTO.LoginResponse> {
const result = await this.accountService.login(body); const result = await this.accountService.login(body);
if (result.success) { if (result.success) {
@@ -86,7 +88,7 @@ export class AccountController {
@Public() @Public()
@UseGuards(AuthGuard('refresh-token')) @UseGuards(AuthGuard('refresh-token'))
@Get('refresh-access-token') @Get(AccountApi.refreshAccessToken)
async refreshAccessToken(@Req() req, @Res({ passthrough: true }) res: FastifyReply): Promise<DTO.RefreshAccessTokenResponse> { async refreshAccessToken(@Req() req, @Res({ passthrough: true }) res: FastifyReply): Promise<DTO.RefreshAccessTokenResponse> {
const result = await this.accountService.refreshAccessToken(req.user.id); const result = await this.accountService.refreshAccessToken(req.user.id);
if (result.success) { if (result.success) {

View File

@@ -2,24 +2,28 @@ import { Body, Controller, Get, Param, Post, Req, UseGuards } from "@nestjs/comm
import { JwtAccessAuthGuard } from "src/middleware/auth/guard/access-token.guard"; import { JwtAccessAuthGuard } from "src/middleware/auth/guard/access-token.guard";
import { ScheduleService } from "./schedule.service"; import { ScheduleService } from "./schedule.service";
import * as DTO from './dto'; import * as DTO from './dto';
import { HttpApiUrl } from "@baekyangdan/core-utils";
const ScheduleApi = HttpApiUrl.Schedule;
@UseGuards(JwtAccessAuthGuard) @UseGuards(JwtAccessAuthGuard)
@Controller('schedule') @Controller(ScheduleApi.base)
export class ScheduleController { export class ScheduleController {
constructor(private readonly scheduleService: ScheduleService) {} constructor(private readonly scheduleService: ScheduleService) {}
@Post('/') @Post(ScheduleApi.getList)
async getList(@Req() req, @Body() data: DTO.ListRequest): Promise<DTO.ListResponse> { async getList(@Req() req, @Body() data: DTO.ListRequest): Promise<DTO.ListResponse> {
const result = await this.scheduleService.getList(req.user.id, data); const result = await this.scheduleService.getList(req.user.id, data);
return result; return result;
} }
@Get('/:id') @Get(ScheduleApi.getDetail)
async getDetail(@Param('id') id: string): Promise<DTO.DetailResponse> { async getDetail(@Param('id') id: string): Promise<DTO.DetailResponse> {
const result = await this.scheduleService.getDetail(id); const result = await this.scheduleService.getDetail(id);
return result; return result;
} }
@Post('/create') @Post(ScheduleApi.create)
async create(@Req() req, @Body() data: DTO.CreateRequest): Promise<DTO.CreateResponse> { async create(@Req() req, @Body() data: DTO.CreateRequest): Promise<DTO.CreateResponse> {
const result = await this.scheduleService.create(req.user.id, data); const result = await this.scheduleService.create(req.user.id, data);
return result; return result;

View File

@@ -1,6 +1,9 @@
import { Injectable } from "@nestjs/common"; import { Injectable } from "@nestjs/common";
import { ScheduleRepo } from "./schedule.repo"; import { ScheduleRepo } from "./schedule.repo";
import * as DTO from './dto'; import * as DTO from './dto';
import { format } from "date-fns";
import { DateFormat, TimeFormat } from "@baekyangdan/core-utils";
import { ko } from "date-fns/locale";
@Injectable() @Injectable()
export class ScheduleService { export class ScheduleService {
@@ -30,7 +33,8 @@ export class ScheduleService {
const data = { const data = {
...result[0], ...result[0],
startDate: new Date(result[0].startDate), startDate: new Date(result[0].startDate),
endDate: new Date(result[0].endDate) endDate: new Date(result[0].endDate),
createdAt: format(result[0].createdAt, `${DateFormat.KOREAN} ${TimeFormat.KOREAN_SIMPLE}`, { locale: ko })
} }
return { return {

View File

@@ -999,14 +999,14 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@baekyangdan/core-utils@npm:^1.0.4": "@baekyangdan/core-utils@npm:^1.0.9":
version: 1.0.4 version: 1.0.9
resolution: "@baekyangdan/core-utils@npm:1.0.4::__archiveUrl=https%3A%2F%2Fgitea.bkdhome.p-e.kr%2Fapi%2Fpackages%2Fbaekyangdan%2Fnpm%2F%2540baekyangdan%252Fcore-utils%2F-%2F1.0.4%2Fcore-utils-1.0.4.tgz" resolution: "@baekyangdan/core-utils@npm:1.0.9::__archiveUrl=https%3A%2F%2Fgitea.bkdhome.p-e.kr%2Fapi%2Fpackages%2Fbaekyangdan%2Fnpm%2F%2540baekyangdan%252Fcore-utils%2F-%2F1.0.9%2Fcore-utils-1.0.9.tgz"
dependencies: dependencies:
date-fns: "npm:^4.1.0" date-fns: "npm:^4.1.0"
reflect-metadata: "npm:^0.2.2" reflect-metadata: "npm:^0.2.2"
tsup: "npm:^8.5.1" tsup: "npm:^8.5.1"
checksum: 10c0/d183abf8b42ca265ede259274ed773e013bb4f178a74552c11541283d92446c70e09e5bdf12cb35b1972deec9dda4290fd3514ad0eb283b8592456516a5f58cb checksum: 10c0/76c23a35dcc40856cd1be0b632a71ddbdb1740b397ddfcf4e2d8b307d0c127419382c0f89a0d92fc2546e9a3e313172d825942d78121d2d16cfde43a8729a7ca
languageName: node languageName: node
linkType: hard linkType: hard
@@ -4757,7 +4757,7 @@ __metadata:
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "back@workspace:." resolution: "back@workspace:."
dependencies: dependencies:
"@baekyangdan/core-utils": "npm:^1.0.4" "@baekyangdan/core-utils": "npm:^1.0.9"
"@eslint/eslintrc": "npm:^3.2.0" "@eslint/eslintrc": "npm:^3.2.0"
"@eslint/js": "npm:^9.18.0" "@eslint/js": "npm:^9.18.0"
"@fastify/cookie": "npm:^11.0.2" "@fastify/cookie": "npm:^11.0.2"
@@ -4785,6 +4785,7 @@ __metadata:
"@types/supertest": "npm:^6.0.2" "@types/supertest": "npm:^6.0.2"
bcrypt: "npm:^6.0.0" bcrypt: "npm:^6.0.0"
cross-env: "npm:^10.1.0" cross-env: "npm:^10.1.0"
date-fns: "npm:^4.1.0"
dotenv: "npm:^17.2.3" dotenv: "npm:^17.2.3"
dotenv-cli: "npm:^11.0.0" dotenv-cli: "npm:^11.0.0"
drizzle-kit: "npm:^0.31.7" drizzle-kit: "npm:^0.31.7"