diff --git a/sk1/.env.example b/sk1/.env.example new file mode 100644 index 0000000..4295075 --- /dev/null +++ b/sk1/.env.example @@ -0,0 +1 @@ +POSTGRES_PASSWORD=changeme diff --git a/sk1/.gitignore b/sk1/.gitignore new file mode 100644 index 0000000..6ed48a9 --- /dev/null +++ b/sk1/.gitignore @@ -0,0 +1,2 @@ +.env +node_modules diff --git a/sk1/backend/Dockerfile b/sk1/backend/Dockerfile new file mode 100644 index 0000000..5c99f6f --- /dev/null +++ b/sk1/backend/Dockerfile @@ -0,0 +1,13 @@ +FROM node:20 + +WORKDIR /app + +COPY package.json . + +RUN npm install + +COPY . . + +EXPOSE 5000 + +CMD ["npm", "start"] diff --git a/sk1/backend/db.js b/sk1/backend/db.js new file mode 100644 index 0000000..51fe44b --- /dev/null +++ b/sk1/backend/db.js @@ -0,0 +1,11 @@ +const { Pool } = require("pg"); + +const pool = new Pool({ + user: "budget_user", + host: "postgres", + database: "budget_db", + password: process.env.POSTGRES_PASSWORD, + port: 5432, +}); + +module.exports = pool; diff --git a/sk1/backend/package.json b/sk1/backend/package.json new file mode 100644 index 0000000..a8b7a4b --- /dev/null +++ b/sk1/backend/package.json @@ -0,0 +1,14 @@ +{ + "name": "budget-backend", + "version": "1.0.0", + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "cors": "^2.8.5", + "dotenv": "^16.4.5", + "express": "^4.19.2", + "pg": "^8.11.5" + } +} diff --git a/sk1/backend/server.js b/sk1/backend/server.js new file mode 100644 index 0000000..f6d2572 --- /dev/null +++ b/sk1/backend/server.js @@ -0,0 +1,65 @@ +const express = require("express"); +const cors = require("cors"); +const dotenv = require("dotenv"); +const pool = require("./db"); + +dotenv.config(); + +const app = express(); + +app.use(cors()); +app.use(express.json()); + +app.get("/transactions", async (req, res) => { + try { + const result = await pool.query( + "SELECT * FROM transactions ORDER BY created_at DESC" + ); + + res.json(result.rows); + + } catch (err) { + console.error(err.message); + } +}); + +app.post("/transactions", async (req, res) => { + + try { + + const { title, amount, type } = req.body; + + const result = await pool.query( + "INSERT INTO transactions (title, amount, type) VALUES ($1, $2, $3) RETURNING *", + [title, amount, type] + ); + + res.json(result.rows[0]); + + } catch (err) { + console.error(err.message); + } +}); + +app.delete("/transactions/:id", async (req, res) => { + + try { + + const { id } = req.params; + + await pool.query( + "DELETE FROM transactions WHERE id = $1", + [id] + ); + + res.json("transaction deleted"); + + } catch (err) { + console.error(err.message); + } +}); + +app.listen(5000, () => { + console.log("server running on port 5000"); +}); + diff --git a/sk1/backup/backup.sh b/sk1/backup/backup.sh new file mode 100755 index 0000000..1392d31 --- /dev/null +++ b/sk1/backup/backup.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +DATE=$(date +%Y-%m-%d_%H-%M-%S) + +mkdir -p backups + +docker exec budget_postgres pg_dump -U budget_user budget_db > backups/backup_$DATE.sql + +echo "backup created: backups/backup_$DATE.sql" diff --git a/sk1/backups/backup_2026-05-19_12-37-24.sql b/sk1/backups/backup_2026-05-19_12-37-24.sql new file mode 100644 index 0000000..07e8b46 --- /dev/null +++ b/sk1/backups/backup_2026-05-19_12-37-24.sql @@ -0,0 +1,98 @@ +-- +-- PostgreSQL database dump +-- + +\restrict TBO5p6lvhgQlVM1tXKahkrIRa7cGMBX5CXBrOfkVAQUoFQjgAIX2DM2f2jG00du + +-- Dumped from database version 16.14 (Debian 16.14-1.pgdg13+1) +-- Dumped by pg_dump version 16.14 (Debian 16.14-1.pgdg13+1) + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +SET default_tablespace = ''; + +SET default_table_access_method = heap; + +-- +-- Name: transactions; Type: TABLE; Schema: public; Owner: budget_user +-- + +CREATE TABLE public.transactions ( + id integer NOT NULL, + title text NOT NULL, + amount numeric NOT NULL, + type text NOT NULL, + created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP +); + + +ALTER TABLE public.transactions OWNER TO budget_user; + +-- +-- Name: transactions_id_seq; Type: SEQUENCE; Schema: public; Owner: budget_user +-- + +CREATE SEQUENCE public.transactions_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER SEQUENCE public.transactions_id_seq OWNER TO budget_user; + +-- +-- Name: transactions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: budget_user +-- + +ALTER SEQUENCE public.transactions_id_seq OWNED BY public.transactions.id; + + +-- +-- Name: transactions id; Type: DEFAULT; Schema: public; Owner: budget_user +-- + +ALTER TABLE ONLY public.transactions ALTER COLUMN id SET DEFAULT nextval('public.transactions_id_seq'::regclass); + + +-- +-- Data for Name: transactions; Type: TABLE DATA; Schema: public; Owner: budget_user +-- + +COPY public.transactions (id, title, amount, type, created_at) FROM stdin; +1 asd 4 expense 2026-05-19 06:56:50.824855 +\. + + +-- +-- Name: transactions_id_seq; Type: SEQUENCE SET; Schema: public; Owner: budget_user +-- + +SELECT pg_catalog.setval('public.transactions_id_seq', 1, true); + + +-- +-- Name: transactions transactions_pkey; Type: CONSTRAINT; Schema: public; Owner: budget_user +-- + +ALTER TABLE ONLY public.transactions + ADD CONSTRAINT transactions_pkey PRIMARY KEY (id); + + +-- +-- PostgreSQL database dump complete +-- + +\unrestrict TBO5p6lvhgQlVM1tXKahkrIRa7cGMBX5CXBrOfkVAQUoFQjgAIX2DM2f2jG00du + diff --git a/sk1/db/init.sql b/sk1/db/init.sql new file mode 100644 index 0000000..fe8a116 --- /dev/null +++ b/sk1/db/init.sql @@ -0,0 +1,7 @@ +CREATE TABLE transactions ( + id SERIAL PRIMARY KEY, + title TEXT NOT NULL, + amount NUMERIC NOT NULL, + type TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); diff --git a/sk1/docker-compose.yaml b/sk1/docker-compose.yaml new file mode 100644 index 0000000..d0e07dd --- /dev/null +++ b/sk1/docker-compose.yaml @@ -0,0 +1,50 @@ +services: + + frontend: + build: ./frontend + container_name: budget_frontend + restart: always + ports: + - "3000:3000" + depends_on: + - backend + + backend: + build: ./backend + container_name: budget_backend + restart: always + env_file: + - .env + ports: + - "5000:5000" + depends_on: + - postgres + + postgres: + image: postgres:16 + container_name: budget_postgres + restart: always + environment: + POSTGRES_USER: budget_user + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: budget_db + volumes: + - postgres_data:/var/lib/postgresql/data + - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql + ports: + - "5432:5432" + + nginx: + image: nginx:latest + container_name: budget_nginx + restart: always + ports: + - "80:80" + volumes: + - ./nginx/default.conf:/etc/nginx/conf.d/default.conf + depends_on: + - frontend + - backend + +volumes: + postgres_data: diff --git a/sk1/frontend/Dockerfile b/sk1/frontend/Dockerfile new file mode 100644 index 0000000..c94a918 --- /dev/null +++ b/sk1/frontend/Dockerfile @@ -0,0 +1,13 @@ +FROM node:20 + +WORKDIR /app + +COPY package.json . + +RUN npm install + +COPY . . + +EXPOSE 3000 + +CMD ["npm", "start"] diff --git a/sk1/frontend/package.json b/sk1/frontend/package.json new file mode 100644 index 0000000..5964699 --- /dev/null +++ b/sk1/frontend/package.json @@ -0,0 +1,14 @@ +{ + "name": "budget-frontend", + "version": "1.0.0", + "private": true, + "dependencies": { + "axios": "^1.7.2", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-scripts": "^5.0.1" + }, + "scripts": { + "start": "react-scripts start" + } +} diff --git a/sk1/frontend/public/index.html b/sk1/frontend/public/index.html new file mode 100644 index 0000000..d71d929 --- /dev/null +++ b/sk1/frontend/public/index.html @@ -0,0 +1,10 @@ + + +
+ +{income} €
+ +{expenses} €
+ +{transaction.amount} €
+ + + {new Date(transaction.created_at).toLocaleString()} + + +