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 <noreply@anthropic.com>
This commit is contained in:
Machiel
2026-10-15 15:01:22 +02:00
co-authored by Claude Opus 5.5
parent 13d0d43fd9
commit 1060cb549b
6 changed files with 158 additions and 2 deletions
+19
View File
@@ -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: 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. 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 ## Opslag
Alles staat in `data/`: `crm.db` (SQLite), `uploads/` (bestanden), `secret.key` (sessies). Alles staat in `data/`: `crm.db` (SQLite), `uploads/` (bestanden), `secret.key` (sessies).
+1 -1
View File
@@ -4,7 +4,7 @@ Starten: python app.py
E-mail ophalen: python app.py sync (bijv. elke 10 minuten via cron) 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) Demoleads: python app.py demo (standaardmodellen uit demo/modellen als gekozen model)
""" """
__version__ = '0.0.2' __version__ = '0.0.3'
import csv import csv
import io import io
+66
View File
@@ -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 <domein> <e-mail voor Let's Encrypt> [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 </dev/tty; echo
read -rsp "Nog een keer: " pw2 </dev/tty; echo
[ -n "$pw1" ] || fail "leeg wachtwoord"
[ "$pw1" = "$pw2" ] || fail "wachtwoorden verschillen"
hash="$(printf '%s' "$pw1" | openssl passwd -6 -stdin)"
{ grep -v "^$LOGIN:" "$HTPASSWD" || true; printf '%s:%s\n' "$LOGIN" "$hash"; } > "$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"
+28
View File
@@ -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;
}
}
+3 -1
View File
@@ -455,7 +455,9 @@
const raw = JSON.parse(document.getElementById('design').textContent); const raw = JSON.parse(document.getElementById('design').textContent);
const key = raw.model || '', model = (HouseModel.MODELS || {})[key]; const key = raw.model || '', model = (HouseModel.MODELS || {})[key];
const name = (st.project && st.project.naam) || (model && model.label) || 'Uw woning'; 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 totals = HouseModel.computeTotals(full), d = HouseModel.computeDimensions(full, S.groundLevel);
const info = { const info = {
price: CostModel.compute(full, totals).summary.inclBtw, kg: totals.totalKg, units: st.units.length, price: CostModel.compute(full, totals).summary.inclBtw, kg: totals.totalKg, units: st.units.length,
+41
View File
@@ -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 <tag>` 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"