diff --git a/package.json b/package.json index 206b8e2..cadf227 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "build": "vite build", "preview": "vite preview", "dev:full": "npm-run-all --parallel dev \"dev --prefix server\"", - "dev:full:bg": "npm-run-all --parallel dev \"dev --prefix server\" &" + "dev:full:bg": "npm-run-all --parallel dev \"dev --prefix server\" &", + "test:full": "npm-run-all --parallel dev \"start:test --prefix server\"", + "prod:full": "npm-run-all --parallel preview \"start:prod --prefix server\"" }, "dependencies": { "@google/genai": "^1.30.0", @@ -29,4 +31,4 @@ "typescript": "~5.8.2", "vite": "^6.2.0" } -} +} \ No newline at end of file diff --git a/server/package-lock.json b/server/package-lock.json index 4db6a61..e373e05 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -26,6 +26,7 @@ "@types/express": "*", "@types/jsonwebtoken": "*", "@types/node": "*", + "cross-env": "^10.1.0", "dotenv-cli": "^11.0.0", "nodemon": "*", "prisma": "^7.1.0", @@ -112,6 +113,13 @@ "@electric-sql/pglite": "0.3.2" } }, + "node_modules/@epic-web/invariant": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz", + "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==", + "dev": true, + "license": "MIT" + }, "node_modules/@google/generative-ai": { "version": "0.24.1", "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz", @@ -1038,6 +1046,24 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "license": "MIT" }, + "node_modules/cross-env": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz", + "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@epic-web/invariant": "^1.0.0", + "cross-spawn": "^7.0.6" + }, + "bin": { + "cross-env": "dist/bin/cross-env.js", + "cross-env-shell": "dist/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", diff --git a/server/package.json b/server/package.json index 93196ff..21aac07 100644 --- a/server/package.json +++ b/server/package.json @@ -4,11 +4,12 @@ "description": "Backend for GymFlow AI", "main": "src/index.ts", "scripts": { - "start": "node dist/index.js", - "dev": "ts-node-dev -r dotenv/config --respawn --transpile-only src/index.ts", + "start": "npm run start:prod", + "start:prod": "cross-env APP_MODE=prod node dist/index.js", + "start:test": "cross-env APP_MODE=test ts-node-dev -r dotenv/config --respawn --transpile-only src/index.ts", + "dev": "cross-env APP_MODE=dev ts-node-dev -r dotenv/config --respawn --transpile-only src/index.ts", "build": "tsc", "migrate:deploy": "npx prisma migrate deploy" - }, "dependencies": { "@google/generative-ai": "^0.24.1", @@ -29,10 +30,11 @@ "@types/express": "*", "@types/jsonwebtoken": "*", "@types/node": "*", + "cross-env": "^10.1.0", "dotenv-cli": "^11.0.0", "nodemon": "*", "prisma": "^7.1.0", "ts-node": "*", "typescript": "*" } -} +} \ No newline at end of file diff --git a/server/prisma.config.js b/server/prisma.config.js new file mode 100644 index 0000000..68efaae --- /dev/null +++ b/server/prisma.config.js @@ -0,0 +1,5 @@ +module.exports = { + datasource: { + url: process.env.DATABASE_URL, + }, +}; diff --git a/server/prisma/dev.db b/server/prisma/dev.db index 34bc2f7..48dc7ec 100644 Binary files a/server/prisma/dev.db and b/server/prisma/dev.db differ diff --git a/server/prisma/prod.db b/server/prisma/prod.db new file mode 100644 index 0000000..48dc7ec Binary files /dev/null and b/server/prisma/prod.db differ diff --git a/server/prisma/test.db b/server/prisma/test.db new file mode 100644 index 0000000..a71ae64 Binary files /dev/null and b/server/prisma/test.db differ diff --git a/server/src/index.ts b/server/src/index.ts index 4f48ef0..25df378 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -23,11 +23,27 @@ const app = express(); // Ensure a default admin user exists on startup // ------------------------------------------------------------------- async function ensureAdminUser() { - const adminEmail = process.env.ADMIN_EMAIL; - const adminPassword = process.env.ADMIN_PASSWORD; + const mode = process.env.APP_MODE || 'dev'; + let adminEmail, adminPassword; + + switch (mode) { + case 'test': + adminEmail = process.env.ADMIN_EMAIL_TEST; + adminPassword = process.env.ADMIN_PASSWORD_TEST; + break; + case 'prod': + adminEmail = process.env.ADMIN_EMAIL_PROD; + adminPassword = process.env.ADMIN_PASSWORD_PROD; + break; + case 'dev': + default: + adminEmail = process.env.ADMIN_EMAIL_DEV; + adminPassword = process.env.ADMIN_PASSWORD_DEV; + break; + } if (!adminEmail || !adminPassword) { - console.warn('⚠️ ADMIN_EMAIL or ADMIN_PASSWORD not set in .env. Skipping default admin creation.'); + console.warn(`⚠️ Admin credentials for mode ${mode} not found in .env. Skipping default admin creation.`); return; } diff --git a/server/src/lib/prisma.ts b/server/src/lib/prisma.ts index 849982e..83d56a0 100644 --- a/server/src/lib/prisma.ts +++ b/server/src/lib/prisma.ts @@ -10,10 +10,32 @@ declare global { var prisma: PrismaClient | undefined; } -const dbUrl = process.env.DATABASE_URL; +const mode = process.env.APP_MODE || 'dev'; +console.log(`[Prisma] Initializing in ${mode.toUpperCase()} mode`); + +let dbUrl: string | undefined; + +switch (mode) { + case 'test': + dbUrl = process.env.DATABASE_URL_TEST; + break; + case 'prod': + dbUrl = process.env.DATABASE_URL_PROD; + break; + case 'dev': + default: + dbUrl = process.env.DATABASE_URL_DEV; + break; +} + +// Fallback to generic DATABASE_URL if specific one is missing +if (!dbUrl) { + console.warn(`[Prisma] DATABASE_URL_${mode.toUpperCase()} not found, falling back to DATABASE_URL`); + dbUrl = process.env.DATABASE_URL; +} if (!dbUrl) { - throw new Error("DATABASE_URL environment variable is not set. Please check your .env file."); + throw new Error(`DATABASE_URL environment variable is not set for mode ${mode}. Please check your .env file.`); } console.log('Initializing Prisma Adapter with URL:', dbUrl); diff --git a/server/src/routes/sessions.ts b/server/src/routes/sessions.ts index 1b9af6e..ac41a07 100644 --- a/server/src/routes/sessions.ts +++ b/server/src/routes/sessions.ts @@ -396,7 +396,7 @@ router.post('/active/log-set', async (req: any, res) => { }); if (plan) { - const planExercises: { id: string }[] = JSON.parse(plan.exercises); + const planExercises: { id: string }[] = JSON.parse(plan.exercises || '[]'); const allPerformedSets = await prisma.workoutSet.findMany({ where: { sessionId: activeSession.id } }); diff --git a/server/test.db b/server/test.db new file mode 100644 index 0000000..48dc7ec Binary files /dev/null and b/server/test.db differ