initial production commit

This commit is contained in:
Fred 2025-07-25 18:07:20 +00:00
parent 6f43d17ddd
commit 773b4773eb
9 changed files with 116 additions and 93 deletions

View file

@ -10,4 +10,4 @@ COPY . .
EXPOSE 3000 EXPOSE 3000
CMD ["npm", "run", "dev"] CMD ["npm", "run", "production"]

View file

@ -1,21 +1,26 @@
const express = require("express"); const express = require("express");
const db = require("./db"); const db = require("./db");
const port = 3000; const port = 3000;
const cors = require('cors') const cors = require("cors");
const app = express(); const app = express();
app.use(cors()); app.use(
cors({
origin: "https://ec683cee72d30c5030.fredzernia.com/",
credentials: true,
}),
);
app.use(express.json()); app.use(express.json());
// ####### ROUTES ####### // ####### ROUTES #######
app.get("/test", async (req, res) => { app.get("/backend/test", async (req, res) => {
console.log('test') console.log("test");
res.json({ test: 'test' }) res.json({ test: "test" });
}); });
// ### GET ALL RECIPES ### // ### GET ALL RECIPES ###
app.get("/recipes", async (req, res) => { app.get("/backend/recipes", async (req, res) => {
try { try {
const recipes = await db('recipes').select('id', 'name', 'cuisine'); const recipes = await db("recipes").select("id", "name", "cuisine");
res.json(recipes); res.json(recipes);
} catch (err) { } catch (err) {
console.log(err); console.log(err);
@ -23,9 +28,9 @@ app.get("/recipes", async (req, res) => {
} }
}); });
// ### GET ALL RECIPE_INGREDIENTS ### // ### GET ALL RECIPE_INGREDIENTS ###
app.get("/recipe-ingredients", async (req, res) => { app.get("/backend/recipe-ingredients", async (req, res) => {
try { try {
const recipe_ingredients = await db('recipe_ingredients').select('*'); const recipe_ingredients = await db("recipe_ingredients").select("*");
res.json(recipe_ingredients); res.json(recipe_ingredients);
} catch (err) { } catch (err) {
console.log(err); console.log(err);
@ -33,9 +38,9 @@ app.get("/recipe-ingredients", async (req, res) => {
} }
}); });
// ### GET ALL RECIPE_STEPS ### // ### GET ALL RECIPE_STEPS ###
app.get("/recipe-steps", async (req, res) => { app.get("/backend/recipe-steps", async (req, res) => {
try { try {
const recipe_steps = await db('recipe_steps').select('*'); const recipe_steps = await db("recipe_steps").select("*");
res.json(recipe_steps); res.json(recipe_steps);
} catch (err) { } catch (err) {
console.log(err); console.log(err);
@ -44,21 +49,32 @@ app.get("/recipe-steps", async (req, res) => {
}); });
// ### GET RECIPE ### // ### GET RECIPE ###
app.get("/recipe/:id", async (req, res) => { app.get("/backend/recipe/:id", async (req, res) => {
const id = req.params.id const id = req.params.id;
try { try {
const recipeQuery = db('recipes').where('id', '=', id).select('id', 'name', 'author', 'cuisine', 'stars'); const recipeQuery = db("recipes")
.where("id", "=", id)
.select("id", "name", "author", "cuisine", "stars");
const ingredientsQuery = db.from('recipe_ingredients').where('recipe_id', '=', id).select('raw'); const ingredientsQuery = db
.from("recipe_ingredients")
.where("recipe_id", "=", id)
.select("raw");
const stepsQuery = db('recipe_steps').where('recipe_id', id).select('step_number', 'instruction'); const stepsQuery = db("recipe_steps")
.where("recipe_id", id)
.select("step_number", "instruction");
const [recipe, ingredients, steps] = await Promise.all([recipeQuery, ingredientsQuery, stepsQuery]); const [recipe, ingredients, steps] = await Promise.all([
recipeQuery,
ingredientsQuery,
stepsQuery,
]);
const result = { const result = {
details: recipe[0], details: recipe[0],
ingredients: ingredients, ingredients: ingredients,
steps: steps steps: steps,
}; };
res.json(result); res.json(result);
@ -69,29 +85,32 @@ app.get("/recipe/:id", async (req, res) => {
}); });
// ### ADD RECIPE ### // ### ADD RECIPE ###
app.post("/add-recipe", async (req, res) => { app.post("/backend/add-recipe", async (req, res) => {
const { name, author, cuisine, stars, ingredients, steps } = req.body; const { name, author, cuisine, stars, ingredients, steps } = req.body;
try { try {
const [id] = await db('recipes').insert({ const [id] = await db("recipes").insert(
name: name, {
author: author, name: name,
cuisine: cuisine, author: author,
stars: stars cuisine: cuisine,
}, ['id']) stars: stars,
},
["id"],
);
const ingredientInserts = ingredients.map(ing => ({ const ingredientInserts = ingredients.map((ing) => ({
recipe_id: id.id, recipe_id: id.id,
raw: ing raw: ing,
})); }));
// //
await db('recipe_ingredients').insert(ingredientInserts); await db("recipe_ingredients").insert(ingredientInserts);
const stepInserts = Object.keys(steps).map(stepNumber => ({ const stepInserts = Object.keys(steps).map((stepNumber) => ({
recipe_id: id.id, recipe_id: id.id,
step_number: parseInt(stepNumber), step_number: parseInt(stepNumber),
instruction: steps[stepNumber] instruction: steps[stepNumber],
})); }));
await db('recipe_steps').insert(stepInserts); await db("recipe_steps").insert(stepInserts);
res.status(200).send({ message: "Recipe added", id: id.id }); res.status(200).send({ message: "Recipe added", id: id.id });
} catch (err) { } catch (err) {
@ -101,13 +120,11 @@ app.post("/add-recipe", async (req, res) => {
}); });
// ### SET STARS ### // ### SET STARS ###
app.post("/set-stars", async (req, res) => { app.post("/backend/set-stars", async (req, res) => {
const { id, stars } = req.body; const { id, stars } = req.body;
try { try {
await db('recipes') await db("recipes").where({ id: id }).update({ stars: stars });
.where({ id: id }) res.status(200).send({ message: "stars updated" });
.update({ stars: stars })
res.status(200).send({ message: "stars updated" })
} catch (err) { } catch (err) {
console.log(err); console.log(err);
res.status(500).json({ error: err.message }); res.status(500).json({ error: err.message });
@ -115,12 +132,12 @@ app.post("/set-stars", async (req, res) => {
}); });
// ### DELETE RECIPE ### // ### DELETE RECIPE ###
app.delete("/delete-recipe", async (req, res) => { app.delete("/backend/delete-recipe", async (req, res) => {
const { id } = req.body; const { id } = req.body;
try { try {
await db('recipe_steps').where({ recipe_id: id }).del(); await db("recipe_steps").where({ recipe_id: id }).del();
await db('recipe_ingredients').where({ recipe_id: id }).del(); await db("recipe_ingredients").where({ recipe_id: id }).del();
await db('recipes').where({ id: id }).del(); await db("recipes").where({ id: id }).del();
res.status(200).send({ message: "Recipe deleted" }); res.status(200).send({ message: "Recipe deleted" });
} catch (err) { } catch (err) {
console.log(err); console.log(err);
@ -130,8 +147,8 @@ app.delete("/delete-recipe", async (req, res) => {
app.listen(port, () => console.log(`Server has started on port: ${port}`)); app.listen(port, () => console.log(`Server has started on port: ${port}`));
process.on('SIGINT', async () => { process.on("SIGINT", async () => {
console.log('Closing database connection...'); console.log("Closing database connection...");
await db.destroy(); await db.destroy();
process.exit(0); process.exit(0);
}); });

View file

@ -1,40 +1,41 @@
require('dotenv').config(); require("dotenv").config();
module.exports = { module.exports = {
development: { development: {
client: 'postgresql', client: "postgresql",
connection: { connection: {
host: 'db', host: "db",
port: 5432, port: process.env.DB_PORT,
database: process.env.DB_NAME, database: process.env.DB_NAME,
user: process.env.DB_USER, user: process.env.DB_USER,
password: process.env.DB_PASSWORD password: process.env.DB_PASSWORD,
}, },
pool: { pool: {
min: 2, min: 2,
max: 10 max: 10,
}, },
migrations: { migrations: {
tableName: 'knex_migrations', tableName: "knex_migrations",
directory: './migrations' directory: "./migrations",
} },
}, },
production: { production: {
client: 'postgresql', client: "postgresql",
connection: { connection: {
database: 'my_db', host: "db",
user: 'username', port: process.env.DB_PORT,
password: 'password' database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
}, },
pool: { pool: {
min: 2, min: 2,
max: 10 max: 10,
}, },
migrations: { migrations: {
tableName: 'knex_migrations' tableName: "knex_migrations",
} directory: "./migrations",
} },
},
}; };

View file

@ -4,7 +4,8 @@
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"dev": "node backendServer.js" "dev": "node backendServer.js",
"production": "node backendServer.js"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",

View file

@ -10,7 +10,7 @@ services:
- POSTGRES_PASSWORD=${DB_PASSWORD} - POSTGRES_PASSWORD=${DB_PASSWORD}
- POSTGRES_DB=${DB_NAME} - POSTGRES_DB=${DB_NAME}
ports: ports:
- "5432:5432" - "${DB_PORT}:5432"
volumes: volumes:
- ./postgres/db:/var/lib/postgresql/data - ./postgres/db:/var/lib/postgresql/data
backend: backend:
@ -22,7 +22,7 @@ services:
volumes: volumes:
- ./backend:/usr/src/app - ./backend:/usr/src/app
environment: environment:
- NODE_ENV=development - NODE_ENV=production
- DB_USER=${DB_USER} - DB_USER=${DB_USER}
- DB_PASSWORD=${DB_PASSWORD} - DB_PASSWORD=${DB_PASSWORD}
- DB_NAME=${DB_NAME} - DB_NAME=${DB_NAME}
@ -31,8 +31,8 @@ services:
container_name: recipes_frontend container_name: recipes_frontend
build: ./frontend build: ./frontend
ports: ports:
- "8080:80" - "8081:80"
volumes: volumes:
- ./frontend:/usr/src/app - ./frontend:/usr/src/app
environment: environment:
- NODE_ENV=development - NODE_ENV=production

View file

@ -10,4 +10,4 @@ COPY . .
EXPOSE 80 EXPOSE 80
CMD ["npm", "run", "dev"] CMD ["npm", "run", "production"]

View file

@ -4,7 +4,8 @@
"version": "0.0.0", "version": "0.0.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --host --port 80", "dev": "vite --host 0.0.0.0 --port 80",
"production": "vite --host 0.0.0.0 --port 80",
"build": "tsc -b && vite build", "build": "tsc -b && vite build",
"lint": "eslint .", "lint": "eslint .",
"preview": "vite preview" "preview": "vite preview"

View file

@ -1,34 +1,34 @@
export const getRecipes = async () => { export const getRecipes = async () => {
const response = await fetch("http://localhost:3000/recipes"); const response = await fetch("/backend/recipes");
const data = await response.json(); const data = await response.json();
return data; return data;
}; };
export const getRecipeSteps = async () => { export const getRecipeSteps = async () => {
const response = await fetch("http://localhost:3000/recipe-steps"); const response = await fetch("/backend/recipe-steps");
const data = await response.json(); const data = await response.json();
return data; return data;
}; };
export const getRecipeIngredients = async () => { export const getRecipeIngredients = async () => {
const response = await fetch("http://localhost:3000/recipe-ingredients"); const response = await fetch("/backend/recipe-ingredients");
const data = await response.json(); const data = await response.json();
return data; return data;
}; };
export const getRecipeById = async (id) => { export const getRecipeById = async (id) => {
const response = await fetch(`http://localhost:3000/recipe/${id}`); const response = await fetch(`/backend/recipe/${id}`);
const data = await response.json(); const data = await response.json();
return data; return data;
}; };
export const addRecipe = async (recipeData) => { export const addRecipe = async (recipeData) => {
console.log(JSON.stringify(recipeData)) console.log(JSON.stringify(recipeData));
// return // return
const response = await fetch("http://localhost:3000/add-recipe", { const response = await fetch("/backend/add-recipe", {
method: 'POST', method: "POST",
headers: { 'Content-Type': 'application/json' }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(recipeData) body: JSON.stringify(recipeData),
}); });
const data = await response.json(); const data = await response.json();
console.log(data); console.log(data);
@ -36,27 +36,26 @@ export const addRecipe = async (recipeData) => {
}; };
export const setDBStars = async (id, stars) => { export const setDBStars = async (id, stars) => {
console.log(JSON.stringify({ id: id, stars: stars })) console.log(JSON.stringify({ id: id, stars: stars }));
// return // return
const response = await fetch("http://localhost:3000/set-stars", { const response = await fetch("/backend/set-stars", {
method: 'POST', method: "POST",
headers: { 'Content-Type': 'application/json' }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: id, stars: stars }) body: JSON.stringify({ id: id, stars: stars }),
}); });
const data = await response.json(); const data = await response.json();
console.log(data); console.log(data);
return data; return data;
} };
export const deleteRecipe = async (id) => { export const deleteRecipe = async (id) => {
console.log(id) console.log(id);
// return // return
const response = await fetch("http://localhost:3000/delete-recipe", { const response = await fetch("/backend/delete-recipe", {
method: 'DELETE', method: "DELETE",
headers: { 'Content-Type': 'application/json' }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id }) body: JSON.stringify({ id }),
}); });
const data = await response.json(); const data = await response.json();
return data; return data;
}; };

View file

@ -1,7 +1,11 @@
import { defineConfig } from 'vite' import { defineConfig } from "vite";
import react from '@vitejs/plugin-react' import react from "@vitejs/plugin-react";
// https://vite.dev/config/ // https://vite.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react()],
}) server: {
host: "ec683cee72d30c5030.fredzernia.com",
allowedHosts: ["ec683cee72d30c5030.fredzernia.com"],
},
});