Initial commit

This commit is contained in:
2026-03-27 19:35:14 +01:00
commit 38581b88a4
68 changed files with 12137 additions and 0 deletions

View File

@@ -0,0 +1,166 @@
-- CreateEnum
CREATE TYPE "PaymentMethodType" AS ENUM (
'PAYPAL',
'BITCOIN',
'ETHEREUM',
'MONERO',
'LITECOIN',
'SOLANA',
'USDT',
'REVOLUT',
'BANK_TRANSFER',
'CUSTOM'
);
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL,
"email" TEXT NOT NULL,
"hashedPassword" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Profile" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"username" TEXT NOT NULL,
"displayName" TEXT NOT NULL,
"bio" TEXT,
"avatarUrl" TEXT,
"themeId" TEXT NOT NULL,
"isPublic" BOOLEAN NOT NULL DEFAULT true,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Profile_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Theme" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"description" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Theme_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "PaymentMethod" (
"id" TEXT NOT NULL,
"profileId" TEXT NOT NULL,
"type" "PaymentMethodType" NOT NULL,
"label" TEXT NOT NULL,
"value" TEXT NOT NULL,
"network" TEXT,
"description" TEXT,
"sortOrder" INTEGER NOT NULL DEFAULT 0,
"isVisible" BOOLEAN NOT NULL DEFAULT true,
"metadata" JSONB,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "PaymentMethod_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "SocialLink" (
"id" TEXT NOT NULL,
"profileId" TEXT NOT NULL,
"label" TEXT NOT NULL,
"url" TEXT NOT NULL,
"sortOrder" INTEGER NOT NULL DEFAULT 0,
"isVisible" BOOLEAN NOT NULL DEFAULT true,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "SocialLink_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Account" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"type" TEXT NOT NULL,
"provider" TEXT NOT NULL,
"providerAccountId" TEXT NOT NULL,
"refresh_token" TEXT,
"access_token" TEXT,
"expires_at" INTEGER,
"token_type" TEXT,
"scope" TEXT,
"id_token" TEXT,
"session_state" TEXT,
CONSTRAINT "Account_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Session" (
"id" TEXT NOT NULL,
"sessionToken" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"expires" TIMESTAMP(3) NOT NULL,
CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "VerificationToken" (
"identifier" TEXT NOT NULL,
"token" TEXT NOT NULL,
"expires" TIMESTAMP(3) NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
-- CreateIndex
CREATE UNIQUE INDEX "Profile_userId_key" ON "Profile"("userId");
-- CreateIndex
CREATE UNIQUE INDEX "Profile_username_key" ON "Profile"("username");
-- CreateIndex
CREATE INDEX "Profile_username_idx" ON "Profile"("username");
-- CreateIndex
CREATE INDEX "PaymentMethod_profileId_sortOrder_idx" ON "PaymentMethod"("profileId", "sortOrder");
-- CreateIndex
CREATE INDEX "SocialLink_profileId_sortOrder_idx" ON "SocialLink"("profileId", "sortOrder");
-- CreateIndex
CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId");
-- CreateIndex
CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");
-- CreateIndex
CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token");
-- CreateIndex
CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token");
-- AddForeignKey
ALTER TABLE "Profile" ADD CONSTRAINT "Profile_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Profile" ADD CONSTRAINT "Profile_themeId_fkey" FOREIGN KEY ("themeId") REFERENCES "Theme"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "PaymentMethod" ADD CONSTRAINT "PaymentMethod_profileId_fkey" FOREIGN KEY ("profileId") REFERENCES "Profile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "SocialLink" ADD CONSTRAINT "SocialLink_profileId_fkey" FOREIGN KEY ("profileId") REFERENCES "Profile"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Account" ADD CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1 @@
provider = "postgresql"

128
prisma/schema.prisma Normal file
View File

@@ -0,0 +1,128 @@
generator client {
provider = "prisma-client-js"
binaryTargets = ["native", "linux-musl-openssl-3.0.x"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum PaymentMethodType {
PAYPAL
BITCOIN
ETHEREUM
MONERO
LITECOIN
SOLANA
USDT
REVOLUT
BANK_TRANSFER
CUSTOM
}
model User {
id String @id @default(cuid())
email String @unique
hashedPassword String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
profile Profile?
accounts Account[]
sessions Session[]
}
model Profile {
id String @id @default(cuid())
userId String @unique
username String @unique
displayName String
bio String?
avatarUrl String?
themeId String
isPublic Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
theme Theme @relation(fields: [themeId], references: [id])
paymentMethods PaymentMethod[]
socialLinks SocialLink[]
@@index([username])
}
model Theme {
id String @id
name String
description String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
profiles Profile[]
}
model PaymentMethod {
id String @id @default(cuid())
profileId String
type PaymentMethodType
label String
value String
network String?
description String?
sortOrder Int @default(0)
isVisible Boolean @default(true)
metadata Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
profile Profile @relation(fields: [profileId], references: [id], onDelete: Cascade)
@@index([profileId, sortOrder])
}
model SocialLink {
id String @id @default(cuid())
profileId String
label String
url String
sortOrder Int @default(0)
isVisible Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
profile Profile @relation(fields: [profileId], references: [id], onDelete: Cascade)
@@index([profileId, sortOrder])
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String?
access_token String?
expires_at Int?
token_type String?
scope String?
id_token String?
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}

40
prisma/seed.ts Normal file
View File

@@ -0,0 +1,40 @@
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
await prisma.theme.upsert({
where: { id: "terminal-dark" },
update: {
name: "Terminal Dark",
description: "Near-black background, warm text, and muted green accent"
},
create: {
id: "terminal-dark",
name: "Terminal Dark",
description: "Near-black background, warm text, and muted green accent"
}
});
await prisma.theme.upsert({
where: { id: "amber-paper" },
update: {
name: "Amber Paper",
description: "Soft dark slate with amber accent and warm mono feel"
},
create: {
id: "amber-paper",
name: "Amber Paper",
description: "Soft dark slate with amber accent and warm mono feel"
}
});
}
main()
.catch((error) => {
console.error(error);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});