diff --git a/.github/workflow/deploy.yml b/.github/workflow/deploy.yml new file mode 100644 index 0000000..e9bdafb --- /dev/null +++ b/.github/workflow/deploy.yml @@ -0,0 +1,20 @@ +on: + push: + branches: [main] + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Deploy via SSH + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ secrets.VPS_HOST }} + username: ${{ secrets.VPS_USER }} + key: ${{ secrets.VPS_SSH_KEY }} + script: | + cd /root/provapratica/backend + git pull origin main + docker compose up -d --build \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..e26a57a --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dist/index.d.ts.map b/dist/index.d.ts.map new file mode 100644 index 0000000..535b86d --- /dev/null +++ b/dist/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..5019620 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,24 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const cors_1 = __importDefault(require("cors")); +const dotenv_1 = __importDefault(require("dotenv")); +dotenv_1.default.config(); +const app = (0, express_1.default)(); +const port = Number(process.env.PORT) || 3003; +app.set("trust proxy", 1); +app.use((0, cors_1.default)({ + origin: process.env.FRONTEND_URL ?? "https://provapraticafrontend.andreavillari.it", + credentials: true, +})); +app.use(express_1.default.json()); +app.get("/api/health", (_req, res) => { + res.json({ status: "ok" }); +}); +app.listen(port, "0.0.0.0", () => { + console.log(`Backend in ascolto sulla porta ${port}`); +}); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/index.js.map b/dist/index.js.map new file mode 100644 index 0000000..2584bde --- /dev/null +++ b/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAAA,sDAA8B;AAC9B,gDAAwB;AACxB,oDAA4B;AAE5B,gBAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,MAAM,GAAG,GAAG,IAAA,iBAAO,GAAE,CAAC;AACtB,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;AAE9C,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;AAC1B,GAAG,CAAC,GAAG,CAAC,IAAA,cAAI,EAAC;IACX,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,+CAA+C;IACnF,WAAW,EAAE,IAAI;CAClB,CAAC,CAAC,CAAC;AACJ,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAExB,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;IACnC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC;AAEH,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE;IAC/B,OAAO,CAAC,GAAG,CAAC,kCAAkC,IAAI,EAAE,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC"} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..dfa4163 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,51 @@ +services: + app: + build: + context: . + dockerfile: dockerfile/Dockerfile + container_name: provapraticabackend + restart: always + env_file: + - .env + environment: + MYSQL_HOST: mysql + PORT: 3003 + ports: + - "127.0.0.1:3003:3003" + depends_on: + mysql: + condition: service_healthy + + mysql: + image: mysql:8.0 + container_name: mysql_provapratica + restart: always + environment: + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} + MYSQL_DATABASE: ${MYSQL_DATABASE} + MYSQL_USER: ${MYSQL_USER} + MYSQL_PASSWORD: ${MYSQL_PASSWORD} + volumes: + - dbdata:/var/lib/mysql + - ./initdb:/docker-entrypoint-initdb.d # opzionale: script SQL iniziali + ports: + - "127.0.0.1:3307:3306" + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] + interval: 5s + timeout: 5s + retries: 10 + + phpmyadmin: + image: phpmyadmin:latest + container_name: phpmyadmin_provapratica + restart: always + ports: + - "127.0.0.1:8083:80" + environment: + PMA_HOST: mysql + depends_on: + - mysql + +volumes: + dbdata: \ No newline at end of file diff --git a/dockerfile/Dockerfile b/dockerfile/Dockerfile new file mode 100644 index 0000000..e51939c --- /dev/null +++ b/dockerfile/Dockerfile @@ -0,0 +1,27 @@ +# syntax=docker/dockerfile:1 +ARG NODE_VERSION=20 + +FROM node:${NODE_VERSION}-slim AS build +WORKDIR /app + +COPY package*.json ./ +RUN npm ci + +COPY tsconfig.json ./ +COPY src ./src +RUN npm run build + +FROM node:${NODE_VERSION}-slim AS runtime +WORKDIR /app + +ENV NODE_ENV=production +ENV PORT=3003 + +COPY package*.json ./ +RUN npm ci --omit=dev + +COPY --from=build /app/dist ./dist + +EXPOSE 3003 + +CMD ["node", "dist/index.js"] \ No newline at end of file diff --git a/package.json b/package.json index 86af2b5..6625d1d 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,11 @@ "name": "provapraticabackend", "version": "1.0.0", "main": "index.js", + "type": "commonjs", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "dev": "tsx watch src/index.ts", + "build": "tsc", + "start": "node dist/index.js" }, "repository": { "type": "git", @@ -31,4 +34,4 @@ "tsx": "^4.22.4", "typescript": "^6.0.3" } -} +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..cb4f01c --- /dev/null +++ b/src/index.ts @@ -0,0 +1,23 @@ +import express from "express"; +import cors from "cors"; +import dotenv from "dotenv"; + +dotenv.config(); + +const app = express(); +const port = Number(process.env.PORT) || 3003; + +app.set("trust proxy", 1); +app.use(cors({ + origin: process.env.FRONTEND_URL ?? "https://provapraticafrontend.andreavillari.it", + credentials: true, +})); +app.use(express.json()); + +app.get("/api/health", (_req, res) => { + res.json({ status: "ok" }); +}); + +app.listen(port, "0.0.0.0", () => { + console.log(`Backend in ascolto sulla porta ${port}`); +}); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index cec4a3a..80d5070 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,44 +1,15 @@ { - // Visit https://aka.ms/tsconfig to read more about this file "compilerOptions": { - // File Layout - // "rootDir": "./src", - // "outDir": "./dist", - - // Environment Settings - // See also https://aka.ms/tsconfig/module - "module": "nodenext", - "target": "esnext", - "types": [], - // For nodejs: - // "lib": ["esnext"], - // "types": ["node"], - // and npm install -D @types/node - - // Other Outputs - "sourceMap": true, - "declaration": true, - "declarationMap": true, - - // Stricter Typechecking Options - "noUncheckedIndexedAccess": true, - "exactOptionalPropertyTypes": true, - - // Style Options - // "noImplicitReturns": true, - // "noImplicitOverride": true, - // "noUnusedLocals": true, - // "noUnusedParameters": true, - // "noFallthroughCasesInSwitch": true, - // "noPropertyAccessFromIndexSignature": true, - - // Recommended Options + "rootDir": "./src", + "outDir": "./dist", + "target": "ES2020", + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": true, "strict": true, - "jsx": "react-jsx", - "verbatimModuleSyntax": true, - "isolatedModules": true, - "noUncheckedSideEffectImports": true, - "moduleDetection": "force", "skipLibCheck": true, - } -} + "sourceMap": true, + "types": ["node"] + }, + "include": ["src/**/*"] +} \ No newline at end of file