Ein leichtes, komplett browserbasiertes Getränke-Wallet für Freund:innen vom
Hackspace bitcircus101.de in Bonn und der
Datenburg e.V. Bonn – kein Backend, kein Server.
Alle Daten liegen ausschließlich lokal im Browser (localStorage) und lassen
sich per Export/Import zwischen Geräten übertragen.
- Live-Demo (GitHub Pages): https://bmmmm.github.io/db-wallet/
- Das ist das Deployment aus dem Original-Repo und dient hier als Beispiel.
index.htmlöffnen.- Namen für die Nutzer:in eingeben (oder leer lassen für Zufall) → weiter zu
wallet.html#<name>(z. B.wallet.html#peter). - Optional: Theme am Seitenende wählen; Auswahl wird gespeichert.
- Optional: In
wallet.html→ Export → „QR-Code (kurz) anzeigen“ (kompakt, minuten-genau, merge-fähig). Tipp: QR-Code antippen → PNG downloaden; der Link unter dem QR ist zum Kopieren markiert.
- Buchen: Getränke hinzufügen, Tagesstatistik inkl. Diagramm/Log/Raw.
- Korrigieren: letzte Buchung rückgängig (Löschmarker im Log, syncbar), danach komplette Neuberechnung aus dem Log.
- Bezahlen: Offene Getränke ausgleichen; Zahlungen sichtbar im Log.
- Guthaben: Gutschriften aufladen und abbauen wie Vorrat.
- Historie: Diagramm (inkl. Tages-Drinkcount in
[n]), Log mit IDs/Ranges inklusive Löschmarker, Raw-Daten pro Nutzer:in/alle. - Statistik: Offen/Guthaben werden ausgeblendet, wenn sie 0 sind.
- Verwaltung: Einträge bearbeiten/löschen, Nutzer:innen einzeln oder gesammelt löschen.
- Migration: v1-Wallets können für robusten QR-Export auf v2 migriert werden.
- Import/Export: Link (auto-merge), kompakter QR-Code oder JSON-Datei; Export enthält auch Theme + Wallet-ID gegen Namens-Kollisionen.
Action Codes können lokal (wallet-gebunden) oder global (wallet-agnostisch) sein. Der Scope wird beim Erstellen/Bearbeiten gewählt. Beim Scannen erfolgt sofort eine Buchung (ohne Reload):
- Typ Trinken: bucht ein Drink-Event.
- Typ Guthaben: bucht eine Gutschrift.
Wichtig:
- Verwaltung erfolgt inline per Buttons (New action code, Bearbeiten, Löschen).
- Die Mengenfrage im Inline-Formular passt sich dem Typ an (trinken vs gutschreiben).
- Pro Code ist der Scope wählbar: 🔒 Lokal (wallet‑gebunden) oder 🌍 Global.
- Lokale Action Codes sind an eine Wallet gebunden (Ziel-WalletId steckt im QR).
- Globale Action Codes sind stateless und wirken auf das aktuell geöffnete Wallet.
- Öffnest du
wallet.html#acg:…direkt, wird bei mehreren Wallets eine Auswahl angezeigt; bei genau einem Wallet wird automatisch gebucht. - Beim Bearbeiten (Name/Menge/Typ) wird der QR bei Bedarf neu erzeugt; alte Codes werden dann ungültig und werden beim Einlösen strikt abgelehnt.
- Der Betrag wird aus dem gespeicherten Action Code gelesen (nicht aus manipulierbaren QR-Feldern).
- QR-Payloads sind schlank gehalten; ältere Payloads bleiben kompatibel.
Globale Action Codes (#acg:...) sind rein datengetrieben:
- deterministisch: gleiche Eingaben → gleicher Link
- keine Speicherung, keine Secrets
- Validierung: Typ
d/g, Menge1..100 - wenn kein Wallet geöffnet ist, wird eine Hinweis‑Meldung angezeigt
- wirkt nur beim Scannen/Öffnen des Links, nicht automatisch
Die Wallet zeigt einen rein lokalen Sync-Status an, um den Stand zwischen Geräten (z. B. Laptop ↔ Handy) sichtbar zu machen. Es gibt keinen Hintergrund-Sync: Synchronisieren passiert ausschließlich durch Export/Import.
- Export/Import (Link/QR/JSON) ist der einzige Weg, Daten zwischen Geräten zu übertragen.
- Für die Sync-Anzeige zählen ausschließlich Events (nicht Getränkemengen).
1 Event = 1 Schritt auf der Timeline – unabhängig davon, ob ein Event
+1oder+10enthält.
Die ASCII-Timeline basiert auf der Anzahl der Events:
===|: fester Marker für „zuletzt sicher gemeinsam“ (die=wachsen nicht)- Zeichen nach
|: lokale Divergenz in Event-Schritten (1 Zeichen = 1 Event) - Die Anzahl der abweichenden lokalen Events wird zusätzlich separat als
Δangezeigt (keinΔR).
Beispiele:
Sync: ===|→ identischSync: ===|MMMM→ lokal 4 Events weiterSync: …==|MMMMMMMMMMMMMMMMMMMMMMMM→ Divergenz gekürzt (rechts priorisiert)
- Grün: Sync aktuell (≤ 5 Tage)
- Gelb: Sync alt (6–10 Tage)
- Rot: Sync veraltet (≥ 11 Tage) → Klick führt zur Export-Sektion
- Button „✅ passt“: manueller Vertrauens-Reset (setzt den Sync-Stand auf „gleich“ auf diesem Gerät, ohne Export/Import).
Pro Wallet gibt es eine synchronisierte Geräte-Liste (mit deviceKey, Symbol,
lastSeenAt), die bei Export/Import mitgesendet und deterministisch gemerged
wird:
- Maximal 6 Geräte pro Wallet (älteste Einträge werden automatisch entfernt).
- Pro Wallet ist jedes Symbol (
L/M/D/K/T/*) eindeutig und wird per Buttons in der Top-Row zugewiesen (keine Texteingabe, keine Prompts). - Das lokale Geräte-Symbol zeigt die eigene Device-ID direkt daneben (mobile-tauglich, kein Hover nötig).
Ein Teil der UI-Logik wurde aus wallet-ui.js in kleinere Dateien ausgelagert,
damit agentic coding / Review einfacher ist:
wallet-device-ui.js: Geräte-Symbol-Picker in der Top-Row (inkl. sichtbarer Device-ID)wallet-sync-ui.js: Sync-Status-Zeile (Ampel, Timeline, „✅ passt“)wallet-export-ui.js: Export-UI (Link, QR, JSON, QR-Session-Cache)wallet-history-ui.js: History-Ansicht (Diagramm/Log/Raw, Log-Tools)
Hinweis: wallet.html lädt diese Dateien vor wallet-ui.js.
Core (Logik/Codec/Storage):
wallet-helpers.js,wallet-storage.js,wallet-import-v2.jswallet-summary.js,wallet-sync.js,migration.jsaction-codes.js(Normalisierung, Merge, Hash encode/decode)hash-router.js(Hash-Parsing)
UI (DOM + Interaktion):
index-ui.js,wallet-ui.jswallet-device-ui.js,wallet-history-ui.js,wallet-export-ui.js,wallet-sync-ui.jsimport-preview.js,theme.js
Tools:
self-check.js(Konsole:window.dbWalletSelfCheck.run())
Im Browser (z. B. wallet.html) in der Konsole ausführen:
window.dbWalletSelfCheck.run()
Der Self-Check prüft u. a. Storage-Roundtrip, Import v2, Migration, Hash-Parsing, Summary-Parität, Tombstones/Undo und Action-Code-Payloads.
wallet.deviceId(Export/Sync-Metadatum) undwallet.seq(Event-Zähler pro Device-Key) bleiben getrennt; eine Zusammenlegung wäre nicht rückwärtskompatibel.
| Datei | Zweck |
|---|---|
index.html |
Startseite, Nutzer:innenwahl, Import/Export, Theme-Wahl |
wallet.html |
Drinks, Guthaben, Zahlungen, Historie/Raw, Theme-Wahl |
index-ui.js |
UI-Logik der Startseite (Routing, Liste, Import) |
wallet-ui.js |
Wallet-Composer/Entry (DOM-Wiring, Hash-Routing, Module initialisieren) |
wallet-device-ui.js |
Geräte-Symbol-Picker (Top-Row, sichtbare Device-ID) |
wallet-sync-ui.js |
Sync-Status UI (Ampel + ASCII-Timeline + „✅ passt“) |
wallet-export-ui.js |
Export UI (Link/QR/JSON, QR-Session-Cache, PNG-Download) |
wallet-helpers.js |
Helper (Base64URL, gzip, Storage-Safety, Registry) |
wallet-storage.js |
Wallet-Storage/Model (load/save, deviceKey, devices-Liste) |
wallet-import-v2.js |
Import/Export-Codec v2 + Hash-Import (inkl. Action Codes) |
wallet-summary.js |
Berechnung von Total/Offen/Guthaben/Diagramm (pure) |
wallet-sync.js |
Sync-Status Helfer (Ampel + ASCII-Timeline; lokal) |
action-codes.js |
Action Codes UI + Hash-Encoding/Decoding |
wallet-history-ui.js |
History-UI (Diagramm/Log/Raw, Log-Tools) |
hash-router.js |
Hash-Parsing (ac/import/i2/i2u) |
self-check.js |
In-Browser Self-Check (Konsole) |
theme.js |
Theme-Logik (Auswahl + Speicherung) |
import-preview.js |
Import-Auswahl (persist/preview) + Preview-Flow |
themes.css |
Theme-Paletten (CSS-Variablen) |
colors.html |
Vorschau aller 5 Themes mit Farbbalken & UI-Beispielen |
colors.css |
Styles für die Theme-Vorschau |
style.css |
Basis-UI, responsive Layout |
qrcodegen.js |
QR-Code-Generator (Nayuki) |
migration.js |
Migration v1 → v2 (für QR-Export) |
db-wallet ist eine reine Static-Webapp (HTML/CSS/JS) und kann auf vielen Open-Source-freundlichen „Pages“-Diensten deployed werden.
- Codeberg Pages (Forgejo-basiert): https://codeberg.page/
- GitLab Pages (gitlab.com oder self-hosted GitLab): https://docs.gitlab.com/ee/user/project/pages/
Forgejo/Gitea bringen üblicherweise kein integriertes „Pages“-Feature wie GitHub/GitLab mit. Typischer Setup:
- Repo in Forgejo (https://forgejo.org/) oder Gitea (https://about.gitea.com/)
- CI (Forgejo Actions / Woodpecker / Drone) baut die Static Site (falls nötig)
- Deploy auf einen separaten Static Host (z. B. Nginx/Caddy oder S3/MinIO)
Tipp: Wenn du keinen Build brauchst, reicht auch simples Hosting des Repo-Roots als Static-Verzeichnis.
Es sind keine Build-Schritte, keine Server-Komponenten und keine API-Keys notwendig.
Beispiel-URL (GitHub Pages):
https://bmmmm.github.io/db-wallet/
Viel Spaß mit deinem minimalistischen, schnellen Getränke-Wallet 🍹🚀
- File map (core vs UI): Core/codec/storage in
wallet-helpers.js,wallet-storage.js,wallet-import-v2.js,wallet-summary.js,wallet-sync.js,migration.js,action-codes.js,hash-router.js. UI inindex-ui.js,wallet-ui.js,wallet-device-ui.js,wallet-sync-ui.js,wallet-export-ui.js,wallet-history-ui.js,import-preview.js,theme.js. - Invariants: storage prefix
db-wallet:, registry keydb-wallet:registry, hash formats#<userId>,#import:,#i2:,#i2u:,#ac:,#acg:; event schema{id,t,n?,ts,ref?}with tombstonest:"x"+ref; action code SOFT/HARD limits 6/10; global#acg:deterministic and stateless. - Entrypoints & flow:
index.html→index-ui.js(list/create/import) andwallet.html→wallet-ui.js(hash classify → load wallet → compute summary → render UI);hash-router.jsis the single classifier/parser for hashes. - Where to edit: storage/model in
wallet-storage.js; summary/tombstones inwallet-summary.js; action-code encode/decode + UI inaction-codes.js; hash parsing inhash-router.js; UI wiring inindex-ui.js/wallet-ui.js/wallet-history-ui.js. - Quick manual checks: open
index.html→ create/open wallet → add drinks/pay → undo (tombstone) → export/import v2 → local/global action codes → openwallet.html#acg:…with 1+ wallets →window.dbWalletSelfCheck.run().