This commit is contained in:
49
prisma/migrations/20260102073121_init/migration.sql
Normal file
49
prisma/migrations/20260102073121_init/migration.sql
Normal file
@@ -0,0 +1,49 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Project" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"niche" TEXT NOT NULL,
|
||||
"productType" TEXT NOT NULL,
|
||||
"creativity" TEXT NOT NULL,
|
||||
"status" TEXT NOT NULL DEFAULT 'draft',
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Asset" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"projectId" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"path" TEXT NOT NULL,
|
||||
"prompt" TEXT,
|
||||
"meta" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "Asset_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SeoData" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"projectId" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"keywords" TEXT NOT NULL,
|
||||
"printingGuide" TEXT NOT NULL,
|
||||
"suggestedPrice" TEXT NOT NULL,
|
||||
CONSTRAINT "SeoData_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "BrandDna" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"referenceIds" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "SeoData_projectId_key" ON "SeoData"("projectId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "BrandDna_name_key" ON "BrandDna"("name");
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the `BrandDna` table. If the table is not empty, all the data it contains will be lost.
|
||||
|
||||
*/
|
||||
-- DropTable
|
||||
PRAGMA foreign_keys=off;
|
||||
DROP TABLE "BrandDna";
|
||||
PRAGMA foreign_keys=on;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "BrandProfile" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"referencePaths" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "BrandProfile_name_key" ON "BrandProfile"("name");
|
||||
@@ -0,0 +1,42 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"email" TEXT NOT NULL,
|
||||
"passwordHash" TEXT NOT NULL,
|
||||
"role" TEXT NOT NULL DEFAULT 'USER',
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- RedefineTables
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_BrandProfile" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"referencePaths" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"userId" TEXT,
|
||||
CONSTRAINT "BrandProfile_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_BrandProfile" ("createdAt", "id", "name", "referencePaths") SELECT "createdAt", "id", "name", "referencePaths" FROM "BrandProfile";
|
||||
DROP TABLE "BrandProfile";
|
||||
ALTER TABLE "new_BrandProfile" RENAME TO "BrandProfile";
|
||||
CREATE UNIQUE INDEX "BrandProfile_name_key" ON "BrandProfile"("name");
|
||||
CREATE TABLE "new_Project" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"niche" TEXT NOT NULL,
|
||||
"productType" TEXT NOT NULL,
|
||||
"creativity" TEXT NOT NULL,
|
||||
"status" TEXT NOT NULL DEFAULT 'draft',
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
"userId" TEXT,
|
||||
CONSTRAINT "Project_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_Project" ("createdAt", "creativity", "id", "niche", "productType", "status", "updatedAt") SELECT "createdAt", "creativity", "id", "niche", "productType", "status", "updatedAt" FROM "Project";
|
||||
DROP TABLE "Project";
|
||||
ALTER TABLE "new_Project" RENAME TO "Project";
|
||||
PRAGMA foreign_key_check;
|
||||
PRAGMA foreign_keys=ON;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
114
prisma/migrations/20260107221253_add_json_ld/migration.sql
Normal file
114
prisma/migrations/20260107221253_add_json_ld/migration.sql
Normal file
@@ -0,0 +1,114 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "SeoData" ADD COLUMN "jsonLd" TEXT;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "EtsyShop" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"shopId" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"shopName" TEXT NOT NULL,
|
||||
"accessToken" TEXT NOT NULL,
|
||||
"refreshToken" TEXT NOT NULL,
|
||||
"expiresAt" BIGINT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "EtsyShop_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "UsageLog" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"userId" TEXT NOT NULL,
|
||||
"action" TEXT NOT NULL,
|
||||
"cost" REAL NOT NULL,
|
||||
"credits" INTEGER NOT NULL,
|
||||
"timestamp" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "UsageLog_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Transaction" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"userId" TEXT NOT NULL,
|
||||
"amount" REAL NOT NULL,
|
||||
"credits" INTEGER NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "Transaction_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SystemConfig" (
|
||||
"key" TEXT NOT NULL PRIMARY KEY,
|
||||
"value" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"updatedAt" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- RedefineTables
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Project" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"niche" TEXT NOT NULL,
|
||||
"productType" TEXT NOT NULL,
|
||||
"creativity" TEXT NOT NULL,
|
||||
"aspectRatio" TEXT NOT NULL DEFAULT '3:4',
|
||||
"useExactReference" BOOLEAN NOT NULL DEFAULT false,
|
||||
"status" TEXT NOT NULL DEFAULT 'draft',
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
"userId" TEXT,
|
||||
CONSTRAINT "Project_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_Project" ("createdAt", "creativity", "id", "niche", "productType", "status", "updatedAt", "userId") SELECT "createdAt", "creativity", "id", "niche", "productType", "status", "updatedAt", "userId" FROM "Project";
|
||||
DROP TABLE "Project";
|
||||
ALTER TABLE "new_Project" RENAME TO "Project";
|
||||
CREATE TABLE "new_Asset" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"projectId" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"path" TEXT NOT NULL,
|
||||
"prompt" TEXT,
|
||||
"meta" TEXT,
|
||||
"quality" TEXT NOT NULL DEFAULT 'DRAFT',
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "Asset_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
INSERT INTO "new_Asset" ("createdAt", "id", "meta", "path", "projectId", "prompt", "type") SELECT "createdAt", "id", "meta", "path", "projectId", "prompt", "type" FROM "Asset";
|
||||
DROP TABLE "Asset";
|
||||
ALTER TABLE "new_Asset" RENAME TO "Asset";
|
||||
CREATE TABLE "new_User" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"email" TEXT NOT NULL,
|
||||
"passwordHash" TEXT,
|
||||
"googleId" TEXT,
|
||||
"avatar" TEXT,
|
||||
"role" TEXT NOT NULL DEFAULT 'USER',
|
||||
"credits" INTEGER NOT NULL DEFAULT 300,
|
||||
"plan" TEXT NOT NULL DEFAULT 'FREE',
|
||||
"betaAccess" BOOLEAN NOT NULL DEFAULT true,
|
||||
"apiKey" TEXT,
|
||||
"etsyShopName" TEXT,
|
||||
"etsyShopLink" TEXT,
|
||||
"etsyShopLogo" TEXT,
|
||||
"paymentMethod" TEXT,
|
||||
"subscriptionId" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"termsAcceptedAt" DATETIME,
|
||||
"kvkkAcceptedAt" DATETIME,
|
||||
"totalRevenue" REAL NOT NULL DEFAULT 0.0,
|
||||
"totalCost" REAL NOT NULL DEFAULT 0.0
|
||||
);
|
||||
INSERT INTO "new_User" ("createdAt", "email", "id", "passwordHash", "role") SELECT "createdAt", "email", "id", "passwordHash", "role" FROM "User";
|
||||
DROP TABLE "User";
|
||||
ALTER TABLE "new_User" RENAME TO "User";
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
CREATE UNIQUE INDEX "User_googleId_key" ON "User"("googleId");
|
||||
PRAGMA foreign_key_check;
|
||||
PRAGMA foreign_keys=ON;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "EtsyShop_shopId_key" ON "EtsyShop"("shopId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "SystemConfig_key_key" ON "SystemConfig"("key");
|
||||
3
prisma/migrations/migration_lock.toml
Normal file
3
prisma/migrations/migration_lock.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (i.e. Git)
|
||||
provider = "sqlite"
|
||||
154
prisma/schema.prisma
Normal file
154
prisma/schema.prisma
Normal file
@@ -0,0 +1,154 @@
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "sqlite"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model Project {
|
||||
id String @id @default(uuid())
|
||||
niche String
|
||||
productType String
|
||||
creativity String
|
||||
aspectRatio String @default("3:4") // 1:1, 3:4, 4:5, 16:9, 9:16, etc.
|
||||
useExactReference Boolean @default(false) // Strict Composition Mode
|
||||
status String @default("draft") // draft, generated, finalized
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
sku String? // e.g. "WLR005"
|
||||
config String? // JSON: { isStickerSet, setSize, basePrompt, characterCore }
|
||||
|
||||
assets Asset[]
|
||||
seoData SeoData?
|
||||
|
||||
userId String?
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
}
|
||||
|
||||
model Asset {
|
||||
id String @id @default(uuid())
|
||||
projectId String
|
||||
type String // master, mockup, reference, revision
|
||||
path String // Local file path relative to /storage
|
||||
prompt String? // The prompt that generated this asset
|
||||
meta String? // JSON string for extra metadata (scenario name, etc.)
|
||||
quality String @default("DRAFT") // DRAFT, MASTER, UPSCALED
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model SeoData {
|
||||
id String @id @default(uuid())
|
||||
projectId String @unique
|
||||
title String
|
||||
description String
|
||||
keywords String // Stored as comma separated string or JSON
|
||||
printingGuide String
|
||||
suggestedPrice String
|
||||
jsonLd String? // Structured Data (Schema.org)
|
||||
attributes String? // JSON String: { primaryColor, occasion, etc. }
|
||||
categoryPath String? // Suggested Category Path
|
||||
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model EtsyShop {
|
||||
id String @id @default(uuid())
|
||||
shopId String @unique
|
||||
userId String
|
||||
shopName String
|
||||
accessToken String
|
||||
refreshToken String
|
||||
expiresAt BigInt
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model BrandProfile {
|
||||
id String @id @default(uuid())
|
||||
name String @unique
|
||||
referencePaths String // JSON array of file paths relative to /storage
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
// Relations
|
||||
userId String?
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
email String @unique
|
||||
passwordHash String? // Optional for Google Users
|
||||
|
||||
// OAuth Fields
|
||||
googleId String? @unique
|
||||
avatar String?
|
||||
|
||||
role String @default("USER") // USER, ADMIN
|
||||
|
||||
// SaaS / Beta Fields
|
||||
credits Int @default(300) // Free credits (Generous tier)
|
||||
plan String @default("FREE") // FREE, PRO
|
||||
betaAccess Boolean @default(true) // Gated access
|
||||
|
||||
// New SaaS Fields (Phase 1)
|
||||
apiKey String? // User's Personal Gemini API Key (Encrypted/Plain per policy)
|
||||
etsyShopName String? // Manual Etsy Shop Name fallback
|
||||
etsyShopLink String? // Manual Etsy Shop Link fallback
|
||||
etsyShopLogo String? // Path to logo file
|
||||
paymentMethod String? // Stripe Payment Method ID (Future)
|
||||
subscriptionId String? // Stripe Subscription ID (Future)
|
||||
|
||||
skuSettings String? // JSON: { "Wall Art": {prefix: "WLR", next: 1} }
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
// Legal Compliance (Phase 6)
|
||||
termsAcceptedAt DateTime? // User Agreement & IP Rights
|
||||
kvkkAcceptedAt DateTime? // KVKK & Data Privacy
|
||||
|
||||
// Profit Analytics (Phase 7)
|
||||
totalRevenue Float @default(0.0) // Total money paid by user (USD)
|
||||
totalCost Float @default(0.0) // Total API cost incurred by user (USD, estimated)
|
||||
|
||||
projects Project[]
|
||||
brandProfiles BrandProfile[]
|
||||
etsyShops EtsyShop[]
|
||||
usageLogs UsageLog[]
|
||||
transactions Transaction[]
|
||||
}
|
||||
|
||||
model UsageLog {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
action String // GENERATE_MASTER, GENERATE_VARIANT, MOCKUP, PROMPT
|
||||
cost Float // Estimated API cost in USD for this action
|
||||
credits Int // Credits deducted
|
||||
timestamp DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model Transaction {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
amount Float // USD Amount paid
|
||||
credits Int // Credits added
|
||||
type String // PURCHASE, ADMIN_GRANT, BONUS
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model SystemConfig {
|
||||
key String @id @unique
|
||||
value String
|
||||
description String?
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
Reference in New Issue
Block a user