# Abundomy 1CoinH — Beheerdershandleiding (deze omgeving) Technische runbook voor de beheerder van **deze machine** (`SER5`, gebruiker `patrick`). Beschrijft alle services, tools, bestandslayout, commando's en het onderhoud van de live omgeving op **https://app.reikiwereld.eu**. > **Conventie:** elk commando is compleet en plak-klaar. Bevat een commando een afgeleide > waarde (sleutel-ID, CID, peer-ID, IP), dan staat **eerst** het commando om die waarde op > te zoeken en **daarna** het commando dat de waarde gebruikt (met een voorbeeldwaarde). --- ## 0. In één oogopslag | Wat | Waarde | |---|---| | Publieke URL | `https://app.reikiwereld.eu` | | Wat het is | Serverless community-munt (1CoinH) — statische SPA op IPFS + libp2p-relay | | SPA-hosting | Systeem-**Kubo** (gateway `127.0.0.1:8080`) via **IPNS + DNSLink** | | Datalaag | **abundomy-relay** (Helia + OrbitDB + floodsub) op `127.0.0.1:9091` (ws) | | TLS-rand | **nginx** op `:443`, Let's Encrypt (auto-renew) | | Publiceren van updates | `cd /home/patrick/Projecten/AbundomyWEB/abundomy-dapp && npm run deploy` | **Twee IPFS-lagen — niet verwarren:** 1. **Systeem-Kubo** (`~/.ipfs`, daemon `ipfs.service`) — host de **statische SPA** en is de **gateway** die nginx aanspreekt. 2. **App-Helia** (`abundomy-dapp/.abundomy-relay/`, in het relay-proces) — draagt de **live OrbitDB-data** (gebruikers, transacties). Apart van Kubo. --- ## 1. Tools & versies | Tool | Versie | Locatie | Rol | |---|---|---|---| | Node.js | v22.22.1 | `/usr/bin/node` | runtime van de app + relay | | npm | 9.2.0 | `/usr/bin/npm` | scripts/dependencies | | Kubo (IPFS) | 0.35.0 | `/usr/local/bin/ipfs` | SPA-hosting + gateway + IPNS | | nginx | 1.28.3 | `/usr/sbin/nginx` | TLS-terminatie + reverse proxy | | certbot | 4.0 | `/usr/bin/certbot` | Let's Encrypt-certificaat | | chromium (snap) | systeem | `/snap/bin/chromium` | browser-tests (Playwright) | Versies bevestigen: ```bash node -v; npm -v; /usr/local/bin/ipfs --version; nginx -v; certbot --version ``` --- ## 2. Netwerk & DNS - **LAN-host:** `192.168.10.10` · **router/gateway:** `192.168.10.1` - **Publiek IPv4:** dynamisch (geen CGNAT). Router-port-forward **80, 443, 4001 → 192.168.10.10** staat aan. - **DNS** wordt gehost bij **dn-s.nl** (nameservers `ns1/ns3.dn-s.nl`, `ns2.dn-s.be`, `ns4.dn-s.org`). Records: | Naam | Type | Waarde | Doel | |---|---|---|---| | `app.reikiwereld.eu` | A | (huidig publiek IPv4) | wijst het subdomein naar deze machine | | `_dnslink.app.reikiwereld.eu` | TXT | `dnslink=/ipns/` | koppelt domein aan de gepubliceerde SPA | | `reikiwereld.eu` (apex) + `*` wildcard | A | `136.144.237.141` | bestaande TransIP-site (ongemoeid laten) | **Huidig publiek IPv4 opzoeken** (de A-record-waarde die moet kloppen): ```bash curl -4 -s https://api.ipify.org; echo # bijv. → 94.209.97.5 ``` **Controleren wat het A-record nú is (autoritatief):** ```bash dig +short @ns1.dn-s.nl app.reikiwereld.eu A # moet gelijk zijn aan de uitkomst hierboven; zo niet → A-record bij dn-s.nl bijwerken ``` > ⚠️ Het publieke IP is **dynamisch**. Wijzigt het, dan is de site onbereikbaar tot het > A-record bij dn-s.nl is bijgewerkt (DDNS is bewust nog niet ingericht). --- ## 3. Bestandslayout ### Projectroot `/home/patrick/Projecten/AbundomyWEB/` | Pad | Belang | Inhoud | |---|---|---| | `abundomy-dapp/` | **kern** | De serverless dapp (SPA, relay, ledger, migratie). | | `Abundomy/` | bron | Kopie van de oude PHP/LAMP-website (teksten/i18n in `json/`). | | `abundomy-money-git/` | bron | Git-bron van de oorspronkelijke 1CoinH-omgeving. | | `1CoinH_24_05_2026.sql` | bron-data | MySQL-dump; door de relay geïmporteerd (versleuteld) naar OrbitDB. | | `Datastructure 1CoinH.pdf` | referentie | Documentatie van het oude SQL-schema. | | `PLAN.md` | referentie | Volledig migratie-/bouwplan (app-internals, fases). | | `.claude.md` | referentie | Project-instructies voor Claude Code. | | `docs/` | documentatie | Dit document + het publieks-overzicht. | | `kubo/` | bron | Kubo-broncode/installatie (niet de actieve repo; die is `~/.ipfs`). | ### `abundomy-dapp/` | Pad | Belang | Inhoud | |---|---|---| | `src/` | **kern-logica (portable)** | `ledger.mjs` (saldo/decay/UBI), `payments.mjs`, `identity.mjs` (SSI/claims), `crypto.mjs` (profielversleuteling), `stores.mjs` (OrbitDB-stores), `orbit.mjs`/`ipfs.mjs` (Helia/OrbitDB-setup), `fork-detection.mjs`, `export.mjs` (zelf-verifieerbare keten), `lists.mjs`, `ipns.mjs`, `publish.mjs`, `config.mjs`, `node-paths.mjs`. | | `web/` | **frontend + relay** | `relay.mjs` (libp2p-relay, **gebruikt door de systemd-service**), `server.mjs` (alles-in-één productieserver, alternatief), `index.html` + `src/` (de SPA), `build-site.mjs`/`publish-site.mjs` (oude site-generator via app-Helia), `public/relay.json`. | | `migration/` | data-import | `parse-sql.mjs` (mysqldump-parser), `migrate.mjs`, `import.mjs`. | | `test/` | tests | `node --test` suite (29 tests). | | `poc/` | bewijs | `two-peer-payment.mjs` (twee-peer-betaling). | | `dist-web/` | **build-output** | Wat naar Kubo wordt gepubliceerd (incl. `relay.json`). Wordt door `npm run build:web` overschreven. | | `deploy.sh` | **deploy-helper** | Publiceert de SPA naar Kubo (zie §8). | | `.abundomy-data/` | runtime | OrbitDB-data van eerdere lokale runs (~3 MB). | | `.abundomy-relay/` | **runtime (live)** | Helia-blockstore + OrbitDB van de **relay-service** (~5 MB). | | `.abundomy-ipfs/` | runtime | App-Helia blockstore van publish-experimenten (~278 MB; niet de live SPA-hosting). | | `.abundomy-poc/` | runtime | Data van de PoC. | ### Systeem-locaties | Pad | Inhoud | |---|---| | `~/.ipfs/` | **Kubo-repo** (config, blocks, keys) van de live gateway/hosting. | | `/etc/systemd/system/ipfs.service` | Kubo-daemon-unit (`User=patrick`, `ExecStart=/usr/local/bin/ipfs daemon`). | | `/etc/systemd/system/abundomy-relay.service` | Relay-unit (zie §4). | | `/etc/nginx/sites-available/app.reikiwereld.eu` | nginx-site (symlink in `sites-enabled/`). | | `/etc/letsencrypt/live/app.reikiwereld.eu/` | TLS-cert (`fullchain.pem`, `privkey.pem`). | | `/var/www/html/` | webroot voor de ACME-challenge (cert-vernieuwing). | --- ## 4. Services (systemd) Twee services houden alles draaiend; beide herstarten automatisch en starten bij boot. **Status van beide bekijken:** ```bash systemctl status ipfs.service abundomy-relay.service --no-pager ``` **De relay (datalaag) beheren:** ```bash sudo systemctl restart abundomy-relay.service # herstarten sudo systemctl stop abundomy-relay.service # stoppen sudo systemctl start abundomy-relay.service # starten journalctl -u abundomy-relay.service -n 50 --no-pager # laatste logregels journalctl -u abundomy-relay.service -f # live meekijken ``` **Kubo (hosting/gateway) beheren:** ```bash sudo systemctl restart ipfs.service journalctl -u ipfs.service -n 50 --no-pager ``` **Relay-unit (env-variabelen):** `/etc/systemd/system/abundomy-relay.service` draait `node web/relay.mjs` met: `ABUNDOMY_RELAY_BIND=127.0.0.1`, `ABUNDOMY_RELAY_WS_PORT=9091`, `ABUNDOMY_ANNOUNCE=/dns4/app.reikiwereld.eu/tcp/443/wss`. Na het wijzigen van de unit: ```bash sudo systemctl daemon-reload && sudo systemctl restart abundomy-relay.service ``` **Controleren dat de relay luistert:** ```bash ss -tlnp | grep ':9091' # verwacht: LISTEN ... 127.0.0.1:9091 ... users:(("node",...)) ``` --- ## 5. IPFS / Kubo-beheer De live SPA wordt geserveerd via een **IPNS-sleutel** (`abundomy-app`) waar de DNSLink-TXT naar wijst. Updaten doe je met de deploy-helper (§8); hieronder de losse beheercommando's. **De IPNS-sleutel-ID opzoeken** (variabele in bijna alle volgende commando's): ```bash ipfs key list -l | awk '$2=="abundomy-app"{print $1}' # bijv. → k51qzi5uqu5diadbqiyg2s4gtq870dyoeop7u8nhw0pltt2ophutljl8qjzwc6 ``` **Welke CID staat er nu live** (resolve de IPNS-naam — vul de sleutel-ID van hierboven in): ```bash ipfs name resolve /ipns/k51qzi5uqu5diadbqiyg2s4gtq870dyoeop7u8nhw0pltt2ophutljl8qjzwc6 # bijv. → /ipfs/bafybeiaciqrh4ieogbqhjkxna6cw44mg2iovx6ngpgohxxyths2cdu2auy ``` **Controleren dat die CID gepind is** (vul de CID uit de vorige stap in): ```bash ipfs pin ls --type=recursive bafybeiaciqrh4ieogbqhjkxna6cw44mg2iovx6ngpgohxxyths2cdu2auy ``` **De DNSLink-TXT controleren (moet naar dezelfde IPNS-sleutel wijzen):** ```bash dig +short TXT _dnslink.app.reikiwereld.eu # verwacht: "dnslink=/ipns/" ``` **Lokaal testen dat de gateway de site via DNSLink serveert:** ```bash curl --resolve app.reikiwereld.eu:443:127.0.0.1 -sS -o /dev/null -w '%{http_code}\n' https://app.reikiwereld.eu/ # verwacht: 200 ``` **Opslag opruimen** (verwijdert losse, niet-gepinde blocks; pins blijven intact): ```bash ipfs repo gc ``` --- ## 6. nginx + TLS De site-config routeert WebSocket-upgrades (`Upgrade: websocket`) naar de relay (`:9091`) en al het overige naar de Kubo-gateway (`:8080`, met `Host: app.reikiwereld.eu` zodat DNSLink werkt). **Config testen en herladen na een wijziging:** ```bash sudo nginx -t && sudo systemctl reload nginx ``` **Certificaat-status bekijken:** ```bash sudo certbot certificates ``` **Auto-renew testen (simulatie, wijzigt niets):** ```bash sudo certbot renew --dry-run ``` Het cert vernieuwt automatisch via `certbot.timer` (HTTP-01/webroot `/var/www/html`). **Handmatig forceren** (zelden nodig): ```bash sudo certbot certonly --webroot -w /var/www/html -d app.reikiwereld.eu \ --cert-name app.reikiwereld.eu --force-renewal -n \ --agree-tos -m patrick.bomer@gmail.com sudo systemctl reload nginx ``` --- ## 7. De app bouwen, testen en lokaal draaien Altijd vanuit de dapp-map: ```bash cd /home/patrick/Projecten/AbundomyWEB/abundomy-dapp ``` | Doel | Commando | |---|---| | Dependencies (her)installeren | `npm install` | | Tests draaien (verwacht 29/29) | `npm test` | | SPA bouwen → `dist-web/` | `npm run build:web` | | Relay los starten (dev) | `npm run relay` | | SPA in dev-server (Vite) | `npm run dev` | | Twee-peer-betaling (PoC) | `npm run poc` | | Dubbele-uitgave scannen | `npm run scan:forks` | **Browser-test (Ubuntu 26.04: Playwright-chromium wordt niet ondersteund → gebruik snap-chromium).** Eenmalig Playwright in een wegwerp-map zetten (laat de app-deps schoon): ```bash mkdir -p /tmp/pwtest && cd /tmp/pwtest && npm init -y >/dev/null && \ PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm i playwright@latest ``` In scripts de systeem-chromium aanwijzen: `chromium.launch({ executablePath: '/snap/bin/chromium', args: ['--no-sandbox'] })`. Tegen de **publieke** URL testen vanaf deze machine (omzeil NAT-hairpin met een host-map): voeg `'--host-resolver-rules=MAP app.reikiwereld.eu 127.0.0.1'` toe aan de launch-args. --- ## 8. Deploy-workflow — de helper `deploy.sh` ⭐ **Wanneer:** alleen bij wijzigingen aan de **frontend/app-code** (UI, teksten, features). Dagelijks gebruik (betalingen, nieuwe leden, saldi) is **live OrbitDB-data** en vergt **geen** deploy. **Eén commando:** ```bash cd /home/patrick/Projecten/AbundomyWEB/abundomy-dapp && npm run deploy ``` (Equivalent: `bash deploy.sh`. Build overslaan als je al gebouwd hebt: `bash deploy.sh --no-build`.) **Wat het script doet (5 stappen):** 1. **`npm run build:web`** → verse `dist-web/`. 2. **`dist-web/relay.json` forceren naar het publieke `wss://`-adres.** Dít is de valkuil: Vite kopieert `web/public/relay.json` (met het lokale `127.0.0.1`-adres) de build in; zonder deze correctie verbreekt elke bezoeker de relay-verbinding. Het script behoudt de store-adressen en zet alleen `addr` om naar `/dns4/app.reikiwereld.eu/tcp/443/wss/p2p/`. 3. **`ipfs add -rQ --cid-version=1 dist-web`** + `ipfs pin add` → nieuwe CID. 4. **`ipfs name publish --key=abundomy-app /ipfs/`** → IPNS wijst naar de nieuwe CID (DNSLink/DNS blijven ongemoeid). 5. **De vorige CID ontpinnen** (gedeelde blocks blijven via de nieuwe CID gepind). **Instelbaar via env-variabelen** (defaults tussen haakjes): ```bash ABUNDOMY_DOMAIN=app.reikiwereld.eu ABUNDOMY_IPNS_KEY=abundomy-app npm run deploy ``` **De relay-peer-ID die het script in `relay.json` zet, opzoeken** (deterministisch uit de seed): ```bash python3 -c "import json;print(json.load(open('/home/patrick/Projecten/AbundomyWEB/abundomy-dapp/web/public/relay.json'))['addr'].split('/p2p/')[-1])" # bijv. → 12D3KooWEAUDdfvNWdqTokQqV64X1gMix56Y35EWAMjKWGB9HjwQ ``` **Na een deploy verifiëren** — eerst de nu-live CID opzoeken, dan de site ophalen: ```bash # 1) live CID opzoeken ipfs name resolve /ipns/k51qzi5uqu5diadbqiyg2s4gtq870dyoeop7u8nhw0pltt2ophutljl8qjzwc6 # bijv. → /ipfs/bafybeiaciqrh4ieogbqhjkxna6cw44mg2iovx6ngpgohxxyths2cdu2auy # 2) site ophalen via de publieke route (lokaal getest) curl --resolve app.reikiwereld.eu:443:127.0.0.1 -sS -o /dev/null -w '%{http_code}\n' https://app.reikiwereld.eu/ ``` > Let op: na publicatie kan de gateway de oude IPNS-resolutie nog even cachen → enkele > minuten vertraging voor bezoekers de update zien. --- ## 9. Externe verificatie (bereikbaarheid van buitenaf) **Haalt een client buiten je netwerk de site op? (HTTP-status via een externe node):** ```bash ID=$(curl -s -H "Accept: application/json" "https://check-host.net/check-http?host=https://app.reikiwereld.eu/&max_nodes=4" | python3 -c "import sys,json;print(json.load(sys.stdin)['request_id'])") # kort wachten, dan resultaat ophalen (vul het ID van hierboven in): curl -s "https://check-host.net/check-result/$ID" | python3 -m json.tool ``` **Is poort 443/4001 extern open?** Vervang `:443` desgewenst door `:4001`: ```bash ID=$(curl -s -H "Accept: application/json" "https://check-host.net/check-tcp?host=app.reikiwereld.eu:443&max_nodes=4" | python3 -c "import sys,json;print(json.load(sys.stdin)['request_id'])") curl -s "https://check-host.net/check-result/$ID" | python3 -m json.tool ``` --- ## 10. MCP-servers (Claude Code) Geconfigureerd voor dit project (zie ook §11): | Server | Scope | Bron | Doel | |---|---|---|---| | `context7` | project (`../.mcp.json`) | `https://mcp.context7.com/mcp` (HTTP) | library-/framework-docs | | `sequential-thinking` | project | npx-pakket | gestructureerd redeneren | | `playwright` | project | `@playwright/mcp` | browser-automatisering | | `ipfs` | local | `npx --package=ipfs-mcp ipfs-mcp-enhanced` | praat met lokale Kubo (`127.0.0.1:5001`) | | `filesystem` | local | `@modelcontextprotocol/server-filesystem` | bestanden in de projectmap | **Overzicht + gezondheid bekijken:** ```bash claude mcp list ``` --- ## 11. Het project voortzetten met Claude Code Voor functionele uitbreiding of wijziging: open een Claude Code-sessie in `/home/patrick/Projecten/AbundomyWEB`. Claude leest dan automatisch de onderstaande context. **Dit zijn de exacte bestanden waarmee het project wordt opgepakt:** | Bestand | Rol bij voortzetten | |---|---| | `/home/patrick/Projecten/AbundomyWEB/.claude.md` | **Project-instructies** voor Claude (rol, bronnen, regels). Lees/actualiseer dit eerst. | | `/home/patrick/Projecten/AbundomyWEB/PLAN.md` | **App-internals & fases** — hoe ledger, migratie, OrbitDB, PoC, relay en hosting in elkaar zitten. De inhoudelijke waarheid van de dapp. | | `~/.claude/projects/-home-patrick-Projecten-AbundomyWEB/memory/MEMORY.md` | **Geheugen-index** — één regel per notitie, elke sessie ingeladen. | | `~/.claude/projects/-home-patrick-Projecten-AbundomyWEB/memory/abundomy-deploy-plan.md` | **Deployment-geheugen** — alle beslissingen, machinefeiten, live-status (CID, IPNS-sleutel, domein, services). Begin hier voor de actuele stand van de productieomgeving. | | `docs/Admin-Runbook.md` (dit bestand) | Operationele handleiding. | | `docs/Abundomy-IPFS-Overview.md` | Publieks-/visiedocument. | **Voorbeeld van een onderhoudshelper — `abundomy-dapp/deploy.sh`.** Dit is hét referentievoorbeeld van hoe een herhaalbare handeling in dit project wordt vastgelegd: het bundelt build → relay.json-correctie → `ipfs add`/pin → `ipfs name publish` → oude CID opruimen in één `npm run deploy` (zie §8). Nieuwe operationele taken (bijv. een DDNS-updater, of een backup-script voor `~/.ipfs` en `.abundomy-relay/`) volgen bij voorkeur ditzelfde patroon: een klein, idempotent script in de repo, met een `npm`-script als ingang, en hier in de runbook gedocumenteerd. **De geheugenbestanden bekijken/bewerken:** ```bash ls -la ~/.claude/projects/-home-patrick-Projecten-AbundomyWEB/memory/ ``` --- *Einde runbook. Live omgeving: https://app.reikiwereld.eu — beheerd vanaf deze machine, geen externe diensten.*