add datasiswa-app project for gitops
This commit is contained in:
commit
e8393f7e03
|
|
@ -0,0 +1,34 @@
|
|||
# === Node modules ===
|
||||
node_modules/
|
||||
backend/node_modules/
|
||||
frontend/node_modules/
|
||||
|
||||
# === Logs ===
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# === Environment files ===
|
||||
.env
|
||||
.env.local
|
||||
.env.development
|
||||
.env.production
|
||||
.env.test
|
||||
|
||||
# === Build output ===
|
||||
frontend/build/
|
||||
frontend/dist/
|
||||
backend/dist/
|
||||
|
||||
# === Dependency locks (optional) ===
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
# === System files ===
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# === Docker artifacts ===
|
||||
*.pid
|
||||
*.tar
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
stages:
|
||||
- build
|
||||
- push
|
||||
- deploy
|
||||
|
||||
variables:
|
||||
DOCKER_DRIVER: overlay2
|
||||
DOCKER_IMAGE_BACKEND: $CI_REGISTRY/$CI_PROJECT_PATH/backend
|
||||
DOCKER_IMAGE_FRONTEND: $CI_REGISTRY/$CI_PROJECT_PATH/frontend
|
||||
GITOPS_REPO: "https://gitlab.com/mauuldya/datasiswa-workflow/datasiswa-gitops.git"
|
||||
|
||||
# ==========================================
|
||||
# 🔧 BEFORE SCRIPT (GLOBAL)
|
||||
# ==========================================
|
||||
before_script:
|
||||
- echo "🔑 Logging in to GitLab Container Registry..."
|
||||
- echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER $CI_REGISTRY --password-stdin
|
||||
|
||||
# ==========================================
|
||||
# 🔹 BUILD BACKEND IMAGE
|
||||
# ==========================================
|
||||
build_backend:
|
||||
stage: build
|
||||
image: docker:latest
|
||||
services:
|
||||
- docker:dind
|
||||
script:
|
||||
- echo "🔧 Building backend image..."
|
||||
- docker build -t "$DOCKER_IMAGE_BACKEND:latest" -t "$DOCKER_IMAGE_BACKEND:$CI_COMMIT_SHORT_SHA" ./backend
|
||||
only:
|
||||
- main
|
||||
|
||||
# ==========================================
|
||||
# 🔹 BUILD FRONTEND IMAGE
|
||||
# ==========================================
|
||||
build_frontend:
|
||||
stage: build
|
||||
image: docker:latest
|
||||
services:
|
||||
- docker:dind
|
||||
script:
|
||||
- echo "🔧 Building frontend image..."
|
||||
- docker build -t "$DOCKER_IMAGE_FRONTEND:latest" -t "$DOCKER_IMAGE_FRONTEND:$CI_COMMIT_SHORT_SHA" ./frontend
|
||||
only:
|
||||
- main
|
||||
|
||||
# ==========================================
|
||||
# 🔹 PUSH BOTH IMAGES
|
||||
# ==========================================
|
||||
push_images:
|
||||
stage: push
|
||||
image: docker:latest
|
||||
services:
|
||||
- docker:dind
|
||||
needs:
|
||||
- build_backend
|
||||
- build_frontend
|
||||
script:
|
||||
- echo "🚀 Pushing both images to GitLab Registry..."
|
||||
- docker push "$DOCKER_IMAGE_BACKEND:latest"
|
||||
- docker push "$DOCKER_IMAGE_BACKEND:$CI_COMMIT_SHORT_SHA"
|
||||
- docker push "$DOCKER_IMAGE_FRONTEND:latest"
|
||||
- docker push "$DOCKER_IMAGE_FRONTEND:$CI_COMMIT_SHORT_SHA"
|
||||
only:
|
||||
- main
|
||||
|
||||
# ==========================================
|
||||
# 🔹 DEPLOY TO DEV (GitOps)
|
||||
# ==========================================
|
||||
deploy_dev:
|
||||
stage: deploy
|
||||
image: alpine:3.19
|
||||
needs: [push_images]
|
||||
variables:
|
||||
KUSTOMIZE_PATH: "k8s/overlays/dev"
|
||||
before_script:
|
||||
- apk add --no-cache git bash sed
|
||||
- git config --global user.email "gitlab-ci@example.com"
|
||||
- git config --global user.name "GitLab CI Bot"
|
||||
script:
|
||||
- echo "📦 Cloning GitOps repo..."
|
||||
- git clone "https://$GITOPS_USERNAME:$GITOPS_TOKEN@gitlab.com/mauuldya/datasiswa-workflow/datasiswa-gitops.git"
|
||||
- cd datasiswa-gitops
|
||||
- echo "🛠 Updating DEV image tags..."
|
||||
- sed -i "s|registry.gitlab.com/.*/backend:.*|$DOCKER_IMAGE_BACKEND:$CI_COMMIT_SHORT_SHA|g" "$KUSTOMIZE_PATH/patch-deployment.yaml"
|
||||
- sed -i "s|registry.gitlab.com/.*/frontend:.*|$DOCKER_IMAGE_FRONTEND:$CI_COMMIT_SHORT_SHA|g" "$KUSTOMIZE_PATH/patch-deployment.yaml"
|
||||
- git add .
|
||||
- git commit -m "🔄 Update DEV images to $CI_COMMIT_SHORT_SHA [skip ci]" || echo "⚠️ No changes to commit"
|
||||
- git push "https://$GITOPS_USERNAME:$GITOPS_TOKEN@gitlab.com/mauuldya/datasiswa-workflow/datasiswa-gitops.git" dev
|
||||
environment:
|
||||
name: dev
|
||||
only:
|
||||
- main
|
||||
|
||||
# ==========================================
|
||||
# 🔹 DEPLOY TO STAGING
|
||||
# ==========================================
|
||||
deploy_staging:
|
||||
stage: deploy
|
||||
image: alpine:3.19
|
||||
variables:
|
||||
KUSTOMIZE_PATH: "k8s/overlays/staging"
|
||||
before_script:
|
||||
- apk add --no-cache git bash sed
|
||||
- git config --global user.email "gitlab-ci@example.com"
|
||||
- git config --global user.name "GitLab CI Bot"
|
||||
script:
|
||||
- echo "📦 Cloning GitOps repo..."
|
||||
- git clone "https://$GITOPS_USERNAME:$GITOPS_TOKEN@gitlab.com/mauuldya/datasiswa-workflow/datasiswa-gitops.git"
|
||||
- cd datasiswa-gitops
|
||||
- echo "🛠 Updating STAGING image tags..."
|
||||
- sed -i "s|registry.gitlab.com/.*/backend:.*|$DOCKER_IMAGE_BACKEND:$CI_COMMIT_SHORT_SHA|g" "$KUSTOMIZE_PATH/patch-deployment.yaml"
|
||||
- sed -i "s|registry.gitlab.com/.*/frontend:.*|$DOCKER_IMAGE_FRONTEND:$CI_COMMIT_SHORT_SHA|g" "$KUSTOMIZE_PATH/patch-deployment.yaml"
|
||||
- git add .
|
||||
- git commit -m "🔄 Update STAGING images to $CI_COMMIT_SHORT_SHA [skip ci]" || echo "⚠️ No changes to commit"
|
||||
- git push "https://$GITOPS_USERNAME:$GITOPS_TOKEN@gitlab.com/mauuldya/datasiswa-workflow/datasiswa-gitops.git" staging
|
||||
environment:
|
||||
name: staging
|
||||
only:
|
||||
- staging
|
||||
|
||||
# ==========================================
|
||||
# 🔹 DEPLOY TO PRODUCTION
|
||||
# ==========================================
|
||||
deploy_production:
|
||||
stage: deploy
|
||||
image: alpine:3.19
|
||||
variables:
|
||||
KUSTOMIZE_PATH: "k8s/overlays/production"
|
||||
before_script:
|
||||
- apk add --no-cache git bash sed
|
||||
- git config --global user.email "gitlab-ci@example.com"
|
||||
- git config --global user.name "GitLab CI Bot"
|
||||
script:
|
||||
- echo "📦 Cloning GitOps repo..."
|
||||
- git clone "https://$GITOPS_USERNAME:$GITOPS_TOKEN@gitlab.com/mauuldya/datasiswa-workflow/datasiswa-gitops.git"
|
||||
- cd datasiswa-gitops
|
||||
- echo "🛠 Updating PRODUCTION image tags..."
|
||||
- sed -i "s|registry.gitlab.com/.*/backend:.*|$DOCKER_IMAGE_BACKEND:$CI_COMMIT_SHORT_SHA|g" "$KUSTOMIZE_PATH/patch-deployment.yaml"
|
||||
- sed -i "s|registry.gitlab.com/.*/frontend:.*|$DOCKER_IMAGE_FRONTEND:$CI_COMMIT_SHORT_SHA|g" "$KUSTOMIZE_PATH/patch-deployment.yaml"
|
||||
- git add .
|
||||
- git commit -m "🚀 Deploy PRODUCTION $CI_COMMIT_SHORT_SHA [skip ci]" || echo "⚠️ No changes to commit"
|
||||
- git push "https://$GITOPS_USERNAME:$GITOPS_TOKEN@gitlab.com/mauuldya/datasiswa-workflow/datasiswa-gitops.git" main
|
||||
environment:
|
||||
name: production
|
||||
only:
|
||||
- production
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
FROM node:18
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
|
||||
# 🔒 Ganti kepemilikan direktori ke user "node" bawaan image
|
||||
RUN chown -R node:node /app
|
||||
|
||||
# 🔒 Jalankan container dengan user non-root
|
||||
USER node
|
||||
|
||||
EXPOSE 5000
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
const mysql = require("mysql2");
|
||||
|
||||
const db = mysql.createConnection({
|
||||
host: process.env.DB_HOST || "mysql-app-syifa",
|
||||
user: process.env.DB_USER || "root",
|
||||
password: process.env.DB_PASSWORD || "",
|
||||
database: process.env.DB_NAME || "datasiswa",
|
||||
});
|
||||
|
||||
db.connect((err) => {
|
||||
if (err) {
|
||||
console.error("❌ Database connection failed:", err);
|
||||
} else {
|
||||
console.log("✅ Connected to MySQL database");
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = db;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "backend",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bcryptjs": "^3.0.2",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.1.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mysql2": "^3.15.1"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const bcrypt = require("bcryptjs");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const db = require("../db");
|
||||
|
||||
// Register
|
||||
router.post("/register", (req, res) => {
|
||||
const { nama, email, password } = req.body;
|
||||
const hashedPassword = bcrypt.hashSync(password, 8);
|
||||
|
||||
db.query(
|
||||
"INSERT INTO users (nama, email, password) VALUES (?, ?, ?)",
|
||||
[nama, email, hashedPassword],
|
||||
(err, result) => {
|
||||
if (err) return res.status(500).json(err);
|
||||
res.json({ message: "User registered!" });
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Login
|
||||
router.post("/login", (req, res) => {
|
||||
const { email, password } = req.body;
|
||||
|
||||
db.query("SELECT * FROM users WHERE email = ?", [email], (err, result) => {
|
||||
if (err) return res.status(500).json(err);
|
||||
if (result.length === 0) return res.status(404).json({ message: "User not found" });
|
||||
|
||||
const user = result[0];
|
||||
const valid = bcrypt.compareSync(password, user.password);
|
||||
if (!valid) return res.status(401).json({ message: "Invalid password" });
|
||||
|
||||
const token = jwt.sign({ id: user.id, email: user.email }, "SECRET_KEY", { expiresIn: "1h" });
|
||||
res.json({ message: "Login success", token, user });
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const db = require("../db");
|
||||
|
||||
// Get semua siswa
|
||||
router.get("/", (req, res) => {
|
||||
db.query("SELECT * FROM siswa", (err, result) => {
|
||||
if (err) return res.status(500).json({ message: err.message });
|
||||
res.json(result); // data array
|
||||
});
|
||||
});
|
||||
|
||||
// Tambah siswa
|
||||
router.post("/add", (req, res) => {
|
||||
const { nama, kelas, umur } = req.body;
|
||||
|
||||
if (!nama || !kelas || !umur) {
|
||||
return res.status(400).json({ message: "Semua field wajib diisi" });
|
||||
}
|
||||
|
||||
db.query(
|
||||
"INSERT INTO siswa (nama, kelas, umur) VALUES (?, ?, ?)",
|
||||
[nama, kelas, umur],
|
||||
(err, result) => {
|
||||
if (err) return res.status(500).json({ message: err.message });
|
||||
res.json({ message: "Siswa berhasil ditambahkan!", id: result.insertId });
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Hapus siswa berdasarkan ID
|
||||
router.delete("/delete/:id", (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
db.query("DELETE FROM siswa WHERE id = ?", [id], (err, result) => {
|
||||
if (err) return res.status(500).json({ message: err.message });
|
||||
if (result.affectedRows === 0)
|
||||
return res.status(404).json({ message: "Siswa tidak ditemukan" });
|
||||
|
||||
res.json({ message: "Siswa berhasil dihapus!" });
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
const express = require("express");
|
||||
const cors = require("cors");
|
||||
const authRoutes = require("./routes/auth");
|
||||
const siswaRoutes = require("./routes/siswa");
|
||||
|
||||
const app = express();
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
// Health check endpoint
|
||||
app.get("/api/health", (req, res) => {
|
||||
res.status(200).json({ status: "OK" });
|
||||
});
|
||||
|
||||
// Routes
|
||||
app.use("/api/auth", authRoutes);
|
||||
app.use("/api/siswa", siswaRoutes);
|
||||
app.use("/api/siswa/add", siswaRoutes);
|
||||
app.use("/api/siswa/delete", siswaRoutes);
|
||||
|
||||
const PORT = 5000;
|
||||
app.listen(PORT, "0.0.0.0", () => console.log(`🚀 Server running on http://localhost:${PORT}`));
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
host: "localhost",
|
||||
user: "root", // user MySQL kamu
|
||||
password: "", // password MySQL kamu
|
||||
database: "datasiswa" // nama database kamu
|
||||
};
|
||||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 9729b56c157549586f396d49bdc48b1e436d1841
|
||||
Loading…
Reference in New Issue