diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..3b1994d41 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +mysql-db diff --git a/backend/Dockerfile b/backend/Dockerfile index 27fa08543..1f6d72554 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,20 +1,15 @@ -# Use the official Node.js 20 image as the base image -FROM node:20 +FROM node -# Set the working directory in the container WORKDIR /app -# Copy the package.json and package-lock.json files to the container COPY package*.json ./ -# Install the dependencies RUN npm install -# Copy the rest of the application's source code to the container COPY . . -# Expose the port that the application listens on EXPOSE 3000 -# Start the Node.js application -CMD [ "npm", "start" ] +CMD ["npm", "start"] + + diff --git a/backend/server.js b/backend/server.js index 15838d139..8f2e258da 100644 --- a/backend/server.js +++ b/backend/server.js @@ -1,63 +1,69 @@ const express = require("express"); const mysql = require("mysql2"); -var cors = require("cors"); +const cors = require("cors"); const bodyParser = require("body-parser"); -// Create the Express app const app = express(); app.use(cors()); app.use(bodyParser.json()); -// Create a connection to the MySQL database +// MySQL connection config const mysqlConfig = { - host: process.env.DB_HOST || "db", + host: process.env.DB_HOST || "mysql", port: process.env.DB_PORT || "3306", user: process.env.DB_USER || "root", password: process.env.DB_PASSWORD || "pass123", database: process.env.DB_NAME || "appdb", }; -let con = null; -const databaseInit = () => { +let con; + +// Try connecting with retry logic (useful when DB takes time to start) +const connectWithRetry = (attempt = 1) => { + console.log(`Attempting to connect to DB... (try ${attempt})`); con = mysql.createConnection(mysqlConfig); + con.connect((err) => { if (err) { - console.error("Error connecting to the database: ", err); - return; + console.error("❌ DB connection failed:", err.message); + // Try again after 3 seconds + setTimeout(() => connectWithRetry(attempt + 1), 3000); + } else { + console.log("✅ Connected to MySQL database"); + initDatabase(); // Create DB and table if missing } - console.log("Connected to the database"); }); }; -const createDatabase = () => { - con.query("CREATE DATABASE IF NOT EXISTS appdb", (err, results) => { - if (err) { - console.error(err); - return; - } - console.log("Database created successfully"); - }); -}; +// Initialize DB and table +const initDatabase = () => { + con.query("CREATE DATABASE IF NOT EXISTS appdb", (err) => { + if (err) return console.error("Error creating DB:", err.message); + console.log("✅ Database ensured"); -const createTable = () => { - con.query( - "CREATE TABLE IF NOT EXISTS apptb (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255))", - (err, results) => { - if (err) { - console.error(err); - return; - } - console.log("Table created successfully"); - } - ); + // Switch to database + con.changeUser({ database: "appdb" }, (err) => { + if (err) return console.error("Error switching DB:", err.message); + + con.query( + `CREATE TABLE IF NOT EXISTS apptb ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) + )`, + (err) => { + if (err) console.error("Error creating table:", err.message); + else console.log("✅ Table ensured"); + } + ); + }); + }); }; -// GET request +// Routes app.get("/user", (req, res) => { - databaseInit(); con.query("SELECT * FROM apptb", (err, results) => { if (err) { - console.error(err); + console.error("Error fetching data:", err); res.status(500).send("Error retrieving data from database"); } else { res.json(results); @@ -65,35 +71,21 @@ app.get("/user", (req, res) => { }); }); -// POST request app.post("/user", (req, res) => { - con.query( - "INSERT INTO apptb (name) VALUES (?)", - [req.body.data], - (err, results) => { - if (err) { - console.error(err); - res.status(500).send("Error retrieving data from database"); - } else { - res.json(results); - } + const { data } = req.body; + con.query("INSERT INTO apptb (name) VALUES (?)", [data], (err, results) => { + if (err) { + console.error("Error inserting data:", err); + res.status(500).send("Error inserting data"); + } else { + res.json(results); } - ); -}); - -app.post("/dbinit", (req, res) => { - databaseInit(); - createDatabase(); - res.json("Database created successfully"); -}); - -app.post("/tbinit", (req, res) => { - databaseInit(); - createTable(); - res.json("Table created successfully"); + }); }); -// Start the server +// Start server app.listen(3000, () => { - console.log("Server running on port 3000"); + console.log("🚀 Server running on port 3000"); + connectWithRetry(); // Start DB connection with retry logic }); + diff --git a/docker-compose.yml b/docker-compose.yml index 4ba4e2ba2..0732f6886 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,41 +1,47 @@ version: "3.8" services: - db: # Defines the 'db' service for MySQL database - image: mysql:8.0 # Uses the MySQL 8.0 Docker image - environment: # Sets environment variables for the database configuration - - MYSQL_DATABASE=appdb # Specifies the name of the database - - MYSQL_PASSWORD=pass123 # Sets the password for the MySQL user - - MYSQL_ROOT_PASSWORD=pass123 # Sets the root password for MySQL + mysql: + restart: always + image: mysql + environment: + - MYSQL_DATABASE=appdb + - MYSQL_PASSWORD=pass123 + - MYSQL_ROOT_PASSWORD=pass123 networks: - - sameNetworkAsMysql # Connects the service to the 'sameNetworkAsMysql' network - ports: - - 3307:3306 # Maps the container's port 3306 to the host's port 3307 + - project-net volumes: - - ./script.sql:/docker-entrypoint-initdb.d/script.sql + - ./mysql-db:/var/lib/mysql + healthcheck: + test: ["CMD-SHELL", "mysqladmin ping -h localhost -uroot -ppass123 || exit 1"] + interval: 10s + retries: 5 + start_period: 30s - api: # Defines the 'api' service for the backend API - build: # Builds the backend API using the provided Dockerfile - context: ./backend # Specifies the build context directory for the backend - dockerfile: Dockerfile # Specifies the Dockerfile to use for building the backend + backend: + build: + context: ./backend ports: - - 3000:3000 # Maps the container's port 3000 to the host's port 3000 + - "3000:3000" networks: - - sameNetworkAsMysql # Connects the service to the 'sameNetworkAsMysql' network + - project-net depends_on: - - db # Specifies that the 'api' service depends on the 'db' service + mysql: + condition: service_healthy - frontend: # Defines the 'frontend' service for the frontend app - restart: on-failure # Restarts the container if it fails - build: # Builds the frontend app using the provided Dockerfile - context: ./frontend # Specifies the build context directory for the frontend + frontend: + restart: on-failure + build: + context: ./frontend ports: - - 3001:3000 # Maps the container's port 3000 to the host's port 3001 + - "3001:3000" networks: - - sameNetworkAsMysql # Connects the service to the 'sameNetworkAsMysql' network + - project-net depends_on: - - api # Specifies that the 'frontend' service depends on the 'api' service + - backend + networks: - sameNetworkAsMysql: # Defines the 'sameNetworkAsMysql' network - driver: bridge # Specifies the network driver as 'bridge' + project-net: +volumes: + mysql-db: diff --git a/frontend/Dockerfile b/frontend/Dockerfile index cc7f38da2..e25e05506 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,23 +1,15 @@ -# Use the official Node.js 20 image as the base image -FROM node:20 +FROM node -# Set the working directory in the container WORKDIR /app -# Copy the package.json and package-lock.json files to the container COPY package*.json ./ -# Install the dependencies RUN npm install -# Copy the rest of the application's source code to the container -COPY . . +COPY . . -# Build the React.js application RUN npm run build -# Expose the port that the application listens on EXPOSE 3001 -# Start a simple web server to serve the built React.js files CMD [ "npx", "serve", "-s", "build" ]