prizma 이상한거거
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -41,3 +41,9 @@ yarn-error.log*
|
|||||||
next-env.d.ts
|
next-env.d.ts
|
||||||
|
|
||||||
/lib/generated/prisma
|
/lib/generated/prisma
|
||||||
|
|
||||||
|
/lib/generated/prisma
|
||||||
|
|
||||||
|
/lib/generated/prisma
|
||||||
|
|
||||||
|
/lib/generated/prisma
|
||||||
|
|||||||
@@ -1,161 +0,0 @@
|
|||||||
import { NextRequest, NextResponse } from 'next/server';
|
|
||||||
import { prisma } from '@/lib/prisma';
|
|
||||||
|
|
||||||
// GET - 교육 과정 목록 조회 또는 단일 교육 과정 조회
|
|
||||||
export async function GET(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const { searchParams } = new URL(request.url);
|
|
||||||
const id = searchParams.get('id');
|
|
||||||
const instructorId = searchParams.get('instructorId');
|
|
||||||
|
|
||||||
if (id) {
|
|
||||||
// 단일 교육 과정 조회
|
|
||||||
const curriculum = await prisma.curriculum.findUnique({
|
|
||||||
where: { id },
|
|
||||||
include: {
|
|
||||||
lectures: {
|
|
||||||
include: {
|
|
||||||
registrant: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!curriculum) {
|
|
||||||
return NextResponse.json({ error: '교육 과정을 찾을 수 없습니다.' }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextResponse.json(curriculum);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 전체 교육 과정 목록 조회
|
|
||||||
let where: any = {};
|
|
||||||
if (instructorId) {
|
|
||||||
where.instructorId = instructorId;
|
|
||||||
}
|
|
||||||
|
|
||||||
const curriculums = await prisma.curriculum.findMany({
|
|
||||||
where,
|
|
||||||
include: {
|
|
||||||
lectures: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
title: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
orderBy: {
|
|
||||||
createdAt: 'desc',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json(curriculums);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching curriculums:', error);
|
|
||||||
return NextResponse.json({ error: '교육 과정 조회 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST - 교육 과정 생성
|
|
||||||
export async function POST(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const body = await request.json();
|
|
||||||
const { title, instructorId } = body;
|
|
||||||
|
|
||||||
if (!title || !instructorId) {
|
|
||||||
return NextResponse.json({ error: '과정 제목과 강사 ID는 필수입니다.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 강사 존재 확인
|
|
||||||
const instructor = await prisma.user.findUnique({
|
|
||||||
where: { id: instructorId },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!instructor) {
|
|
||||||
return NextResponse.json({ error: '강사를 찾을 수 없습니다.' }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const curriculum = await prisma.curriculum.create({
|
|
||||||
data: {
|
|
||||||
title,
|
|
||||||
instructorId,
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
lectures: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json(curriculum, { status: 201 });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error creating curriculum:', error);
|
|
||||||
return NextResponse.json({ error: '교육 과정 생성 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PUT - 교육 과정 수정
|
|
||||||
export async function PUT(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const body = await request.json();
|
|
||||||
const { id, title, instructorId } = body;
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
return NextResponse.json({ error: '교육 과정 ID는 필수입니다.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateData: any = {};
|
|
||||||
if (title !== undefined) updateData.title = title;
|
|
||||||
if (instructorId !== undefined) {
|
|
||||||
// 강사 존재 확인
|
|
||||||
const instructor = await prisma.user.findUnique({
|
|
||||||
where: { id: instructorId },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!instructor) {
|
|
||||||
return NextResponse.json({ error: '강사를 찾을 수 없습니다.' }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
updateData.instructorId = instructorId;
|
|
||||||
}
|
|
||||||
|
|
||||||
const curriculum = await prisma.curriculum.update({
|
|
||||||
where: { id },
|
|
||||||
data: updateData,
|
|
||||||
include: {
|
|
||||||
lectures: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json(curriculum);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error updating curriculum:', error);
|
|
||||||
return NextResponse.json({ error: '교육 과정 수정 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE - 교육 과정 삭제
|
|
||||||
export async function DELETE(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const { searchParams } = new URL(request.url);
|
|
||||||
const id = searchParams.get('id');
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
return NextResponse.json({ error: '교육 과정 ID는 필수입니다.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.curriculum.delete({
|
|
||||||
where: { id },
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json({ message: '교육 과정이 삭제되었습니다.' });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error deleting curriculum:', error);
|
|
||||||
return NextResponse.json({ error: '교육 과정 삭제 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
import { NextRequest, NextResponse } from 'next/server';
|
|
||||||
import { prisma } from '@/lib/prisma';
|
|
||||||
|
|
||||||
// GET - 강좌 목록 조회 또는 단일 강좌 조회
|
|
||||||
export async function GET(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const { searchParams } = new URL(request.url);
|
|
||||||
const id = searchParams.get('id');
|
|
||||||
const curriculumId = searchParams.get('curriculumId');
|
|
||||||
const registrantId = searchParams.get('registrantId');
|
|
||||||
|
|
||||||
if (id) {
|
|
||||||
// 단일 강좌 조회
|
|
||||||
const lecture = await prisma.lecture.findUnique({
|
|
||||||
where: { id },
|
|
||||||
include: {
|
|
||||||
curriculum: true,
|
|
||||||
registrant: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
enrolledUsers: {
|
|
||||||
include: {
|
|
||||||
user: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!lecture) {
|
|
||||||
return NextResponse.json({ error: '강좌를 찾을 수 없습니다.' }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextResponse.json(lecture);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 전체 강좌 목록 조회
|
|
||||||
let where: any = {};
|
|
||||||
if (curriculumId) {
|
|
||||||
where.curriculumId = curriculumId;
|
|
||||||
}
|
|
||||||
if (registrantId) {
|
|
||||||
where.registrantId = registrantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lectures = await prisma.lecture.findMany({
|
|
||||||
where,
|
|
||||||
include: {
|
|
||||||
curriculum: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
title: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
registrant: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
orderBy: {
|
|
||||||
createdAt: 'desc',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json(lectures);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching lectures:', error);
|
|
||||||
return NextResponse.json({ error: '강좌 조회 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST - 강좌 생성
|
|
||||||
export async function POST(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const body = await request.json();
|
|
||||||
const { title, attachmentFile, evaluationQuestionCount, curriculumId, registrantId } = body;
|
|
||||||
|
|
||||||
if (!title || !curriculumId || !registrantId) {
|
|
||||||
return NextResponse.json({ error: '강좌명, 교육 과정 ID, 등록자 ID는 필수입니다.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 교육 과정 존재 확인
|
|
||||||
const curriculum = await prisma.curriculum.findUnique({
|
|
||||||
where: { id: curriculumId },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!curriculum) {
|
|
||||||
return NextResponse.json({ error: '교육 과정을 찾을 수 없습니다.' }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 등록자 존재 확인
|
|
||||||
const registrant = await prisma.user.findUnique({
|
|
||||||
where: { id: registrantId },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!registrant) {
|
|
||||||
return NextResponse.json({ error: '등록자를 찾을 수 없습니다.' }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const lecture = await prisma.lecture.create({
|
|
||||||
data: {
|
|
||||||
title,
|
|
||||||
attachmentFile: attachmentFile || null,
|
|
||||||
evaluationQuestionCount: evaluationQuestionCount || 0,
|
|
||||||
curriculumId,
|
|
||||||
registrantId,
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
curriculum: true,
|
|
||||||
registrant: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json(lecture, { status: 201 });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error creating lecture:', error);
|
|
||||||
return NextResponse.json({ error: '강좌 생성 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PUT - 강좌 수정
|
|
||||||
export async function PUT(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const body = await request.json();
|
|
||||||
const { id, title, attachmentFile, evaluationQuestionCount, curriculumId, registrantId } = body;
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
return NextResponse.json({ error: '강좌 ID는 필수입니다.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateData: any = {};
|
|
||||||
if (title !== undefined) updateData.title = title;
|
|
||||||
if (attachmentFile !== undefined) updateData.attachmentFile = attachmentFile;
|
|
||||||
if (evaluationQuestionCount !== undefined) updateData.evaluationQuestionCount = parseInt(evaluationQuestionCount);
|
|
||||||
if (curriculumId !== undefined) {
|
|
||||||
// 교육 과정 존재 확인
|
|
||||||
const curriculum = await prisma.curriculum.findUnique({
|
|
||||||
where: { id: curriculumId },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!curriculum) {
|
|
||||||
return NextResponse.json({ error: '교육 과정을 찾을 수 없습니다.' }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
updateData.curriculumId = curriculumId;
|
|
||||||
}
|
|
||||||
if (registrantId !== undefined) {
|
|
||||||
// 등록자 존재 확인
|
|
||||||
const registrant = await prisma.user.findUnique({
|
|
||||||
where: { id: registrantId },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!registrant) {
|
|
||||||
return NextResponse.json({ error: '등록자를 찾을 수 없습니다.' }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
updateData.registrantId = registrantId;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lecture = await prisma.lecture.update({
|
|
||||||
where: { id },
|
|
||||||
data: updateData,
|
|
||||||
include: {
|
|
||||||
curriculum: true,
|
|
||||||
registrant: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json(lecture);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error updating lecture:', error);
|
|
||||||
return NextResponse.json({ error: '강좌 수정 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE - 강좌 삭제
|
|
||||||
export async function DELETE(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const { searchParams } = new URL(request.url);
|
|
||||||
const id = searchParams.get('id');
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
return NextResponse.json({ error: '강좌 ID는 필수입니다.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.lecture.delete({
|
|
||||||
where: { id },
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json({ message: '강좌가 삭제되었습니다.' });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error deleting lecture:', error);
|
|
||||||
return NextResponse.json({ error: '강좌 삭제 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,234 +0,0 @@
|
|||||||
import { NextRequest, NextResponse } from 'next/server';
|
|
||||||
import { prisma } from '@/lib/prisma';
|
|
||||||
|
|
||||||
// GET - 수강 목록 조회 또는 단일 수강 조회
|
|
||||||
export async function GET(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const { searchParams } = new URL(request.url);
|
|
||||||
const id = searchParams.get('id');
|
|
||||||
const userId = searchParams.get('userId');
|
|
||||||
const lectureId = searchParams.get('lectureId');
|
|
||||||
|
|
||||||
if (id) {
|
|
||||||
// 단일 수강 조회
|
|
||||||
const userLecture = await prisma.userLecture.findUnique({
|
|
||||||
where: { id },
|
|
||||||
include: {
|
|
||||||
user: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
lecture: {
|
|
||||||
include: {
|
|
||||||
curriculum: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!userLecture) {
|
|
||||||
return NextResponse.json({ error: '수강 정보를 찾을 수 없습니다.' }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextResponse.json(userLecture);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 수강 목록 조회
|
|
||||||
let where: any = {};
|
|
||||||
if (userId) {
|
|
||||||
where.userId = userId;
|
|
||||||
}
|
|
||||||
if (lectureId) {
|
|
||||||
where.lectureId = lectureId;
|
|
||||||
}
|
|
||||||
|
|
||||||
const userLectures = await prisma.userLecture.findMany({
|
|
||||||
where,
|
|
||||||
include: {
|
|
||||||
user: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
lecture: {
|
|
||||||
include: {
|
|
||||||
curriculum: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
title: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
orderBy: {
|
|
||||||
enrolledAt: 'desc',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json(userLectures);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching user lectures:', error);
|
|
||||||
return NextResponse.json({ error: '수강 정보 조회 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST - 수강 등록
|
|
||||||
export async function POST(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const body = await request.json();
|
|
||||||
const { userId, lectureId } = body;
|
|
||||||
|
|
||||||
if (!userId || !lectureId) {
|
|
||||||
return NextResponse.json({ error: '사용자 ID와 강좌 ID는 필수입니다.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 사용자 존재 확인
|
|
||||||
const user = await prisma.user.findUnique({
|
|
||||||
where: { id: userId },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
return NextResponse.json({ error: '사용자를 찾을 수 없습니다.' }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 강좌 존재 확인
|
|
||||||
const lecture = await prisma.lecture.findUnique({
|
|
||||||
where: { id: lectureId },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!lecture) {
|
|
||||||
return NextResponse.json({ error: '강좌를 찾을 수 없습니다.' }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 이미 수강 중인지 확인
|
|
||||||
const existingEnrollment = await prisma.userLecture.findUnique({
|
|
||||||
where: {
|
|
||||||
userId_lectureId: {
|
|
||||||
userId,
|
|
||||||
lectureId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (existingEnrollment) {
|
|
||||||
return NextResponse.json({ error: '이미 수강 중인 강좌입니다.' }, { status: 409 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 수강 등록
|
|
||||||
const userLecture = await prisma.userLecture.create({
|
|
||||||
data: {
|
|
||||||
userId,
|
|
||||||
lectureId,
|
|
||||||
progress: 0,
|
|
||||||
isCompleted: false,
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
user: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
lecture: {
|
|
||||||
include: {
|
|
||||||
curriculum: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json(userLecture, { status: 201 });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error enrolling lecture:', error);
|
|
||||||
return NextResponse.json({ error: '수강 등록 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PUT - 수강 정보 수정 (진행률, 완료 여부 등)
|
|
||||||
export async function PUT(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const body = await request.json();
|
|
||||||
const { id, progress, isCompleted, score } = body;
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
return NextResponse.json({ error: '수강 ID는 필수입니다.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateData: any = {};
|
|
||||||
if (progress !== undefined) {
|
|
||||||
const progressValue = parseInt(progress);
|
|
||||||
if (progressValue < 0 || progressValue > 100) {
|
|
||||||
return NextResponse.json({ error: '진행률은 0-100 사이여야 합니다.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
updateData.progress = progressValue;
|
|
||||||
}
|
|
||||||
if (isCompleted !== undefined) {
|
|
||||||
updateData.isCompleted = isCompleted;
|
|
||||||
if (isCompleted && !updateData.completedAt) {
|
|
||||||
updateData.completedAt = new Date();
|
|
||||||
} else if (!isCompleted) {
|
|
||||||
updateData.completedAt = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (score !== undefined) {
|
|
||||||
const scoreValue = parseInt(score);
|
|
||||||
if (scoreValue < 0 || scoreValue > 100) {
|
|
||||||
return NextResponse.json({ error: '점수는 0-100 사이여야 합니다.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
updateData.score = scoreValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const userLecture = await prisma.userLecture.update({
|
|
||||||
where: { id },
|
|
||||||
data: updateData,
|
|
||||||
include: {
|
|
||||||
user: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
email: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
lecture: {
|
|
||||||
include: {
|
|
||||||
curriculum: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json(userLecture);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error updating user lecture:', error);
|
|
||||||
return NextResponse.json({ error: '수강 정보 수정 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE - 수강 취소
|
|
||||||
export async function DELETE(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const { searchParams } = new URL(request.url);
|
|
||||||
const id = searchParams.get('id');
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
return NextResponse.json({ error: '수강 ID는 필수입니다.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.userLecture.delete({
|
|
||||||
where: { id },
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json({ message: '수강이 취소되었습니다.' });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error deleting user lecture:', error);
|
|
||||||
return NextResponse.json({ error: '수강 취소 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import { NextRequest, NextResponse } from 'next/server';
|
|
||||||
import { prisma } from '@/lib/prisma';
|
|
||||||
import bcrypt from 'bcryptjs';
|
|
||||||
|
|
||||||
// POST - 로그인
|
|
||||||
export async function POST(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const body = await request.json();
|
|
||||||
const { email, password } = body;
|
|
||||||
|
|
||||||
if (!email || !password) {
|
|
||||||
return NextResponse.json({ error: '이메일과 비밀번호를 입력해주세요.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 사용자 조회
|
|
||||||
const user = await prisma.user.findUnique({
|
|
||||||
where: { email },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
return NextResponse.json({ error: '아이디 또는 비밀번호가 올바르지 않습니다.' }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 계정 활성화 확인
|
|
||||||
if (!user.isActive) {
|
|
||||||
return NextResponse.json({ error: '비활성화된 계정입니다.' }, { status: 403 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 비밀번호 확인
|
|
||||||
const isPasswordValid = await bcrypt.compare(password, user.password);
|
|
||||||
|
|
||||||
if (!isPasswordValid) {
|
|
||||||
return NextResponse.json({ error: '아이디 또는 비밀번호가 올바르지 않습니다.' }, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 비밀번호 제외하고 사용자 정보 반환
|
|
||||||
const { password: _, ...userWithoutPassword } = user;
|
|
||||||
|
|
||||||
return NextResponse.json({
|
|
||||||
user: userWithoutPassword,
|
|
||||||
message: '로그인 성공',
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error during login:', error);
|
|
||||||
return NextResponse.json({ error: '로그인 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
import { NextRequest, NextResponse } from 'next/server';
|
|
||||||
import { prisma } from '@/lib/prisma';
|
|
||||||
import bcrypt from 'bcryptjs';
|
|
||||||
|
|
||||||
// GET - 사용자 목록 조회 또는 단일 사용자 조회
|
|
||||||
export async function GET(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const { searchParams } = new URL(request.url);
|
|
||||||
const id = searchParams.get('id');
|
|
||||||
const email = searchParams.get('email');
|
|
||||||
|
|
||||||
if (id) {
|
|
||||||
// 단일 사용자 조회
|
|
||||||
const user = await prisma.user.findUnique({
|
|
||||||
where: { id },
|
|
||||||
include: {
|
|
||||||
enrolledLectures: {
|
|
||||||
include: {
|
|
||||||
lecture: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
return NextResponse.json({ error: '사용자를 찾을 수 없습니다.' }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 비밀번호 제외
|
|
||||||
const { password, ...userWithoutPassword } = user;
|
|
||||||
return NextResponse.json(userWithoutPassword);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (email) {
|
|
||||||
// 이메일로 사용자 조회
|
|
||||||
const user = await prisma.user.findUnique({
|
|
||||||
where: { email },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
return NextResponse.json({ error: '사용자를 찾을 수 없습니다.' }, { status: 404 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const { password, ...userWithoutPassword } = user;
|
|
||||||
return NextResponse.json(userWithoutPassword);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 전체 사용자 목록 조회
|
|
||||||
const users = await prisma.user.findMany({
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
email: true,
|
|
||||||
name: true,
|
|
||||||
phone: true,
|
|
||||||
gender: true,
|
|
||||||
role: true,
|
|
||||||
isActive: true,
|
|
||||||
createdAt: true,
|
|
||||||
updatedAt: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json(users);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching users:', error);
|
|
||||||
return NextResponse.json({ error: '사용자 조회 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST - 사용자 생성 (회원가입)
|
|
||||||
export async function POST(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const body = await request.json();
|
|
||||||
const { email, password, name, phone, gender, birthYear, birthMonth, birthDay, role } = body;
|
|
||||||
|
|
||||||
// 필수 필드 검증
|
|
||||||
if (!email || !password) {
|
|
||||||
return NextResponse.json({ error: '이메일과 비밀번호는 필수입니다.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 이메일 중복 확인
|
|
||||||
const existingUser = await prisma.user.findUnique({
|
|
||||||
where: { email },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (existingUser) {
|
|
||||||
return NextResponse.json({ error: '이미 등록된 이메일입니다.' }, { status: 409 });
|
|
||||||
}
|
|
||||||
|
|
||||||
// 비밀번호 해시화
|
|
||||||
const hashedPassword = await bcrypt.hash(password, 10);
|
|
||||||
|
|
||||||
// 사용자 생성
|
|
||||||
const user = await prisma.user.create({
|
|
||||||
data: {
|
|
||||||
email,
|
|
||||||
password: hashedPassword,
|
|
||||||
name: name || null,
|
|
||||||
phone: phone || null,
|
|
||||||
gender: gender || null,
|
|
||||||
birthYear: birthYear ? parseInt(birthYear) : null,
|
|
||||||
birthMonth: birthMonth ? parseInt(birthMonth) : null,
|
|
||||||
birthDay: birthDay ? parseInt(birthDay) : null,
|
|
||||||
role: role || 'STUDENT',
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
email: true,
|
|
||||||
name: true,
|
|
||||||
phone: true,
|
|
||||||
gender: true,
|
|
||||||
role: true,
|
|
||||||
isActive: true,
|
|
||||||
createdAt: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json(user, { status: 201 });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error creating user:', error);
|
|
||||||
return NextResponse.json({ error: '사용자 생성 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PUT - 사용자 정보 수정
|
|
||||||
export async function PUT(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const body = await request.json();
|
|
||||||
const { id, name, phone, gender, birthYear, birthMonth, birthDay, role, isActive } = body;
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
return NextResponse.json({ error: '사용자 ID는 필수입니다.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateData: any = {};
|
|
||||||
if (name !== undefined) updateData.name = name;
|
|
||||||
if (phone !== undefined) updateData.phone = phone;
|
|
||||||
if (gender !== undefined) updateData.gender = gender;
|
|
||||||
if (birthYear !== undefined) updateData.birthYear = birthYear ? parseInt(birthYear) : null;
|
|
||||||
if (birthMonth !== undefined) updateData.birthMonth = birthMonth ? parseInt(birthMonth) : null;
|
|
||||||
if (birthDay !== undefined) updateData.birthDay = birthDay ? parseInt(birthDay) : null;
|
|
||||||
if (role !== undefined) updateData.role = role;
|
|
||||||
if (isActive !== undefined) updateData.isActive = isActive;
|
|
||||||
|
|
||||||
const user = await prisma.user.update({
|
|
||||||
where: { id },
|
|
||||||
data: updateData,
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
email: true,
|
|
||||||
name: true,
|
|
||||||
phone: true,
|
|
||||||
gender: true,
|
|
||||||
role: true,
|
|
||||||
isActive: true,
|
|
||||||
updatedAt: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json(user);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error updating user:', error);
|
|
||||||
return NextResponse.json({ error: '사용자 정보 수정 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE - 사용자 삭제
|
|
||||||
export async function DELETE(request: NextRequest) {
|
|
||||||
try {
|
|
||||||
const { searchParams } = new URL(request.url);
|
|
||||||
const id = searchParams.get('id');
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
return NextResponse.json({ error: '사용자 ID는 필수입니다.' }, { status: 400 });
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.user.delete({
|
|
||||||
where: { id },
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json({ message: '사용자가 삭제되었습니다.' });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error deleting user:', error);
|
|
||||||
return NextResponse.json({ error: '사용자 삭제 중 오류가 발생했습니다.' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { PrismaClient } from './generated/prisma';
|
|
||||||
|
|
||||||
const globalForPrisma = globalThis as unknown as {
|
|
||||||
prisma: PrismaClient | undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const prisma =
|
|
||||||
globalForPrisma.prisma ??
|
|
||||||
new PrismaClient({
|
|
||||||
log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
|
|
||||||
|
|
||||||
35
package-lock.json
generated
35
package-lock.json
generated
@@ -15,7 +15,6 @@
|
|||||||
"better-sqlite3": "^12.4.1",
|
"better-sqlite3": "^12.4.1",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"next": "16.0.1",
|
"next": "16.0.1",
|
||||||
"prisma": "^6.19.0",
|
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
"react-dom": "19.2.0"
|
"react-dom": "19.2.0"
|
||||||
},
|
},
|
||||||
@@ -26,6 +25,7 @@
|
|||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"eslint": "^9",
|
"eslint": "^9",
|
||||||
"eslint-config-next": "16.0.1",
|
"eslint-config-next": "16.0.1",
|
||||||
|
"prisma": "^6.19.0",
|
||||||
"tailwindcss": "^4",
|
"tailwindcss": "^4",
|
||||||
"typescript": "5.9.3"
|
"typescript": "5.9.3"
|
||||||
}
|
}
|
||||||
@@ -1221,6 +1221,7 @@
|
|||||||
"version": "6.19.0",
|
"version": "6.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.19.0.tgz",
|
||||||
"integrity": "sha512-zwCayme+NzI/WfrvFEtkFhhOaZb/hI+X8TTjzjJ252VbPxAl2hWHK5NMczmnG9sXck2lsXrxIZuK524E25UNmg==",
|
"integrity": "sha512-zwCayme+NzI/WfrvFEtkFhhOaZb/hI+X8TTjzjJ252VbPxAl2hWHK5NMczmnG9sXck2lsXrxIZuK524E25UNmg==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"c12": "3.1.0",
|
"c12": "3.1.0",
|
||||||
@@ -1233,12 +1234,14 @@
|
|||||||
"version": "6.19.0",
|
"version": "6.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.19.0.tgz",
|
||||||
"integrity": "sha512-8hAdGG7JmxrzFcTzXZajlQCidX0XNkMJkpqtfbLV54wC6LSSX6Vni25W/G+nAANwLnZ2TmwkfIuWetA7jJxJFA==",
|
"integrity": "sha512-8hAdGG7JmxrzFcTzXZajlQCidX0XNkMJkpqtfbLV54wC6LSSX6Vni25W/G+nAANwLnZ2TmwkfIuWetA7jJxJFA==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/engines": {
|
"node_modules/@prisma/engines": {
|
||||||
"version": "6.19.0",
|
"version": "6.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.19.0.tgz",
|
||||||
"integrity": "sha512-pMRJ+1S6NVdXoB8QJAPIGpKZevFjxhKt0paCkRDTZiczKb7F4yTgRP8M4JdVkpQwmaD4EoJf6qA+p61godDokw==",
|
"integrity": "sha512-pMRJ+1S6NVdXoB8QJAPIGpKZevFjxhKt0paCkRDTZiczKb7F4yTgRP8M4JdVkpQwmaD4EoJf6qA+p61godDokw==",
|
||||||
|
"devOptional": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1252,12 +1255,14 @@
|
|||||||
"version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773",
|
"version": "6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.19.0-26.2ba551f319ab1df4bc874a89965d8b3641056773.tgz",
|
||||||
"integrity": "sha512-gV7uOBQfAFlWDvPJdQxMT1aSRur3a0EkU/6cfbAC5isV67tKDWUrPauyaHNpB+wN1ebM4A9jn/f4gH+3iHSYSQ==",
|
"integrity": "sha512-gV7uOBQfAFlWDvPJdQxMT1aSRur3a0EkU/6cfbAC5isV67tKDWUrPauyaHNpB+wN1ebM4A9jn/f4gH+3iHSYSQ==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/@prisma/fetch-engine": {
|
"node_modules/@prisma/fetch-engine": {
|
||||||
"version": "6.19.0",
|
"version": "6.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.19.0.tgz",
|
||||||
"integrity": "sha512-OOx2Lda0DGrZ1rodADT06ZGqHzr7HY7LNMaFE2Vp8dp146uJld58sRuasdX0OiwpHgl8SqDTUKHNUyzEq7pDdQ==",
|
"integrity": "sha512-OOx2Lda0DGrZ1rodADT06ZGqHzr7HY7LNMaFE2Vp8dp146uJld58sRuasdX0OiwpHgl8SqDTUKHNUyzEq7pDdQ==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/debug": "6.19.0",
|
"@prisma/debug": "6.19.0",
|
||||||
@@ -1269,6 +1274,7 @@
|
|||||||
"version": "6.19.0",
|
"version": "6.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.19.0.tgz",
|
||||||
"integrity": "sha512-ym85WDO2yDhC3fIXHWYpG3kVMBA49cL1XD2GCsCF8xbwoy2OkDQY44gEbAt2X46IQ4Apq9H6g0Ex1iFfPqEkHA==",
|
"integrity": "sha512-ym85WDO2yDhC3fIXHWYpG3kVMBA49cL1XD2GCsCF8xbwoy2OkDQY44gEbAt2X46IQ4Apq9H6g0Ex1iFfPqEkHA==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/debug": "6.19.0"
|
"@prisma/debug": "6.19.0"
|
||||||
@@ -1285,6 +1291,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
|
||||||
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
|
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@swc/helpers": {
|
"node_modules/@swc/helpers": {
|
||||||
@@ -2665,6 +2672,7 @@
|
|||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/c12/-/c12-3.1.0.tgz",
|
||||||
"integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==",
|
"integrity": "sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": "^4.0.3",
|
"chokidar": "^4.0.3",
|
||||||
@@ -2693,6 +2701,7 @@
|
|||||||
"version": "16.6.1",
|
"version": "16.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
|
||||||
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
|
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
@@ -2802,6 +2811,7 @@
|
|||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"readdirp": "^4.0.1"
|
"readdirp": "^4.0.1"
|
||||||
@@ -2823,6 +2833,7 @@
|
|||||||
"version": "0.1.6",
|
"version": "0.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz",
|
||||||
"integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==",
|
"integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"consola": "^3.2.3"
|
"consola": "^3.2.3"
|
||||||
@@ -2865,12 +2876,14 @@
|
|||||||
"version": "0.2.2",
|
"version": "0.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz",
|
||||||
"integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==",
|
"integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/consola": {
|
"node_modules/consola": {
|
||||||
"version": "3.4.2",
|
"version": "3.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz",
|
||||||
"integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==",
|
"integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^14.18.0 || >=16.10.0"
|
"node": "^14.18.0 || >=16.10.0"
|
||||||
@@ -3019,6 +3032,7 @@
|
|||||||
"version": "7.1.5",
|
"version": "7.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz",
|
||||||
"integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==",
|
"integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.0.0"
|
"node": ">=16.0.0"
|
||||||
@@ -3064,12 +3078,14 @@
|
|||||||
"version": "6.1.4",
|
"version": "6.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
|
||||||
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
|
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/destr": {
|
"node_modules/destr": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz",
|
||||||
"integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==",
|
"integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/detect-libc": {
|
"node_modules/detect-libc": {
|
||||||
@@ -3125,6 +3141,7 @@
|
|||||||
"version": "3.18.4",
|
"version": "3.18.4",
|
||||||
"resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz",
|
"resolved": "https://registry.npmjs.org/effect/-/effect-3.18.4.tgz",
|
||||||
"integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==",
|
"integrity": "sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@standard-schema/spec": "^1.0.0",
|
"@standard-schema/spec": "^1.0.0",
|
||||||
@@ -3149,6 +3166,7 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz",
|
||||||
"integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==",
|
"integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14"
|
"node": ">=14"
|
||||||
@@ -3814,12 +3832,14 @@
|
|||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz",
|
||||||
"integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==",
|
"integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fast-check": {
|
"node_modules/fast-check": {
|
||||||
"version": "3.23.2",
|
"version": "3.23.2",
|
||||||
"resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz",
|
"resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz",
|
||||||
"integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==",
|
"integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==",
|
||||||
|
"devOptional": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "individual",
|
"type": "individual",
|
||||||
@@ -4126,6 +4146,7 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz",
|
||||||
"integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==",
|
"integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"citty": "^0.1.6",
|
"citty": "^0.1.6",
|
||||||
@@ -4861,6 +4882,7 @@
|
|||||||
"version": "2.6.1",
|
"version": "2.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
|
||||||
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
|
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"jiti": "lib/jiti-cli.mjs"
|
"jiti": "lib/jiti-cli.mjs"
|
||||||
@@ -5546,6 +5568,7 @@
|
|||||||
"version": "1.6.7",
|
"version": "1.6.7",
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz",
|
"resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz",
|
||||||
"integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==",
|
"integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
@@ -5559,6 +5582,7 @@
|
|||||||
"version": "0.6.2",
|
"version": "0.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz",
|
||||||
"integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==",
|
"integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"citty": "^0.1.6",
|
"citty": "^0.1.6",
|
||||||
@@ -5701,6 +5725,7 @@
|
|||||||
"version": "2.0.11",
|
"version": "2.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz",
|
||||||
"integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
|
"integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/once": {
|
"node_modules/once": {
|
||||||
@@ -5824,12 +5849,14 @@
|
|||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
|
||||||
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
|
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/perfect-debounce": {
|
"node_modules/perfect-debounce": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
|
||||||
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
|
"integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
@@ -5855,6 +5882,7 @@
|
|||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz",
|
||||||
"integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==",
|
"integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"confbox": "^0.2.2",
|
"confbox": "^0.2.2",
|
||||||
@@ -5941,6 +5969,7 @@
|
|||||||
"version": "6.19.0",
|
"version": "6.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/prisma/-/prisma-6.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/prisma/-/prisma-6.19.0.tgz",
|
||||||
"integrity": "sha512-F3eX7K+tWpkbhl3l4+VkFtrwJlLXbAM+f9jolgoUZbFcm1DgHZ4cq9AgVEgUym2au5Ad/TDLN8lg83D+M10ycw==",
|
"integrity": "sha512-F3eX7K+tWpkbhl3l4+VkFtrwJlLXbAM+f9jolgoUZbFcm1DgHZ4cq9AgVEgUym2au5Ad/TDLN8lg83D+M10ycw==",
|
||||||
|
"devOptional": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -5998,6 +6027,7 @@
|
|||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
|
||||||
"integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
|
"integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
|
||||||
|
"devOptional": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "individual",
|
"type": "individual",
|
||||||
@@ -6059,6 +6089,7 @@
|
|||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz",
|
||||||
"integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==",
|
"integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"defu": "^6.1.4",
|
"defu": "^6.1.4",
|
||||||
@@ -6111,6 +6142,7 @@
|
|||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||||
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
|
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14.18.0"
|
"node": ">= 14.18.0"
|
||||||
@@ -6857,6 +6889,7 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz",
|
||||||
"integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==",
|
"integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==",
|
||||||
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
|
|||||||
@@ -10,7 +10,11 @@
|
|||||||
"db:generate": "prisma generate",
|
"db:generate": "prisma generate",
|
||||||
"db:push": "prisma db push",
|
"db:push": "prisma db push",
|
||||||
"db:migrate": "prisma migrate dev",
|
"db:migrate": "prisma migrate dev",
|
||||||
"db:studio": "prisma studio"
|
"db:studio": "prisma studio",
|
||||||
|
"db:seed": "tsx prisma/seed.ts"
|
||||||
|
},
|
||||||
|
"prisma": {
|
||||||
|
"seed": "tsx prisma/seed.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@prisma/client": "^6.19.0",
|
"@prisma/client": "^6.19.0",
|
||||||
@@ -20,7 +24,6 @@
|
|||||||
"better-sqlite3": "^12.4.1",
|
"better-sqlite3": "^12.4.1",
|
||||||
"dotenv": "^17.2.3",
|
"dotenv": "^17.2.3",
|
||||||
"next": "16.0.1",
|
"next": "16.0.1",
|
||||||
"prisma": "^6.19.0",
|
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
"react-dom": "19.2.0"
|
"react-dom": "19.2.0"
|
||||||
},
|
},
|
||||||
@@ -31,7 +34,9 @@
|
|||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"eslint": "^9",
|
"eslint": "^9",
|
||||||
"eslint-config-next": "16.0.1",
|
"eslint-config-next": "16.0.1",
|
||||||
|
"prisma": "^6.19.0",
|
||||||
"tailwindcss": "^4",
|
"tailwindcss": "^4",
|
||||||
|
"tsx": "^4.19.2",
|
||||||
"typescript": "5.9.3"
|
"typescript": "5.9.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,4 @@
|
|||||||
import { config } from "dotenv";
|
import { defineConfig, env } from "prisma/config";
|
||||||
import { defineConfig } from "prisma/config";
|
|
||||||
import { resolve } from "path";
|
|
||||||
import { existsSync } from "fs";
|
|
||||||
|
|
||||||
// .env 파일을 명시적으로 로드
|
|
||||||
const envPath = resolve(process.cwd(), ".env");
|
|
||||||
if (existsSync(envPath)) {
|
|
||||||
config({ path: envPath });
|
|
||||||
}
|
|
||||||
|
|
||||||
// .env 파일에서 DATABASE_URL을 읽어옵니다 (기본값: file:./dev.db)
|
|
||||||
const databaseUrl = process.env.DATABASE_URL || "file:./dev.db";
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
schema: "prisma/schema.prisma",
|
schema: "prisma/schema.prisma",
|
||||||
@@ -19,6 +7,6 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
engine: "classic",
|
engine: "classic",
|
||||||
datasource: {
|
datasource: {
|
||||||
url: databaseUrl,
|
url: env("DATABASE_URL"),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
BIN
prisma/dev.db
BIN
prisma/dev.db
Binary file not shown.
@@ -1,6 +1,9 @@
|
|||||||
// This is your Prisma schema file,
|
// This is your Prisma schema file,
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||||
|
|
||||||
|
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
||||||
|
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
||||||
|
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client"
|
provider = "prisma-client"
|
||||||
output = "../lib/generated/prisma"
|
output = "../lib/generated/prisma"
|
||||||
@@ -11,81 +14,9 @@ datasource db {
|
|||||||
url = env("DATABASE_URL")
|
url = env("DATABASE_URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 사용자 권한 Enum
|
model Test {
|
||||||
enum UserRole {
|
id String @id @default(uuid())
|
||||||
STUDENT // 학습자
|
name String
|
||||||
INSTRUCTOR // 강사
|
|
||||||
ADMIN // 관리자
|
|
||||||
}
|
|
||||||
|
|
||||||
// User 모델
|
|
||||||
model User {
|
|
||||||
id String @id @default(cuid())
|
|
||||||
email String @unique
|
|
||||||
name String?
|
|
||||||
password String
|
|
||||||
phone String?
|
|
||||||
gender String?
|
|
||||||
birthYear Int?
|
|
||||||
birthMonth Int?
|
|
||||||
birthDay Int?
|
|
||||||
role UserRole @default(STUDENT) // 권한 (기본값: 학습자)
|
|
||||||
isActive Boolean @default(true) // 계정 활성화 여부 (true: 활성화, false: 비활성화)
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
registeredLectures Lecture[] @relation("Registrant") // 등록한 강좌 목록
|
|
||||||
enrolledLectures UserLecture[] // 수강 중인 강좌 목록
|
|
||||||
|
|
||||||
@@map("users")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 교육 과정 관리
|
|
||||||
model Curriculum {
|
|
||||||
id String @id @default(cuid())
|
|
||||||
title String // 과정 제목
|
|
||||||
instructorId String // 강사 ID (User와의 관계)
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
lectures Lecture[] // 강좌 목록 (1:N 관계)
|
|
||||||
|
|
||||||
@@map("curriculums")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 강좌 관리
|
|
||||||
model Lecture {
|
|
||||||
id String @id @default(cuid())
|
|
||||||
title String // 강좌명
|
|
||||||
attachmentFile String? // 첨부 파일 경로
|
|
||||||
evaluationQuestionCount Int @default(0) // 학습 평가 문제 수
|
|
||||||
curriculumId String // 교육 과정 ID (Curriculum과의 관계)
|
|
||||||
registrantId String // 등록자 ID (User와의 관계)
|
|
||||||
registeredAt DateTime @default(now()) // 등록일
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
|
|
||||||
curriculum Curriculum @relation(fields: [curriculumId], references: [id], onDelete: Cascade)
|
|
||||||
registrant User @relation("Registrant", fields: [registrantId], references: [id])
|
|
||||||
enrolledUsers UserLecture[] // 수강 중인 사용자 목록
|
|
||||||
|
|
||||||
@@map("lectures")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 사용자-강좌 수강 관계 (다대다 관계)
|
|
||||||
model UserLecture {
|
|
||||||
id String @id @default(cuid())
|
|
||||||
userId String // 사용자 ID
|
|
||||||
lectureId String // 강좌 ID
|
|
||||||
enrolledAt DateTime @default(now()) // 수강 시작일
|
|
||||||
completedAt DateTime? // 수강 완료일
|
|
||||||
isCompleted Boolean @default(false) // 수강 완료 여부
|
|
||||||
progress Int @default(0) // 수강 진행률 (0-100)
|
|
||||||
score Int? // 평가 점수
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
|
|
||||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
||||||
lecture Lecture @relation(fields: [lectureId], references: [id], onDelete: Cascade)
|
|
||||||
|
|
||||||
@@unique([userId, lectureId]) // 한 사용자는 같은 강좌를 중복 수강할 수 없음
|
|
||||||
@@map("user_lectures")
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user