Skip to content
Open
741 changes: 735 additions & 6 deletions package-lock.json

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
"react-dom": "^19.1.1",
"react-hook-form": "^7.62.0",
"react-hot-toast": "^2.5.2",
"sanitize-html": "^2.17.0",
"shiki": "^3.12.2",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",
"zod": "^4.0.17",
"zustand": "^5.0.6"
Expand All @@ -55,9 +58,10 @@
"@faker-js/faker": "^9.9.0",
"@tailwindcss/postcss": "^4.1.11",
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"@types/node": "^20",
"@types/node": "^20.19.13",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@types/sanitize-html": "^2.16.0",
"cross-env": "^10.0.0",
"eslint": "^9",
"eslint-config-next": "15.3.5",
Expand All @@ -70,7 +74,7 @@
"tailwindcss": "^4.1.11",
"ts-node": "^10.9.2",
"tw-animate-css": "^1.3.5",
"typescript": "^5"
"typescript": "^5.9.2"
},
"lint-staged": {
"*.{ts,tsx,js,jsx}": [
Expand All @@ -80,5 +84,8 @@
"*.{md,json}": [
"prettier --write"
]
},
"prisma": {
"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
}
}
28 changes: 28 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ model User {
accounts Account[]
apiKeys ApiKey[]
memberships TeamMembership[]
aiKeys AiKeys[]

@@index([role])
@@index([emailVerified])
Expand Down Expand Up @@ -96,6 +97,7 @@ model Team {

memberships TeamMembership[]
invites InviteToken[]
aiKeys AiKeys[]
}

model TeamMembership {
Expand Down Expand Up @@ -123,3 +125,29 @@ model InviteToken {

@@index([teamId])
}

model AiProviders {
id String @id @default(uuid())
name String @unique
code String @unique
createdAt DateTime @default(now())

aiKeys AiKeys[]
}

model AiKeys {
id String @id @default(uuid())
teamId String?
createdBy String
provider String
aiKey String
validated Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
user User @relation(fields: [createdBy], references: [id], onDelete: Cascade)
aiProvider AiProviders @relation(fields: [provider], references: [id], onDelete: Restrict)

@@index([teamId, provider])
}
64 changes: 57 additions & 7 deletions prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,15 @@
*
* Run with: `npm run db:seed`
*/
// import { PrismaClient, Role } from '@prisma/client';
import { PrismaClient } from '@prisma/client';

// import argon2 from 'argon2';
// import { randomBytes } from 'crypto';

// const prisma = new PrismaClient();

// async function main() {
// const email = '[email protected]';
// const rawPassword = process.env.ADMIN_PASSWORD ?? randomBytes(16).toString('base64url');

// const hashed = await argon2.hash(rawPassword);

// await prisma.user.upsert({
// where: { email },
// update: {},
Expand All @@ -27,16 +24,69 @@
// emailVerified: new Date(),
// },
// });

// // stdout so deploy logs show the credentials exactly once
// console.log('\n🌱 Admin user seeded:');
// console.log(` email: ${email}`);
// console.log(` password: ${rawPassword}\n`);
// }

// main()
// .catch((e) => {
// console.error(e);
// process.exit(1);
// })
// .finally(() => prisma.$disconnect());
/**
* Seed Ai providers
*
*/

const prisma = new PrismaClient();

async function main() {
const providers = [
{
name: 'GPT3.5',
code: 'gpt3.5-turbo',
},
{
name: 'GPT4',
code: 'gpt4',
},
{
name: 'GPT4o',
code: 'gpt4o',
},
{
name: 'GPT4o-mini',
code: 'gpt4o-mini',
},
{
name: 'Claude',
code: 'claude-2',
},
{
name: 'Claude-instant',
code: 'claude-instant-100k',
},
{
name: 'Llama2',
code: 'llama2-70b-chat',
},
{
name: 'Llama3',
code: 'llama3-70b-chat',
},
];
await prisma.aiProviders.createMany({
data: providers,
skipDuplicates: true,
});
console.log('\n🌱 AI Providers seeded/updated.\n');
}
Comment on lines +80 to +85
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

createMany + skipDuplicates relies on unique constraints; consider idempotent upsert for safety.

If code isn’t uniquely indexed, createMany will insert duplicates. Prefer explicit upserts if uniqueness isn’t guaranteed.

Example (if needed):

await Promise.all(
  providers.map((p) =>
    prisma.aiProviders.upsert({
      where: { code: p.code },
      update: { name: p.name },
      create: p,
    }),
  ),
);
🤖 Prompt for AI Agents
In prisma/seed.ts around lines 80 to 85, the code uses
prisma.aiProviders.createMany with skipDuplicates which only prevents duplicates
if a unique constraint exists; replace this with idempotent upserts to guarantee
no duplicates regardless of schema: iterate over providers and perform
prisma.aiProviders.upsert for each entry (use the provider unique key such as
code in the where clause, provide create with the full provider object and
update with the fields to sync), run them concurrently (e.g., Promise.all) and
remove the createMany call and skipDuplicates.


main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(() => prisma.$disconnect());
Loading