diff --git a/README.md b/README.md index a62d0ce..2366854 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Local SPA for family budget tracking: import bank statements, categorize transac ## Monorepo structure -``` +```text family_budget/ ├── backend/ — Node.js API server (Express + TypeScript) ├── frontend/ — React SPA (Vite + TypeScript) @@ -15,13 +15,13 @@ family_budget/ ## Tech stack -| Layer | Choice | Rationale | -|----------|------------------------|--------------------------------------------------------| -| Backend | Express + TypeScript | Simple, well-known, sufficient for a small local app | -| Frontend | React + Vite + TS | Fast dev experience, modern tooling | -| Database | PostgreSQL | Deployed on Synology NAS | -| Migrations | Knex | Lightweight, SQL-close, supports seeds | -| Shared | Pure TypeScript types | Zero-runtime, imported by both backend and frontend | +| Layer | Choice | Rationale | +|---------- |------------------------|--------------------------------------------------------| +| Backend | Express + TypeScript | Simple, well-known, sufficient for a small local app | +| Frontend | React + Vite + TS | Fast dev experience, modern tooling | +| Database | PostgreSQL | Deployed on Synology NAS | +| Migrations | Knex | Lightweight, SQL-close, supports seeds | +| Shared | Pure TypeScript types | Zero-runtime, imported by both backend and frontend | ## Prerequisites diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..e5d627a --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,20 @@ +FROM node:20-alpine AS deps +WORKDIR /app +COPY package.json package-lock.json* ./ +RUN npm ci + +FROM node:20-alpine AS build +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY tsconfig*.json ./ +COPY src ./src +RUN npm run build + +FROM node:20-alpine AS runner +WORKDIR /app +ENV NODE_ENV=production +COPY --from=deps /app/node_modules ./node_modules +COPY --from=build /app/dist ./dist +COPY package.json ./ +EXPOSE 3000 +CMD ["npm","run","start"] diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml new file mode 100644 index 0000000..ebfd610 --- /dev/null +++ b/backend/docker-compose.yml @@ -0,0 +1,15 @@ +services: + backend: + build: . + container_name: family-budget-backend + env_file: + - file.env + ports: + - "3000:3000" + restart: unless-stopped + networks: + - postgre_buget_default + +networks: + postgre_buget_default: + external: true diff --git a/package-lock.json b/package-lock.json index f99ce4a..b159813 100644 --- a/package-lock.json +++ b/package-lock.json @@ -85,7 +85,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -1369,7 +1368,6 @@ "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", @@ -1438,7 +1436,6 @@ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -1572,7 +1569,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -2575,7 +2571,6 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.19.0.tgz", "integrity": "sha512-QIcLGi508BAHkQ3pJNptsFz5WQMlpGbuBGBaIaXsWK8mel2kQ/rThYI+DbgjUvZrIr7MiuEuc9LcChJoEZK1xQ==", "license": "MIT", - "peer": true, "dependencies": { "pg-connection-string": "^2.11.0", "pg-pool": "^3.12.0", @@ -2673,7 +2668,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -2823,7 +2817,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -2833,7 +2826,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -3286,6 +3278,7 @@ "os": [ "aix" ], + "peer": true, "engines": { "node": ">=18" } @@ -3303,6 +3296,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -3320,6 +3314,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -3337,6 +3332,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -3354,6 +3350,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -3371,6 +3368,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -3388,6 +3386,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -3405,6 +3404,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -3422,6 +3422,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3439,6 +3440,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3456,6 +3458,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3473,6 +3476,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3490,6 +3494,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3507,6 +3512,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3524,6 +3530,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3541,6 +3548,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3558,6 +3566,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -3575,6 +3584,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -3592,6 +3602,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -3609,6 +3620,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -3626,6 +3638,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -3643,6 +3656,7 @@ "os": [ "openharmony" ], + "peer": true, "engines": { "node": ">=18" } @@ -3660,6 +3674,7 @@ "os": [ "sunos" ], + "peer": true, "engines": { "node": ">=18" } @@ -3677,6 +3692,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -3694,6 +3710,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -3711,6 +3728,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -3882,7 +3900,6 @@ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4",