344 lines
9.3 KiB
Markdown
344 lines
9.3 KiB
Markdown
# Saludut
|
|
|
|
Frontend Angular (`saludut-inpec`) + backend Node.js (`backend`) + PostgreSQL + Python + LibreOffice.
|
|
|
|
## Produccion (Alpine 3.21)
|
|
|
|
### 1) Preparar servidor
|
|
```bash
|
|
apk add nginx certbot certbot-nginx nftables rsync nodejs npm \
|
|
postgresql postgresql-client python3 py3-pip libreoffice
|
|
rc-update add postgresql default
|
|
rc-service postgresql setup
|
|
rc-service postgresql start
|
|
```
|
|
|
|
### 2) Crear BD y usuario
|
|
```bash
|
|
su - postgres
|
|
psql -c "CREATE USER saludut_user WITH PASSWORD 'jhyutfgv7745676tfbhjgf687yu87';"
|
|
psql -c "CREATE DATABASE saludut_db OWNER saludut_user;"
|
|
exit
|
|
psql -U postgres -d postgres -c "ALTER ROLE postgres WITH PASSWORD 'JKHUG9876hBhjhvjjhldfuy345trgfdf';"
|
|
HBA=$(psql -U postgres -d postgres -Atc "show hba_file"); cp "$HBA" "$HBA.bak"; sed -i 's/\btrust\b/scram-sha-256/g' "$HBA"; rc-service postgresql reload
|
|
```
|
|
|
|
### 3) Subir codigo (desde tu maquina)
|
|
```bash
|
|
mkdir -p /opt/saludut/backend
|
|
tar -czf backend.tar.gz \
|
|
--exclude="node_modules" \
|
|
--exclude=".env" \
|
|
--exclude="backend.tar.gz" \
|
|
.
|
|
|
|
scp -C backend.tar.gz root@autorizacion.saludut.com:/opt/saludut/
|
|
```
|
|
|
|
En el servidor:
|
|
```bash
|
|
tar -xzf /opt/saludut/backend.tar.gz -C /opt/saludut/
|
|
```
|
|
|
|
### 4) Inicializar esquema minimo
|
|
Ejecuta el script minimo (schema + roles base):
|
|
```bash
|
|
psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/insert.sql
|
|
```
|
|
|
|
El admin se crea automaticamente al iniciar el backend si defines
|
|
`ADMIN_USER` y `ADMIN_PASS` en el `.env`.
|
|
|
|
Opcional: cargar datos masivos desde archivos:
|
|
```bash
|
|
psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/establecimiento.sql
|
|
psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/paciente.sql
|
|
psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/ingreso.sql
|
|
```
|
|
|
|
Opcional (solo si quieres cargar CUPS por SQL y no por la UI):
|
|
```bash
|
|
psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/cups_schema.sql
|
|
psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/cups_referencia.sql
|
|
psql -U saludut_user -d saludut_db -f /opt/saludut/backend/src/cups_cubiertos.sql
|
|
```
|
|
|
|
### 5) Backend (.env)
|
|
Crear `backend/.env` en el servidor:
|
|
```
|
|
DB_HOST=127.0.0.1
|
|
DB_PORT=5432
|
|
DB_USER=saludut_user
|
|
DB_PASSWORD=jhyutfgv7745676tfbhjgf687yu87
|
|
DB_NAME=saludut_db
|
|
JWT_SECRET=jhyutfgv7745676tfbhjgf687yu87
|
|
JWT_EXPIRES_IN=24h
|
|
PORT=3000
|
|
SOFFICE_PATH=/usr/bin/soffice
|
|
PYTHON_PATH=python3
|
|
ADMIN_USER=admin
|
|
ADMIN_PASS=admin123
|
|
ADMIN_EMAIL=admin@saludut.com
|
|
ADMIN_NAME=Administrador Sistema
|
|
```
|
|
|
|
### 6) Backend (instalar y correr)
|
|
```bash
|
|
cd /opt/saludut/backend
|
|
npm ci --omit=dev
|
|
node src/server.js
|
|
```
|
|
|
|
#### 6.1) OpenRC (servicio backend)
|
|
```bash
|
|
cat <<'EOF' > /etc/init.d/saludut-backend
|
|
#!/sbin/openrc-run
|
|
|
|
name="saludut-backend"
|
|
description="Backend Node para Saludut"
|
|
directory="/opt/saludut/backend"
|
|
command="/usr/bin/node"
|
|
command_args="src/server.js"
|
|
command_background="yes"
|
|
pidfile="/run/${RC_SVCNAME}.pid"
|
|
output_log="/var/log/saludut-backend.log"
|
|
error_log="/var/log/saludut-backend.err"
|
|
|
|
depend() {
|
|
need net
|
|
}
|
|
EOF
|
|
|
|
chmod +x /etc/init.d/saludut-backend
|
|
rc-update add saludut-backend default
|
|
rc-service saludut-backend start
|
|
```
|
|
|
|
### 7) Frontend + Nginx (deploy)
|
|
|
|
#### 7.1) Acceso SSH y paquetes base
|
|
```bash
|
|
sed -i 's/#Port 22/Port 48952/g' /etc/ssh/sshd_config
|
|
rc-service sshd restart
|
|
ssh -p 48952 root@autorizacion.saludut.com
|
|
apk add nginx certbot certbot-nginx nftables rsync
|
|
```
|
|
|
|
#### 7.2) Publicar scripts (nftables + frontend)
|
|
```bash
|
|
# Ejecutar publishNftables.sh
|
|
head -n1 ./scripts/publishNftables.sh | cat -A
|
|
sed -i 's/\r$//' ./scripts/publishNftables.sh
|
|
sed -i '1s|^.*$|#!/usr/bin/env bash|' ./scripts/publishNftables.sh
|
|
chmod +x ./scripts/publishNftables.sh
|
|
file ./scripts/publishNftables.sh
|
|
bash ./scripts/publishNftables.sh
|
|
|
|
# Ejecutar publish.sh
|
|
head -n1 ./scripts/publish.sh | cat -A
|
|
sed -i 's/\r$//' ./scripts/publish.sh
|
|
sed -i '1s|^.*$|#!/usr/bin/env bash|' ./scripts/publish.sh
|
|
chmod +x ./scripts/publish.sh
|
|
file ./scripts/publish.sh
|
|
bash ./scripts/publish.sh
|
|
```
|
|
|
|
#### 7.3) Nginx HTTP + certbot
|
|
```bash
|
|
# Ejecutar el nginx de autorizacion.saludut.com
|
|
scp -P 48952 scripts/vhost/autorizacion.saludut.com.conf root@autorizacion.saludut.com:/etc/nginx/http.d/
|
|
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
|
|
server_name autorizacion.saludut.com;
|
|
|
|
client_max_body_size 60m;
|
|
|
|
root /var/www/autorizacion.saludut.com/htdocs;
|
|
index index.html;
|
|
|
|
location / {
|
|
try_files $uri $uri/ /index.html;
|
|
}
|
|
|
|
location /api/ {
|
|
client_max_body_size 60m;
|
|
|
|
proxy_pass http://127.0.0.1:3000;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_read_timeout 600;
|
|
proxy_send_timeout 600;
|
|
}
|
|
|
|
error_page 404 /index.html;
|
|
}
|
|
|
|
rc-service nginx start
|
|
sudo certbot --nginx -d autorizacion.saludut.com
|
|
```
|
|
|
|
#### 7.4) Nginx HTTPS (redirect + SSL)
|
|
```bash
|
|
scp -P 48952 scripts/vhost/autorizacion.saludut.com.conf root@autorizacion.saludut.com:/etc/nginx/http.d/
|
|
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name autorizacion.saludut.com;
|
|
|
|
return 301 https://$host$request_uri;
|
|
}
|
|
|
|
server {
|
|
http2 on;
|
|
listen 443 ssl;
|
|
listen [::]:443 ssl;
|
|
|
|
server_name autorizacion.saludut.com;
|
|
|
|
client_max_body_size 60m;
|
|
|
|
# Ojo: Angular esta dentro de /browser
|
|
root /var/www/autorizacion.saludut.com/htdocs/browser;
|
|
index index.html;
|
|
|
|
location / {
|
|
try_files $uri $uri/ /index.html;
|
|
}
|
|
|
|
location /api/ {
|
|
client_max_body_size 60m;
|
|
|
|
proxy_pass http://127.0.0.1:3000;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_read_timeout 600;
|
|
proxy_send_timeout 600;
|
|
}
|
|
|
|
error_page 404 /index.html;
|
|
|
|
ssl_certificate /etc/letsencrypt/live/autorizacion.saludut.com/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/autorizacion.saludut.com/privkey.pem;
|
|
}
|
|
|
|
nginx -t && rc-service nginx restart
|
|
```
|
|
|
|
#### 7.5) Python venv (scripts)
|
|
```bash
|
|
set -e
|
|
|
|
# 1) Paquetes base para Python + compilacion (Alpine)
|
|
apk add --no-cache \
|
|
python3 py3-pip py3-virtualenv \
|
|
build-base python3-dev musl-dev \
|
|
libffi-dev openssl-dev \
|
|
openblas-dev lapack-dev gfortran \
|
|
postgresql-dev
|
|
|
|
# 2) Crear entorno virtual "general" para SaludUT
|
|
mkdir -p /opt/saludut
|
|
python3 -m venv /opt/saludut/venv
|
|
. /opt/saludut/venv/bin/activate
|
|
|
|
# 3) Actualizar pip y herramientas
|
|
python -m pip install --upgrade pip setuptools wheel
|
|
|
|
# 4) Librerias recomendadas (Excel + pandas + postgres + .env + utilidades comunes)
|
|
pip install pandas numpy openpyxl xlsxwriter xlrd python-dotenv psycopg2-binary requests pytz python-dateutil tqdm
|
|
|
|
# (Opcional util si en algun punto generas PDF con python)
|
|
pip install reportlab || true
|
|
|
|
# 5) Probar que todo importa bien
|
|
/opt/saludut/venv/bin/python -c "import pandas as pd; import openpyxl; import psycopg2; import dotenv; print('OK: pandas/openpyxl/psycopg2/dotenv')"
|
|
|
|
# 6) Actualizar .env para que Node use el Python del venv
|
|
# (cambia PYTHON_PATH=python3 -> PYTHON_PATH=/opt/saludut/venv/bin/python)
|
|
sed -i 's|^PYTHON_PATH=.*|PYTHON_PATH=/opt/saludut/venv/bin/python|g' /opt/saludut/backend/.env
|
|
|
|
# 7) Reiniciar backend y ver errores
|
|
rc-service saludut-backend restart || true
|
|
sleep 1
|
|
tail -n 80 /var/log/saludut-backend.err || true
|
|
```
|
|
|
|
#### 7.6) LibreOffice + fuentes (opcional)
|
|
```bash
|
|
set -e
|
|
|
|
apk update
|
|
apk add --no-cache \
|
|
libreoffice \
|
|
fontconfig \
|
|
ttf-dejavu \
|
|
ttf-liberation \
|
|
font-noto \
|
|
font-noto-cjk \
|
|
poppler-utils \
|
|
python3 py3-pip \
|
|
py3-pandas py3-openpyxl py3-psycopg2 py3-dateutil py3-dotenv
|
|
|
|
# cache de fuentes (clave para que no salgan cuadritos)
|
|
fc-cache -f -v
|
|
|
|
# por si tu codigo usa librerias extra (opcional)
|
|
pip3 install --break-system-packages --upgrade pip
|
|
pip3 install --break-system-packages pdfplumber pypdf reportlab pillow
|
|
|
|
# verificacion
|
|
python3 -c "import pandas, openpyxl, dotenv; print('OK', pandas.__version__, openpyxl.__version__, dotenv.__version__)"
|
|
```
|
|
|
|
#### 7.7) OCR (PDF real + escaneado) con Tesseract (Alpine)
|
|
Si necesitas leer PDFs escaneados para el autorrelleno, usa este flujo.
|
|
```bash
|
|
# Uso:
|
|
# sh -c '...este bloque...' archivo.pdf
|
|
# Si no pasas argumento, usa "archivo.pdf"
|
|
|
|
# 1) Asegura repo community (donde esta ocrmypdf/tesseract-data)
|
|
ALPINE_VER="$(cut -d. -f1,2 /etc/alpine-release)"
|
|
sed -i 's/^#\(.*\/community\)/\1/' /etc/apk/repositories
|
|
grep -q "/v${ALPINE_VER}/community" /etc/apk/repositories || \
|
|
echo "https://dl-cdn.alpinelinux.org/alpine/v${ALPINE_VER}/community" >> /etc/apk/repositories
|
|
|
|
# 2) Instala herramientas: pdftotext (poppler), ocrmypdf, tesseract + idiomas
|
|
apk update
|
|
apk add --no-cache \
|
|
poppler-utils \
|
|
ocrmypdf \
|
|
tesseract-ocr-data-spa \
|
|
tesseract-ocr-data-eng
|
|
|
|
# 3) Procesa el PDF (real/escaneado/mixto)
|
|
IN="${1:-archivo.pdf}"
|
|
BASE="${IN%.pdf}"
|
|
TXT="${BASE}.txt"
|
|
OCRPDF="${BASE}.ocr.pdf"
|
|
|
|
# Intenta extraer texto directo
|
|
pdftotext -layout "$IN" - > "$TXT" 2>/dev/null || true
|
|
|
|
# Si el texto es muy corto, probablemente es escaneado (o casi todo imagen) -> OCR
|
|
LEN="$(tr -d '[:space:]' < "$TXT" | wc -c | tr -d ' ')"
|
|
if [ "${LEN:-0}" -lt 80 ]; then
|
|
ocrmypdf -l spa+eng --skip-text --rotate-pages --deskew --optimize 3 "$IN" "$OCRPDF"
|
|
pdftotext -layout "$OCRPDF" "$TXT"
|
|
echo "OK (OCR aplicado cuando hacia falta): $OCRPDF | Texto: $TXT"
|
|
else
|
|
echo "OK (PDF con texto): Texto: $TXT"
|
|
fi
|
|
```
|
|
|