# logship-template-3 (VM 115) — clean LogShip golden VM

Built 2026-10-01 from a PBS backup of VM 105 (logship-production,
snapshot 2026-10-01T16:00Z, frontend build GITHASH 8fdc65f85 / 29.09.2026).
Production was never touched. Supersedes VM 113 `logship-template-2`
(built 2026-07-26; destroyed after sign-off).

**Last incremental sync from prod: 2026-10-23** (`sync-from-prod.sh`, no
re-clone): frontend build e5b38904b / 23.10.2026 (Nuxt 4.6.2), Node 22.22.3 +
pm2 7.1.1 (pm2-root unit/override from prod), PostgreSQL 17.11, Docker 29.9.2,
kernel 6.1.0-54, libsasl2-modules; iDempiere AD: 17 lead-CRM columns on
AD_User + BusinessModel/LostReason lists, C_Order DHL transport-insurance
columns (+2 physical-only flags); Jasper order/letterhead .jasper recompiles;
jetty.xml 32 KB header size; postfix sender-dependent relay structure
(main.cf/sender_relay/tls_policy — sasl_passwd is a placeholder, postfix
stays disabled); data.logship.de hosts line; logship-scripts 1129cec;
price lists Standard/Einkauf-Alt/Versandkosten DHL/Fulfillment Einkauf
inactive as on prod; cust_printer labelprinter-6 renamed. New .env keys
appended blank: MAIL_ARCHIVE_URL/TOKEN, ANTHROPIC_API_KEY/WORKSPACE_ID
(ANTHROPIC_MODEL=claude-opus-5-5, ASTERISK_ORIGINATE_CHANNEL +
NUXT_ASTERISK_CHANNEL_TEMPLATE set as on prod).

## What this VM is
Full LogShip stack, data-free: iDempiere (:8443, REST via nginx /api/v1),
PostgreSQL 17 (idempiere / strapi), Nuxt frontend (:3001), Strapi
(:1337, media via nginx :80), PostgREST (:3000), ES 9 + Kibana + sync
(docker, 127.0.0.1 only), whisper-cpp, Check_MK agent (unregistered).
IP 192.168.12.67 via Proxmox cloud-init.

## What was removed / changed vs production
- All transactional data of client 1000000: orders, invoices, shipments,
  payments, accounting posts, stock, requests, logs, attachments, contact
  activities, payment selections, bank statements, AP/Amazon invoice inboxes,
  serial/Charge/MHD attribute instances.
- All customer orgs — only org 1000000 (LogYou) remains.
- All business partners/products except config-referenced ones
  (3 partners, ~18 billing products). Staff users + roles kept,
  passwords identical to production at clone time.
- Kept config: doc types, price lists, taxes, warehouses/locators of org
  1000000, `cust_commissiontable`, `cust_printer`, `cust_labeltemplate`,
  `cust_nonworkingdays`, `cust_shippingcost_default`, the 4 `LogShip …`
  attribute sets, Jasper print processes, bank 1000001 + charges.
- Strapi content + uploads wiped (admin login + API tokens kept).
- ES indices rebuilt empty. DocumentNo sequences reset.
- root crontab REMOVED (backup: /root/crontab.production.bak).
- postfix disabled. Frontend runtime data (`data/` SQLite DBs + dirs:
  chat, push, contract signing, legal docs, amazon-ads, bank imports, call
  transcripts, mobile APK releases) cleared; `/root/storage` PDFs wiped;
  stale deploy copies pruned; Check_MK registration removed.
- /opt/erp-nuxt-frontend/.env NEUTRALIZED: LARAVEL, Sentry, DHL/DPD/
  Sendcloud/Amazon/Amazon-Ads/JTL credentials, Synology, VAPID/FCM keys,
  FreePBX (AMI/CDR/recordings/caller-id), IVR, landing-page + Laravel
  service tokens, mobile download secret, SEPA creditor id blanked;
  CLICK_TO_DIAL_ENABLED=false; STRAPIPUBLIC/WEBAUTHN/MOBILE_APP_PUBLIC_BASE
  point at 192.168.12.67; fresh CREDENTIAL_ENCRYPTION_KEY.
  GardenWorld demo client untouched.

## Known gaps fixed on clones (apply to the golden VM at the next refresh)
- **Merchant template role**: `MERCHANT_TEMPLATE_ROLE_ID=1000006` (prod role "dunasan") is purged
  with the merchant orgs, so merchant onboarding stops at step 8 ("Template role not found") after
  partner/org/user/warehouse exist. Fix = `apply-role.sql` pattern used on the demo VM 2026-10-23:
  recreate AD_Role 1000006 as "Merchant Template" (org 0) with prod's window/process/form/
  doc-action/workflow access rows. iDempiere's validator then provisions each new merchant role
  (verified: role 1000019 got the full access set on creation).
- **Baked runtimeConfig**: see `05-apply-env-overrides.sh` (README step 3).

## Instances cloned from this template
| VM | IP | Tenant | Public host | Built | Notes |
|----|----|--------|-------------|-------|-------|
| 118 `musterlager-demo` | 192.168.12.68 | Musterlager GmbH | https://edge.logship.de | 2026-10-23 | lead demo; seeded by `reference/demo-instance/seed-demo-data.sh` (merchant "Muster Shop GmbH", 10 products, orders/shipments/invoice); plus lead merchant "Kazaar Fragrances" (org `kazaar`, 843 articles with images imported from their shop via `reference/demo-instance/import-merchant-catalog.sh`); logins in `/root/demo-credentials.txt` on the VM; REST secret rotated; reset = re-clone |

## Turning a clone of this template into a real instance

ONE COMMAND on prox2 (staged at /root/clone-logship-instance.sh, source in
repo reference/template-cleanup/) — clones, sets IP, boots, rebrands:

    /root/clone-logship-instance.sh <NEWID> <IP> "<ClientName>" \
        ["<OrgName>"] ["<CompanyLegalName>"] [--name x] [--memory MB] [--cores N] [--domain fqdn]

It performs steps 1–2 below; 3–8 stay manual per instance.

1. prox2: qm clone 115 <ID> --name <name> --full; qm set <ID>
   --ipconfig0 ip=<IP>/24,gw=192.168.12.1; start.
2. Rebrand the tenant (client/org/linked partner/warehouse/roles +
   .env COMPANYNAME — the template says "LogYou" everywhere):
     /root/template-cleanup/04-set-instance-identity.sh \
       "<ClientName>" "<OrgName>" "<CompanyLegalName>"
   (--dry-run first to preview; restarts iDempiere + frontend itself.
   Staff users/emails stay — replace them in the app.)
3. Fill /opt/erp-nuxt-frontend/.env: endpoints + credentials as needed;
   pm2 restart erpfrontend --update-env.
4. Rotate the iDempiere REST secret — it lives in AD_SysConfig, NOT in
   idempiere.properties. The cloned one equals production's, so prod
   tokens would be valid here:
     sudo -u postgres psql -d idempiere -c "UPDATE adempiere.ad_sysconfig
       SET value='$(openssl rand -hex 32)' WHERE name='REST_TOKEN_SECRET'"
     systemctl restart idempiere
   then re-issue IDEMPIERETOKEN (.env) via POST /api/v1/auth/tokens.
5. Re-enable wanted cron jobs from /root/crontab.production.bak.
6. Create orgs/partners/products via the app (Initial Org Setup).
7. If mail is needed: systemctl enable --now postfix + iDempiere SMTP config.
8. Monitoring: cmk-agent-ctl register ... against the monitoring site.
9. Public access: DNS A record → 5.9.170.82, then on edge-proxy-1 (192.168.12.52)
     /root/edge-proxy/add-instance.sh <fqdn> <IP> --letsencrypt info@logyou.de
   (standard LogShip host incl. REST/ZK/Strapi/SSE/websocket routes, see reference/edge-proxy/README.md).

## Cleanup tooling
/root/template-cleanup/ (also in ERP repo reference/template-cleanup/):
re-runnable on a fresh prod clone: 00-defuse.sh -> 03-neutralize-env.sh
-> run-cleanup.sh [--dry-run]. All scripts refuse to run on production
(guarded). The iDempiere/Strapi truncation has a dynamic catch-all for
tables that did not exist when the explicit lists were written.
