Switch database from SQLite to PostgreSQL

Replace in-memory JSON file storage with Prisma ORM using PostgreSQL.
Update environment variables and Prisma schema accordingly.
This commit is contained in:
2026-05-19 14:19:01 +02:00
parent 06ab791755
commit 45cf61525e
10 changed files with 79 additions and 60 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ export async function POST(request: Request) {
.filter((product): product is Product => Boolean(product))
.map((product) => setupVerification[product.id])
.filter(Boolean);
const prefs = store.preferences();
const prefs = await store.preferences();
const prompt = [
"You are a professional mountain bike suspension and tire setup tuner.",
"Combine manufacturer setup ranges, community setup patterns, and the rider's past preferences.",
+2 -2
View File
@@ -21,7 +21,7 @@ const schema = z.object({
});
export async function GET() {
return NextResponse.json(store.listBuilds());
return NextResponse.json(await store.listBuilds());
}
export async function POST(request: Request) {
@@ -35,7 +35,7 @@ export async function POST(request: Request) {
rearTireId: body.rearTireId,
};
const setup = { ...buildSetupDefaults(selection, body.rider), ...body.setup };
const build = store.createBuild({
const build = await store.createBuild({
name: body.name,
riderWeightKg: body.rider.weight,
discipline: body.rider.discipline,
+1 -1
View File
@@ -19,6 +19,6 @@ const schema = z.object({
export async function POST(request: Request) {
const body = schema.parse(await request.json());
const review = store.createReview(body);
const review = await store.createReview(body);
return NextResponse.json(review, { status: 201 });
}
+31 -53
View File
@@ -1,58 +1,36 @@
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
import path from "node:path";
import { prisma } from "./prisma";
type Database = {
builds: any[];
reviews: any[];
};
const dbPath = path.join(process.cwd(), "data", "bike-app.json");
function readDb(): Database {
mkdirSync(path.dirname(dbPath), { recursive: true });
try {
return JSON.parse(readFileSync(dbPath, "utf8")) as Database;
} catch {
return { builds: [], reviews: [] };
}
}
function writeDb(data: Database) {
mkdirSync(path.dirname(dbPath), { recursive: true });
writeFileSync(dbPath, JSON.stringify(data, null, 2));
function parseSetup(build: any) {
return {
...build,
setup: build.setup ? JSON.parse(build.setup) : {},
};
}
export const store = {
listBuilds() {
return readDb().builds.sort((a, b) => String(b.createdAt).localeCompare(String(a.createdAt)));
},
createBuild(input: any) {
const data = readDb();
const build = {
id: crypto.randomUUID(),
...input,
createdAt: new Date().toISOString(),
};
data.builds.unshift(build);
writeDb(data);
return build;
},
createReview(input: any) {
const data = readDb();
const review = {
id: crypto.randomUUID(),
...input,
createdAt: new Date().toISOString(),
};
data.reviews.unshift(review);
writeDb(data);
return review;
},
preferences() {
const reviews = readDb().reviews;
return {
harshTendency: reviews.filter((review) => review.suspFeel >= 7).length,
softTendency: reviews.filter((review) => review.suspFeel <= 3).length,
};
},
async listBuilds() {
const builds = await prisma.bikeBuild.findMany({
orderBy: { createdAt: "desc" },
});
return builds.map(parseSetup);
},
async createBuild(input: any) {
const build = await prisma.bikeBuild.create({
data: {
...input,
setup: JSON.stringify(input.setup ?? {}),
},
});
return parseSetup(build);
},
async createReview(input: any) {
return prisma.rideReview.create({ data: input });
},
async preferences() {
const reviews = await prisma.rideReview.findMany();
return {
harshTendency: reviews.filter((review) => review.suspFeel >= 7).length,
softTendency: reviews.filter((review) => review.suspFeel <= 3).length,
};
},
};
+7
View File
@@ -0,0 +1,7 @@
import { PrismaClient } from "@prisma/client";
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;