- 디렉토리 구조 개선
This commit is contained in:
geonhee-min
2025-12-10 17:13:28 +09:00
parent f451306c90
commit 9578b37c64
19 changed files with 84 additions and 48 deletions

View File

@@ -1,7 +1,7 @@
import { defineConfig } from 'drizzle-kit';
import dotenv from 'dotenv';
dotenv.config();
dotenv.config({ path: `.env.${process.env.NODE_ENV}` });
export default defineConfig({
dialect: "postgresql",

View File

@@ -20,7 +20,7 @@ export const userBlockingIdSeq = pgSequence("user_blocking_id_seq", { startWith
export const emailAddressIdSeq = pgSequence("email_address_id_seq", { startWith: "1", increment: "1", minValue: "1", maxValue: "9223372036854775807", cache: "1", cycle: false })
export const comment = pgTable("comment", {
id: uuid().primaryKey().notNull(),
id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(),
content: text(),
createdAt: date("created_at"),
isDeleted: boolean("is_deleted").default(false),
@@ -72,19 +72,20 @@ export const participant = pgTable("participant", {
]);
export const schedule = pgTable("schedule", {
id: uuid().primaryKey().notNull(),
name: varchar(),
startDate: date("start_date"),
endDate: date("end_date"),
status: varchar(),
id: uuid().default(sql`uuid_generate_v4()`).primaryKey().notNull(),
name: varchar().notNull(),
startDate: date("start_date").notNull(),
endDate: date("end_date").notNull(),
status: varchar().default('yet').notNull(),
content: text(),
isDeleted: boolean("is_deleted").default(false),
type: varchar(),
isDeleted: boolean("is_deleted").default(false).notNull(),
type: varchar().notNull(),
createdAt: date("created_at"),
owner: uuid(),
style: varchar(),
startTime: time("start_time"),
endTime: time("end_time"),
owner: uuid().notNull(),
style: varchar().notNull(),
startTime: time("start_time").notNull(),
endTime: time("end_time").notNull(),
dayList: varchar("day_list"),
}, (table) => [
index("schedule_enddatetime_idx").using("btree", table.endDate.asc().nullsLast().op("date_ops")),
index("schedule_name_idx").using("btree", table.name.asc().nullsLast().op("text_ops"), table.content.asc().nullsLast().op("text_ops")),

View File

@@ -6,9 +6,10 @@ import { RedisModule } from './redis/redis.module';
import { AccountModule } from './modules/account/account.module';
import { MailerModule } from './util/mailer/mailer.module';
import { AppConfigModule } from './config/config.module';
import { ScheduleModule } from './modules/schedule/schedule.module';
@Module({
imports: [AppConfigModule, DbModule, RedisModule, MailerModule, AccountModule],
imports: [AppConfigModule, DbModule, RedisModule, MailerModule, AccountModule, ScheduleModule],
controllers: [AppController],
providers: [AppService],
})

View File

@@ -5,6 +5,7 @@ import {
HttpException,
HttpStatus
} from '@nestjs/common';
import { JsonWebTokenError, TokenExpiredError } from '@nestjs/jwt';
import { FastifyReply, FastifyRequest } from 'fastify';
@Catch()
@@ -13,6 +14,39 @@ export class AllExceptionsFilter implements ExceptionFilter {
const ctx = host.switchToHttp();
const response = ctx.getResponse<FastifyReply>();
const request = ctx.getRequest<FastifyRequest>();
console.log(exception);
// TokenExpiredError
if (exception instanceof TokenExpiredError) {
const status = HttpStatus.UNAUTHORIZED;
const responseBody = {
statusCode: status,
message: 'Access Token Expired',
code: 'AccessTokenExpired',
timestamp: new Date().toISOString(),
path: ctx.getRequest().url
};
response.status(status).send(responseBody);
return;
}
// JsonWebTokenError
if (exception instanceof JsonWebTokenError) {
const status = HttpStatus.UNAUTHORIZED;
const responseBody = {
statusCode: status,
message: 'Invalid Token',
code: 'InvalidToken',
timestamp: new Date().toISOString(),
path: ctx.getRequest().url
};
response.status(status).send(responseBody);
return;
}
let status =
exception instanceof HttpException

View File

@@ -45,7 +45,7 @@ async function bootstrap() {
app.register(fastifyCookie, {
secret: process.env.JWT_SECRET
});
await app.listen(process.env.PORT ?? 3000, '0.0.0.0', () => { process.env.NODE_ENV !== 'prod' && console.log(`servier is running on ${process.env.PORT}`) });
// await app.listen(process.env.PORT ?? 3000, '0.0.0.0', () => { process.env.NODE_ENV !== 'prod' && console.log(`servier is running on ${process.env.PORT}`) });
await app.listen(process.env.PORT || 3000, () => { process.env.NODE_ENV !== 'prod' && console.log(`service is running on ${process.env.PORT}`)});
}
bootstrap();

View File

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

View File

@@ -1,6 +1,6 @@
import { ExecutionContext, Injectable, UnauthorizedException } from "@nestjs/common";
import { Reflector } from "@nestjs/core";
import { TokenExpiredError } from "@nestjs/jwt";
import { JsonWebTokenError, TokenExpiredError } from "@nestjs/jwt";
import { AuthGuard } from "@nestjs/passport";
import { IS_PUBLIC_KEY } from "src/common/decorators/public.decorator";
@@ -23,23 +23,18 @@ export class JwtAccessAuthGuard extends AuthGuard('access-token') {
return super.canActivate(context);
}
handleRequest(err: any, user:any, info:any) {
if (info instanceof TokenExpiredError) {
throw new UnauthorizedException({
statusCode: 401,
message: 'Access Token Expired',
code: 'AccessTokenExpired'
});
}
handleRequest(err: any, user:any, info:any, context: ExecutionContext) {
if (err || !user) {
throw new UnauthorizedException({
statusCode: 401,
message: 'Invalid Token',
code: 'InvalidToken'
});
if (info instanceof TokenExpiredError) {
throw info;
}
if (info instanceof JsonWebTokenError) {
throw info;
}
throw err || new JsonWebTokenError('Unauthorized');
}
return user;
}
}

View File

@@ -2,10 +2,14 @@ import { Injectable, UnauthorizedException } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { PassportStrategy } from "@nestjs/passport";
import { ExtractJwt, Strategy } from "passport-jwt";
import { AccountRepo } from "src/modules/account/account.repo";
@Injectable()
export class JwtAccessStrategy extends PassportStrategy(Strategy, "access-token") {
constructor(configService: ConfigService) {
constructor(
configService: ConfigService,
private accountRepo: AccountRepo
) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: configService.get<string>('JWT_SECRET')!
@@ -13,10 +17,11 @@ export class JwtAccessStrategy extends PassportStrategy(Strategy, "access-token"
}
async validate(payload: any) {
const token = ExtractJwt.fromAuthHeaderAsBearerToken();
if (!token) {
console.log(payload);
const user = await this.accountRepo.findById(payload.id);
if (!user) {
throw new UnauthorizedException();
}
return { id: payload.id };
return user;
}
}

View File

@@ -26,7 +26,7 @@ export class AccountRepo {
email: string,
password: string
) {
return this
return await this
.db
.insert(schema.account)
.values({
@@ -42,7 +42,7 @@ export class AccountRepo {
type: 'email' | 'accountId'
, id: string
) {
return this
return await this
.db
.select()
.from(schema.account)

View File

@@ -1,4 +1,4 @@
import { BaseResponseDto } from "../base-response.dto";
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
export class CheckDuplicationResponseDto extends BaseResponseDto {
isDuplicated: boolean;

View File

@@ -1,4 +1,4 @@
import { BaseResponseDto } from "../base-response.dto";
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
export class LoginResponseDto extends BaseResponseDto {
accessToken?: string;

View File

@@ -1,4 +1,4 @@
import { BaseResponseDto } from "../base-response.dto";
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
export class RefreshAccessTokenResponseDto extends BaseResponseDto{
accessToken: string;

View File

@@ -1,4 +1,4 @@
import { BaseResponseDto } from "../base-response.dto";
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
export class ResetPasswordResponseDto extends BaseResponseDto {

View File

@@ -1,4 +1,4 @@
import { BaseResponseDto } from "../base-response.dto";
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
export class SendEmailVerificationCodeResponseDto extends BaseResponseDto{
}

View File

@@ -1,4 +1,4 @@
import { BaseResponseDto } from "../base-response.dto";
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
export class SendResetPasswordCodeResponseDto extends BaseResponseDto {
}

View File

@@ -1,4 +1,4 @@
import { BaseResponseDto } from "../base-response.dto";
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
export class SignupResponseDto extends BaseResponseDto {
}

View File

@@ -1,4 +1,4 @@
import { BaseResponseDto } from "../base-response.dto";
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
export class VerifyEmailVerificationCodeResponseDto extends BaseResponseDto{
verified: boolean;

View File

@@ -1,4 +1,4 @@
import { BaseResponseDto } from "../base-response.dto";
import { BaseResponseDto } from "../../../../common/dto/base-response.dto";
export class VerifyResetPasswordCodeResponseDto extends BaseResponseDto {
verified: boolean;