diff --git a/app/api/my_contents/route.ts b/app/api/my_contents/route.ts deleted file mode 100644 index 387f3ee..0000000 --- a/app/api/my_contents/route.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { NextResponse } from 'next/server'; -import { auth } from '@/auth'; -import { PrismaClient } from '@/app/generated/prisma'; - -const prisma = new PrismaClient(); - -function parseDateOr(value: string | null, fallback: Date): Date { - if (!value) return fallback; - const d = new Date(value); - return isNaN(d.getTime()) ? fallback : d; -} - -export async function GET(request: Request) { - try { - const session = await auth(); - if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - const email = session.user?.email as string | undefined; - if (!email) return NextResponse.json({ error: '세션 이메일을 찾을 수 없습니다' }, { status: 400 }); - - const { searchParams } = new URL(request.url); - const endDefault = new Date(); - const startDefault = new Date(endDefault.getTime() - 30 * 24 * 60 * 60 * 1000); - const startParam = searchParams.get('start'); - const endParam = searchParams.get('end'); - const startDate = startParam ? new Date(startParam) : startDefault; - const endDate = endParam ? new Date(endParam) : endDefault; - // 날짜 경계 보정: 하루 전체 포함 (UTC 기준) - const startInclusive = new Date(startDate); - startInclusive.setUTCHours(0, 0, 0, 0); - const endInclusive = new Date(endDate); - endInclusive.setUTCHours(23, 59, 59, 999); - - // 안전가드 - if (endInclusive < startInclusive) endInclusive.setTime(startInclusive.getTime()); - console.log('startDate', startDate.toISOString()); - console.log('endDate', endDate.toISOString()); - - // 1) 내 핸들 - const handles = await prisma.userHandle.findMany({ - where: { email }, - select: { id: true, handle: true, icon: true } - }); - if (handles.length === 0) return NextResponse.json({ items: [] }); - const handleStrs = handles.map(h => h.handle); - const handleByStr = new Map(handles.map(h => [h.handle, h] as const)); - - // 2) 매핑된 콘텐츠 - const links = await prisma.contentHandle.findMany({ - where: { handle: { in: handleStrs } }, - select: { contentId: true, handle: true } - }); - if (links.length === 0) return NextResponse.json({ items: [] }); - const contentIds = links.map(l => l.contentId); - const normalizeId = (s: string) => (s ?? '').trim(); - const contentIdsNormalized = Array.from(new Set(contentIds.map(normalizeId))); - const idsForQuery = Array.from(new Set([...contentIds, ...contentIdsNormalized])); - const handleByContentId = new Map(links.map(l => [l.contentId, l.handle] as const)); - - // 3) 콘텐츠 본문 - const contents = await prisma.content.findMany({ - where: { id: { in: contentIds } }, - select: { - id: true, subject: true, pubDate: true, - views: true, premiumViews: true, watchTime: true - } - }); - - // 4) 기간 합계 유효조회수 (findMany로 가져와 JS에서 합산 - groupBy 일부 환경 이슈 회피) - const viewRows = await prisma.viewPerDay.findMany({ - where: { - contented: { in: idsForQuery }, - date: { gte: startInclusive, lte: endInclusive } - }, - select: { contented: true, validViewDay: true } - }); - const validSumById = new Map(); - for (const r of viewRows) { - const key = normalizeId(r.contented); - validSumById.set(key, (validSumById.get(key) ?? 0) + (r.validViewDay ?? 0)); - } - - // 5) 비용 단가 - const cpvRow = await prisma.costPerView.findUnique({ where: { id: 1 } }); - const cpv = cpvRow?.costPerView ?? 0; - - const items = contents.map(c => { - const handle = handleByContentId.get(c.id) ?? ''; - const handleObj = handleByStr.get(handle); - const validViews = validSumById.get(normalizeId(c.id)) ?? 0; - const expectedRevenue = validViews * cpv; - return { - id: c.id, - subject: c.subject, - pubDate: c.pubDate, - views: c.views, - premiumViews: c.premiumViews, - watchTime: c.watchTime, - handle, - handleId: handleObj?.id ?? null, - icon: handleObj?.icon ?? '', - validViews, - expectedRevenue, - }; - }); - - return NextResponse.json({ items, cpv, start: startInclusive.toISOString(), end: endInclusive.toISOString() }); - } catch (e) { - console.error('my_contents 오류:', e); - return NextResponse.json({ error: '조회 실패' }, { status: 500 }); - } finally { - await prisma.$disconnect(); - } -} - - diff --git a/app/components/NavBar.tsx b/app/components/NavBar.tsx index 93eec94..5b05451 100644 --- a/app/components/NavBar.tsx +++ b/app/components/NavBar.tsx @@ -37,9 +37,10 @@ const NavBar: React.FC = ({ isOpen, setIsOpen, user }) => {
- + + {/* - + */} EVERFACTORY
diff --git a/app/components/SignInClient.tsx b/app/components/SignInClient.tsx index 49faa85..564148e 100644 --- a/app/components/SignInClient.tsx +++ b/app/components/SignInClient.tsx @@ -3,6 +3,7 @@ import { signIn } from "next-auth/react" export default function SignIn() { - return } \ No newline at end of file diff --git a/app/favicon.ico b/app/favicon.ico index 3aa5252..81ffa5b 100644 Binary files a/app/favicon.ico and b/app/favicon.ico differ diff --git a/app/login/page.tsx b/app/login/page.tsx deleted file mode 100644 index bf85a20..0000000 --- a/app/login/page.tsx +++ /dev/null @@ -1,13 +0,0 @@ -"use client"; - -import SignIn from "@/app/components/SignInClient"; - -export default function Test() { - - - return ( -
- -
- ); -} \ No newline at end of file diff --git a/app/page.tsx b/app/page.tsx index c8711e1..6a80070 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -44,7 +44,7 @@ export default function Home() { logo
콘텐츠 음원 수익
에버팩토리에서 편리하게
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi lobortis maximus
+ {/*
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi lobortis maximus
*/}
Ready to travel with us?
Enter your email to create or restart your membership.
diff --git a/app/usr/1_dashboard/page.tsx b/app/usr/1_dashboard/page.tsx index 5c24a33..da7fcef 100644 --- a/app/usr/1_dashboard/page.tsx +++ b/app/usr/1_dashboard/page.tsx @@ -5,7 +5,8 @@ import DashboardClient from "@/app/components/Dashboard"; // 기존 코드 대 export default async function Page() { const session = await auth(); - if (!session) redirect("/login"); + if (!session) redirect("/"); + // 초기 데이터 서버에서 미리 가져오면 더 빠르고 안전 (예시) // const [channels, contents] = await Promise.all([ diff --git a/auth.ts b/auth.ts index 882282b..b0d951a 100644 --- a/auth.ts +++ b/auth.ts @@ -11,5 +11,15 @@ export const { handlers, auth, signIn, signOut } = NextAuth({ ], - // ...callbacks 등등 + events: { + async signIn({ user, account, profile }) { + console.log("[NextAuth] signIn user:", { + id: (user as any)?.id, + name: user?.name, + email: user?.email, + image: (user as any)?.image, + provider: account?.provider, + }); + }, + }, }); \ No newline at end of file diff --git a/middleware.ts b/middleware.ts index f9736af..abe7327 100644 --- a/middleware.ts +++ b/middleware.ts @@ -26,7 +26,6 @@ export default auth(async (req) => { } } - // 이미 로그인된 경우 루트 경로로 접근 시 대시보드로 리다이렉트 if (session) { if (pathname === "/") { diff --git a/prisma/migrations/20250908172816_0908new/migration.sql b/prisma/migrations/20250908172816_0908new/migration.sql new file mode 100644 index 0000000..d5760c7 --- /dev/null +++ b/prisma/migrations/20250908172816_0908new/migration.sql @@ -0,0 +1,18 @@ +/* + Warnings: + + - You are about to drop the column `premiumViews` on the `content` table. All the data in the column will be lost. + - You are about to drop the column `validViews` on the `content` table. All the data in the column will be lost. + - You are about to drop the column `views` on the `content` table. All the data in the column will be lost. + - You are about to drop the column `watchTime` on the `content` table. All the data in the column will be lost. + - You are about to drop the `costPerView` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- AlterTable +ALTER TABLE `content` DROP COLUMN `premiumViews`, + DROP COLUMN `validViews`, + DROP COLUMN `views`, + DROP COLUMN `watchTime`; + +-- DropTable +DROP TABLE `costPerView`; diff --git a/prisma/migrations/20250908173757_0908new02/migration.sql b/prisma/migrations/20250908173757_0908new02/migration.sql new file mode 100644 index 0000000..d74588e --- /dev/null +++ b/prisma/migrations/20250908173757_0908new02/migration.sql @@ -0,0 +1,49 @@ +/* + Warnings: + + - You are about to drop the `ContentHandle` table. If the table is not empty, all the data it contains will be lost. + - You are about to drop the `userHandle` table. If the table is not empty, all the data it contains will be lost. + - Added the required column `handleId` to the `content` table without a default value. This is not possible if the table is not empty. + +*/ +-- DropForeignKey +ALTER TABLE `ContentHandle` DROP FOREIGN KEY `ContentHandle_contentId_fkey`; + +-- DropForeignKey +ALTER TABLE `ContentHandle` DROP FOREIGN KEY `ContentHandle_handle_fkey`; + +-- AlterTable +ALTER TABLE `content` ADD COLUMN `handleId` VARCHAR(191) NOT NULL; + +-- DropTable +DROP TABLE `ContentHandle`; + +-- DropTable +DROP TABLE `userHandle`; + +-- CreateTable +CREATE TABLE `user` ( + `id` VARCHAR(191) NOT NULL, + `email` VARCHAR(191) NOT NULL, + `icon` VARCHAR(191) NOT NULL DEFAULT '', + `isApproved` BOOLEAN NOT NULL DEFAULT false, + `createtime` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- CreateTable +CREATE TABLE `handle` ( + `id` VARCHAR(191) NOT NULL, + `handle` VARCHAR(191) NOT NULL, + `userId` VARCHAR(191) NOT NULL, + + UNIQUE INDEX `handle_handle_key`(`handle`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +-- AddForeignKey +ALTER TABLE `content` ADD CONSTRAINT `content_handleId_fkey` FOREIGN KEY (`handleId`) REFERENCES `handle`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE `handle` ADD CONSTRAINT `handle_userId_fkey` FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 3c3d70b..3e20d6b 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -14,16 +14,54 @@ datasource db { url = env("DATABASE_URL") } -model content{ +// user +model User { + id String @id @default(uuid()) + email String + icon String @default("") + isApproved Boolean @default(false) + createtime DateTime @default(now()) + RegisgerCode String @default("") + + // Many-to-many: a user can have many handles + handles Handle[] + // One-to-many: a user can have many register channels + registerChannels RegisterChannel[] +} + +model RegisterChannel { + id String @id @default(uuid()) + handle String + // Relation: many register channels belong to one user + userId String + user User @relation(fields: [userId], references: [id]) +} + +// handle +model Handle { + id String @id @default(uuid()) + handle String @unique + constPerView Float @default(1) + // Relations + contents Content[] + // Many-to-many: a handle can belong to many users + users User[] +} + +// content +model Content{ id String @id @default(uuid()) subject String pubDate DateTime - views Int - validViews Int - premiumViews Int - watchTime Int - // Back relation: a content may link to at most one handle - contentHandle ContentHandle? + // views Int + // validViews Int + // premiumViews Int + // watchTime Int + // Relation: many contents belong to one handle + handleId String + handle Handle @relation(fields: [handleId], references: [id]) + // Back relation: one content has many day views + dayViews contentDayView[] } model contentDayView{ @@ -34,21 +72,13 @@ model contentDayView{ validViews Int premiumViews Int watchTime Int + // Relation: many day views belong to one content + content Content @relation(fields: [contentId], references: [id]) @@unique([contentId, date]) } -model userHandle { - id String @id @default(uuid()) - email String - handle String @unique - icon String @default("") - isApproved Boolean @default(false) - createtime DateTime @default(now()) - // Relation: a handle can be linked to many contents - contentLinks ContentHandle[] -} - +// notice model noticeBoard{ id String @id @default(uuid()) title String @@ -59,35 +89,6 @@ model noticeBoard{ } -model registerChannel { - id String @id @default(uuid()) - email String - handle String - randomcode String - createtime DateTime @default(now()) -} - -model costPerView{ - id Int @id @default(1) - costPerView Float -} - - -// Mapping table: Each content can be linked to at most one handle (unique contentId) -// A handle can have many contents -model ContentHandle { - id String @id @default(uuid()) - contentId String @unique - handle String - - // Relations - content content @relation(fields: [contentId], references: [id]) - user userHandle @relation(fields: [handle], references: [handle]) - - @@index([handle]) -} - - /* npx prisma migrate dev --name diff --git a/public/falogo1.png b/public/falogo1.png new file mode 100644 index 0000000..d61174e Binary files /dev/null and b/public/falogo1.png differ diff --git a/public/falogo2.png b/public/falogo2.png new file mode 100644 index 0000000..d7ab43a Binary files /dev/null and b/public/falogo2.png differ diff --git a/public/falogo3.png b/public/falogo3.png new file mode 100644 index 0000000..05ba595 Binary files /dev/null and b/public/falogo3.png differ