diff --git a/.env b/.env index 8a76c09..f0bd3a9 100644 --- a/.env +++ b/.env @@ -10,6 +10,7 @@ SHARE_CODE_IV=9f1d67b8a3c4d261fa2b7c44a1d4f9c8 STEAM_API_KEY=0B3B2BF79ECD1E9262BB118A7FEF1973 NEXTAUTH_SECRET=ironieopen NEXTAUTH_URL=https://new.ironieopen.de +NEXT_PUBLIC_APP_URL=https://new.ironieopen.de AUTH_SECRET="57AUHXa+UmFrlnIEKxtrk8fLo+aZMtsa/oV6fklXkcE=" # Added by `npx auth`. Read more: https://cli.authjs.dev ALLSTAR_TOKEN=ed033ac0-5df7-482e-a322-e2b4601955d3 PTERODACTYL_APP_API=ptla_O6Je82OvlCBFITDRgB1ZJ95AIyUSXYnVGgwRF6pO6d9 diff --git a/next.config.ts b/next.config.ts index 21a6a2e..0d0ed6d 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,8 +1,10 @@ +// next.config.ts + import type { NextConfig } from 'next' import createNextIntlPlugin from 'next-intl/plugin'; const nextConfig: NextConfig = { - allowedDevOrigins: ['ironieopen.local', '*.ironieopen.local'], + output: 'standalone', images: { remotePatterns: [ { diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 7f172df..e22057a 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,7 +1,7 @@ generator client { provider = "prisma-client-js" output = "../src/generated/prisma" - binaryTargets = ["debian-openssl-3.0.x"] + binaryTargets = ["native", "debian-openssl-3.0.x"] } diff --git a/src/generated/prisma/edge.js b/src/generated/prisma/edge.js index 8f1b750..1a99b57 100644 --- a/src/generated/prisma/edge.js +++ b/src/generated/prisma/edge.js @@ -417,7 +417,7 @@ const config = { "value": "prisma-client-js" }, "output": { - "value": "C:\\Users\\Rother\\fork\\ironie-nextjs\\src\\generated\\prisma", + "value": "C:\\Users\\Chris\\fork\\ironie-nextjs\\src\\generated\\prisma", "fromEnvVar": null }, "config": { @@ -428,15 +428,18 @@ const config = { "fromEnvVar": null, "value": "windows", "native": true + }, + { + "fromEnvVar": null, + "value": "debian-openssl-3.0.x" } ], "previewFeatures": [], - "sourceFilePath": "C:\\Users\\Rother\\fork\\ironie-nextjs\\prisma\\schema.prisma", + "sourceFilePath": "C:\\Users\\Chris\\fork\\ironie-nextjs\\prisma\\schema.prisma", "isCustomOutput": true }, "relativeEnvPaths": { - "rootEnvPath": null, - "schemaEnvPath": "../../../.env" + "rootEnvPath": null }, "relativePath": "../../../prisma", "clientVersion": "6.17.1", @@ -454,8 +457,8 @@ const config = { } } }, - "inlineSchema": "generator client {\n provider = \"prisma-client-js\"\n output = \"../src/generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\n//\n// ──────────────────────────────────────────────\n// 🧑 Benutzer, Teams & Verwaltung\n// ──────────────────────────────────────────────\n//\n\nmodel User {\n steamId String @id\n name String?\n avatar String?\n location String?\n isAdmin Boolean @default(false)\n\n teamId String?\n team Team? @relation(\"UserTeam\", fields: [teamId], references: [id])\n ledTeam Team? @relation(\"TeamLeader\")\n\n matchesAsTeamA Match[] @relation(\"TeamAPlayers\")\n matchesAsTeamB Match[] @relation(\"TeamBPlayers\")\n\n premierRank Int?\n authCode String?\n lastKnownShareCode String?\n lastKnownShareCodeDate DateTime?\n createdAt DateTime @default(now())\n\n invites TeamInvite[] @relation(\"UserInvitations\")\n notifications Notification[]\n matchPlayers MatchPlayer[]\n serverRequests ServerRequest[] @relation(\"MatchRequests\")\n rankHistory RankHistory[] @relation(\"UserRankHistory\")\n demoFiles DemoFile[]\n\n createdSchedules Schedule[] @relation(\"CreatedSchedules\")\n confirmedSchedules Schedule[] @relation(\"ConfirmedSchedules\")\n\n mapVoteChoices MapVoteStep[] @relation(\"VoteStepChooser\")\n\n status UserStatus @default(offline) // 👈 neu\n lastActiveAt DateTime? // optional: wann zuletzt aktiv\n\n readyAcceptances MatchReady[] @relation(\"MatchReadyUser\")\n\n pterodactylClientApiKey String?\n\n timeZone String? // IANA-TZ, z.B. \"Europe/Berlin\"\n\n // ✅ Datenschutz: darf eingeladen werden?\n canBeInvited Boolean @default(true)\n\n // ⬇️ Dauerhafter Ban-Status (zuletzt bekannter Stand)\n vacBanned Boolean? @default(false)\n numberOfVACBans Int? @default(0)\n numberOfGameBans Int? @default(0)\n daysSinceLastBan Int? @default(0)\n communityBanned Boolean? @default(false)\n economyBan String?\n lastBanCheck DateTime?\n\n // FaceIt Account\n faceitId String? @unique\n faceitNickname String?\n faceitAvatar String?\n faceitCountry String?\n faceitUrl String?\n faceitVerified Boolean? @default(false)\n\n faceitSteamId64 String?\n faceitGames FaceitGameStat[]\n\n @@index([vacBanned])\n @@index([numberOfVACBans])\n @@index([numberOfGameBans])\n}\n\nenum UserStatus {\n online\n away\n offline\n}\n\nenum FaceitGameId {\n csgo\n cs2\n}\n\nmodel FaceitGameStat {\n id String @id @default(cuid())\n user User @relation(fields: [userSteamId], references: [steamId], onDelete: Cascade)\n userSteamId String\n game FaceitGameId\n region String? // \"EU\"\n gamePlayerId String? // \"76561198000414190\"\n gamePlayerName String? // \"Army\"\n skillLevel Int? // 4\n elo Int? // 1045\n skillLabel String?\n gameProfileId String?\n updatedAt DateTime @updatedAt\n\n @@unique([userSteamId, game])\n @@index([game, elo])\n}\n\nenum TeamJoinPolicy {\n REQUEST\n INVITE_ONLY\n}\n\nmodel Team {\n id String @id @default(uuid())\n name String @unique\n logo String?\n logoUpdatedAt DateTime? @default(now())\n\n leaderId String? @unique\n createdAt DateTime @default(now())\n\n activePlayers String[]\n inactivePlayers String[]\n\n leader User? @relation(\"TeamLeader\", fields: [leaderId], references: [steamId])\n members User[] @relation(\"UserTeam\")\n invites TeamInvite[]\n matchPlayers MatchPlayer[]\n\n matchesAsTeamA Match[] @relation(\"MatchTeamA\")\n matchesAsTeamB Match[] @relation(\"MatchTeamB\")\n\n schedulesAsTeamA Schedule[] @relation(\"ScheduleTeamA\")\n schedulesAsTeamB Schedule[] @relation(\"ScheduleTeamB\")\n\n mapVoteSteps MapVoteStep[] @relation(\"VoteStepTeam\")\n\n // Default bleibt REQUEST\n joinPolicy TeamJoinPolicy @default(REQUEST)\n}\n\nmodel TeamInvite {\n id String @id @default(uuid())\n steamId String\n teamId String\n type String\n createdAt DateTime @default(now())\n\n user User @relation(\"UserInvitations\", fields: [steamId], references: [steamId])\n team Team @relation(fields: [teamId], references: [id])\n}\n\nmodel Notification {\n id String @id @default(uuid())\n steamId String\n title String?\n message String\n read Boolean @default(false)\n persistent Boolean @default(false)\n actionType String?\n actionData String?\n createdAt DateTime @default(now())\n\n user User @relation(fields: [steamId], references: [steamId])\n}\n\n//\n// ──────────────────────────────────────────────\n// 🎮 Matches & Spieler\n// ──────────────────────────────────────────────\n//\n\n// ──────────────────────────────────────────────\n// 🎮 Matches\n// ──────────────────────────────────────────────\n\nmodel Match {\n id String @id @default(uuid())\n title String\n matchType String @default(\"community\")\n map String?\n description String?\n scoreA Int?\n scoreB Int?\n\n teamAId String?\n teamA Team? @relation(\"MatchTeamA\", fields: [teamAId], references: [id])\n\n teamBId String?\n teamB Team? @relation(\"MatchTeamB\", fields: [teamBId], references: [id])\n\n teamAUsers User[] @relation(\"TeamAPlayers\")\n teamBUsers User[] @relation(\"TeamBPlayers\")\n\n filePath String?\n demoFile DemoFile?\n demoDate DateTime?\n demoData Json?\n\n players MatchPlayer[]\n rankUpdates RankHistory[] @relation(\"MatchRankHistory\")\n\n roundCount Int?\n roundHistory Json?\n winnerTeam String?\n\n matchDate DateTime? // geplante Startzeit (separat von demoDate)\n mapVote MapVote?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n schedule Schedule?\n\n readyAcceptances MatchReady[] @relation(\"MatchReadyMatch\")\n\n cs2MatchId BigInt? @unique // <— wichtig (Postgres lässt mehrere NULLs zu)\n exportedAt DateTime? // wann die JSON exportiert wurde\n}\n\nmodel MatchPlayer {\n id String @id @default(uuid())\n steamId String\n matchId String\n teamId String?\n team Team? @relation(fields: [teamId], references: [id])\n\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(fields: [steamId], references: [steamId])\n\n stats PlayerStats?\n\n createdAt DateTime @default(now())\n\n @@unique([matchId, steamId])\n}\n\nmodel PlayerStats {\n id String @id @default(uuid())\n matchId String\n steamId String\n\n kills Int\n assists Int\n deaths Int\n headshotPct Float\n\n totalDamage Float @default(0)\n utilityDamage Int @default(0)\n flashAssists Int @default(0)\n mvps Int @default(0)\n mvpEliminations Int @default(0)\n mvpDefuse Int @default(0)\n mvpPlant Int @default(0)\n knifeKills Int @default(0)\n zeusKills Int @default(0)\n wallbangKills Int @default(0)\n smokeKills Int @default(0)\n headshots Int @default(0)\n noScopes Int @default(0)\n blindKills Int @default(0)\n\n aim Int @default(0)\n\n oneK Int @default(0)\n twoK Int @default(0)\n threeK Int @default(0)\n fourK Int @default(0)\n fiveK Int @default(0)\n\n rankOld Int?\n rankNew Int?\n rankChange Int?\n winCount Int?\n\n matchPlayer MatchPlayer @relation(fields: [matchId, steamId], references: [matchId, steamId])\n\n @@unique([matchId, steamId])\n}\n\nmodel RankHistory {\n id String @id @default(uuid())\n steamId String\n matchId String?\n\n rankOld Int\n rankNew Int\n delta Int\n winCount Int\n\n createdAt DateTime @default(now())\n\n user User @relation(\"UserRankHistory\", fields: [steamId], references: [steamId])\n match Match? @relation(\"MatchRankHistory\", fields: [matchId], references: [id], onDelete: Cascade)\n}\n\nmodel Schedule {\n id String @id @default(uuid())\n title String\n description String?\n map String?\n date DateTime\n status ScheduleStatus @default(PENDING)\n\n teamAId String?\n teamA Team? @relation(\"ScheduleTeamA\", fields: [teamAId], references: [id])\n\n teamBId String?\n teamB Team? @relation(\"ScheduleTeamB\", fields: [teamBId], references: [id])\n\n createdById String\n createdBy User @relation(\"CreatedSchedules\", fields: [createdById], references: [steamId])\n\n confirmedById String?\n confirmedBy User? @relation(\"ConfirmedSchedules\", fields: [confirmedById], references: [steamId])\n\n linkedMatchId String? @unique\n linkedMatch Match? @relation(fields: [linkedMatchId], references: [id], onDelete: Cascade)\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nenum ScheduleStatus {\n PENDING\n CONFIRMED\n DECLINED\n CANCELLED\n COMPLETED\n}\n\n//\n// ──────────────────────────────────────────────\n// 📦 Demo-Dateien & CS2 Requests\n// ──────────────────────────────────────────────\n//\n\nmodel DemoFile {\n id String @id @default(uuid())\n matchId String @unique\n steamId String\n fileName String @unique\n filePath String\n parsed Boolean @default(false)\n\n createdAt DateTime @default(now())\n\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(fields: [steamId], references: [steamId])\n}\n\nmodel ServerRequest {\n id String @id @default(uuid())\n steamId String\n matchId String\n reservationId BigInt\n tvPort BigInt\n processed Boolean @default(false)\n failed Boolean @default(false)\n\n createdAt DateTime @default(now())\n\n user User @relation(\"MatchRequests\", fields: [steamId], references: [steamId])\n\n @@unique([steamId, matchId])\n}\n\n// ──────────────────────────────────────────────\n// 🗺️ Map-Vote\n// ──────────────────────────────────────────────\n\nenum MapVoteAction {\n BAN\n PICK\n DECIDER\n}\n\nmodel MapVote {\n id String @id @default(uuid())\n matchId String @unique\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n\n bestOf Int @default(3)\n mapPool String[]\n currentIdx Int @default(0)\n locked Boolean @default(false)\n opensAt DateTime?\n\n leadMinutes Int @default(60)\n\n adminEditingBy String?\n adminEditingSince DateTime?\n\n steps MapVoteStep[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel MapVoteStep {\n id String @id @default(uuid())\n voteId String\n order Int\n action MapVoteAction\n\n teamId String?\n team Team? @relation(\"VoteStepTeam\", fields: [teamId], references: [id])\n\n map String?\n chosenAt DateTime?\n chosenBy String?\n chooser User? @relation(\"VoteStepChooser\", fields: [chosenBy], references: [steamId])\n\n vote MapVote @relation(fields: [voteId], references: [id], onDelete: Cascade)\n\n @@unique([voteId, order])\n @@index([teamId])\n @@index([chosenBy])\n}\n\nmodel MatchReady {\n matchId String\n steamId String\n acceptedAt DateTime @default(now())\n\n match Match @relation(\"MatchReadyMatch\", fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(\"MatchReadyUser\", fields: [steamId], references: [steamId])\n\n @@id([matchId, steamId])\n @@index([steamId])\n}\n\n// ──────────────────────────────────────────────\n// 🛠️ Server-Konfiguration & Pterodactyl\n// ──────────────────────────────────────────────\n\nmodel ServerConfig {\n id String @id\n serverIp String\n serverPassword String?\n pterodactylServerId String\n pterodactylServerApiKey String\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n // ───── Live / GameBanner ─────\n activeMatchId String?\n activeMapKey String?\n activeMapLabel String?\n activeMapBg String?\n activeParticipants String[] // steamIds\n activeSince DateTime?\n bannerExpiresAt DateTime?\n\n @@index([activeMatchId])\n}\n", - "inlineSchemaHash": "ae45c35aab6de6d8e0cd40561344ec0315364f4f39a0c0452b246c08cd7cbca5", + "inlineSchema": "generator client {\n provider = \"prisma-client-js\"\n output = \"../src/generated/prisma\"\n binaryTargets = [\"native\", \"debian-openssl-3.0.x\"]\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\n//\n// ──────────────────────────────────────────────\n// 🧑 Benutzer, Teams & Verwaltung\n// ──────────────────────────────────────────────\n//\n\nmodel User {\n steamId String @id\n name String?\n avatar String?\n location String?\n isAdmin Boolean @default(false)\n\n teamId String?\n team Team? @relation(\"UserTeam\", fields: [teamId], references: [id])\n ledTeam Team? @relation(\"TeamLeader\")\n\n matchesAsTeamA Match[] @relation(\"TeamAPlayers\")\n matchesAsTeamB Match[] @relation(\"TeamBPlayers\")\n\n premierRank Int?\n authCode String?\n lastKnownShareCode String?\n lastKnownShareCodeDate DateTime?\n createdAt DateTime @default(now())\n\n invites TeamInvite[] @relation(\"UserInvitations\")\n notifications Notification[]\n matchPlayers MatchPlayer[]\n serverRequests ServerRequest[] @relation(\"MatchRequests\")\n rankHistory RankHistory[] @relation(\"UserRankHistory\")\n demoFiles DemoFile[]\n\n createdSchedules Schedule[] @relation(\"CreatedSchedules\")\n confirmedSchedules Schedule[] @relation(\"ConfirmedSchedules\")\n\n mapVoteChoices MapVoteStep[] @relation(\"VoteStepChooser\")\n\n status UserStatus @default(offline) // 👈 neu\n lastActiveAt DateTime? // optional: wann zuletzt aktiv\n\n readyAcceptances MatchReady[] @relation(\"MatchReadyUser\")\n\n pterodactylClientApiKey String?\n\n timeZone String? // IANA-TZ, z.B. \"Europe/Berlin\"\n\n // ✅ Datenschutz: darf eingeladen werden?\n canBeInvited Boolean @default(true)\n\n // ⬇️ Dauerhafter Ban-Status (zuletzt bekannter Stand)\n vacBanned Boolean? @default(false)\n numberOfVACBans Int? @default(0)\n numberOfGameBans Int? @default(0)\n daysSinceLastBan Int? @default(0)\n communityBanned Boolean? @default(false)\n economyBan String?\n lastBanCheck DateTime?\n\n // FaceIt Account\n faceitId String? @unique\n faceitNickname String?\n faceitAvatar String?\n faceitCountry String?\n faceitUrl String?\n faceitVerified Boolean? @default(false)\n\n faceitSteamId64 String?\n faceitGames FaceitGameStat[]\n\n @@index([vacBanned])\n @@index([numberOfVACBans])\n @@index([numberOfGameBans])\n}\n\nenum UserStatus {\n online\n away\n offline\n}\n\nenum FaceitGameId {\n csgo\n cs2\n}\n\nmodel FaceitGameStat {\n id String @id @default(cuid())\n user User @relation(fields: [userSteamId], references: [steamId], onDelete: Cascade)\n userSteamId String\n game FaceitGameId\n region String? // \"EU\"\n gamePlayerId String? // \"76561198000414190\"\n gamePlayerName String? // \"Army\"\n skillLevel Int? // 4\n elo Int? // 1045\n skillLabel String?\n gameProfileId String?\n updatedAt DateTime @updatedAt\n\n @@unique([userSteamId, game])\n @@index([game, elo])\n}\n\nenum TeamJoinPolicy {\n REQUEST\n INVITE_ONLY\n}\n\nmodel Team {\n id String @id @default(uuid())\n name String @unique\n logo String?\n logoUpdatedAt DateTime? @default(now())\n\n leaderId String? @unique\n createdAt DateTime @default(now())\n\n activePlayers String[]\n inactivePlayers String[]\n\n leader User? @relation(\"TeamLeader\", fields: [leaderId], references: [steamId])\n members User[] @relation(\"UserTeam\")\n invites TeamInvite[]\n matchPlayers MatchPlayer[]\n\n matchesAsTeamA Match[] @relation(\"MatchTeamA\")\n matchesAsTeamB Match[] @relation(\"MatchTeamB\")\n\n schedulesAsTeamA Schedule[] @relation(\"ScheduleTeamA\")\n schedulesAsTeamB Schedule[] @relation(\"ScheduleTeamB\")\n\n mapVoteSteps MapVoteStep[] @relation(\"VoteStepTeam\")\n\n // Default bleibt REQUEST\n joinPolicy TeamJoinPolicy @default(REQUEST)\n}\n\nmodel TeamInvite {\n id String @id @default(uuid())\n steamId String\n teamId String\n type String\n createdAt DateTime @default(now())\n\n user User @relation(\"UserInvitations\", fields: [steamId], references: [steamId])\n team Team @relation(fields: [teamId], references: [id])\n}\n\nmodel Notification {\n id String @id @default(uuid())\n steamId String\n title String?\n message String\n read Boolean @default(false)\n persistent Boolean @default(false)\n actionType String?\n actionData String?\n createdAt DateTime @default(now())\n\n user User @relation(fields: [steamId], references: [steamId])\n}\n\n//\n// ──────────────────────────────────────────────\n// 🎮 Matches & Spieler\n// ──────────────────────────────────────────────\n//\n\n// ──────────────────────────────────────────────\n// 🎮 Matches\n// ──────────────────────────────────────────────\n\nmodel Match {\n id String @id @default(uuid())\n title String\n matchType String @default(\"community\")\n map String?\n description String?\n scoreA Int?\n scoreB Int?\n\n teamAId String?\n teamA Team? @relation(\"MatchTeamA\", fields: [teamAId], references: [id])\n\n teamBId String?\n teamB Team? @relation(\"MatchTeamB\", fields: [teamBId], references: [id])\n\n teamAUsers User[] @relation(\"TeamAPlayers\")\n teamBUsers User[] @relation(\"TeamBPlayers\")\n\n filePath String?\n demoFile DemoFile?\n demoDate DateTime?\n demoData Json?\n\n players MatchPlayer[]\n rankUpdates RankHistory[] @relation(\"MatchRankHistory\")\n\n roundCount Int?\n roundHistory Json?\n winnerTeam String?\n\n matchDate DateTime? // geplante Startzeit (separat von demoDate)\n mapVote MapVote?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n schedule Schedule?\n\n readyAcceptances MatchReady[] @relation(\"MatchReadyMatch\")\n\n cs2MatchId BigInt? @unique // <— wichtig (Postgres lässt mehrere NULLs zu)\n exportedAt DateTime? // wann die JSON exportiert wurde\n}\n\nmodel MatchPlayer {\n id String @id @default(uuid())\n steamId String\n matchId String\n teamId String?\n team Team? @relation(fields: [teamId], references: [id])\n\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(fields: [steamId], references: [steamId])\n\n stats PlayerStats?\n\n createdAt DateTime @default(now())\n\n @@unique([matchId, steamId])\n}\n\nmodel PlayerStats {\n id String @id @default(uuid())\n matchId String\n steamId String\n\n kills Int\n assists Int\n deaths Int\n headshotPct Float\n\n totalDamage Float @default(0)\n utilityDamage Int @default(0)\n flashAssists Int @default(0)\n mvps Int @default(0)\n mvpEliminations Int @default(0)\n mvpDefuse Int @default(0)\n mvpPlant Int @default(0)\n knifeKills Int @default(0)\n zeusKills Int @default(0)\n wallbangKills Int @default(0)\n smokeKills Int @default(0)\n headshots Int @default(0)\n noScopes Int @default(0)\n blindKills Int @default(0)\n\n aim Int @default(0)\n\n oneK Int @default(0)\n twoK Int @default(0)\n threeK Int @default(0)\n fourK Int @default(0)\n fiveK Int @default(0)\n\n rankOld Int?\n rankNew Int?\n rankChange Int?\n winCount Int?\n\n matchPlayer MatchPlayer @relation(fields: [matchId, steamId], references: [matchId, steamId])\n\n @@unique([matchId, steamId])\n}\n\nmodel RankHistory {\n id String @id @default(uuid())\n steamId String\n matchId String?\n\n rankOld Int\n rankNew Int\n delta Int\n winCount Int\n\n createdAt DateTime @default(now())\n\n user User @relation(\"UserRankHistory\", fields: [steamId], references: [steamId])\n match Match? @relation(\"MatchRankHistory\", fields: [matchId], references: [id], onDelete: Cascade)\n}\n\nmodel Schedule {\n id String @id @default(uuid())\n title String\n description String?\n map String?\n date DateTime\n status ScheduleStatus @default(PENDING)\n\n teamAId String?\n teamA Team? @relation(\"ScheduleTeamA\", fields: [teamAId], references: [id])\n\n teamBId String?\n teamB Team? @relation(\"ScheduleTeamB\", fields: [teamBId], references: [id])\n\n createdById String\n createdBy User @relation(\"CreatedSchedules\", fields: [createdById], references: [steamId])\n\n confirmedById String?\n confirmedBy User? @relation(\"ConfirmedSchedules\", fields: [confirmedById], references: [steamId])\n\n linkedMatchId String? @unique\n linkedMatch Match? @relation(fields: [linkedMatchId], references: [id], onDelete: Cascade)\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nenum ScheduleStatus {\n PENDING\n CONFIRMED\n DECLINED\n CANCELLED\n COMPLETED\n}\n\n//\n// ──────────────────────────────────────────────\n// 📦 Demo-Dateien & CS2 Requests\n// ──────────────────────────────────────────────\n//\n\nmodel DemoFile {\n id String @id @default(uuid())\n matchId String @unique\n steamId String\n fileName String @unique\n filePath String\n parsed Boolean @default(false)\n\n createdAt DateTime @default(now())\n\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(fields: [steamId], references: [steamId])\n}\n\nmodel ServerRequest {\n id String @id @default(uuid())\n steamId String\n matchId String\n reservationId BigInt\n tvPort BigInt\n processed Boolean @default(false)\n failed Boolean @default(false)\n\n createdAt DateTime @default(now())\n\n user User @relation(\"MatchRequests\", fields: [steamId], references: [steamId])\n\n @@unique([steamId, matchId])\n}\n\n// ──────────────────────────────────────────────\n// 🗺️ Map-Vote\n// ──────────────────────────────────────────────\n\nenum MapVoteAction {\n BAN\n PICK\n DECIDER\n}\n\nmodel MapVote {\n id String @id @default(uuid())\n matchId String @unique\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n\n bestOf Int @default(3)\n mapPool String[]\n currentIdx Int @default(0)\n locked Boolean @default(false)\n opensAt DateTime?\n\n leadMinutes Int @default(60)\n\n adminEditingBy String?\n adminEditingSince DateTime?\n\n steps MapVoteStep[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel MapVoteStep {\n id String @id @default(uuid())\n voteId String\n order Int\n action MapVoteAction\n\n teamId String?\n team Team? @relation(\"VoteStepTeam\", fields: [teamId], references: [id])\n\n map String?\n chosenAt DateTime?\n chosenBy String?\n chooser User? @relation(\"VoteStepChooser\", fields: [chosenBy], references: [steamId])\n\n vote MapVote @relation(fields: [voteId], references: [id], onDelete: Cascade)\n\n @@unique([voteId, order])\n @@index([teamId])\n @@index([chosenBy])\n}\n\nmodel MatchReady {\n matchId String\n steamId String\n acceptedAt DateTime @default(now())\n\n match Match @relation(\"MatchReadyMatch\", fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(\"MatchReadyUser\", fields: [steamId], references: [steamId])\n\n @@id([matchId, steamId])\n @@index([steamId])\n}\n\n// ──────────────────────────────────────────────\n// 🛠️ Server-Konfiguration & Pterodactyl\n// ──────────────────────────────────────────────\n\nmodel ServerConfig {\n id String @id\n serverIp String\n serverPassword String?\n pterodactylServerId String\n pterodactylServerApiKey String\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n // ───── Live / GameBanner ─────\n activeMatchId String?\n activeMapKey String?\n activeMapLabel String?\n activeMapBg String?\n activeParticipants String[] // steamIds\n activeSince DateTime?\n bannerExpiresAt DateTime?\n\n @@index([activeMatchId])\n}\n", + "inlineSchemaHash": "cfb52fd332462ae98f2ea1e237f84e3da920102b14ba8426145d801d41338756", "copyEngine": true } config.dirname = '/' diff --git a/src/generated/prisma/index.js b/src/generated/prisma/index.js index c34b6d7..8c20745 100644 --- a/src/generated/prisma/index.js +++ b/src/generated/prisma/index.js @@ -418,7 +418,7 @@ const config = { "value": "prisma-client-js" }, "output": { - "value": "C:\\Users\\Rother\\fork\\ironie-nextjs\\src\\generated\\prisma", + "value": "C:\\Users\\Chris\\fork\\ironie-nextjs\\src\\generated\\prisma", "fromEnvVar": null }, "config": { @@ -429,15 +429,18 @@ const config = { "fromEnvVar": null, "value": "windows", "native": true + }, + { + "fromEnvVar": null, + "value": "debian-openssl-3.0.x" } ], "previewFeatures": [], - "sourceFilePath": "C:\\Users\\Rother\\fork\\ironie-nextjs\\prisma\\schema.prisma", + "sourceFilePath": "C:\\Users\\Chris\\fork\\ironie-nextjs\\prisma\\schema.prisma", "isCustomOutput": true }, "relativeEnvPaths": { - "rootEnvPath": null, - "schemaEnvPath": "../../../.env" + "rootEnvPath": null }, "relativePath": "../../../prisma", "clientVersion": "6.17.1", @@ -455,8 +458,8 @@ const config = { } } }, - "inlineSchema": "generator client {\n provider = \"prisma-client-js\"\n output = \"../src/generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\n//\n// ──────────────────────────────────────────────\n// 🧑 Benutzer, Teams & Verwaltung\n// ──────────────────────────────────────────────\n//\n\nmodel User {\n steamId String @id\n name String?\n avatar String?\n location String?\n isAdmin Boolean @default(false)\n\n teamId String?\n team Team? @relation(\"UserTeam\", fields: [teamId], references: [id])\n ledTeam Team? @relation(\"TeamLeader\")\n\n matchesAsTeamA Match[] @relation(\"TeamAPlayers\")\n matchesAsTeamB Match[] @relation(\"TeamBPlayers\")\n\n premierRank Int?\n authCode String?\n lastKnownShareCode String?\n lastKnownShareCodeDate DateTime?\n createdAt DateTime @default(now())\n\n invites TeamInvite[] @relation(\"UserInvitations\")\n notifications Notification[]\n matchPlayers MatchPlayer[]\n serverRequests ServerRequest[] @relation(\"MatchRequests\")\n rankHistory RankHistory[] @relation(\"UserRankHistory\")\n demoFiles DemoFile[]\n\n createdSchedules Schedule[] @relation(\"CreatedSchedules\")\n confirmedSchedules Schedule[] @relation(\"ConfirmedSchedules\")\n\n mapVoteChoices MapVoteStep[] @relation(\"VoteStepChooser\")\n\n status UserStatus @default(offline) // 👈 neu\n lastActiveAt DateTime? // optional: wann zuletzt aktiv\n\n readyAcceptances MatchReady[] @relation(\"MatchReadyUser\")\n\n pterodactylClientApiKey String?\n\n timeZone String? // IANA-TZ, z.B. \"Europe/Berlin\"\n\n // ✅ Datenschutz: darf eingeladen werden?\n canBeInvited Boolean @default(true)\n\n // ⬇️ Dauerhafter Ban-Status (zuletzt bekannter Stand)\n vacBanned Boolean? @default(false)\n numberOfVACBans Int? @default(0)\n numberOfGameBans Int? @default(0)\n daysSinceLastBan Int? @default(0)\n communityBanned Boolean? @default(false)\n economyBan String?\n lastBanCheck DateTime?\n\n // FaceIt Account\n faceitId String? @unique\n faceitNickname String?\n faceitAvatar String?\n faceitCountry String?\n faceitUrl String?\n faceitVerified Boolean? @default(false)\n\n faceitSteamId64 String?\n faceitGames FaceitGameStat[]\n\n @@index([vacBanned])\n @@index([numberOfVACBans])\n @@index([numberOfGameBans])\n}\n\nenum UserStatus {\n online\n away\n offline\n}\n\nenum FaceitGameId {\n csgo\n cs2\n}\n\nmodel FaceitGameStat {\n id String @id @default(cuid())\n user User @relation(fields: [userSteamId], references: [steamId], onDelete: Cascade)\n userSteamId String\n game FaceitGameId\n region String? // \"EU\"\n gamePlayerId String? // \"76561198000414190\"\n gamePlayerName String? // \"Army\"\n skillLevel Int? // 4\n elo Int? // 1045\n skillLabel String?\n gameProfileId String?\n updatedAt DateTime @updatedAt\n\n @@unique([userSteamId, game])\n @@index([game, elo])\n}\n\nenum TeamJoinPolicy {\n REQUEST\n INVITE_ONLY\n}\n\nmodel Team {\n id String @id @default(uuid())\n name String @unique\n logo String?\n logoUpdatedAt DateTime? @default(now())\n\n leaderId String? @unique\n createdAt DateTime @default(now())\n\n activePlayers String[]\n inactivePlayers String[]\n\n leader User? @relation(\"TeamLeader\", fields: [leaderId], references: [steamId])\n members User[] @relation(\"UserTeam\")\n invites TeamInvite[]\n matchPlayers MatchPlayer[]\n\n matchesAsTeamA Match[] @relation(\"MatchTeamA\")\n matchesAsTeamB Match[] @relation(\"MatchTeamB\")\n\n schedulesAsTeamA Schedule[] @relation(\"ScheduleTeamA\")\n schedulesAsTeamB Schedule[] @relation(\"ScheduleTeamB\")\n\n mapVoteSteps MapVoteStep[] @relation(\"VoteStepTeam\")\n\n // Default bleibt REQUEST\n joinPolicy TeamJoinPolicy @default(REQUEST)\n}\n\nmodel TeamInvite {\n id String @id @default(uuid())\n steamId String\n teamId String\n type String\n createdAt DateTime @default(now())\n\n user User @relation(\"UserInvitations\", fields: [steamId], references: [steamId])\n team Team @relation(fields: [teamId], references: [id])\n}\n\nmodel Notification {\n id String @id @default(uuid())\n steamId String\n title String?\n message String\n read Boolean @default(false)\n persistent Boolean @default(false)\n actionType String?\n actionData String?\n createdAt DateTime @default(now())\n\n user User @relation(fields: [steamId], references: [steamId])\n}\n\n//\n// ──────────────────────────────────────────────\n// 🎮 Matches & Spieler\n// ──────────────────────────────────────────────\n//\n\n// ──────────────────────────────────────────────\n// 🎮 Matches\n// ──────────────────────────────────────────────\n\nmodel Match {\n id String @id @default(uuid())\n title String\n matchType String @default(\"community\")\n map String?\n description String?\n scoreA Int?\n scoreB Int?\n\n teamAId String?\n teamA Team? @relation(\"MatchTeamA\", fields: [teamAId], references: [id])\n\n teamBId String?\n teamB Team? @relation(\"MatchTeamB\", fields: [teamBId], references: [id])\n\n teamAUsers User[] @relation(\"TeamAPlayers\")\n teamBUsers User[] @relation(\"TeamBPlayers\")\n\n filePath String?\n demoFile DemoFile?\n demoDate DateTime?\n demoData Json?\n\n players MatchPlayer[]\n rankUpdates RankHistory[] @relation(\"MatchRankHistory\")\n\n roundCount Int?\n roundHistory Json?\n winnerTeam String?\n\n matchDate DateTime? // geplante Startzeit (separat von demoDate)\n mapVote MapVote?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n schedule Schedule?\n\n readyAcceptances MatchReady[] @relation(\"MatchReadyMatch\")\n\n cs2MatchId BigInt? @unique // <— wichtig (Postgres lässt mehrere NULLs zu)\n exportedAt DateTime? // wann die JSON exportiert wurde\n}\n\nmodel MatchPlayer {\n id String @id @default(uuid())\n steamId String\n matchId String\n teamId String?\n team Team? @relation(fields: [teamId], references: [id])\n\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(fields: [steamId], references: [steamId])\n\n stats PlayerStats?\n\n createdAt DateTime @default(now())\n\n @@unique([matchId, steamId])\n}\n\nmodel PlayerStats {\n id String @id @default(uuid())\n matchId String\n steamId String\n\n kills Int\n assists Int\n deaths Int\n headshotPct Float\n\n totalDamage Float @default(0)\n utilityDamage Int @default(0)\n flashAssists Int @default(0)\n mvps Int @default(0)\n mvpEliminations Int @default(0)\n mvpDefuse Int @default(0)\n mvpPlant Int @default(0)\n knifeKills Int @default(0)\n zeusKills Int @default(0)\n wallbangKills Int @default(0)\n smokeKills Int @default(0)\n headshots Int @default(0)\n noScopes Int @default(0)\n blindKills Int @default(0)\n\n aim Int @default(0)\n\n oneK Int @default(0)\n twoK Int @default(0)\n threeK Int @default(0)\n fourK Int @default(0)\n fiveK Int @default(0)\n\n rankOld Int?\n rankNew Int?\n rankChange Int?\n winCount Int?\n\n matchPlayer MatchPlayer @relation(fields: [matchId, steamId], references: [matchId, steamId])\n\n @@unique([matchId, steamId])\n}\n\nmodel RankHistory {\n id String @id @default(uuid())\n steamId String\n matchId String?\n\n rankOld Int\n rankNew Int\n delta Int\n winCount Int\n\n createdAt DateTime @default(now())\n\n user User @relation(\"UserRankHistory\", fields: [steamId], references: [steamId])\n match Match? @relation(\"MatchRankHistory\", fields: [matchId], references: [id], onDelete: Cascade)\n}\n\nmodel Schedule {\n id String @id @default(uuid())\n title String\n description String?\n map String?\n date DateTime\n status ScheduleStatus @default(PENDING)\n\n teamAId String?\n teamA Team? @relation(\"ScheduleTeamA\", fields: [teamAId], references: [id])\n\n teamBId String?\n teamB Team? @relation(\"ScheduleTeamB\", fields: [teamBId], references: [id])\n\n createdById String\n createdBy User @relation(\"CreatedSchedules\", fields: [createdById], references: [steamId])\n\n confirmedById String?\n confirmedBy User? @relation(\"ConfirmedSchedules\", fields: [confirmedById], references: [steamId])\n\n linkedMatchId String? @unique\n linkedMatch Match? @relation(fields: [linkedMatchId], references: [id], onDelete: Cascade)\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nenum ScheduleStatus {\n PENDING\n CONFIRMED\n DECLINED\n CANCELLED\n COMPLETED\n}\n\n//\n// ──────────────────────────────────────────────\n// 📦 Demo-Dateien & CS2 Requests\n// ──────────────────────────────────────────────\n//\n\nmodel DemoFile {\n id String @id @default(uuid())\n matchId String @unique\n steamId String\n fileName String @unique\n filePath String\n parsed Boolean @default(false)\n\n createdAt DateTime @default(now())\n\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(fields: [steamId], references: [steamId])\n}\n\nmodel ServerRequest {\n id String @id @default(uuid())\n steamId String\n matchId String\n reservationId BigInt\n tvPort BigInt\n processed Boolean @default(false)\n failed Boolean @default(false)\n\n createdAt DateTime @default(now())\n\n user User @relation(\"MatchRequests\", fields: [steamId], references: [steamId])\n\n @@unique([steamId, matchId])\n}\n\n// ──────────────────────────────────────────────\n// 🗺️ Map-Vote\n// ──────────────────────────────────────────────\n\nenum MapVoteAction {\n BAN\n PICK\n DECIDER\n}\n\nmodel MapVote {\n id String @id @default(uuid())\n matchId String @unique\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n\n bestOf Int @default(3)\n mapPool String[]\n currentIdx Int @default(0)\n locked Boolean @default(false)\n opensAt DateTime?\n\n leadMinutes Int @default(60)\n\n adminEditingBy String?\n adminEditingSince DateTime?\n\n steps MapVoteStep[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel MapVoteStep {\n id String @id @default(uuid())\n voteId String\n order Int\n action MapVoteAction\n\n teamId String?\n team Team? @relation(\"VoteStepTeam\", fields: [teamId], references: [id])\n\n map String?\n chosenAt DateTime?\n chosenBy String?\n chooser User? @relation(\"VoteStepChooser\", fields: [chosenBy], references: [steamId])\n\n vote MapVote @relation(fields: [voteId], references: [id], onDelete: Cascade)\n\n @@unique([voteId, order])\n @@index([teamId])\n @@index([chosenBy])\n}\n\nmodel MatchReady {\n matchId String\n steamId String\n acceptedAt DateTime @default(now())\n\n match Match @relation(\"MatchReadyMatch\", fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(\"MatchReadyUser\", fields: [steamId], references: [steamId])\n\n @@id([matchId, steamId])\n @@index([steamId])\n}\n\n// ──────────────────────────────────────────────\n// 🛠️ Server-Konfiguration & Pterodactyl\n// ──────────────────────────────────────────────\n\nmodel ServerConfig {\n id String @id\n serverIp String\n serverPassword String?\n pterodactylServerId String\n pterodactylServerApiKey String\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n // ───── Live / GameBanner ─────\n activeMatchId String?\n activeMapKey String?\n activeMapLabel String?\n activeMapBg String?\n activeParticipants String[] // steamIds\n activeSince DateTime?\n bannerExpiresAt DateTime?\n\n @@index([activeMatchId])\n}\n", - "inlineSchemaHash": "ae45c35aab6de6d8e0cd40561344ec0315364f4f39a0c0452b246c08cd7cbca5", + "inlineSchema": "generator client {\n provider = \"prisma-client-js\"\n output = \"../src/generated/prisma\"\n binaryTargets = [\"native\", \"debian-openssl-3.0.x\"]\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\n//\n// ──────────────────────────────────────────────\n// 🧑 Benutzer, Teams & Verwaltung\n// ──────────────────────────────────────────────\n//\n\nmodel User {\n steamId String @id\n name String?\n avatar String?\n location String?\n isAdmin Boolean @default(false)\n\n teamId String?\n team Team? @relation(\"UserTeam\", fields: [teamId], references: [id])\n ledTeam Team? @relation(\"TeamLeader\")\n\n matchesAsTeamA Match[] @relation(\"TeamAPlayers\")\n matchesAsTeamB Match[] @relation(\"TeamBPlayers\")\n\n premierRank Int?\n authCode String?\n lastKnownShareCode String?\n lastKnownShareCodeDate DateTime?\n createdAt DateTime @default(now())\n\n invites TeamInvite[] @relation(\"UserInvitations\")\n notifications Notification[]\n matchPlayers MatchPlayer[]\n serverRequests ServerRequest[] @relation(\"MatchRequests\")\n rankHistory RankHistory[] @relation(\"UserRankHistory\")\n demoFiles DemoFile[]\n\n createdSchedules Schedule[] @relation(\"CreatedSchedules\")\n confirmedSchedules Schedule[] @relation(\"ConfirmedSchedules\")\n\n mapVoteChoices MapVoteStep[] @relation(\"VoteStepChooser\")\n\n status UserStatus @default(offline) // 👈 neu\n lastActiveAt DateTime? // optional: wann zuletzt aktiv\n\n readyAcceptances MatchReady[] @relation(\"MatchReadyUser\")\n\n pterodactylClientApiKey String?\n\n timeZone String? // IANA-TZ, z.B. \"Europe/Berlin\"\n\n // ✅ Datenschutz: darf eingeladen werden?\n canBeInvited Boolean @default(true)\n\n // ⬇️ Dauerhafter Ban-Status (zuletzt bekannter Stand)\n vacBanned Boolean? @default(false)\n numberOfVACBans Int? @default(0)\n numberOfGameBans Int? @default(0)\n daysSinceLastBan Int? @default(0)\n communityBanned Boolean? @default(false)\n economyBan String?\n lastBanCheck DateTime?\n\n // FaceIt Account\n faceitId String? @unique\n faceitNickname String?\n faceitAvatar String?\n faceitCountry String?\n faceitUrl String?\n faceitVerified Boolean? @default(false)\n\n faceitSteamId64 String?\n faceitGames FaceitGameStat[]\n\n @@index([vacBanned])\n @@index([numberOfVACBans])\n @@index([numberOfGameBans])\n}\n\nenum UserStatus {\n online\n away\n offline\n}\n\nenum FaceitGameId {\n csgo\n cs2\n}\n\nmodel FaceitGameStat {\n id String @id @default(cuid())\n user User @relation(fields: [userSteamId], references: [steamId], onDelete: Cascade)\n userSteamId String\n game FaceitGameId\n region String? // \"EU\"\n gamePlayerId String? // \"76561198000414190\"\n gamePlayerName String? // \"Army\"\n skillLevel Int? // 4\n elo Int? // 1045\n skillLabel String?\n gameProfileId String?\n updatedAt DateTime @updatedAt\n\n @@unique([userSteamId, game])\n @@index([game, elo])\n}\n\nenum TeamJoinPolicy {\n REQUEST\n INVITE_ONLY\n}\n\nmodel Team {\n id String @id @default(uuid())\n name String @unique\n logo String?\n logoUpdatedAt DateTime? @default(now())\n\n leaderId String? @unique\n createdAt DateTime @default(now())\n\n activePlayers String[]\n inactivePlayers String[]\n\n leader User? @relation(\"TeamLeader\", fields: [leaderId], references: [steamId])\n members User[] @relation(\"UserTeam\")\n invites TeamInvite[]\n matchPlayers MatchPlayer[]\n\n matchesAsTeamA Match[] @relation(\"MatchTeamA\")\n matchesAsTeamB Match[] @relation(\"MatchTeamB\")\n\n schedulesAsTeamA Schedule[] @relation(\"ScheduleTeamA\")\n schedulesAsTeamB Schedule[] @relation(\"ScheduleTeamB\")\n\n mapVoteSteps MapVoteStep[] @relation(\"VoteStepTeam\")\n\n // Default bleibt REQUEST\n joinPolicy TeamJoinPolicy @default(REQUEST)\n}\n\nmodel TeamInvite {\n id String @id @default(uuid())\n steamId String\n teamId String\n type String\n createdAt DateTime @default(now())\n\n user User @relation(\"UserInvitations\", fields: [steamId], references: [steamId])\n team Team @relation(fields: [teamId], references: [id])\n}\n\nmodel Notification {\n id String @id @default(uuid())\n steamId String\n title String?\n message String\n read Boolean @default(false)\n persistent Boolean @default(false)\n actionType String?\n actionData String?\n createdAt DateTime @default(now())\n\n user User @relation(fields: [steamId], references: [steamId])\n}\n\n//\n// ──────────────────────────────────────────────\n// 🎮 Matches & Spieler\n// ──────────────────────────────────────────────\n//\n\n// ──────────────────────────────────────────────\n// 🎮 Matches\n// ──────────────────────────────────────────────\n\nmodel Match {\n id String @id @default(uuid())\n title String\n matchType String @default(\"community\")\n map String?\n description String?\n scoreA Int?\n scoreB Int?\n\n teamAId String?\n teamA Team? @relation(\"MatchTeamA\", fields: [teamAId], references: [id])\n\n teamBId String?\n teamB Team? @relation(\"MatchTeamB\", fields: [teamBId], references: [id])\n\n teamAUsers User[] @relation(\"TeamAPlayers\")\n teamBUsers User[] @relation(\"TeamBPlayers\")\n\n filePath String?\n demoFile DemoFile?\n demoDate DateTime?\n demoData Json?\n\n players MatchPlayer[]\n rankUpdates RankHistory[] @relation(\"MatchRankHistory\")\n\n roundCount Int?\n roundHistory Json?\n winnerTeam String?\n\n matchDate DateTime? // geplante Startzeit (separat von demoDate)\n mapVote MapVote?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n schedule Schedule?\n\n readyAcceptances MatchReady[] @relation(\"MatchReadyMatch\")\n\n cs2MatchId BigInt? @unique // <— wichtig (Postgres lässt mehrere NULLs zu)\n exportedAt DateTime? // wann die JSON exportiert wurde\n}\n\nmodel MatchPlayer {\n id String @id @default(uuid())\n steamId String\n matchId String\n teamId String?\n team Team? @relation(fields: [teamId], references: [id])\n\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(fields: [steamId], references: [steamId])\n\n stats PlayerStats?\n\n createdAt DateTime @default(now())\n\n @@unique([matchId, steamId])\n}\n\nmodel PlayerStats {\n id String @id @default(uuid())\n matchId String\n steamId String\n\n kills Int\n assists Int\n deaths Int\n headshotPct Float\n\n totalDamage Float @default(0)\n utilityDamage Int @default(0)\n flashAssists Int @default(0)\n mvps Int @default(0)\n mvpEliminations Int @default(0)\n mvpDefuse Int @default(0)\n mvpPlant Int @default(0)\n knifeKills Int @default(0)\n zeusKills Int @default(0)\n wallbangKills Int @default(0)\n smokeKills Int @default(0)\n headshots Int @default(0)\n noScopes Int @default(0)\n blindKills Int @default(0)\n\n aim Int @default(0)\n\n oneK Int @default(0)\n twoK Int @default(0)\n threeK Int @default(0)\n fourK Int @default(0)\n fiveK Int @default(0)\n\n rankOld Int?\n rankNew Int?\n rankChange Int?\n winCount Int?\n\n matchPlayer MatchPlayer @relation(fields: [matchId, steamId], references: [matchId, steamId])\n\n @@unique([matchId, steamId])\n}\n\nmodel RankHistory {\n id String @id @default(uuid())\n steamId String\n matchId String?\n\n rankOld Int\n rankNew Int\n delta Int\n winCount Int\n\n createdAt DateTime @default(now())\n\n user User @relation(\"UserRankHistory\", fields: [steamId], references: [steamId])\n match Match? @relation(\"MatchRankHistory\", fields: [matchId], references: [id], onDelete: Cascade)\n}\n\nmodel Schedule {\n id String @id @default(uuid())\n title String\n description String?\n map String?\n date DateTime\n status ScheduleStatus @default(PENDING)\n\n teamAId String?\n teamA Team? @relation(\"ScheduleTeamA\", fields: [teamAId], references: [id])\n\n teamBId String?\n teamB Team? @relation(\"ScheduleTeamB\", fields: [teamBId], references: [id])\n\n createdById String\n createdBy User @relation(\"CreatedSchedules\", fields: [createdById], references: [steamId])\n\n confirmedById String?\n confirmedBy User? @relation(\"ConfirmedSchedules\", fields: [confirmedById], references: [steamId])\n\n linkedMatchId String? @unique\n linkedMatch Match? @relation(fields: [linkedMatchId], references: [id], onDelete: Cascade)\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nenum ScheduleStatus {\n PENDING\n CONFIRMED\n DECLINED\n CANCELLED\n COMPLETED\n}\n\n//\n// ──────────────────────────────────────────────\n// 📦 Demo-Dateien & CS2 Requests\n// ──────────────────────────────────────────────\n//\n\nmodel DemoFile {\n id String @id @default(uuid())\n matchId String @unique\n steamId String\n fileName String @unique\n filePath String\n parsed Boolean @default(false)\n\n createdAt DateTime @default(now())\n\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(fields: [steamId], references: [steamId])\n}\n\nmodel ServerRequest {\n id String @id @default(uuid())\n steamId String\n matchId String\n reservationId BigInt\n tvPort BigInt\n processed Boolean @default(false)\n failed Boolean @default(false)\n\n createdAt DateTime @default(now())\n\n user User @relation(\"MatchRequests\", fields: [steamId], references: [steamId])\n\n @@unique([steamId, matchId])\n}\n\n// ──────────────────────────────────────────────\n// 🗺️ Map-Vote\n// ──────────────────────────────────────────────\n\nenum MapVoteAction {\n BAN\n PICK\n DECIDER\n}\n\nmodel MapVote {\n id String @id @default(uuid())\n matchId String @unique\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n\n bestOf Int @default(3)\n mapPool String[]\n currentIdx Int @default(0)\n locked Boolean @default(false)\n opensAt DateTime?\n\n leadMinutes Int @default(60)\n\n adminEditingBy String?\n adminEditingSince DateTime?\n\n steps MapVoteStep[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel MapVoteStep {\n id String @id @default(uuid())\n voteId String\n order Int\n action MapVoteAction\n\n teamId String?\n team Team? @relation(\"VoteStepTeam\", fields: [teamId], references: [id])\n\n map String?\n chosenAt DateTime?\n chosenBy String?\n chooser User? @relation(\"VoteStepChooser\", fields: [chosenBy], references: [steamId])\n\n vote MapVote @relation(fields: [voteId], references: [id], onDelete: Cascade)\n\n @@unique([voteId, order])\n @@index([teamId])\n @@index([chosenBy])\n}\n\nmodel MatchReady {\n matchId String\n steamId String\n acceptedAt DateTime @default(now())\n\n match Match @relation(\"MatchReadyMatch\", fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(\"MatchReadyUser\", fields: [steamId], references: [steamId])\n\n @@id([matchId, steamId])\n @@index([steamId])\n}\n\n// ──────────────────────────────────────────────\n// 🛠️ Server-Konfiguration & Pterodactyl\n// ──────────────────────────────────────────────\n\nmodel ServerConfig {\n id String @id\n serverIp String\n serverPassword String?\n pterodactylServerId String\n pterodactylServerApiKey String\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n // ───── Live / GameBanner ─────\n activeMatchId String?\n activeMapKey String?\n activeMapLabel String?\n activeMapBg String?\n activeParticipants String[] // steamIds\n activeSince DateTime?\n bannerExpiresAt DateTime?\n\n @@index([activeMatchId])\n}\n", + "inlineSchemaHash": "cfb52fd332462ae98f2ea1e237f84e3da920102b14ba8426145d801d41338756", "copyEngine": true } @@ -497,6 +500,10 @@ Object.assign(exports, Prisma) // file annotations for bundling tools to include these files path.join(__dirname, "query_engine-windows.dll.node"); path.join(process.cwd(), "src/generated/prisma/query_engine-windows.dll.node") + +// file annotations for bundling tools to include these files +path.join(__dirname, "libquery_engine-debian-openssl-3.0.x.so.node"); +path.join(process.cwd(), "src/generated/prisma/libquery_engine-debian-openssl-3.0.x.so.node") // file annotations for bundling tools to include these files path.join(__dirname, "schema.prisma"); path.join(process.cwd(), "src/generated/prisma/schema.prisma") diff --git a/src/generated/prisma/libquery_engine-debian-openssl-3.0.x.so.node b/src/generated/prisma/libquery_engine-debian-openssl-3.0.x.so.node new file mode 100644 index 0000000..6cb5800 Binary files /dev/null and b/src/generated/prisma/libquery_engine-debian-openssl-3.0.x.so.node differ diff --git a/src/generated/prisma/package.json b/src/generated/prisma/package.json index 5470e3d..60446b8 100644 --- a/src/generated/prisma/package.json +++ b/src/generated/prisma/package.json @@ -1,5 +1,5 @@ { - "name": "prisma-client-36cae6f6c55a75367433ee2726eff09a48a8505c964fc6fc94b065a58ace6eab", + "name": "prisma-client-b0dd8e490fa796a1b8f7491edf507ed2476889f3413a4e0ea5f23c3e5f8271e6", "main": "index.js", "types": "index.d.ts", "browser": "default.js", diff --git a/src/generated/prisma/schema.prisma b/src/generated/prisma/schema.prisma index 4352b92..abb83f6 100644 --- a/src/generated/prisma/schema.prisma +++ b/src/generated/prisma/schema.prisma @@ -1,6 +1,7 @@ generator client { - provider = "prisma-client-js" - output = "../src/generated/prisma" + provider = "prisma-client-js" + output = "../src/generated/prisma" + binaryTargets = ["native", "debian-openssl-3.0.x"] } datasource db { diff --git a/src/generated/prisma/wasm.js b/src/generated/prisma/wasm.js index 2842bf2..57e1147 100644 --- a/src/generated/prisma/wasm.js +++ b/src/generated/prisma/wasm.js @@ -417,7 +417,7 @@ const config = { "value": "prisma-client-js" }, "output": { - "value": "C:\\Users\\Rother\\fork\\ironie-nextjs\\src\\generated\\prisma", + "value": "C:\\Users\\Chris\\fork\\ironie-nextjs\\src\\generated\\prisma", "fromEnvVar": null }, "config": { @@ -428,15 +428,18 @@ const config = { "fromEnvVar": null, "value": "windows", "native": true + }, + { + "fromEnvVar": null, + "value": "debian-openssl-3.0.x" } ], "previewFeatures": [], - "sourceFilePath": "C:\\Users\\Rother\\fork\\ironie-nextjs\\prisma\\schema.prisma", + "sourceFilePath": "C:\\Users\\Chris\\fork\\ironie-nextjs\\prisma\\schema.prisma", "isCustomOutput": true }, "relativeEnvPaths": { - "rootEnvPath": null, - "schemaEnvPath": "../../../.env" + "rootEnvPath": null }, "relativePath": "../../../prisma", "clientVersion": "6.17.1", @@ -454,8 +457,8 @@ const config = { } } }, - "inlineSchema": "generator client {\n provider = \"prisma-client-js\"\n output = \"../src/generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\n//\n// ──────────────────────────────────────────────\n// 🧑 Benutzer, Teams & Verwaltung\n// ──────────────────────────────────────────────\n//\n\nmodel User {\n steamId String @id\n name String?\n avatar String?\n location String?\n isAdmin Boolean @default(false)\n\n teamId String?\n team Team? @relation(\"UserTeam\", fields: [teamId], references: [id])\n ledTeam Team? @relation(\"TeamLeader\")\n\n matchesAsTeamA Match[] @relation(\"TeamAPlayers\")\n matchesAsTeamB Match[] @relation(\"TeamBPlayers\")\n\n premierRank Int?\n authCode String?\n lastKnownShareCode String?\n lastKnownShareCodeDate DateTime?\n createdAt DateTime @default(now())\n\n invites TeamInvite[] @relation(\"UserInvitations\")\n notifications Notification[]\n matchPlayers MatchPlayer[]\n serverRequests ServerRequest[] @relation(\"MatchRequests\")\n rankHistory RankHistory[] @relation(\"UserRankHistory\")\n demoFiles DemoFile[]\n\n createdSchedules Schedule[] @relation(\"CreatedSchedules\")\n confirmedSchedules Schedule[] @relation(\"ConfirmedSchedules\")\n\n mapVoteChoices MapVoteStep[] @relation(\"VoteStepChooser\")\n\n status UserStatus @default(offline) // 👈 neu\n lastActiveAt DateTime? // optional: wann zuletzt aktiv\n\n readyAcceptances MatchReady[] @relation(\"MatchReadyUser\")\n\n pterodactylClientApiKey String?\n\n timeZone String? // IANA-TZ, z.B. \"Europe/Berlin\"\n\n // ✅ Datenschutz: darf eingeladen werden?\n canBeInvited Boolean @default(true)\n\n // ⬇️ Dauerhafter Ban-Status (zuletzt bekannter Stand)\n vacBanned Boolean? @default(false)\n numberOfVACBans Int? @default(0)\n numberOfGameBans Int? @default(0)\n daysSinceLastBan Int? @default(0)\n communityBanned Boolean? @default(false)\n economyBan String?\n lastBanCheck DateTime?\n\n // FaceIt Account\n faceitId String? @unique\n faceitNickname String?\n faceitAvatar String?\n faceitCountry String?\n faceitUrl String?\n faceitVerified Boolean? @default(false)\n\n faceitSteamId64 String?\n faceitGames FaceitGameStat[]\n\n @@index([vacBanned])\n @@index([numberOfVACBans])\n @@index([numberOfGameBans])\n}\n\nenum UserStatus {\n online\n away\n offline\n}\n\nenum FaceitGameId {\n csgo\n cs2\n}\n\nmodel FaceitGameStat {\n id String @id @default(cuid())\n user User @relation(fields: [userSteamId], references: [steamId], onDelete: Cascade)\n userSteamId String\n game FaceitGameId\n region String? // \"EU\"\n gamePlayerId String? // \"76561198000414190\"\n gamePlayerName String? // \"Army\"\n skillLevel Int? // 4\n elo Int? // 1045\n skillLabel String?\n gameProfileId String?\n updatedAt DateTime @updatedAt\n\n @@unique([userSteamId, game])\n @@index([game, elo])\n}\n\nenum TeamJoinPolicy {\n REQUEST\n INVITE_ONLY\n}\n\nmodel Team {\n id String @id @default(uuid())\n name String @unique\n logo String?\n logoUpdatedAt DateTime? @default(now())\n\n leaderId String? @unique\n createdAt DateTime @default(now())\n\n activePlayers String[]\n inactivePlayers String[]\n\n leader User? @relation(\"TeamLeader\", fields: [leaderId], references: [steamId])\n members User[] @relation(\"UserTeam\")\n invites TeamInvite[]\n matchPlayers MatchPlayer[]\n\n matchesAsTeamA Match[] @relation(\"MatchTeamA\")\n matchesAsTeamB Match[] @relation(\"MatchTeamB\")\n\n schedulesAsTeamA Schedule[] @relation(\"ScheduleTeamA\")\n schedulesAsTeamB Schedule[] @relation(\"ScheduleTeamB\")\n\n mapVoteSteps MapVoteStep[] @relation(\"VoteStepTeam\")\n\n // Default bleibt REQUEST\n joinPolicy TeamJoinPolicy @default(REQUEST)\n}\n\nmodel TeamInvite {\n id String @id @default(uuid())\n steamId String\n teamId String\n type String\n createdAt DateTime @default(now())\n\n user User @relation(\"UserInvitations\", fields: [steamId], references: [steamId])\n team Team @relation(fields: [teamId], references: [id])\n}\n\nmodel Notification {\n id String @id @default(uuid())\n steamId String\n title String?\n message String\n read Boolean @default(false)\n persistent Boolean @default(false)\n actionType String?\n actionData String?\n createdAt DateTime @default(now())\n\n user User @relation(fields: [steamId], references: [steamId])\n}\n\n//\n// ──────────────────────────────────────────────\n// 🎮 Matches & Spieler\n// ──────────────────────────────────────────────\n//\n\n// ──────────────────────────────────────────────\n// 🎮 Matches\n// ──────────────────────────────────────────────\n\nmodel Match {\n id String @id @default(uuid())\n title String\n matchType String @default(\"community\")\n map String?\n description String?\n scoreA Int?\n scoreB Int?\n\n teamAId String?\n teamA Team? @relation(\"MatchTeamA\", fields: [teamAId], references: [id])\n\n teamBId String?\n teamB Team? @relation(\"MatchTeamB\", fields: [teamBId], references: [id])\n\n teamAUsers User[] @relation(\"TeamAPlayers\")\n teamBUsers User[] @relation(\"TeamBPlayers\")\n\n filePath String?\n demoFile DemoFile?\n demoDate DateTime?\n demoData Json?\n\n players MatchPlayer[]\n rankUpdates RankHistory[] @relation(\"MatchRankHistory\")\n\n roundCount Int?\n roundHistory Json?\n winnerTeam String?\n\n matchDate DateTime? // geplante Startzeit (separat von demoDate)\n mapVote MapVote?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n schedule Schedule?\n\n readyAcceptances MatchReady[] @relation(\"MatchReadyMatch\")\n\n cs2MatchId BigInt? @unique // <— wichtig (Postgres lässt mehrere NULLs zu)\n exportedAt DateTime? // wann die JSON exportiert wurde\n}\n\nmodel MatchPlayer {\n id String @id @default(uuid())\n steamId String\n matchId String\n teamId String?\n team Team? @relation(fields: [teamId], references: [id])\n\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(fields: [steamId], references: [steamId])\n\n stats PlayerStats?\n\n createdAt DateTime @default(now())\n\n @@unique([matchId, steamId])\n}\n\nmodel PlayerStats {\n id String @id @default(uuid())\n matchId String\n steamId String\n\n kills Int\n assists Int\n deaths Int\n headshotPct Float\n\n totalDamage Float @default(0)\n utilityDamage Int @default(0)\n flashAssists Int @default(0)\n mvps Int @default(0)\n mvpEliminations Int @default(0)\n mvpDefuse Int @default(0)\n mvpPlant Int @default(0)\n knifeKills Int @default(0)\n zeusKills Int @default(0)\n wallbangKills Int @default(0)\n smokeKills Int @default(0)\n headshots Int @default(0)\n noScopes Int @default(0)\n blindKills Int @default(0)\n\n aim Int @default(0)\n\n oneK Int @default(0)\n twoK Int @default(0)\n threeK Int @default(0)\n fourK Int @default(0)\n fiveK Int @default(0)\n\n rankOld Int?\n rankNew Int?\n rankChange Int?\n winCount Int?\n\n matchPlayer MatchPlayer @relation(fields: [matchId, steamId], references: [matchId, steamId])\n\n @@unique([matchId, steamId])\n}\n\nmodel RankHistory {\n id String @id @default(uuid())\n steamId String\n matchId String?\n\n rankOld Int\n rankNew Int\n delta Int\n winCount Int\n\n createdAt DateTime @default(now())\n\n user User @relation(\"UserRankHistory\", fields: [steamId], references: [steamId])\n match Match? @relation(\"MatchRankHistory\", fields: [matchId], references: [id], onDelete: Cascade)\n}\n\nmodel Schedule {\n id String @id @default(uuid())\n title String\n description String?\n map String?\n date DateTime\n status ScheduleStatus @default(PENDING)\n\n teamAId String?\n teamA Team? @relation(\"ScheduleTeamA\", fields: [teamAId], references: [id])\n\n teamBId String?\n teamB Team? @relation(\"ScheduleTeamB\", fields: [teamBId], references: [id])\n\n createdById String\n createdBy User @relation(\"CreatedSchedules\", fields: [createdById], references: [steamId])\n\n confirmedById String?\n confirmedBy User? @relation(\"ConfirmedSchedules\", fields: [confirmedById], references: [steamId])\n\n linkedMatchId String? @unique\n linkedMatch Match? @relation(fields: [linkedMatchId], references: [id], onDelete: Cascade)\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nenum ScheduleStatus {\n PENDING\n CONFIRMED\n DECLINED\n CANCELLED\n COMPLETED\n}\n\n//\n// ──────────────────────────────────────────────\n// 📦 Demo-Dateien & CS2 Requests\n// ──────────────────────────────────────────────\n//\n\nmodel DemoFile {\n id String @id @default(uuid())\n matchId String @unique\n steamId String\n fileName String @unique\n filePath String\n parsed Boolean @default(false)\n\n createdAt DateTime @default(now())\n\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(fields: [steamId], references: [steamId])\n}\n\nmodel ServerRequest {\n id String @id @default(uuid())\n steamId String\n matchId String\n reservationId BigInt\n tvPort BigInt\n processed Boolean @default(false)\n failed Boolean @default(false)\n\n createdAt DateTime @default(now())\n\n user User @relation(\"MatchRequests\", fields: [steamId], references: [steamId])\n\n @@unique([steamId, matchId])\n}\n\n// ──────────────────────────────────────────────\n// 🗺️ Map-Vote\n// ──────────────────────────────────────────────\n\nenum MapVoteAction {\n BAN\n PICK\n DECIDER\n}\n\nmodel MapVote {\n id String @id @default(uuid())\n matchId String @unique\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n\n bestOf Int @default(3)\n mapPool String[]\n currentIdx Int @default(0)\n locked Boolean @default(false)\n opensAt DateTime?\n\n leadMinutes Int @default(60)\n\n adminEditingBy String?\n adminEditingSince DateTime?\n\n steps MapVoteStep[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel MapVoteStep {\n id String @id @default(uuid())\n voteId String\n order Int\n action MapVoteAction\n\n teamId String?\n team Team? @relation(\"VoteStepTeam\", fields: [teamId], references: [id])\n\n map String?\n chosenAt DateTime?\n chosenBy String?\n chooser User? @relation(\"VoteStepChooser\", fields: [chosenBy], references: [steamId])\n\n vote MapVote @relation(fields: [voteId], references: [id], onDelete: Cascade)\n\n @@unique([voteId, order])\n @@index([teamId])\n @@index([chosenBy])\n}\n\nmodel MatchReady {\n matchId String\n steamId String\n acceptedAt DateTime @default(now())\n\n match Match @relation(\"MatchReadyMatch\", fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(\"MatchReadyUser\", fields: [steamId], references: [steamId])\n\n @@id([matchId, steamId])\n @@index([steamId])\n}\n\n// ──────────────────────────────────────────────\n// 🛠️ Server-Konfiguration & Pterodactyl\n// ──────────────────────────────────────────────\n\nmodel ServerConfig {\n id String @id\n serverIp String\n serverPassword String?\n pterodactylServerId String\n pterodactylServerApiKey String\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n // ───── Live / GameBanner ─────\n activeMatchId String?\n activeMapKey String?\n activeMapLabel String?\n activeMapBg String?\n activeParticipants String[] // steamIds\n activeSince DateTime?\n bannerExpiresAt DateTime?\n\n @@index([activeMatchId])\n}\n", - "inlineSchemaHash": "ae45c35aab6de6d8e0cd40561344ec0315364f4f39a0c0452b246c08cd7cbca5", + "inlineSchema": "generator client {\n provider = \"prisma-client-js\"\n output = \"../src/generated/prisma\"\n binaryTargets = [\"native\", \"debian-openssl-3.0.x\"]\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\n//\n// ──────────────────────────────────────────────\n// 🧑 Benutzer, Teams & Verwaltung\n// ──────────────────────────────────────────────\n//\n\nmodel User {\n steamId String @id\n name String?\n avatar String?\n location String?\n isAdmin Boolean @default(false)\n\n teamId String?\n team Team? @relation(\"UserTeam\", fields: [teamId], references: [id])\n ledTeam Team? @relation(\"TeamLeader\")\n\n matchesAsTeamA Match[] @relation(\"TeamAPlayers\")\n matchesAsTeamB Match[] @relation(\"TeamBPlayers\")\n\n premierRank Int?\n authCode String?\n lastKnownShareCode String?\n lastKnownShareCodeDate DateTime?\n createdAt DateTime @default(now())\n\n invites TeamInvite[] @relation(\"UserInvitations\")\n notifications Notification[]\n matchPlayers MatchPlayer[]\n serverRequests ServerRequest[] @relation(\"MatchRequests\")\n rankHistory RankHistory[] @relation(\"UserRankHistory\")\n demoFiles DemoFile[]\n\n createdSchedules Schedule[] @relation(\"CreatedSchedules\")\n confirmedSchedules Schedule[] @relation(\"ConfirmedSchedules\")\n\n mapVoteChoices MapVoteStep[] @relation(\"VoteStepChooser\")\n\n status UserStatus @default(offline) // 👈 neu\n lastActiveAt DateTime? // optional: wann zuletzt aktiv\n\n readyAcceptances MatchReady[] @relation(\"MatchReadyUser\")\n\n pterodactylClientApiKey String?\n\n timeZone String? // IANA-TZ, z.B. \"Europe/Berlin\"\n\n // ✅ Datenschutz: darf eingeladen werden?\n canBeInvited Boolean @default(true)\n\n // ⬇️ Dauerhafter Ban-Status (zuletzt bekannter Stand)\n vacBanned Boolean? @default(false)\n numberOfVACBans Int? @default(0)\n numberOfGameBans Int? @default(0)\n daysSinceLastBan Int? @default(0)\n communityBanned Boolean? @default(false)\n economyBan String?\n lastBanCheck DateTime?\n\n // FaceIt Account\n faceitId String? @unique\n faceitNickname String?\n faceitAvatar String?\n faceitCountry String?\n faceitUrl String?\n faceitVerified Boolean? @default(false)\n\n faceitSteamId64 String?\n faceitGames FaceitGameStat[]\n\n @@index([vacBanned])\n @@index([numberOfVACBans])\n @@index([numberOfGameBans])\n}\n\nenum UserStatus {\n online\n away\n offline\n}\n\nenum FaceitGameId {\n csgo\n cs2\n}\n\nmodel FaceitGameStat {\n id String @id @default(cuid())\n user User @relation(fields: [userSteamId], references: [steamId], onDelete: Cascade)\n userSteamId String\n game FaceitGameId\n region String? // \"EU\"\n gamePlayerId String? // \"76561198000414190\"\n gamePlayerName String? // \"Army\"\n skillLevel Int? // 4\n elo Int? // 1045\n skillLabel String?\n gameProfileId String?\n updatedAt DateTime @updatedAt\n\n @@unique([userSteamId, game])\n @@index([game, elo])\n}\n\nenum TeamJoinPolicy {\n REQUEST\n INVITE_ONLY\n}\n\nmodel Team {\n id String @id @default(uuid())\n name String @unique\n logo String?\n logoUpdatedAt DateTime? @default(now())\n\n leaderId String? @unique\n createdAt DateTime @default(now())\n\n activePlayers String[]\n inactivePlayers String[]\n\n leader User? @relation(\"TeamLeader\", fields: [leaderId], references: [steamId])\n members User[] @relation(\"UserTeam\")\n invites TeamInvite[]\n matchPlayers MatchPlayer[]\n\n matchesAsTeamA Match[] @relation(\"MatchTeamA\")\n matchesAsTeamB Match[] @relation(\"MatchTeamB\")\n\n schedulesAsTeamA Schedule[] @relation(\"ScheduleTeamA\")\n schedulesAsTeamB Schedule[] @relation(\"ScheduleTeamB\")\n\n mapVoteSteps MapVoteStep[] @relation(\"VoteStepTeam\")\n\n // Default bleibt REQUEST\n joinPolicy TeamJoinPolicy @default(REQUEST)\n}\n\nmodel TeamInvite {\n id String @id @default(uuid())\n steamId String\n teamId String\n type String\n createdAt DateTime @default(now())\n\n user User @relation(\"UserInvitations\", fields: [steamId], references: [steamId])\n team Team @relation(fields: [teamId], references: [id])\n}\n\nmodel Notification {\n id String @id @default(uuid())\n steamId String\n title String?\n message String\n read Boolean @default(false)\n persistent Boolean @default(false)\n actionType String?\n actionData String?\n createdAt DateTime @default(now())\n\n user User @relation(fields: [steamId], references: [steamId])\n}\n\n//\n// ──────────────────────────────────────────────\n// 🎮 Matches & Spieler\n// ──────────────────────────────────────────────\n//\n\n// ──────────────────────────────────────────────\n// 🎮 Matches\n// ──────────────────────────────────────────────\n\nmodel Match {\n id String @id @default(uuid())\n title String\n matchType String @default(\"community\")\n map String?\n description String?\n scoreA Int?\n scoreB Int?\n\n teamAId String?\n teamA Team? @relation(\"MatchTeamA\", fields: [teamAId], references: [id])\n\n teamBId String?\n teamB Team? @relation(\"MatchTeamB\", fields: [teamBId], references: [id])\n\n teamAUsers User[] @relation(\"TeamAPlayers\")\n teamBUsers User[] @relation(\"TeamBPlayers\")\n\n filePath String?\n demoFile DemoFile?\n demoDate DateTime?\n demoData Json?\n\n players MatchPlayer[]\n rankUpdates RankHistory[] @relation(\"MatchRankHistory\")\n\n roundCount Int?\n roundHistory Json?\n winnerTeam String?\n\n matchDate DateTime? // geplante Startzeit (separat von demoDate)\n mapVote MapVote?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n schedule Schedule?\n\n readyAcceptances MatchReady[] @relation(\"MatchReadyMatch\")\n\n cs2MatchId BigInt? @unique // <— wichtig (Postgres lässt mehrere NULLs zu)\n exportedAt DateTime? // wann die JSON exportiert wurde\n}\n\nmodel MatchPlayer {\n id String @id @default(uuid())\n steamId String\n matchId String\n teamId String?\n team Team? @relation(fields: [teamId], references: [id])\n\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(fields: [steamId], references: [steamId])\n\n stats PlayerStats?\n\n createdAt DateTime @default(now())\n\n @@unique([matchId, steamId])\n}\n\nmodel PlayerStats {\n id String @id @default(uuid())\n matchId String\n steamId String\n\n kills Int\n assists Int\n deaths Int\n headshotPct Float\n\n totalDamage Float @default(0)\n utilityDamage Int @default(0)\n flashAssists Int @default(0)\n mvps Int @default(0)\n mvpEliminations Int @default(0)\n mvpDefuse Int @default(0)\n mvpPlant Int @default(0)\n knifeKills Int @default(0)\n zeusKills Int @default(0)\n wallbangKills Int @default(0)\n smokeKills Int @default(0)\n headshots Int @default(0)\n noScopes Int @default(0)\n blindKills Int @default(0)\n\n aim Int @default(0)\n\n oneK Int @default(0)\n twoK Int @default(0)\n threeK Int @default(0)\n fourK Int @default(0)\n fiveK Int @default(0)\n\n rankOld Int?\n rankNew Int?\n rankChange Int?\n winCount Int?\n\n matchPlayer MatchPlayer @relation(fields: [matchId, steamId], references: [matchId, steamId])\n\n @@unique([matchId, steamId])\n}\n\nmodel RankHistory {\n id String @id @default(uuid())\n steamId String\n matchId String?\n\n rankOld Int\n rankNew Int\n delta Int\n winCount Int\n\n createdAt DateTime @default(now())\n\n user User @relation(\"UserRankHistory\", fields: [steamId], references: [steamId])\n match Match? @relation(\"MatchRankHistory\", fields: [matchId], references: [id], onDelete: Cascade)\n}\n\nmodel Schedule {\n id String @id @default(uuid())\n title String\n description String?\n map String?\n date DateTime\n status ScheduleStatus @default(PENDING)\n\n teamAId String?\n teamA Team? @relation(\"ScheduleTeamA\", fields: [teamAId], references: [id])\n\n teamBId String?\n teamB Team? @relation(\"ScheduleTeamB\", fields: [teamBId], references: [id])\n\n createdById String\n createdBy User @relation(\"CreatedSchedules\", fields: [createdById], references: [steamId])\n\n confirmedById String?\n confirmedBy User? @relation(\"ConfirmedSchedules\", fields: [confirmedById], references: [steamId])\n\n linkedMatchId String? @unique\n linkedMatch Match? @relation(fields: [linkedMatchId], references: [id], onDelete: Cascade)\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nenum ScheduleStatus {\n PENDING\n CONFIRMED\n DECLINED\n CANCELLED\n COMPLETED\n}\n\n//\n// ──────────────────────────────────────────────\n// 📦 Demo-Dateien & CS2 Requests\n// ──────────────────────────────────────────────\n//\n\nmodel DemoFile {\n id String @id @default(uuid())\n matchId String @unique\n steamId String\n fileName String @unique\n filePath String\n parsed Boolean @default(false)\n\n createdAt DateTime @default(now())\n\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(fields: [steamId], references: [steamId])\n}\n\nmodel ServerRequest {\n id String @id @default(uuid())\n steamId String\n matchId String\n reservationId BigInt\n tvPort BigInt\n processed Boolean @default(false)\n failed Boolean @default(false)\n\n createdAt DateTime @default(now())\n\n user User @relation(\"MatchRequests\", fields: [steamId], references: [steamId])\n\n @@unique([steamId, matchId])\n}\n\n// ──────────────────────────────────────────────\n// 🗺️ Map-Vote\n// ──────────────────────────────────────────────\n\nenum MapVoteAction {\n BAN\n PICK\n DECIDER\n}\n\nmodel MapVote {\n id String @id @default(uuid())\n matchId String @unique\n match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)\n\n bestOf Int @default(3)\n mapPool String[]\n currentIdx Int @default(0)\n locked Boolean @default(false)\n opensAt DateTime?\n\n leadMinutes Int @default(60)\n\n adminEditingBy String?\n adminEditingSince DateTime?\n\n steps MapVoteStep[]\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n}\n\nmodel MapVoteStep {\n id String @id @default(uuid())\n voteId String\n order Int\n action MapVoteAction\n\n teamId String?\n team Team? @relation(\"VoteStepTeam\", fields: [teamId], references: [id])\n\n map String?\n chosenAt DateTime?\n chosenBy String?\n chooser User? @relation(\"VoteStepChooser\", fields: [chosenBy], references: [steamId])\n\n vote MapVote @relation(fields: [voteId], references: [id], onDelete: Cascade)\n\n @@unique([voteId, order])\n @@index([teamId])\n @@index([chosenBy])\n}\n\nmodel MatchReady {\n matchId String\n steamId String\n acceptedAt DateTime @default(now())\n\n match Match @relation(\"MatchReadyMatch\", fields: [matchId], references: [id], onDelete: Cascade)\n user User @relation(\"MatchReadyUser\", fields: [steamId], references: [steamId])\n\n @@id([matchId, steamId])\n @@index([steamId])\n}\n\n// ──────────────────────────────────────────────\n// 🛠️ Server-Konfiguration & Pterodactyl\n// ──────────────────────────────────────────────\n\nmodel ServerConfig {\n id String @id\n serverIp String\n serverPassword String?\n pterodactylServerId String\n pterodactylServerApiKey String\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n // ───── Live / GameBanner ─────\n activeMatchId String?\n activeMapKey String?\n activeMapLabel String?\n activeMapBg String?\n activeParticipants String[] // steamIds\n activeSince DateTime?\n bannerExpiresAt DateTime?\n\n @@index([activeMatchId])\n}\n", + "inlineSchemaHash": "cfb52fd332462ae98f2ea1e237f84e3da920102b14ba8426145d801d41338756", "copyEngine": true } config.dirname = '/' diff --git a/src/i18n/request.ts b/src/i18n/request.ts index c2d3ab5..80179f2 100644 --- a/src/i18n/request.ts +++ b/src/i18n/request.ts @@ -1,14 +1,15 @@ // /src/i18n/request.ts -import {getRequestConfig} from 'next-intl/server' -import {hasLocale} from 'next-intl' -import {routing} from './routing' +export const runtime = 'nodejs'; // wichtig: nicht Edge -export default getRequestConfig(async ({requestLocale}) => { - const requested = await requestLocale - const locale = hasLocale(routing.locales, requested) ? (requested as string) : routing.defaultLocale +import {getRequestConfig} from 'next-intl/server'; +import {hasLocale} from 'next-intl'; +import {routing} from './routing'; - // ⬇️ Eine JSON pro Locale laden - const messages = (await import(`../messages/${locale}.json`)).default +export default getRequestConfig(async ({locale}) => { + const effective = + hasLocale(routing.locales, locale) ? (locale as string) : routing.defaultLocale; - return { locale, messages } -}) + const messages = (await import(`../messages/${effective}.json`)).default; + + return { locale: effective, messages }; +}); diff --git a/src/middleware.ts b/src/middleware.ts index 3cd806b..c513f33 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,4 +1,4 @@ -// middleware.ts +// /src/middleware.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import createIntlMiddleware from 'next-intl/middleware'; @@ -7,12 +7,10 @@ import { routing } from './i18n/routing'; const handleI18n = createIntlMiddleware(routing); -// ---- Type-Guard: prüft, ob ein Objekt eine boolsche isAdmin-Property hat function hasAdminFlag(v: unknown): v is { isAdmin: boolean } { return typeof v === 'object' && v !== null && typeof (v as Record).isAdmin === 'boolean'; } - function getCurrentLocaleFromPath(pathname: string, locales: readonly string[], fallback: string) { const first = pathname.split('/')[1]; return locales.includes(first) ? first : fallback; @@ -28,10 +26,10 @@ function stripLeadingLocale(pathname: string, locales: readonly string[]) { } function isProtectedPath(pathnameNoLocale: string) { return ( - pathnameNoLocale.startsWith('/') || - pathnameNoLocale.startsWith('/settings') || - pathnameNoLocale.startsWith('/matches') || - pathnameNoLocale.startsWith('/team') || + pathnameNoLocale === '/' || + pathnameNoLocale.startsWith('/settings') || + pathnameNoLocale.startsWith('/matches') || + pathnameNoLocale.startsWith('/team') || pathnameNoLocale.startsWith('/admin') ); } @@ -54,10 +52,31 @@ export default async function middleware(req: NextRequest) { } const i18nRes = handleI18n(req); - if (i18nRes.headers.get('location') || i18nRes.headers.get('x-middleware-rewrite')) { + + // 1) Rewrites -> immer auf aktuelle öffentliche Origin + const rew = i18nRes.headers.get('x-middleware-rewrite'); + if (rew) { + const t = new URL(rew, req.url); + const out = new URL(req.url); + out.pathname = t.pathname; + out.search = t.search; + return NextResponse.rewrite(out); + } + + // 2) Redirects (Location) -> ebenfalls auf aktuelle Origin mappen + const loc = i18nRes.headers.get('location'); + if (loc) { + const t = new URL(loc, req.url); + if (t.hostname !== req.nextUrl.hostname) { + const out = new URL(req.url); + out.pathname = t.pathname; + out.search = t.search; + return NextResponse.redirect(out); // 307 + } return i18nRes; } + // 3) Geschützte Bereiche const { locales, defaultLocale } = routing; const url = req.nextUrl; const pathnameNoLocale = stripLeadingLocale(pathname, locales); @@ -67,7 +86,6 @@ export default async function middleware(req: NextRequest) { const token = await getToken({ req, secret: process.env.NEXTAUTH_SECRET }); - // Adminschutz (ohne any) if (pathnameNoLocale.startsWith('/admin')) { const isAdmin = hasAdminFlag(token) && token.isAdmin === true; if (!isAdmin) { @@ -78,7 +96,6 @@ export default async function middleware(req: NextRequest) { } } - // Allgemeiner Auth-Schutz if (!token) { const loginUrl = new URL('/api/auth/signin', req.url); loginUrl.searchParams.set('callbackUrl', url.toString());