z1 docker app

This commit is contained in:
Ferko 2026-04-08 21:35:23 +02:00
commit 9fb1ac67af
10 changed files with 314 additions and 0 deletions

42
README.md Normal file
View File

@ -0,0 +1,42 @@
# TODO Docker aplikacia
## Podmienky
- Linux
- Docker
- Docker Compose
## Opis aplikacie
Jednoducha TODO aplikacia, kde moze pouzivatel:
- pridavat ulohy
- upravovat ich
- mazat ich
- nastavovat datum a cas
## Sluzby
- frontend: nginx (port 8080)
- backend: Node.js (port 3000)
- databaza: MongoDB
## Siet a volume
- siet: app_network
- volume: mongo_data (uchovanie dat)
## Spustenie
- Priprava:
./prepare-app.sh
- Spustenie:
.start-app.sh
- Aplikacia:
http://localhost:8080
- Zastavenie:
./stop-app.sh
- Odstranenie:
./remove-app.sh

9
backend/Dockerfile Normal file
View File

@ -0,0 +1,9 @@
FROM node:18
WORKDIR /app
COPY server.js .
RUN npm init -y && npm install express mongoose cors
CMD ["node", "server.js"]

50
backend/server.js Normal file
View File

@ -0,0 +1,50 @@
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const app = express();
app.use(express.json());
app.use(cors());
mongoose.connect('mongodb://db:27017/todo');
const Task = mongoose.model('Task', {
text: String,
due: String
});
// GET
app.get('/tasks', async (req, res) => {
const tasks = await Task.find();
res.json(tasks);
});
// POST
app.post('/tasks', async (req, res) => {
const task = new Task({
text: req.body.text,
due: req.body.due
});
await task.save();
res.send("ok");
});
// DELETE
app.delete('/tasks/:id', async (req, res) => {
await Task.findByIdAndDelete(req.params.id);
res.send("deleted");
});
// UPDATE
app.put('/tasks/:id', async (req, res) => {
await Task.findByIdAndUpdate(req.params.id, {
text: req.body.text,
due: req.body.due
});
res.send("updated");
});
app.listen(3000, () => {
console.log("Backend bezi na porte 3000");
});

36
docker-compose.yaml Normal file
View File

@ -0,0 +1,36 @@
services:
frontend:
image: nginx:latest
restart: always
ports:
- "8080:80"
volumes:
- ./frontend:/usr/share/nginx/html
depends_on:
- backend
networks:
- app_network
backend:
build: ./backend
restart: always
ports:
- "3000:3000"
depends_on:
- db
networks:
- app_network
db:
image: mongo:latest
restart: always
volumes:
- mongo_data:/data/db
networks:
- app_network
volumes:
mongo_data:
networks:
app_network:

86
frontend/index.html Normal file
View File

@ -0,0 +1,86 @@
<!DOCTYPE html>
<html>
<head>
<title>TODO App</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>TODO List</h1>
<input id="task" placeholder="napis ulohu">
<input id="due" type="datetime-local">
<button onclick="addTask()">Pridaj</button>
<div id="list"></div>
</div>
<script>
async function loadTasks() {
const res = await fetch('http://localhost:3000/tasks');
const data = await res.json();
const list = document.getElementById('list');
list.innerHTML = "";
data.forEach(t => {
const li = document.createElement('div');
li.className = "task";
li.innerHTML = `
<span>
${t.text} |
${t.due ? t.due.split('T')[0] : ""} |
${t.due ? t.due.split('T')[1] : ""}
</span>
<div class="buttons">
<button class="delete" onclick="deleteTask('${t._id}')">X</button>
<button class="edit" onclick="editTask('${t._id}', '${t.text}', '${t.due}')">Edit</button>
</div>
`;
list.appendChild(li);
});
}
async function addTask() {
const text = document.getElementById('task').value;
const due = document.getElementById('due').value;
await fetch('http://localhost:3000/tasks', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({text, due})
});
document.getElementById('task').value = "";
document.getElementById('due').value = "";
loadTasks();
}
async function deleteTask(id) {
await fetch(`http://localhost:3000/tasks/${id}`, {
method: 'DELETE'
});
loadTasks();
}
async function editTask(id, oldText, oldDue) {
const text = prompt("novy text:", oldText);
const due = prompt("novy datum:", oldDue);
await fetch(`http://localhost:3000/tasks/${id}`, {
method: 'PUT',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({text, due})
});
loadTasks();
}
loadTasks();
</script>
</body>
</html>

65
frontend/style.css Normal file
View File

@ -0,0 +1,65 @@
body {
font-family: Arial;
background: #f4f6f8;
margin: 0;
padding: 0;
}
.container {
background: white;
padding: 20px;
border-radius: 10px;
width: 400px;
margin: 50px auto; /* vycentrovanie */
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
h1 {
text-align: center; /* nadpis na stred */
}
input {
padding: 8px;
margin: 5px 0;
width: 100%;
box-sizing: border-box;
}
button {
padding: 8px;
margin-top: 5px;
cursor: pointer;
width: 100%;
}
#list {
margin-top: 15px;
}
.task {
display: flex;
justify-content: space-between;
align-items: center;
background: #eee;
padding: 8px;
margin-top: 5px;
border-radius: 5px;
}
.task span {
text-align: left; /* zarovnanie dolava */
}
.buttons button {
margin-left: 5px;
}
.delete {
background: red;
color: white;
}
.edit {
background: orange;
color: white;
}

7
prepare-app.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
echo "Preparing app..."
docker network create app_network || true
docker volume create mongo_data || true
docker compose build

9
remove-app.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/bash
echo "Removing app..."
docker compose down -v
docker volume rm mongo_data || true
docker network rm app_network || true
echo "Removed app."

6
start-app.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash
echo "Running app..."
docker compose up -d
echo "App bezi na: http://localhost:8080"

4
stop-app.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
echo "Stopping app..."
docker compose down