fix(admin): migration Subscription/BYOK et repli getUsers
La table Subscription était dans le schéma sans migration SQL, ce qui cassait le rendu Server Components de /admin. Migration idempotente + fallback getUsers si la jointure échoue encore. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -23,9 +23,31 @@ async function checkAdmin() {
|
|||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const userListSelect = {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
email: true,
|
||||||
|
role: true,
|
||||||
|
createdAt: true,
|
||||||
|
subscription: {
|
||||||
|
select: {
|
||||||
|
tier: true,
|
||||||
|
status: true,
|
||||||
|
currentPeriodEnd: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const
|
||||||
|
|
||||||
export async function getUsers() {
|
export async function getUsers() {
|
||||||
await checkAdmin()
|
await checkAdmin()
|
||||||
try {
|
try {
|
||||||
|
return await prisma.user.findMany({
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
select: userListSelect,
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
// Prod DB parfois en retard sur les migrations (ex. table Subscription absente).
|
||||||
|
console.error('getUsers with subscription failed, fallback without:', error)
|
||||||
const users = await prisma.user.findMany({
|
const users = await prisma.user.findMany({
|
||||||
orderBy: { createdAt: 'desc' },
|
orderBy: { createdAt: 'desc' },
|
||||||
select: {
|
select: {
|
||||||
@@ -34,19 +56,9 @@ export async function getUsers() {
|
|||||||
email: true,
|
email: true,
|
||||||
role: true,
|
role: true,
|
||||||
createdAt: true,
|
createdAt: true,
|
||||||
subscription: {
|
},
|
||||||
select: {
|
|
||||||
tier: true,
|
|
||||||
status: true,
|
|
||||||
currentPeriodEnd: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
return users
|
return users.map((u) => ({ ...u, subscription: null }))
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to fetch users:', error)
|
|
||||||
throw new Error('Failed to fetch users')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
-- Tables présentes dans schema.prisma mais jamais migrées (admin / billing / BYOK).
|
||||||
|
|
||||||
|
DO $$ BEGIN
|
||||||
|
CREATE TYPE "SubscriptionTier" AS ENUM ('BASIC', 'PRO', 'BUSINESS', 'ENTERPRISE');
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN NULL;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
DO $$ BEGIN
|
||||||
|
CREATE TYPE "SubscriptionStatus" AS ENUM ('ACTIVE', 'PAST_DUE', 'CANCELED', 'TRIALING', 'INACTIVE');
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN NULL;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "UserAPIKey" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"provider" TEXT NOT NULL,
|
||||||
|
"alias" TEXT NOT NULL DEFAULT '',
|
||||||
|
"encryptedKey" TEXT NOT NULL,
|
||||||
|
"keyHash" TEXT NOT NULL,
|
||||||
|
"model" TEXT,
|
||||||
|
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
"lastUsedAt" TIMESTAMP(3),
|
||||||
|
"lastUsedFor" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "UserAPIKey_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS "UserAPIKey_userId_provider_key" ON "UserAPIKey"("userId", "provider");
|
||||||
|
CREATE INDEX IF NOT EXISTS "UserAPIKey_userId_idx" ON "UserAPIKey"("userId");
|
||||||
|
CREATE INDEX IF NOT EXISTS "UserAPIKey_keyHash_idx" ON "UserAPIKey"("keyHash");
|
||||||
|
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "UserAPIKey" ADD CONSTRAINT "UserAPIKey_userId_fkey"
|
||||||
|
FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN NULL;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "Subscription" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"tier" "SubscriptionTier" NOT NULL DEFAULT 'BASIC',
|
||||||
|
"status" "SubscriptionStatus" NOT NULL DEFAULT 'ACTIVE',
|
||||||
|
"stripeCustomerId" TEXT,
|
||||||
|
"stripeSubscriptionId" TEXT,
|
||||||
|
"stripePriceId" TEXT,
|
||||||
|
"trialEndsAt" TIMESTAMP(3),
|
||||||
|
"currentPeriodStart" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"currentPeriodEnd" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"canceledAt" TIMESTAMP(3),
|
||||||
|
"cancelAtPeriodEnd" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "Subscription_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS "Subscription_userId_key" ON "Subscription"("userId");
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS "Subscription_stripeCustomerId_key" ON "Subscription"("stripeCustomerId");
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS "Subscription_stripeSubscriptionId_key" ON "Subscription"("stripeSubscriptionId");
|
||||||
|
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "Subscription" ADD CONSTRAINT "Subscription_userId_fkey"
|
||||||
|
FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN NULL;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "UsageLog" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"feature" TEXT NOT NULL,
|
||||||
|
"periodStart" TIMESTAMP(3) NOT NULL,
|
||||||
|
"periodEnd" TIMESTAMP(3) NOT NULL,
|
||||||
|
"requestsCount" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"tokensUsed" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"syncedAt" TIMESTAMP(3),
|
||||||
|
"metadata" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "UsageLog_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS "UsageLog_userId_feature_periodStart_key" ON "UsageLog"("userId", "feature", "periodStart");
|
||||||
|
CREATE INDEX IF NOT EXISTS "UsageLog_userId_periodStart_idx" ON "UsageLog"("userId", "periodStart");
|
||||||
|
CREATE INDEX IF NOT EXISTS "UsageLog_periodStart_idx" ON "UsageLog"("periodStart");
|
||||||
|
|
||||||
|
DO $$ BEGIN
|
||||||
|
ALTER TABLE "UsageLog" ADD CONSTRAINT "UsageLog_userId_fkey"
|
||||||
|
FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN NULL;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "FeatureFlag" (
|
||||||
|
"id" TEXT NOT NULL,
|
||||||
|
"key" TEXT NOT NULL,
|
||||||
|
"enabled" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"tiers" TEXT[],
|
||||||
|
"metadata" TEXT,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "FeatureFlag_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS "FeatureFlag_key_key" ON "FeatureFlag"("key");
|
||||||
|
|
||||||
|
DO $$ BEGIN
|
||||||
|
IF NOT EXISTS (
|
||||||
|
SELECT 1 FROM information_schema.columns
|
||||||
|
WHERE table_name = 'User' AND column_name = 'accentColor'
|
||||||
|
) THEN
|
||||||
|
ALTER TABLE "User" ADD COLUMN "accentColor" TEXT NOT NULL DEFAULT '#A47148';
|
||||||
|
END IF;
|
||||||
|
END $$;
|
||||||
Reference in New Issue
Block a user