This commit is contained in:
Trabajo
2026-05-05 09:20:06 +02:00
10 changed files with 459 additions and 1 deletions

View File

@@ -0,0 +1,17 @@
FROM node:22-alpine
WORKDIR /home/node/app
COPY ./package.json ./
COPY ./dist ./dist
COPY tsconfig.json ./
COPY ./deployment/database/migrations ./deployment/database/migrations
COPY ./deployment/develop/start.sh ./
RUN npm config set @sf-alvar:registry https://git.savefamilygps.net/api/packages/SaveFamily/npm/ &&\
npm install &&\
chmod +x start.sh
EXPOSE ${PORT}
ENTRYPOINT [ "./start.sh" ]

View File

@@ -0,0 +1,50 @@
name: sf-monitorizacion-health
networks:
savefamily:
external: true
proxy:
external: true
internal:
driver: bridge
services:
sf-monitorizacion-health:
container_name: sf-monitorizacion-health
image: sf-monitorizacion-health
build:
context: .
dockerfile: Dockerfile
args:
PORT: "${PORT:-3000}"
ports:
- ${PORT}:${PORT}
networks:
- internal
- savefamily
- proxy
env_file:
- .env
restart: unless-stopped
healthcheck:
test:
[
"CMD-SHELL",
"wget -q --spider http://127.0.0.1:${PORT:-3000}/health || exit 1",
]
interval: 60s
timeout: 5s
retries: 5
start_period: 15s
labels:
- "io.portainer.accesscontrol.teams=develop"
- "traefik.enable=true"
- "traefik.http.routers.sf-monitorizacion-health.entrypoints=web"
- "traefik.http.routers.sf-monitorizacion-health.rule=Host(`sf-monitorizacion-health.savefamilygps.net`)"
- "traefik.http.middlewares.sf-monitorizacion-health-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.sf-monitorizacion-health.middlewares=sf-monitorizacion-health-https-redirect"
- "traefik.http.routers.sf-monitorizacion-health-secure.entrypoints=websecure"
- "traefik.http.routers.sf-monitorizacion-health-secure.rule=Host(`sf-monitorizacion-health.savefamilygps.net`)"
- "traefik.http.routers.sf-monitorizacion-health-secure.tls=true"
- "traefik.http.routers.sf-monitorizacion-health-secure.service=sf-monitorizacion-health"
- "traefik.http.services.sf-monitorizacion-health.loadbalancer.server.port=${PORT}"
- "traefik.docker.network=proxy"

View File

@@ -0,0 +1,109 @@
#!/usr/bin/env groovy
String BASE_REMOTE_PATH = "//home/devops"
String APP_REMOTE_PATH = "//mnt/docker-storage/containers/savefamily/sf-monitorizacion-health"
// Muchos paths son mas simples, hay que cambiar movimientos de archivos
pipeline {
agent any
tools { nodejs "22.15.0" }
environment {
GENERAL_CHANGES = "false"
}
stages {
stage('📦 Install dependencies') {
steps {
sh 'npm install'
}
}
stage("🧱 Building") {
steps {
sh 'npm run build:esbuild'
}
}
stage("🏗 Deploying") {
steps {
sshPublisher(
publishers: [
sshPublisherDesc(
verbose: true,
configName: "Save Family",
transfers: [
sshTransfer(
cleanRemote: false,
execCommand: "mkdir -p $APP_REMOTE_PATH"
),
sshTransfer(
cleanRemote: false,
execCommand: "ln -sf $BASE_REMOTE_PATH/vault/savefamily/sf-monitorizacion-health/.env $APP_REMOTE_PATH/.env"
),
sshTransfer(
cleanRemote: false,
remoteDirectory: "$APP_REMOTE_PATH",
sourceFiles: "docs/**/*",
),
sshTransfer(
cleanRemote: false,
remoteDirectory: "$APP_REMOTE_PATH",
sourceFiles: "deployment/develop/**/*",
removePrefix:"deployment/develop",
excludes: "deployment/develop/docker"
),
sshTransfer(
cleanRemote: false,
remoteDirectory: "$APP_REMOTE_PATH",
sourceFiles: "deployment/develop/docker/**/*",
removePrefix:"deployment/develop/docker"
),
sshTransfer(
cleanRemote: false,
remoteDirectory: "$APP_REMOTE_PATH",
sourceFiles: "deployment/database/**/*",
),
sshTransfer(
cleanRemote: false,
remoteDirectory: "$APP_REMOTE_PATH",
sourceFiles: "package.json",
),
sshTransfer(
cleanRemote: false,
remoteDirectory: "$APP_REMOTE_PATH",
sourceFiles: "src/**/*"
),
sshTransfer(
cleanRemote: false,
remoteDirectory: "$APP_REMOTE_PATH",
sourceFiles: "dist/**/*"
),
sshTransfer(
cleanRemote: false,
remoteDirectory: "$APP_REMOTE_PATH",
sourceFiles: "tsconfig.json"
),
sshTransfer(
cleanRemote: false,
remoteDirectory: "$APP_REMOTE_PATH",
sourceFiles: "package-lock.json",
),
sshTransfer(
cleanRemote: false,
execCommand: "sh $APP_REMOTE_PATH/rebuild.sh"
)
]
)
]
)
}
}
}
post {
failure {
echo '👎🏼 Processing failed'
}
success {
echo '👍🏼 Processing success'
}
}
}

View File

@@ -0,0 +1,9 @@
#!/bin/sh
cd /mnt/docker-storage/containers/savefamily/sf-monitorizacion-health
docker compose -f docker-compose.yaml down || echo "Error parando servidor"
docker rm sf-monitorizacion-health || echo "Error eliminando contenedor antiguo"
docker rmi sf-monitorizacion-health || echo "Error eliminando (rmi) contenedor antiguo"
docker compose -f docker-compose.yaml up --build -d

View File

@@ -0,0 +1,6 @@
#!/bin/sh
cd /home/node/app
echo "Lanzando migraciones e iniciando servidor"
# npm config set @sf-alvar:registry https://git.savefamilygps.net/api/packages/SaveFamily/npm/ #npm install
npm run migrate
npm run start

View File

@@ -0,0 +1,23 @@
FROM node:22-alpine
WORKDIR /home/node/app
COPY ./package.json ./package-lock.json ./
COPY ./src ./src
# copia el codigo en general
COPY tsconfig.json ./
COPY .env* ./
COPY ./deployment/local/start.sh ./
# Copiar el archivo de migrations? porque ahora no creo que se esté lanzando nada
COPY ./deployment/database/migrations ./deployment/database/migrations
RUN npm config set registry https://git.savefamilygps.net/api/packages/SaveFamily/npm/ &&\
echo "registry=https://registry.npmjs.org/" >> .npmrc &&\
npm install &&\
ls && npm run build:esbuild &&\
chmod +x start.sh
EXPOSE ${PORT}
ENTRYPOINT [ "./start.sh" ]

View File

@@ -0,0 +1,57 @@
name: sf-monitorizacion-health
networks:
default:
driver: bridge
name: network-test # Tiene que coincidir con el compose objetivo
services:
sf-monitorizacion-health:
container_name: sf-monitorizacion-health
image: sf-monitorizacion-health
build:
context: ./
dockerfile: deployment/local/docker/Dockerfile.local
args:
PORT: "${PORT:-3000}"
develop:
watch:
- path: ./src
action: sync
target: /usr/local/app/packages
- path: ./package.json
action: rebuild
ports:
- ${PORT}:${PORT}
env_file:
- .env
restart: unless-stopped
healthcheck:
test:
[
"CMD-SHELL",
"wget -q --spider http://127.0.0.1:${PORT:-3000}/health || exit 1",
]
interval: 10s
timeout: 5s
retries: 5
start_period: 15s
depends_on:
postgresql-health:
condition: service_healthy
postgresql-health:
container_name: postgresql-health
image: postgres:16.1
env_file:
- .env
ports:
- "${POSTGRES_PORT}:5432"
volumes:
- ./sql-data/:/var/lib/postgres/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
retries: 5
start_period: 5s
timeout: 5s
command: -p 5432

186
package-lock.json generated
View File

@@ -17,6 +17,7 @@
"tsx": "^4.21.0"
},
"devDependencies": {
"@sf-alvar/db-migrate": "^1.0.10",
"@types/ejs": "^3.1.5",
"@types/express": "^5.0.6",
"@types/node": "^25.6.0",
@@ -483,6 +484,20 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@sf-alvar/db-migrate": {
"version": "1.0.10",
"resolved": "https://git.savefamilygps.net/api/packages/SaveFamily/npm/%40sf-alvar%2Fdb-migrate/-/1.0.10/db-migrate-1.0.10.tgz",
"integrity": "sha512-tD8Ziytn0Yh88vCIL+vOKTwwSh3hDp+1ZX02eaPUQtmbec/Iz1Beq2izHU+vre1dHMGUPI9Tu79HsDbx159nfQ==",
"dev": true,
"license": "ISC",
"dependencies": {
"pg": "^8.18.0",
"yargs": "^18.0.0"
},
"bin": {
"db-migrate": "lib/index.js"
}
},
"node_modules/@tsconfig/node10": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
@@ -667,6 +682,32 @@
"node": ">=0.4.0"
}
},
"node_modules/ansi-regex": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
"integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
"node_modules/ansi-styles": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
@@ -841,6 +882,21 @@
"fsevents": "~2.3.2"
}
},
"node_modules/cliui": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
"integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==",
"dev": true,
"license": "ISC",
"dependencies": {
"string-width": "^7.2.0",
"strip-ansi": "^7.1.0",
"wrap-ansi": "^9.0.0"
},
"engines": {
"node": ">=20"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -989,6 +1045,13 @@
"node": ">=0.12.18"
}
},
"node_modules/emoji-regex": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
"integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
"dev": true,
"license": "MIT"
},
"node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
@@ -1084,6 +1147,16 @@
"@esbuild/win32-x64": "0.27.7"
}
},
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -1274,6 +1347,29 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
"license": "ISC",
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
},
"node_modules/get-east-asian-width": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz",
"integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
@@ -2111,6 +2207,40 @@
"node": ">= 0.8"
}
},
"node_modules/string-width": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"emoji-regex": "^10.3.0",
"get-east-asian-width": "^1.0.0",
"strip-ansi": "^7.1.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/strip-ansi": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
"integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.2.2"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -2286,6 +2416,24 @@
"node": ">= 0.8"
}
},
"node_modules/wrap-ansi": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
"integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.2.1",
"string-width": "^7.0.0",
"strip-ansi": "^7.1.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@@ -2301,6 +2449,44 @@
"node": ">=0.4"
}
},
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=10"
}
},
"node_modules/yargs": {
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz",
"integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==",
"dev": true,
"license": "MIT",
"dependencies": {
"cliui": "^9.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"string-width": "^7.2.0",
"y18n": "^5.0.5",
"yargs-parser": "^22.0.0"
},
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=23"
}
},
"node_modules/yargs-parser": {
"version": "22.0.0",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz",
"integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
"dev": true,
"license": "ISC",
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=23"
}
},
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",

View File

@@ -19,6 +19,7 @@
"author": "",
"license": "ISC",
"devDependencies": {
"@sf-alvar/db-migrate": "^1.0.10",
"@types/ejs": "^3.1.5",
"@types/express": "^5.0.6",
"@types/node": "^25.6.0",
@@ -35,4 +36,4 @@
"pg": "^8.20.0",
"tsx": "^4.21.0"
}
}
}