From 81fc27fa86c4c846b92942a37c4bf9817d8b4ec6 Mon Sep 17 00:00:00 2001 From: Machiel Date: Thu, 15 Oct 2026 15:01:22 +0200 Subject: [PATCH] v0.0.3: klant-PDF rekent met het volledige model (totalKg faalde met skip3D); Tectum (configurator) op eigen subdomein achter wachtwoord Co-Authored-By: Claude Opus 5.5 --- README.md | 19 ++++++++++++ app.py | 2 +- server/tectum-setup.sh | 66 +++++++++++++++++++++++++++++++++++++++++ server/tectum-site.conf | 28 +++++++++++++++++ static/viewer.js | 4 ++- tools/tectum-release.sh | 41 +++++++++++++++++++++++++ 6 files changed, 158 insertions(+), 2 deletions(-) create mode 100755 server/tectum-setup.sh create mode 100644 server/tectum-site.conf create mode 100755 tools/tectum-release.sh diff --git a/README.md b/README.md index 3bbe903..02fb416 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,25 @@ Lokaal zoals op de server, maar zonder nginx: `./deploy.sh` (zie het script). Back-ups buiten de server (bijv. de back-upoptie van OVH of een rsync van `/srv/vanemous-crm/data`) regel je apart: de nachtelijke kopie staat op dezelfde schijf en dekt `uploads/` niet. +### Tectum (configurator) op dezelfde server + +De configurator (`../configurator`) staat als statische site op een eigen subdomein, helemaal achter één +wachtwoord (nginx basic auth). Eenmalig, na `server/setup.sh`: + +```sh +scp -r server ubuntu@SERVER: +ssh -t ubuntu@SERVER sudo bash server/tectum-setup.sh tectum.voorbeeld.nl jij@voorbeeld.nl [gebruikersnaam] +``` + +Dat vraagt het wachtwoord (gebruikersnaam standaard `vanemous`; wijzigen: `sudo WACHTWOORD=1 bash ...`), maakt +`/srv/www/tectum` (van `crm`, zodat releases via dezelfde SSH-toegang gaan) en de nginx-site met HTTPS. +Uitrollen of terugrollen vanaf je eigen machine, vanuit een tag van de configurator: + +```sh +tools/tectum-release.sh crm@tectum.voorbeeld.nl # nieuwste tag +tools/tectum-release.sh crm@tectum.voorbeeld.nl v0.7.6 # bepaalde versie +``` + ## Opslag Alles staat in `data/`: `crm.db` (SQLite), `uploads/` (bestanden), `secret.key` (sessies). diff --git a/app.py b/app.py index dd67c76..dea856b 100644 --- a/app.py +++ b/app.py @@ -4,7 +4,7 @@ Starten: python app.py E-mail ophalen: python app.py sync (bijv. elke 10 minuten via cron) Demoleads: python app.py demo (standaardmodellen uit demo/modellen als gekozen model) """ -__version__ = '0.0.2' +__version__ = '0.0.3' import csv import io diff --git a/server/tectum-setup.sh b/server/tectum-setup.sh new file mode 100755 index 0000000..58e7f04 --- /dev/null +++ b/server/tectum-setup.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# Eenmalig op de server (na server/setup.sh): Tectum, de configurator, als statische site achter een wachtwoord. +# +# scp -r server ubuntu@SERVER: +# ssh -t ubuntu@SERVER sudo bash server/tectum-setup.sh tectum.voorbeeld.nl jij@voorbeeld.nl [gebruikersnaam] +# +# Vraagt het wachtwoord als die gebruiker nog niet bestaat; met WACHTWOORD=1 ervoor wijzig je het: +# ssh -t ubuntu@SERVER sudo WACHTWOORD=1 bash server/tectum-setup.sh tectum.voorbeeld.nl jij@voorbeeld.nl +# Daarna rolt tools/tectum-release.sh (op je eigen machine) een versie uit naar crm@SERVER. +# Opnieuw draaien kan: elke stap controleert wat er al is. +set -euo pipefail + +DOMAIN="${1:-}" +EMAIL="${2:-}" +LOGIN="${3:-vanemous}" +ROOT=/srv/www/tectum +SITE=tectum +HTPASSWD=/etc/nginx/tectum.htpasswd +HERE="$(cd "$(dirname "$0")" && pwd)" + +say() { printf '\033[38;2;185;89;19m▸\033[0m %s\n' "$*"; } +fail() { printf 'Fout: %s\n' "$*" >&2; exit 1; } + +[ "$(id -u)" = 0 ] || fail "draai dit met sudo" +[ -n "$DOMAIN" ] && [ -n "$EMAIL" ] || fail "gebruik: sudo bash tectum-setup.sh [gebruikersnaam]" +id crm >/dev/null 2>&1 || fail "gebruiker crm bestaat niet; draai eerst server/setup.sh" +command -v nginx >/dev/null || fail "nginx ontbreekt; draai eerst server/setup.sh" + +# --- map: releases komen binnen als crm (zelfde SSH-toegang als de CRM-releases) ---------------- +say "map $ROOT" +install -d -o root -g root -m 755 /srv/www +install -d -o crm -g crm -m 755 "$ROOT" "$ROOT/releases" + +# --- wachtwoord ---------------------------------------------------------------------------------- +touch "$HTPASSWD" +chown root:www-data "$HTPASSWD"; chmod 640 "$HTPASSWD" +if [ -n "${WACHTWOORD:-}" ] || ! grep -q "^$LOGIN:" "$HTPASSWD"; then + say "wachtwoord voor gebruiker $LOGIN" + read -rsp "Wachtwoord: " pw1 "$HTPASSWD.new" + chown root:www-data "$HTPASSWD.new"; chmod 640 "$HTPASSWD.new" + mv "$HTPASSWD.new" "$HTPASSWD" +fi + +# --- nginx ------------------------------------------------------------------------------- +say "nginx voor $DOMAIN" +if [ ! -f /etc/nginx/sites-available/$SITE ] || ! grep -q "listen 443" /etc/nginx/sites-available/$SITE; then + sed "s/__DOMAIN__/$DOMAIN/g" "$HERE/tectum-site.conf" > /etc/nginx/sites-available/$SITE +fi +ln -sfn /etc/nginx/sites-available/$SITE /etc/nginx/sites-enabled/$SITE +nginx -t +systemctl reload nginx + +# --- HTTPS ------------------------------------------------------------------------------- +say "certificaat aanvragen (DNS van $DOMAIN moet al naar deze server wijzen)" +if certbot --nginx -d "$DOMAIN" -m "$EMAIL" --agree-tos --non-interactive --redirect; then + say "HTTPS actief; verlengen gaat automatisch (certbot.timer)" +else + say "let op: certificaat mislukt. Klopt de DNS? Daarna opnieuw: sudo certbot --nginx -d $DOMAIN -m $EMAIL --agree-tos --redirect" +fi + +say "klaar. Rol nu vanaf je eigen machine een versie uit: tools/tectum-release.sh crm@$DOMAIN" diff --git a/server/tectum-site.conf b/server/tectum-site.conf new file mode 100644 index 0000000..dfe17cc --- /dev/null +++ b/server/tectum-site.conf @@ -0,0 +1,28 @@ +# Tectum (configurator) als statische site achter één wachtwoord (server/tectum-setup.sh vult __DOMAIN__ in; +# certbot voegt HTTPS en de doorverwijzing toe; de ACME-controle valt niet onder auth_basic). +server { + listen 80; + listen [::]:80; + server_name __DOMAIN__; + + root /srv/www/tectum/current; + index index.html; + + auth_basic "Tectum"; + auth_basic_user_file /etc/nginx/tectum.htpasswd; + + add_header X-Robots-Tag "noindex, nofollow" always; + + location / { + try_files $uri $uri/ =404; + # steeds even navragen zodat een nieuwe versie meteen zichtbaar is + add_header Cache-Control "no-cache"; + add_header X-Robots-Tag "noindex, nofollow" always; + } + + location /assets/ { + access_log off; + add_header Cache-Control "no-cache"; + add_header X-Robots-Tag "noindex, nofollow" always; + } +} diff --git a/static/viewer.js b/static/viewer.js index 06bb711..b451b20 100644 --- a/static/viewer.js +++ b/static/viewer.js @@ -455,7 +455,9 @@ const raw = JSON.parse(document.getElementById('design').textContent); const key = raw.model || '', model = (HouseModel.MODELS || {})[key]; const name = (st.project && st.project.naam) || (model && model.label) || 'Uw woning'; - const full = HouseModel.computeParts(st, { skip3D: true }); + // Afgewerkte woning met 3D, zoals light.js: met skip3D hebben de wandstukken geen specs (gewicht) en faalt computeTotals. + const full = HouseModel.computeParts(st, Object.assign({ layers: ViewLayers.all(), finishedOnly: true }, mats)); + HouseModel.rootGroups(full).forEach(disposeGeo); const totals = HouseModel.computeTotals(full), d = HouseModel.computeDimensions(full, S.groundLevel); const info = { price: CostModel.compute(full, totals).summary.inclBtw, kg: totals.totalKg, units: st.units.length, diff --git a/tools/tectum-release.sh b/tools/tectum-release.sh new file mode 100755 index 0000000..5d7e32b --- /dev/null +++ b/tools/tectum-release.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Een getagde versie van Tectum (de configurator) naar de server brengen (eerst eenmalig server/tectum-setup.sh). +# +# tools/tectum-release.sh crm@tectum.voorbeeld.nl nieuwste tag +# tools/tectum-release.sh crm@tectum.voorbeeld.nl v0.7.6 een bepaalde versie (ook om terug te rollen) +# +# De bestanden komen uit `git archive ` van $CONFIGURATOR (standaard ../configurator), dus niet-gecommit +# werk gaat niet mee. rsync met hardlinks naar de vorige versie, zodat alleen wijzigingen over de lijn gaan; +# daarna wijst `current` naar de nieuwe versie. De laatste 5 versies blijven staan. +set -euo pipefail + +REPO="$(cd "$(dirname "$0")/.." && pwd)" +HOST="${1:-}" +CONFIGURATOR="${CONFIGURATOR:-$REPO/../configurator}" +ROOT=/srv/www/tectum + +say() { printf '\033[38;2;185;89;19m▸\033[0m %s\n' "$*"; } +fail() { printf 'Fout: %s\n' "$*" >&2; exit 1; } + +[ -n "$HOST" ] || fail "gebruik: tools/tectum-release.sh crm@server [vX.Y.Z]" +[ -f "$CONFIGURATOR/index.html" ] || fail "geen configurator in $CONFIGURATOR (zet CONFIGURATOR=pad)" +TAG="${2:-$(git -C "$CONFIGURATOR" tag --list 'v*' --sort=-v:refname | head -n1)}" +[[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] || fail "onbekende versie '$TAG' (verwacht vX.Y.Z)" +git -C "$CONFIGURATOR" rev-parse -q --verify "refs/tags/$TAG" >/dev/null || fail "tag $TAG bestaat niet" +[ -z "$(git -C "$CONFIGURATOR" status --porcelain)" ] || say "let op: niet-gecommitte wijzigingen in de configurator zitten niet in $TAG" + +tmp="$(mktemp -d)" +trap 'rm -rf "$tmp"' EXIT +chmod 755 "$tmp" # mktemp maakt hem 700, en rsync -a neemt dat mee (nginx moet erin kunnen) +git -C "$CONFIGURATOR" archive "$TAG" | tar -x -C "$tmp" +rm -f "$tmp/README.md" "$tmp/start.sh" "$tmp/.gitignore" + +say "Tectum $TAG uploaden naar $HOST" +ssh "$HOST" "mkdir -p $ROOT/releases/$TAG" +rsync -az --delete --link-dest="$ROOT/current/" "$tmp/" "$HOST:$ROOT/releases/$TAG/" + +say "$TAG actief maken" +ssh "$HOST" "set -e; cd $ROOT; ln -sfn releases/$TAG current.new; mv -T current.new current + ls -1 releases | sort -V | head -n -5 | grep -vxF '$TAG' | sed 's|^|releases/|' | xargs -r rm -rf" + +say "klaar: Tectum $TAG staat live"