- Create proxy.ts at repo root with clerkMiddleware + createRouteMatcher (public allowlist: sign-up, log-in, forgot-password, reset-password, verify-email) - Create prisma/schema.prisma: Owner, Species, Breed, Pet models with ownership index and FK constraints - Create prisma.config.ts with Prisma 7 defineConfig (datasource url via env) - Create src/lib/prisma.ts: Prisma 7 singleton using @prisma/adapter-pg for local dev, withAccelerate() for Prisma Accelerate on Vercel - Create src/lib/r2.ts (server-only): S3Client + getPresignedUploadUrl with contentType enforcement and 300s expiry - Create src/lib/auth.ts: getOwnerId() Clerk auth wrapper - Create src/trpc/init.ts: createTRPCContext, router, publicProcedure, protectedProcedure (throws UNAUTHORIZED) - Create src/trpc/routers/pets.ts: pets.create (upserts Owner, creates Pet with ownerId=ctx.userId), pets.list (scoped), pets.byId (ownership-asserted) - Create src/trpc/routers/_app.ts: appRouter + AppRouter type export - Create src/trpc/query-client.ts, server.ts (RSC caller), client.tsx (TRPCReactProvider + useTRPC) - Create src/app/api/trpc/[trpc]/route.ts: tRPC fetch handler (GET + POST) - Create src/context/ActivePetContext.tsx + src/hooks/useActivePet.ts: localStorage-backed active pet context - Create prisma/seed.ts: seeds Dog/Cat/Bird species idempotently via upsert - Update src/app/layout.tsx: wrap children in ClerkProvider (orange primary), TRPCReactProvider, ActivePetProvider, Toaster - Install @prisma/adapter-pg + pg for Prisma 7 local dev (Rule 2: required for Prisma 7 engine compatibility) - [Rule 1 - Bug] Prisma 7 no longer supports url/directUrl in schema.prisma; moved to prisma.config.ts with defineConfig
49 lines
1.1 KiB
Plaintext
49 lines
1.1 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
}
|
|
|
|
model Owner {
|
|
id String @id // = Clerk userId (e.g. "user_xxx")
|
|
createdAt DateTime @default(now())
|
|
pets Pet[]
|
|
}
|
|
|
|
model Species {
|
|
id String @id @default(cuid())
|
|
name String @unique // "Dog" | "Cat" | "Bird"
|
|
breeds Breed[]
|
|
pets Pet[]
|
|
}
|
|
|
|
model Breed {
|
|
id String @id @default(cuid())
|
|
name String
|
|
species Species @relation(fields: [speciesId], references: [id])
|
|
speciesId String
|
|
pets Pet[]
|
|
|
|
@@unique([speciesId, name])
|
|
}
|
|
|
|
model Pet {
|
|
id String @id @default(cuid())
|
|
owner Owner @relation(fields: [ownerId], references: [id])
|
|
ownerId String
|
|
species Species @relation(fields: [speciesId], references: [id])
|
|
speciesId String
|
|
breed Breed? @relation(fields: [breedId], references: [id])
|
|
breedId String?
|
|
name String
|
|
bio String?
|
|
adoptionStory String?
|
|
avatarKey String? // R2 object key, NOT a full URL
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([ownerId])
|
|
}
|