Ein in 2 Tagen entwickeltes Self-Checkout-System für einen unbemannten Laden

Bohfula / ボーフラ
Geschrieben von:
Ein in 2 Tagen entwickeltes Self-Checkout-System für einen unbemannten Laden

Hinweis: Dieser Artikel ist eine maschinelle Übersetzung aus dem ursprünglichen japanischen Beitrag. Falls Sie Übersetzungsfehler bemerken, lassen Sie es uns bitte wissen.

Hier erklären wir das bargeldlose, vollständige Self-Checkout-System, das wir in nur zwei Tagen für die Eröffnung des LOPPO Art Supply Shibuya Store (ein unbemannter Verkaufsstandort) entwickelt haben.

Einleitung: Das Projekt des unbemannten LOPPO Art Supply Ladens

LOPPO Art Supply ist eine Marke für Cel-Animations-Kunstbedarf, die als Hobby von Takahashi begann und bisher hauptsächlich über den Online-Handel vertrieben wurde. Anfang dieses Jahres beschlossen wir, ein kleines Ladenlokal als Veranstaltungsraum für LOPPO Art Supply zu mieten. Ursprünglich sollte eine Ecke als Lagerraum dienen, doch dann kam die Idee auf: „Wenn wir hier schon Waren lagern, könnten wir den Raum nicht gleich als Verkaufsstelle nutzen?"

Es gab schon seit Längerem Wünsche nach einem physischen Geschäft, aber die Sicherstellung der für den Ladenbetrieb notwendigen personellen Ressourcen war schwierig. So entstand die Idee eines „unbemannten Kunstbedarfsladens". Ähnlich wie ein Gemüse-Selbstbedienungsstand, aber für Cel-Animations-Kunstbedarf — ein traumhafter (oder verrückter!) Ort, an dem man 24 Stunden am Tag, 365 Tage im Jahr einkaufen kann.

Unbemannter Kunstbedarf-Laden (Konzeptbild) Unbemannter Kunstbedarf-Laden (Konzeptbild)

1. Herausforderungen bestehender Self-Checkout-Lösungen

Um einen unbemannten Laden ohne ständiges Personal zu realisieren, ist ein vollständiges Self-Checkout-System erforderlich. Für dieses Projekt haben wir uns entschieden, als Diebstahlschutz ausschließlich bargeldlose Zahlungen zu akzeptieren.

Zunächst haben wir kommerzielle Self-Checkout-Lösungen in Betracht gezogen, stießen aber auf zwei wesentliche Probleme:

  1. Hohe monatliche Fixkosten zusätzlich zu den Anfangsinvestitionen
  2. Lange Zyklen bis zur Gutschrift der Einnahmen

Für eine nachhaltige Betriebsführung ist es wichtig, die Fixkosten minimal zu halten und gleichzeitig einen gesunden Cashflow zu gewährleisten. So richteten wir unsere Aufmerksamkeit auf das Square-Zahlungssystem, das wir bereits bei früheren Veranstaltungsverkäufen eingesetzt hatten.

Square unterstützt eine Vielzahl von Zahlungsmethoden, erhebt keine monatlichen Gebühren (nur Transaktionsgebühren) und bietet schnelle Gutschriften — bereits am nächsten Geschäftstag. Darüber hinaus ermöglicht die Square API die Erstellung benutzerdefinierter Anwendungen. Da wir bereits ein Square Terminal besaßen, stellten wir fest, dass dessen Nutzung auch die Anfangskosten niedrig halten würde.

Allerdings gab es eine große Einschränkung bei der Entwicklung. Wir waren bereits mit der Produktherstellung für die Ladeneröffnung voll ausgelastet und konnten nur ganze 2 Tage für die Entwicklung des Self-Checkout-Systems aufwenden.

2. Systemdesign: Ein sicheres und benutzerfreundliches Self-Checkout

Gesamtarchitektur

Systemarchitektur-Diagramm

Das System besteht aus folgenden Hauptkomponenten:

  • Linux-Anwendungsserver: React-Frontend und Express-Backend
  • In-Store-System: Windows 11 Pro Kiosk-Modus-Client-Terminal, Peripheriegeräte und Square Terminal
  • Square-Dienste: Square API, Produktstammdaten
  • Überwachung & Betrieb: Überwachungskameras, unterbrechungsfreie Stromversorgung (USV), Netzwerkredundanz

Aus Sicht des Kunden sind nur der Touchscreen-Monitor, der Barcode-Scanner und das Square Terminal sichtbar. Der Client läuft im Windows 11 Pro Kiosk-Modus, während die Hauptanwendungslogik auf einem Linux-Rechner außerhalb des Ladens liegt.

Sicherheit und Netzwerk

Das Netzwerk arbeitet in einer VPN-Umgebung mit Tailscale, die die Kommunikation zwischen dem Client-Terminal und dem Linux-Server schützt. Zusätzlich sind alle Geräte an eine unterbrechungsfreie Stromversorgung angeschlossen, um vor Blitzschlag und Stromausfällen zu schützen, und das Netzwerk ist redundant konfiguriert, um einen stabilen Betrieb zu gewährleisten.

Die Einführung von Tailscale erleichtert auch die Fernwartung. Auf keinem Terminal werden lokale Daten gespeichert — alle Daten werden aus den Square-Systemen abgerufen.

Hardware-Konfiguration

  • Touchscreen-Monitor
  • USB-Barcode-Scanner
  • Square Terminal (Zahlungsabwicklung und Quittungsdruck)
  • Überwachungskamera (für Echtzeit-Überwachung)

Frontend-Implementierung

Zahlungsmethoden-Auswahlbildschirm Zahlungsmethoden-Auswahlbildschirm

Das Frontend wurde mit React entwickelt und besteht aus folgenden Hauptbildschirmen:

  1. Produktscan-Bildschirm
  2. Zahlungsmethoden-Auswahlbildschirm
  3. Zahlungsverarbeitungs-Bildschirm
  4. Zahlungsabschluss-Bildschirm

Obwohl maschinelle Übersetzung verwendet wird, haben wir auch eine Mehrsprachigkeit implementiert, die 6 Sprachen umfasst: Japanisch, Englisch, Französisch, Spanisch, Traditionelles Chinesisch und Vereinfachtes Chinesisch. Dadurch können auch internationale Besucher das System problemlos nutzen.

// Beispiel für Sprachkonfiguration
const translations = {
  ja: {
    title: 'セルフレジシステム',
    scanTitle: '商品スキャン',
    // ...ausgelassen
  },
  en: {
    title: 'Self-Checkout System',
    scanTitle: 'Product Scan',
    // ...ausgelassen
  },
  // Weitere Sprachen...
};

Wir haben das System so gestaltet, dass Barcode-Scanner-Eingaben priorisiert werden, um eine Benutzeroberfläche zu schaffen, die Nutzer ohne Verwirrung bedienen können.

3. Wichtige Aspekte der Square API-Integration

Zahlungsabwicklung mit der Terminal API

Unter den Square APIs ist die Terminal API besonders wichtig. Sie ermöglicht es uns, Zahlungsverarbeitungsanfragen an das Square Terminal zu senden.

// Terminal-Checkout erstellen
app.post("/api/create-terminal-checkout", async (req, res) => {
  try {
    const { order, amountMoney, paymentType = "CARD_PRESENT" } = req.body;

    const ALLOWED = new Set([
      "CARD_PRESENT",
      "FELICA_TRANSPORTATION_GROUP",
      "FELICA_ID",
      "FELICA_QUICPAY",
      "QR_CODE"
    ]);

    if (!ALLOWED.has(paymentType)) {
      return res.status(400).json({ error: "Nicht unterstützte Zahlungsmethode angegeben" });
    }

    // Bestellung zuerst erstellen
    const orderId = await createOrder(order);

    // Square Terminal Checkout erstellen
    const checkoutResponse = await squareClient.terminal.checkouts.create({
      idempotencyKey: randomUUID(),
      checkout: {
        amountMoney: {
          // Betrag muss BigInt sein
          amount: BigInt(amountMoney.amount),
          currency: amountMoney.currency,
        },
        deviceOptions: {
          deviceId: SQUARE_DEVICE_ID,
          skip_receipt_screen: true,
          show_itemized_cart: false,
        },
        referenceId: orderId,
        orderId,
        note: "Zahlung am LOPPO Self-Checkout",
        paymentType: paymentType
      },
    });

    res.json(checkoutResponse);
  } catch (error) {
    handleError("Terminal-Checkout-Erstellungsfehler", error, res);
  }
});

Vielfältige Zahlungsmethoden

Da das Square Terminal eine Vielzahl von Zahlungsmethoden unterstützt, können Kunden mit ihrer bevorzugten Methode bezahlen:

  • Kredit-/Debitkarten
  • Transit-IC-Karten (Suica/PASMO usw.)
  • iD
  • QUICPay
  • QR-Code-Zahlungen (PayPay usw.)

Bitte beachten Sie, dass UnionPay-Karten nicht unterstützt werden.

Polling des Zahlungsstatus

Da die Zahlungsverarbeitung auf dem Square Terminal stattfindet, müssen wir den Status wie Abschluss oder Stornierung durch Polling abfragen.

// Zahlungsstatus durch Polling prüfen
const checkPaymentStatus = async () => {
  try {
    const statusResponse = await fetch(`/api/get-checkout-status?checkoutId=${data.checkout.id}`);
    const statusData = await statusResponse.json();

    if (statusData.status === 'COMPLETED') {
      setPaymentStatus(t.paymentCompleted);
      // Abschlussverarbeitung
      setTimeout(() => {
        setStatus('complete');
        setCart([]);
      }, 2000);
    } else if (statusData.status === 'CANCELED' || statusData.status === 'CANCEL_REQUESTED') {
      setPaymentStatus(t.paymentCanceled);
      setTimeout(() => {
        setStatus('ready');
      }, 3000);
    } else {
      // Falls noch nicht abgeschlossen, erneut prüfen
      setPaymentStatus(t.processing);
      setTimeout(checkPaymentStatus, 2000);
    }
  } catch (error) {
    console.error(t.statusCheckFailed, error);
    setPaymentStatus(t.statusCheckFailed);
    setTimeout(() => {
      setStatus('ready');
    }, 3000);
  }
};

Produktstammdaten-Verwaltung

Alle Produktinformationen werden über das Square-Dashboard registriert und über die API abgerufen. Dies vereinfacht betriebliche Aufgaben wie das Hinzufügen von Produkten oder Preisänderungen.

app.get("/api/catalog-items", async (_req, res) => {
  try {
    const TYPES = "ITEM,ITEM_VARIATION,CATEGORY,IMAGE"; // Alle benötigten Typen auflisten
    //------------------------------------------------------------------
    // 1. Alles laden
    //------------------------------------------------------------------
    const objects = [];
    for await (const obj of await squareClient.catalog.list({ types: TYPES }))
      objects.push(obj);

    //------------------------------------------------------------------
    // 2. Zuerst Maps für CATEGORY / IMAGE / VARIATION erstellen
    //------------------------------------------------------------------
    const imageMap     = {};
    const categoryMap  = {};
    const variationMap = {};

    // ...ausgelassen (Map-Erstellungslogik)

    //------------------------------------------------------------------
    // 3. ITEMs erweitern und Informationen mit den oben erstellten Maps einbetten
    //------------------------------------------------------------------
    const filtered = objects
      .filter((o) => o.type === "ITEM")
      .map((item) => {
        // ...ausgelassen (Datentransformationslogik)
      })
      // -- Anforderungsfilter hier anwenden --
      .filter(
        (item) =>
          !item.isArchived &&
          item.categoryNames.includes("六方画材")
      );

    res.json(filtered);
  } catch (error) {
    handleError("Fehler beim Abrufen der Katalogartikel", error, res);
  }
});

4. Schnelle Entwicklung mit LLMs

Das herausragende Merkmal dieses Projekts ist, dass es in nur 2 Tagen abgeschlossen wurde. Dies wurde durch den Einsatz von LLMs (Large Language Models) ermöglicht.

Aufteilung der Entwicklungszeit

  • Kernsystementwicklung: ca. 2 Stunden
  • Verfeinerung & UI-Anpassungen: ca. 4 Stunden
  • Tests & Deployment: verbleibende Zeit

Einsatz von Claude 3.7 Sonnet

Wir haben hauptsächlich Claude 3.7 Sonnet während der Entwicklung eingesetzt, um die Implementierung zu optimieren. Es bewältigte nicht nur die Anwendungslogik, sondern auch das UI-Design mühelos und bereitete sogar Setup-Dokumentation vor — ein wirklich umfassender Assistent. Die Vorschläge des LLM waren besonders wertvoll für den Mehrsprachigkeitscode und die Square API-Integration.

Wir haben auch ChatGPT 4o und ChatGPT o3 kombiniert eingesetzt, aber was das Verständnis von Webanwendungen betrifft, konnten sie mit 3.7 Sonnet nicht mithalten.

Praktische Beispiele für den LLM-Einsatz

Dies ist eine gängige Warnung bei der Verwendung von LLMs in der Entwicklung, aber es ist schwierig, generierten Code direkt zu verwenden — es ist essenziell, ihn zu verstehen und notwendige Anpassungen vorzunehmen. Zum Beispiel waren folgende Korrekturen für die Square Terminal API-Integration erforderlich:

  1. Hinzufügen von Zahlungsmethoden: Der vom LLM generierte Code unterstützte nur Kreditkartenzahlungen, daher mussten wir einen Bildschirm zur Auswahl der Zahlungsmethode hinzufügen
  2. Fehlerbehandlung: Die Behandlung von Terminal-Zahlungsstornierungsereignissen war fehlerhaft, daher haben wir sie anhand der API-Dokumentation korrigiert
  3. Sicherheit: Ein Teil der Anwendungskommunikation verwendete unsichere Protokolle, daher haben wir ein privates VPN aufgebaut, um den Kommunikationsweg zu sichern

Das LLM lieferte die grundlegende Codestruktur, aber Anpassungen für die Produktionsreife mussten manuell vorgenommen werden.

5. Internationalisierung und Benutzerfreundlichkeit

Mehrsprachige Implementierung

Um internationale Besucher zu unterstützen, unterstützt das System 6 Sprachen: Japanisch, Englisch, Französisch, Spanisch, Traditionelles Chinesisch und Vereinfachtes Chinesisch. Spracheinstellungen werden innerhalb von React-Komponenten verwaltet, und alle Bildschirmtexte werden aus Übersetzungsobjekten abgerufen.

// Zustandsverwaltung der Sprachauswahl
const [language, setLanguage] = useState('ja'); // Standardsprache auf Japanisch setzen
// Spracheinstellungen abrufen
const t = translations[language];

// Verwendungsbeispiel
<h1 className="text-4xl font-bold">{t.title}</h1>
<p className="text-lg text-gray-700 mb-6">
  {t.scanDescription}
</p>

Überlegungen zur Benutzerfreundlichkeit

Wir haben eine Benutzererfahrung angestrebt, die den Self-Checkout-Automaten in Supermärkten und Convenience Stores ähnelt, und dabei folgende Designentscheidungen getroffen:

  1. Barcode-Scan-Priorität: Tastatureingaben werden überall auf der Seite akzeptiert und Barcode-Scanner-Eingaben immer priorisiert
  2. Große Schaltflächen: Schaltflächengrößen optimiert für einfache Touch-Bedienung
  3. Klares Feedback: Leicht verständliche Nachrichten, die Operationsergebnisse anzeigen

Durch diese Designentscheidungen glauben wir, eine Benutzeroberfläche geschaffen zu haben, die Nutzer ohne Verwirrung bedienen können.

6. Betriebliche Überlegungen

Echtzeit-Überwachung und Störungsreaktion

Netzwerkkameras sind im Laden installiert, sodass wir den Zustand des Ladens in Echtzeit überprüfen können. Bei Problemen können Kunden die an der Ladenfront ausgehängte Telefonnummer anrufen, um Hilfe zu erhalten.

Wenn eine Betriebsanomalie erkannt wird, haben wir ein System, das es ermöglicht, innerhalb von 30 Minuten bis 2 Stunden vor Ort zu sein. Zusätzlich können wir als Ausweichlösung, falls das Zahlungsterminal nicht funktioniert, nachträglich einen Zahlungslink bereitstellen, um die Transaktion abzuschließen.

Für einen stabilen Betrieb haben wir auch eine USV-Stromversorgung, Netzwerkredundanz und periodische Neustarts während Leerlaufzeiten eingerichtet.

Es gab einen Vorfall, bei dem das Stromkabel des Clients locker war, weil es nicht vollständig eingesteckt war, aber seitdem läuft das System sehr stabil.

7. Ergebnisse und Auswirkungen

Erweiterung der Verkaufsmöglichkeiten

Die Eröffnung des unbemannten Ladens ermöglichte es uns, wertvolle 24/7-Verkaufsmöglichkeiten in der Nähe eines zentralen Bahnhofs zu sichern. Die größte Errungenschaft war es, die Nachfrage nach einem physischen Geschäft zu erfüllen und gleichzeitig die personellen Ressourcenbeschränkungen zu überwinden.

Trends bei Zahlungsmethoden

Alle implementierten Zahlungsmethoden werden recht gleichmäßig genutzt, aber die beliebtesten sind in dieser Reihenfolge:

  1. Transit-IC-Karten
  2. QR-Code-Zahlungen (PayPay usw.)
  3. Kreditkarten (kontaktloses Bezahlen)

8. Zukunftspläne und Erweiterung

Ausbau des Online-Vertriebs

Der aktuelle LOPPO Art Supply Online-Shop basiert auf BASE, aber wir planen die Migration auf ein Square API-basiertes System. Dies wird nicht nur die Transaktionsgebühren senken, sondern auch den Produktkaufablauf verbessern und die Bestands- und Umsatzverwaltung zwischen physischem Laden und Online-Verkauf vereinheitlichen.

Darüber hinaus möchten wir die Möglichkeit anbieten, online zu kaufen und im Laden abzuholen.

Fazit: Wer Farben herstellen kann, kann auch ein Kassensystem bauen

LOPPO hat verschiedene Cel-Animations-Kunstbedarfsartikel von Hand nachgefertigt, und diesmal haben wir ein Kassensystem handgefertigt.

Softwareanwendungen können manchmal relativ einfach erstellt werden, indem vorhandene APIs und LLM-Unterstützung genutzt werden, wie hier demonstriert. Dennoch hätten wir nie gedacht, dass ein Kassensystem so einfach gebaut werden kann, und es war eine äußerst lehrreiche Erfahrung.

Wichtige Prinzipien

  1. Nutzung bestehender Dienste: Maximale Nutzung vorhandener Plattformen wie Square API
  2. Einsatz von Unterstützungstools wie LLMs: Proaktive Einführung von Tools zur Steigerung der Entwicklungseffizienz
  3. Fokus auf den minimal notwendigen Umfang: Einfache Implementierung durch Konzentration auf wesentliche Funktionen

Wir hoffen, dass dieser Artikel als nützliche Referenz für alle dient, die am Aufbau eines Self-Checkout-Systems interessiert sind oder den Einsatz der Square API in Betracht ziehen.

Der vollständige Quellcode des von uns entwickelten Systems ist auf GitHub verfügbar. loppo-llc/loppo-register - GitHub

Bohfula / ボーフラ

Bohfula / ボーフラ

Ein unabhängiger Spieleentwickler mit einem eigentümlichen teekannenförmigen Kopf. Wird oft von Takahashi gerufen, um bei LOPPO-Operationen und Werbung zu helfen.