diff --git a/package-lock.json b/package-lock.json index f358d76..3c68aa2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,9 @@ "name": "trading_bot_v3", "version": "0.1.0", "dependencies": { - "next": "15.3.5" + "@prisma/client": "^6.11.1", + "next": "15.3.5", + "prisma": "^6.11.1" }, "devDependencies": { "@eslint/eslintrc": "^3", @@ -892,6 +894,75 @@ "node": ">=12.4.0" } }, + "node_modules/@prisma/client": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.11.1.tgz", + "integrity": "sha512-5CLFh8QP6KxRm83pJ84jaVCeSVPQr8k0L2SEtOJHwdkS57/VQDcI/wQpGmdyOZi+D9gdNabdo8tj1Uk+w+upsQ==", + "hasInstallScript": true, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "prisma": "*", + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@prisma/config": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.11.1.tgz", + "integrity": "sha512-z6rCTQN741wxDq82cpdzx2uVykpnQIXalLhrWQSR0jlBVOxCIkz3HZnd8ern3uYTcWKfB3IpVAF7K2FU8t/8AQ==", + "dependencies": { + "jiti": "2.4.2" + } + }, + "node_modules/@prisma/debug": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.11.1.tgz", + "integrity": "sha512-lWRb/YSWu8l4Yum1UXfGLtqFzZkVS2ygkWYpgkbgMHn9XJlMITIgeMvJyX5GepChzhmxuSuiq/MY/kGFweOpGw==" + }, + "node_modules/@prisma/engines": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.11.1.tgz", + "integrity": "sha512-6eKEcV6V8W2eZAUwX2xTktxqPM4vnx3sxz3SDtpZwjHKpC6lhOtc4vtAtFUuf5+eEqBk+dbJ9Dcaj6uQU+FNNg==", + "hasInstallScript": true, + "dependencies": { + "@prisma/debug": "6.11.1", + "@prisma/engines-version": "6.11.1-1.f40f79ec31188888a2e33acda0ecc8fd10a853a9", + "@prisma/fetch-engine": "6.11.1", + "@prisma/get-platform": "6.11.1" + } + }, + "node_modules/@prisma/engines-version": { + "version": "6.11.1-1.f40f79ec31188888a2e33acda0ecc8fd10a853a9", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.11.1-1.f40f79ec31188888a2e33acda0ecc8fd10a853a9.tgz", + "integrity": "sha512-swFJTOOg4tHyOM1zB/pHb3MeH0i6t7jFKn5l+ZsB23d9AQACuIRo9MouvuKGvnDogzkcjbWnXi/NvOZ0+n5Jfw==" + }, + "node_modules/@prisma/fetch-engine": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.11.1.tgz", + "integrity": "sha512-NBYzmkXTkj9+LxNPRSndaAeALOL1Gr3tjvgRYNqruIPlZ6/ixLeuE/5boYOewant58tnaYFZ5Ne0jFBPfGXHpQ==", + "dependencies": { + "@prisma/debug": "6.11.1", + "@prisma/engines-version": "6.11.1-1.f40f79ec31188888a2e33acda0ecc8fd10a853a9", + "@prisma/get-platform": "6.11.1" + } + }, + "node_modules/@prisma/get-platform": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.11.1.tgz", + "integrity": "sha512-b2Z8oV2gwvdCkFemBTFd0x4lsL4O2jLSx8lB7D+XqoFALOQZPa7eAPE1NU0Mj1V8gPHRxIsHnyUNtw2i92psUw==", + "dependencies": { + "@prisma/debug": "6.11.1" + } + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -3823,7 +3894,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", - "dev": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -4691,6 +4761,30 @@ "node": ">= 0.8.0" } }, + "node_modules/prisma": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.11.1.tgz", + "integrity": "sha512-VzJToRlV0s9Vu2bfqHiRJw73hZNCG/AyJeX+kopbu4GATTjTUdEWUteO3p4BLYoHpMS4o8pD3v6tF44BHNZI1w==", + "hasInstallScript": true, + "dependencies": { + "@prisma/config": "6.11.1", + "@prisma/engines": "6.11.1" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=18.18" + }, + "peerDependencies": { + "typescript": ">=5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -5544,7 +5638,7 @@ "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, + "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 3cec49c..22f9b09 100644 --- a/package.json +++ b/package.json @@ -8,16 +8,18 @@ "start": "next start" }, "dependencies": { - "next": "15.3.5" + "@prisma/client": "^6.11.1", + "next": "15.3.5", + "prisma": "^6.11.1" }, "devDependencies": { - "typescript": "^5", + "@eslint/eslintrc": "^3", + "@tailwindcss/postcss": "^4", "@types/node": "^20", "@types/react": "^19", - "@tailwindcss/postcss": "^4", - "tailwindcss": "^4", "eslint": "^9", "eslint-config-next": "15.3.5", - "@eslint/eslintrc": "^3" + "tailwindcss": "^4", + "typescript": "^5" } } diff --git a/prisma/dev.db b/prisma/dev.db new file mode 100644 index 0000000..11b64a9 Binary files /dev/null and b/prisma/dev.db differ diff --git a/prisma/migrations/20250709083040_init/migration.sql b/prisma/migrations/20250709083040_init/migration.sql new file mode 100644 index 0000000..21de1ca --- /dev/null +++ b/prisma/migrations/20250709083040_init/migration.sql @@ -0,0 +1,102 @@ +-- CreateTable +CREATE TABLE "users" ( + "id" TEXT NOT NULL PRIMARY KEY, + "email" TEXT NOT NULL, + "name" TEXT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL +); + +-- CreateTable +CREATE TABLE "api_keys" ( + "id" TEXT NOT NULL PRIMARY KEY, + "userId" TEXT NOT NULL, + "provider" TEXT NOT NULL, + "keyName" TEXT NOT NULL, + "encryptedKey" TEXT NOT NULL, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + CONSTRAINT "api_keys_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "user_settings" ( + "id" TEXT NOT NULL PRIMARY KEY, + "userId" TEXT NOT NULL, + "autoTrading" BOOLEAN NOT NULL DEFAULT false, + "tradingAmount" REAL NOT NULL DEFAULT 100, + "riskPercentage" REAL NOT NULL DEFAULT 2, + "maxDailyTrades" INTEGER NOT NULL DEFAULT 5, + "enableNotifications" BOOLEAN NOT NULL DEFAULT true, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + CONSTRAINT "user_settings_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "trades" ( + "id" TEXT NOT NULL PRIMARY KEY, + "userId" TEXT NOT NULL, + "symbol" TEXT NOT NULL, + "side" TEXT NOT NULL, + "amount" REAL NOT NULL, + "price" REAL NOT NULL, + "status" TEXT NOT NULL DEFAULT 'PENDING', + "driftTxId" TEXT, + "profit" REAL, + "fees" REAL, + "screenshotUrl" TEXT, + "aiAnalysis" TEXT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + "executedAt" DATETIME, + "closedAt" DATETIME, + CONSTRAINT "trades_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "trading_journals" ( + "id" TEXT NOT NULL PRIMARY KEY, + "userId" TEXT NOT NULL, + "date" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "screenshotUrl" TEXT NOT NULL, + "aiAnalysis" TEXT NOT NULL, + "marketSentiment" TEXT, + "keyLevels" JSONB, + "recommendation" TEXT NOT NULL, + "confidence" REAL NOT NULL, + "notes" TEXT, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" DATETIME NOT NULL, + CONSTRAINT "trading_journals_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +-- CreateTable +CREATE TABLE "screenshots" ( + "id" TEXT NOT NULL PRIMARY KEY, + "url" TEXT NOT NULL, + "filename" TEXT NOT NULL, + "fileSize" INTEGER NOT NULL, + "mimeType" TEXT NOT NULL, + "metadata" JSONB, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +-- CreateTable +CREATE TABLE "system_logs" ( + "id" TEXT NOT NULL PRIMARY KEY, + "level" TEXT NOT NULL, + "message" TEXT NOT NULL, + "metadata" JSONB, + "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +-- CreateIndex +CREATE UNIQUE INDEX "users_email_key" ON "users"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "api_keys_userId_provider_keyName_key" ON "api_keys"("userId", "provider", "keyName"); + +-- CreateIndex +CREATE UNIQUE INDEX "user_settings_userId_key" ON "user_settings"("userId"); diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..2a5a444 --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (e.g., Git) +provider = "sqlite" diff --git a/prisma/schema.prisma b/prisma/schema.prisma new file mode 100644 index 0000000..dcb3bed --- /dev/null +++ b/prisma/schema.prisma @@ -0,0 +1,114 @@ +generator client { + provider = "prisma-client-js" +} + +datasource db { + provider = "sqlite" + url = env("DATABASE_URL") +} + +model User { + id String @id @default(cuid()) + email String @unique + name String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + apiKeys ApiKey[] + trades Trade[] + journals TradingJournal[] + settings UserSettings? + + @@map("users") +} + +model ApiKey { + id String @id @default(cuid()) + userId String + provider String + keyName String + encryptedKey String + isActive Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([userId, provider, keyName]) + @@map("api_keys") +} + +model UserSettings { + id String @id @default(cuid()) + userId String @unique + autoTrading Boolean @default(false) + tradingAmount Float @default(100) + riskPercentage Float @default(2) + maxDailyTrades Int @default(5) + enableNotifications Boolean @default(true) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@map("user_settings") +} + +model Trade { + id String @id @default(cuid()) + userId String + symbol String + side String + amount Float + price Float + status String @default("PENDING") + driftTxId String? + profit Float? + fees Float? + screenshotUrl String? + aiAnalysis String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + executedAt DateTime? + closedAt DateTime? + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@map("trades") +} + +model TradingJournal { + id String @id @default(cuid()) + userId String + date DateTime @default(now()) + screenshotUrl String + aiAnalysis String + marketSentiment String? + keyLevels Json? + recommendation String + confidence Float + notes String? + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@map("trading_journals") +} + +model Screenshot { + id String @id @default(cuid()) + url String + filename String + fileSize Int + mimeType String + metadata Json? + createdAt DateTime @default(now()) + + @@map("screenshots") +} + +model SystemLog { + id String @id @default(cuid()) + level String + message String + metadata Json? + createdAt DateTime @default(now()) + + @@map("system_logs") +}