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
Copy link
Collaborator

Choose a reason for hiding this comment

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

DB 마이그레이션용 파일인가요?

Copy link
Member Author

@JangDongHo JangDongHo Jan 6, 2026

Choose a reason for hiding this comment

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

넵 DB 마이그레이션용 파일 맞습니다!
PR 설명에서 해당 부분을 놓쳤네요 😅

처음에는 마이그레이션 파일을 .gitignore 로 관리해야 하나 고민했는데, 개발 환경에서 팀원들마다 동일한 DB 상태를 재현하기 위해 레포지토리에 포함하는 것이 맞다고 판단했습니다!

다만, 스키마가 변경될 때마다 마이그레이션 파일이 추가되는 구조라서 이를 어떻게 하면 효율적으로 관리할 수 있을지에 대한 논의가 필요해보여요!

Copy link
Collaborator

Choose a reason for hiding this comment

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

다만, 스키마가 변경될 때마다 마이그레이션 파일이 추가되는 구조라서 이를 어떻게 하면 효율적으로 관리할 수 있을지에 대한 논의가 필요해보여요!

오 저도 이 부분이 안그래도 궁금해서 AI에게 방금 물어봤는데, 다음과 같은 이유들로 migrations 폴더가 커져도 괜찮다고 하네요?! 물론 이건 AI의 답변일 뿐이라 추가적으로 조금 더 찾아보고 학습해봐야 하겠지만요!

2) migrations 폴더가 커져도 보통 문제 없는 이유

(1) 파일 크기가 작습니다

migration.sql은 대개 ALTER TABLE, CREATE TABLE 같은 DDL 몇 줄 수준이라
대부분 수 KB ~ 수십 KB 정도입니다.

(2) 실행 시 전체를 매번 재실행하지 않습니다

운영 배포에서 prisma migrate deploy는

  • DB의 _prisma_migrations 테이블을 보고
  • 아직 적용 안 된 마이그레이션만 순서대로 적용합니다.

이미 적용된 옛날 마이그레이션이 “성능 비용”으로 매번 재실행되는 구조가 아닙니다.

(3) Git 저장소 크기도 일반적으로는 안정적입니다

마이그레이션이 100개, 300개 쌓여도 텍스트 파일이어서 대개 큰 부담이 아닙니다.

Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
Warnings:

- The primary key for the `answers` table will be changed. If it partially fails, the table could be left without primary key constraint.
- The primary key for the `questions` table will be changed. If it partially fails, the table could be left without primary key constraint.
- The primary key for the `users` table will be changed. If it partially fails, the table could be left without primary key constraint.

*/
-- DropForeignKey
Copy link
Collaborator

Choose a reason for hiding this comment

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

여기서 왜 제약조건이랑 index를 드랍했다가 다시 설정하는지가 궁금해요
이 부분만 설명 부탁해요~

Copy link
Member Author

Choose a reason for hiding this comment

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

제 생각에는 PK와 FK의 타입을 BIGINT에서 INT형으로 변경하면서 그와 관련된 제약조건과 index를 모두 다 지웠다가 다시 설정한게 아닌가 싶네요!

ALTER TABLE `answers` DROP FOREIGN KEY `answers_question_id_fkey`;

-- DropForeignKey
ALTER TABLE `answers` DROP FOREIGN KEY `answers_user_id_fkey`;

-- DropForeignKey
ALTER TABLE `questions` DROP FOREIGN KEY `questions_accepted_answer_id_fkey`;

-- DropForeignKey
ALTER TABLE `questions` DROP FOREIGN KEY `questions_user_id_fkey`;

-- DropIndex
DROP INDEX `answers_question_id_fkey` ON `answers`;

-- DropIndex
DROP INDEX `answers_user_id_fkey` ON `answers`;

-- DropIndex
DROP INDEX `questions_user_id_fkey` ON `questions`;

-- AlterTable
ALTER TABLE `answers` DROP PRIMARY KEY,
MODIFY `id` BIGINT NOT NULL AUTO_INCREMENT,
MODIFY `question_id` BIGINT NOT NULL,
MODIFY `user_id` BIGINT NOT NULL,
ADD PRIMARY KEY (`id`);

-- AlterTable
ALTER TABLE `questions` DROP PRIMARY KEY,
MODIFY `id` BIGINT NOT NULL AUTO_INCREMENT,
MODIFY `user_id` BIGINT NOT NULL,
MODIFY `accepted_answer_id` BIGINT NULL,
ADD PRIMARY KEY (`id`);

-- AlterTable
ALTER TABLE `users` DROP PRIMARY KEY,
MODIFY `id` BIGINT NOT NULL AUTO_INCREMENT,
ADD PRIMARY KEY (`id`);

-- AddForeignKey
ALTER TABLE `questions` ADD CONSTRAINT `questions_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE `questions` ADD CONSTRAINT `questions_accepted_answer_id_fkey` FOREIGN KEY (`accepted_answer_id`) REFERENCES `answers`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE `answers` ADD CONSTRAINT `answers_question_id_fkey` FOREIGN KEY (`question_id`) REFERENCES `questions`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE `answers` ADD CONSTRAINT `answers_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
Warnings:

- The primary key for the `answers` table will be changed. If it partially fails, the table could be left without primary key constraint.
- You are about to alter the column `id` on the `answers` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `question_id` on the `answers` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `user_id` on the `answers` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
Comment on lines +6 to +7
Copy link
Collaborator

Choose a reason for hiding this comment

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

BIGINT 에서 INTEGER 로 변경하면서 경고 메시지가 생긴 것 같은데, id 를 INTEGER 로 변경하신 이유가 따로 있을까요?!

Copy link
Collaborator

Choose a reason for hiding this comment

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

저도 위에 20260101084425 에서는 INT -> BIGINT로 변경했는데
여기서 다시 BIGINT -> INT로 변경했는지 궁급합니다~

Copy link
Member Author

@JangDongHo JangDongHo Jan 8, 2026

Choose a reason for hiding this comment

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

아이고 이 부분도 PR 문서에 설명이 누락되어 있어 혼동을 드렸군요.

DB 설계상의 의도 변경이라기보다는, ORM 사용 과정에서 발생한 런타임 이슈를 우회하기 위한 선택이었습니다!

만약 BigInt를 사용한다면 문서와 같이 해결할 수 있을 것 같은데, 이 부분은 저 혼자 결정할 수 있는 부분이 아닌 것 같아서 회의 시간에 다시 논의해보면 좋을 것 같아요.

- The primary key for the `questions` table will be changed. If it partially fails, the table could be left without primary key constraint.
- You are about to alter the column `id` on the `questions` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `user_id` on the `questions` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- You are about to alter the column `accepted_answer_id` on the `questions` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.
- The primary key for the `users` table will be changed. If it partially fails, the table could be left without primary key constraint.
- You are about to alter the column `id` on the `users` table. The data in that column could be lost. The data in that column will be cast from `BigInt` to `Int`.

*/
-- DropForeignKey
ALTER TABLE `answers` DROP FOREIGN KEY `answers_question_id_fkey`;

-- DropForeignKey
ALTER TABLE `answers` DROP FOREIGN KEY `answers_user_id_fkey`;

-- DropForeignKey
ALTER TABLE `questions` DROP FOREIGN KEY `questions_accepted_answer_id_fkey`;

-- DropForeignKey
ALTER TABLE `questions` DROP FOREIGN KEY `questions_user_id_fkey`;

-- DropIndex
DROP INDEX `answers_question_id_fkey` ON `answers`;

-- DropIndex
DROP INDEX `answers_user_id_fkey` ON `answers`;

-- DropIndex
DROP INDEX `questions_user_id_fkey` ON `questions`;

-- AlterTable
ALTER TABLE `answers` DROP PRIMARY KEY,
MODIFY `id` INTEGER NOT NULL AUTO_INCREMENT,
MODIFY `question_id` INTEGER NOT NULL,
MODIFY `user_id` INTEGER NOT NULL,
ADD PRIMARY KEY (`id`);

-- AlterTable
ALTER TABLE `questions` DROP PRIMARY KEY,
MODIFY `id` INTEGER NOT NULL AUTO_INCREMENT,
MODIFY `user_id` INTEGER NOT NULL,
MODIFY `accepted_answer_id` INTEGER NULL,
ADD PRIMARY KEY (`id`);

-- AlterTable
ALTER TABLE `users` DROP PRIMARY KEY,
MODIFY `id` INTEGER NOT NULL AUTO_INCREMENT,
ADD PRIMARY KEY (`id`);

-- AddForeignKey
ALTER TABLE `questions` ADD CONSTRAINT `questions_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE `questions` ADD CONSTRAINT `questions_accepted_answer_id_fkey` FOREIGN KEY (`accepted_answer_id`) REFERENCES `answers`(`id`) ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE `answers` ADD CONSTRAINT `answers_question_id_fkey` FOREIGN KEY (`question_id`) REFERENCES `questions`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE `answers` ADD CONSTRAINT `answers_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
Warnings:

- The primary key for the `answers` table will be changed. If it partially fails, the table could be left without primary key constraint.
- You are about to drop the column `user_id` on the `answers` table. All the data in the column will be lost.
- The primary key for the `questions` table will be changed. If it partially fails, the table could be left without primary key constraint.
- You are about to drop the column `accepted_answer_id` on the `questions` table. All the data in the column will be lost.
- You are about to drop the column `user_id` on the `questions` table. All the data in the column will be lost.
- You are about to drop the `users` table. If the table is not empty, all the data it contains will be lost.
- Added the required column `member_id` to the `answers` table without a default value. This is not possible if the table is not empty.
- Added the required column `member_id` to the `questions` table without a default value. This is not possible if the table is not empty.

*/
-- DropForeignKey
ALTER TABLE `answers` DROP FOREIGN KEY `answers_question_id_fkey`;

-- DropForeignKey
ALTER TABLE `answers` DROP FOREIGN KEY `answers_user_id_fkey`;

-- DropForeignKey
ALTER TABLE `questions` DROP FOREIGN KEY `questions_accepted_answer_id_fkey`;

-- DropForeignKey
ALTER TABLE `questions` DROP FOREIGN KEY `questions_user_id_fkey`;

-- DropIndex
DROP INDEX `answers_question_id_fkey` ON `answers`;

-- DropIndex
DROP INDEX `answers_user_id_fkey` ON `answers`;

-- DropIndex
DROP INDEX `questions_accepted_answer_id_key` ON `questions`;

-- DropIndex
DROP INDEX `questions_user_id_fkey` ON `questions`;

-- AlterTable
ALTER TABLE `answers` DROP PRIMARY KEY,
DROP COLUMN `user_id`,
ADD COLUMN `member_id` BIGINT NOT NULL,
MODIFY `id` BIGINT NOT NULL AUTO_INCREMENT,
MODIFY `question_id` BIGINT NOT NULL,
ADD PRIMARY KEY (`id`);

-- AlterTable
ALTER TABLE `questions` DROP PRIMARY KEY,
DROP COLUMN `accepted_answer_id`,
DROP COLUMN `user_id`,
ADD COLUMN `is_resolved` BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN `member_id` BIGINT NOT NULL,
MODIFY `id` BIGINT NOT NULL AUTO_INCREMENT,
ADD PRIMARY KEY (`id`);

-- DropTable
DROP TABLE `users`;

-- CreateTable
CREATE TABLE `members` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`nickname` VARCHAR(191) NOT NULL,
`avatar_url` VARCHAR(191) NULL,
`cohort` TINYINT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),

PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- AddForeignKey
ALTER TABLE `questions` ADD CONSTRAINT `questions_member_id_fkey` FOREIGN KEY (`member_id`) REFERENCES `members`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE `answers` ADD CONSTRAINT `answers_question_id_fkey` FOREIGN KEY (`question_id`) REFERENCES `questions`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE `answers` ADD CONSTRAINT `answers_member_id_fkey` FOREIGN KEY (`member_id`) REFERENCES `members`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
54 changes: 25 additions & 29 deletions BE/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -14,56 +14,52 @@ datasource db {
provider = "mysql"
}

model User {
id Int @id @default(autoincrement())
user_id String @unique
password String
model Member {
id BigInt @id @default(autoincrement())
nickname String
avatar_url String?
avatarUrl String? @map("avatar_url")
cohort Int? @db.TinyInt
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")

questions Question[]
answers Answer[]

@@map("users")
@@map("members")
}

model Question {
id Int @id @default(autoincrement())
user_id Int
accepted_answer_id Int? @unique
id BigInt @id @default(autoincrement())
memberId BigInt @map("member_id")
title String
contents String
hashtags String?
like_count Int @default(0)
view_count Int @default(0)
answer_count Int @default(0)
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
likeCount Int @default(0) @map("like_count")
viewCount Int @default(0) @map("view_count")
answerCount Int @default(0) @map("answer_count")
isResolved Boolean @default(false) @map("is_resolved")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")

user User @relation(fields: [user_id], references: [id])
member Member @relation(fields: [memberId], references: [id])
answers Answer[] @relation("QuestionAnswers")
accepted_answer Answer? @relation("AcceptedAnswer", fields: [accepted_answer_id], references: [id])

@@map("questions")
}

model Answer {
id Int @id @default(autoincrement())
question_id Int
user_id Int
id BigInt @id @default(autoincrement())
questionId BigInt @map("question_id")
memberId BigInt @map("member_id")
contents String
like_count Int @default(0)
is_accepted Boolean @default(false)
view_count Int @default(0)
created_at DateTime @default(now())
updated_at DateTime @default(now()) @updatedAt
likeCount Int @default(0) @map("like_count")
isAccepted Boolean @default(false) @map("is_accepted")
viewCount Int @default(0) @map("view_count")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @updatedAt @map("updated_at")

question Question @relation("QuestionAnswers", fields: [question_id], references: [id])
user User @relation(fields: [user_id], references: [id])
accepted_in Question? @relation("AcceptedAnswer")
question Question @relation("QuestionAnswers", fields: [questionId], references: [id])
member Member @relation(fields: [memberId], references: [id])

@@map("answers")
}
5 changes: 5 additions & 0 deletions BE/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

// BigInt 전역 설정 (JSON.stringify 시 문자열로 변환)
(BigInt.prototype as any).toJSON = function () {
return this.toString();
};

async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(process.env.PORT ?? 3000);
Expand Down