# Online-Betrieb: API, MySQL, Tablet, Rechnungsversand Seine Idee vom 06.09.2026, wörtlich: > „die software ist aktuell nur lokal, und da reicht sqlite. wenn wir die online funktion einbauen, > dann muss man einen api key eintragen, und die api verteilt das auf die mysql — dann ist das > extern auf dem server und du kannst von überall über domain und apikey auch unterwegs per tablet > beim kunden die rechnung schreiben, live oder vorab-rechnung, und der smtp-server schickt sie > direkt dem kunden auf die hinterlegte e-mail. fertig. alles automatisch." **Status: Idee. Nichts davon ist gebaut.** Der Schnitt ist richtig gedacht — lokal SQLite, zentral MySQL, die API als einzige Tür dazwischen. --- ## 1. ⭐ Die Rechnungsnummer darf nur vom Server kommen Heute stimmen sich zwei lokale Programme über eine gemeinsame SQLite ab. Zentral wird das **einfacher**: eine Transaktion in MySQL vergibt die Nummer, fertig. **Aber:** Auf dem Tablet beim Kunden ohne Empfang darf keine Nummer entstehen. > **Regel: Offline entsteht ein ENTWURF, keine Rechnung.** Die Nummer wird vergeben, sobald der > Server erreichbar ist. Sonst gibt es irgendwann zwei Belege mit derselben Nummer — genau der Fehler, wegen dem das Amt-Blatt herausgeflogen ist (§ 14 Abs. 4 Nr. 4 UStG). Daraus folgt für die Oberfläche: Ein Entwurf muss **sichtbar** ein Entwurf sein, ohne Nummer, und darf nicht ausgedruckt oder verschickt werden können. ## ⭐⭐ Das Offline-Problem — und seine Lösung: NUMMERNKONTINGENTE Sein Einwand (06.09.2026): > „das ding, was wir haben, ist das offline-problem. wenn das internet schwach oder weg ist, bringt > das online nichts — also musst du auf dem client eine kopie per sqlite haben. wie willst es sonst > machen?" **Er hat recht, und das ersetzt die zu strenge Regel „offline nur Entwürfe" aus Punkt 1.** ### Was zwischengespeichert werden kann — und was nicht | | offline möglich? | |---|---| | Kundenstamm, Preise, Einstellungen, alte Rechnungen zum Nachschlagen | **ja** — lokale SQLite, lesend, mit sichtbarem Alter | | **Vergabe der Rechnungsnummer** | **nein** — zwei Geräte nähmen beide „die nächste" | ### Die Lösung: der Server gibt Blöcke im Voraus aus So machen es Kassensysteme. Tablet A bekommt **2026-101 bis 2026-150**, Tablet B **2026-151 bis 2026-200**. Offline vergibt jedes Gerät aus **seinem eigenen** Block — eine Kollision ist **unmöglich**, weil kein anderes Gerät diese Nummern besitzt. Bei Netz meldet es den Verbrauch und holt einen neuen Block. → **Damit sind beim Kunden echte Rechnungen möglich, nicht nur Entwürfe.** ### Zwei Bedingungen, die dazugehören 1. **Lücken werden normal — und müssen erklärbar sein.** Kommt Tablet A nur bis 2026-137 und holt dann einen neuen Block, fehlen 138–150. Das ist zulässig: § 14 UStG verlangt eine **einmalig vergebene** fortlaufende Nummer, ausdrücklich auch in mehreren Kreisen (z. B. je Filiale). **Aber das System muss zeigen können, welcher Block wem gehörte und welche Nummern daraus nie verbraucht wurden.** Sonst sieht ein Prüfer eine Lücke und fragt nach der Rechnung. → Gehört in den **Steuerprüfungs-Ausdruck** (siehe `AUFGABE_BEWEISKETTE_PRUEFBAR.md`, Schritt 3). 2. **Der Block ist endlich.** Ist er verbraucht und kein Netz da, ist Schluss — dann wieder Entwürfe. **Lieber ein Gerät, das sagt „ich kann gerade nicht", als eines, das sich Nummern ausdenkt.** ### ⭐⭐ Woher die Blockgröße kommt: aus der Disposition (Andreas, 06.09.2026) > „die disponentin hat jedem handwerker ja kunden zugeteilt — daraus kann ein block generiert > werden. die software sagt: handwerker hans werner hat 10 kunden, also bekommt er block A mit 10 > nummern, der hans werner heißt. dann ist es erklärbar, weil hans die kunden im log hatte. wenn er > mehr kunden hatte, bekommt er von anfang an 10 puffernummern als schutz. und wenn die nicht > gebraucht werden, bekommt er sie für den nächsten tag wieder. wenn sie voll sind, überspringt er > in den nächsten block. der server hält selber immer reserve." **Der starke Punkt daran ist die Erklärbarkeit.** Ein Prüfer sieht reservierte Nummernbereiche und fragt, warum ausgerechnet diese. Hier gibt es eine Antwort **aus dem Betrieb heraus**: Die Disposition hat Hans an dem Tag zehn Kunden zugeteilt, also zehn Nummern plus Puffer. **Die Zuteilung ist der Beleg für die Reservierung** — besser als jede technische Begründung. ### ⚠️ Zwei Korrekturen daran **1. Der Block darf NICHT am Kalendertag hängen.** *„Heute hast du 100 bis 110"* klingt logisch, ist aber gefährlich: Hat Hans zwei Tage keinen Empfang, wäre er am zweiten Tag arbeitsunfähig, obwohl er noch Nummern hätte. > **Der Block gehört ihm, bis er ihn zurückmeldet. Kein Ablaufdatum.** Die Disposition gibt morgens > neue *dazu*, nimmt aber nichts weg, was er noch hat. Am Bild der Disposition ändert das nichts — nur verhungert das Tablet nicht, wenn das Netz drei Tage weg ist. **2. Eine Nummer ist erst verbraucht, wenn ein BELEG entsteht.** Nicht bei der Zuteilung, und **nicht durch einen Entwurf**. Nur so stimmt, dass unbenutzte Nummern am nächsten Tag wieder gelten — sonst würden Nummern wiederverwendet, die schon auf einem Bildschirm standen. **Der Rest passt unverändert:** Puffer von Anfang an · Überspringen in den nächsten Block, wenn voll · **Server hält eigene Reserve** für das, was die Disposition nicht wusste (Notfall, Zusatzauftrag, Kunde ruft an). ### ⭐ Beim Synchronisieren: Verbrauch melden, nicht blind neu ausgeben Sein Einwand (06.09.2026): > „wenn das tablet lte wieder hat, kann er das syncen und bekommt einen neuen block — oder sagt > einfach: eh, ich habe aber in dem block erst 10 % genutzt" **Richtig, und das vermeidet Lücken statt sie nur zu erklären.** Das Gerät meldet seinen Stand: *„2026-101 bis 110 verbraucht, 111 bis 150 gehören mir noch."* Der Server entscheidet: | Lage | Antwort | |---|---| | noch viel übrig | **nichts tun** — kein neuer Block, keine verbrannten Nummern | | fast leer, folgende Nummern frei | **den vorhandenen Block VERLÄNGERN** (101–150 → 101–180) → **keine Lücke** | | fast leer, folgende Nummern gehören schon jemandem | neuer Block weiter hinten → Lücke, aber eine, die der Server **benennen** kann | **Verlängern schlägt Neuausgabe.** Das ist der Unterschied zwischen einem System, das Lücken erzeugt und sie hinterher erklären muss, und einem, das erst gar keine macht. ### Warum das nicht optional ist > „kannst ja nicht kunden fragen nach wlan" Beim Kunden im Keller, im Neubau ohne Anschluss, auf dem Hof: kein WLAN, oft auch kein Mobilfunknetz. Nach dem Passwort fragen macht kein Handwerker. **Zwei praktische Regeln daraus:** 1. **Der Block muss großzügig sein** — nicht zehn Nummern, sondern so viele, dass eine Woche Arbeit hineinpasst. Nummern kosten nichts, ein abgerissener Vorgang beim Kunden schon. 2. **Das Gerät warnt, BEVOR es eng wird.** *„Noch 5 Nummern im Vorrat, bitte einmal ins Netz"* — solange man noch in der Werkstatt steht. Eine Warnung, die erst beim Kunden kommt, ist wertlos. Nachgefüllt wird **automatisch**, sobald irgendwo Netz da ist. Der Benutzer soll darüber nicht nachdenken müssen. ## 2. ⚠️ Beim Datenschutz kippt die Lage vollständig Heute lautet die Aussage im Programm: *Es verlässt nichts den Rechner.* Das ist der ganze Datenschutztext. Sobald Gästedaten auf einem Server liegen, gilt die DSGVO in voller Breite: - verschlüsselte Übertragung (TLS), keine Ausnahme - **Zugriffstrennung je Betrieb** — ein API-Schlüssel ist ein Passwort, keine Zugriffskontrolle - Löschkonzept und Aufbewahrungsfristen (§ 147 AO) müssen zusammenpassen - **Wenn er das für ANDERE Betriebe hostet, ist er deren Auftragsverarbeiter** und braucht einen Vertrag nach Art. 28 DSGVO. Das ist keine Formalie, sondern Voraussetzung dafür, dass die Betriebe das Programm überhaupt einsetzen dürfen. Der Datenschutztext im Programm muss dann neu geschrieben werden — der heutige wäre schlicht falsch. ## 3. ⭐⭐ E-Rechnung (ZUGFeRD) — jetzt entscheiden, nicht später In Deutschland läuft die Pflicht zur elektronischen Rechnung im B2B an. Wer ein System baut, das Rechnungen **per Mail verschickt**, sollte die PDF gleich mit **eingebettetem strukturiertem XML** erzeugen (ZUGFeRD / PDF/A-3). Der Unterschied zwischen „von Anfang an mitgedacht" und „später nachrüsten" ist hier ein halber Neubau: PDF/A-3 stellt andere Anforderungen an Schriften und Farbprofile als das heutige PDF, und das XML muss aus denselben Daten kommen wie das Blatt — nicht daneben gepflegt werden. Stand schon auf der allerersten Aufgabenliste des Rechnungstools. ## 4. Versand - **SMTP genügt zum Senden.** POP3/IMAP braucht man nur, um **Unzustellbarkeitsmeldungen** zu lesen — und die *muss* man lesen. Sonst meldet das Programm „verschickt", und die Rechnung liegt nirgends. - **Eine per Mail verschickte Rechnung ist eine Rechnung** (§ 14 UStG). Für die GoBD muss das Dokument **genau so archiviert werden, wie es verschickt wurde** — samt Versandnachweis. - Zustellung ist nicht garantiert. Der Versandstatus gehört sichtbar in die Oberfläche, nicht nur ins Log. ## ⭐ Das Produktbild (Andreas, 06.09.2026) — lokal ist der Normalfall > „solange er den apikey mit domain nicht hat, kann er auch nur sqlite nutzen — reicht auch, wenn > einer es als single programm für sich nutzt. will einer das online nutzen, dann trägt er beides > ein, das programm synct einmal auf die mysql, fertig." **Damit ist der Aufbau entschieden: local-first, Online ist eine Zusatzfunktion, die man einschaltet.** Wer nichts einträgt, merkt vom Server nichts. Kein Konto, keine Pflicht, keine Abhängigkeit. ### Die eine Regel, die den Umzug sicher macht **„Synct einmal" ist eine EINMALIGE ÜBERNAHME, keine ständige Synchronisierung in beide Richtungen.** Danach gehört die Nummernvergabe dem Server; die lokale SQLite ist nur noch Zwischenspeicher für Entwürfe (siehe Punkt 1). Zwei Richtungen dauerhaft offen zu halten hieße: zwei Stellen vergeben Nummern. Genau der Fehler, wegen dem das Amt-Blatt herausflog. ### Und daraus folgt eine Entscheidung VOR der ersten Übernahme Zwei Installationen, die beide 2026-001 bis 2026-050 vergeben haben, lassen sich **nicht** in eine Datenbank übernehmen — dort lägen Nummern doppelt. Gehen je mehrere Betriebe auf denselben Server, muss die **Trennung der Nummernkreise vorher** feststehen (eigene Datenbank je Betrieb, oder Präfix je Betrieb). Nachträglich geht es nicht: die Belege sind dann schon beim Kunden. ### Was der Umzug NICHT gefährdet **Die Wahrheit bleiben die Rechnungs-PDFs** — so steht es schon heute im Nummernbuch-Code: *„Die Datei ist ein REGISTER, keine zweite Buchhaltung."* Geht bei der Übernahme etwas schief, fehlt keine Rechnung; es muss nur neu eingelesen werden. ## ⭐⭐ Die Umschaltung ist eine Tür, die nur in eine Richtung aufgeht Sein Modell (06.09.2026): > „ein einmal sync, danach ist es only online. die sql ist dann deaktiviert für immer — außer er > trägt den key und die domain aus, dann hat er aber einen alten datenstand." > „das muss er mit einem popup — mit dem speichern-button, den es dafür gibt — am ende noch mal als > ja/nein-frage kommen, ob ihm das bewusst ist, dass er sozusagen bei 0 anfängt." ### Harte Anforderung **Beim SPEICHERN** von API-Schlüssel und Domain (nicht beim Eintippen) kommt eine Ja/Nein-Frage. Beim Tippen weiß niemand, ob es ernst gemeint ist — beim Speichern schon. Entwurf des Textes: > **Auf Online-Betrieb umstellen?** > > Die vorhandenen Daten werden einmalig auf den Server übernommen. Danach läuft alles über den > Server: Rechnungsnummern werden dort vergeben, und die lokale Datenbank wird **nicht mehr > fortgeführt**. > > Entfernen Sie später Schlüssel und Domain, arbeitet das Programm wieder lokal weiter — dann aber > mit dem Stand von **[Datum von heute]**. Alles, was zwischenzeitlich online entstanden ist, fehlt > dort. > > Diese Umstellung lässt sich nicht rückgängig machen. > > Jetzt umstellen? Dasselbe Muster wie beim Erprobungshinweis und bei der Freigabe vor dem Beleg: Der Nutzer wird **vorher** aufgeklärt, und die Entscheidung wird mit Datum vermerkt. ### Die lokale Datenbank wird STILLGELEGT, nicht gelöscht Sie ist der Stand von damals und muss lesbar bleiben — schon wegen § 147 AO. ### ⭐ Und der Punkt, der daran hängt: die PDFs müssen erreichbar bleiben Heute gilt in beiden Programmen: **Die Wahrheit sind die Rechnungs-PDFs, die Datenbank ist nur ein Register.** Wird künftig auf dem Server erzeugt, muss der Betrieb **jederzeit an alle seine Belege herankommen — als Dateien**, nicht nur als Ansicht im Browser. Der Grund ist **§ 147 AO: zehn Jahre Aufbewahrungspflicht.** Ein System, das den Betrieb von seinen eigenen Belegen trennen kann — Server fällt aus, Vertrag endet, man zerstreitet sich — bringt den BETRIEB in Schwierigkeiten. → **Empfehlung: automatische lokale Kopie jeder Rechnung, auch im Online-Betrieb.** Dann bleibt der Satz „die Wahrheit sind die PDFs" wahr, und der Betrieb hat seine Unterlagen auch dann, wenn nichts mehr läuft. Das ist zugleich ein Verkaufsargument. ## 📄 Paperless als Archiv (Andreas, 06.09.2026) — löst die Aufbewahrungsfrage > „ich dachte später an ein paperless — da muss eh alles rein" **Das ist die bessere Antwort auf § 147 AO als eine Exportfunktion.** Läuft jede Rechnung automatisch in ein Dokumentensystem, liegt das Archiv **außerhalb** des Programms und überlebt sowohl einen abgeschalteten Server als auch das Programm selbst. **Anbindung ist klein:** Paperless-ngx nimmt Dokumente über eine REST-Schnittstelle **oder über einen überwachten Ordner** entgegen — Datei hineinlegen, fertig. Für das Rechnungstool eine zusätzliche Zeile beim Speichern, kein Umbau. **⭐ Und die Verschlagwortung ist schon gebaut:** Rechnungsnummer, Datum, Beträge, Art und Vorgang stehen bereits als maschinenlesbare Kenndaten im `/Subject` jeder PDF (das Steuerjournal liest sie von dort). Daraus kann das Archiv seine Schlagworte ziehen — ohne Abtippen, ohne Texterkennung. ⚠️ **Ehrlicher Vorbehalt:** Ein Dokumentensystem macht **nicht automatisch GoBD-konform**. Es erfüllt den Kern (Belege bleiben unverändert und vollständig), aber dazu gehört eine **Verfahrensdokumentation** — wie Belege entstehen, wohin sie laufen, wer was darf. Die schreibt kein Programm. Ein großer Teil davon steht allerdings schon in den Aufgabendateien und Commit-Texten dieser Projekte. ## 🔑 Die API ist der Schlüssel zu allem (Andreas, 06.09.2026) > „das tool schickt es an die api, die api verteilt das alles. die api ist der schlüssel zu allem — > wie beim gta fivem server" **Das ist seine eigene Serverregel, angewandt:** *Der Wille kommt vom Client, gerechnet wird auf dem Server.* (Vgl. PcoreLife: nichts im Client, was Serversachen übernimmt.) | | Client (Tool/Tablet) | Server (API) | |---|---|---| | Was | „Rechnung für diese Leistungen an diesen Kunden" | Nummer vergeben, Beträge und Steuer rechnen, PDF erzeugen | | Danach | zeigt an, was zurückkommt | verteilt: MySQL · Paperless · Mailversand | ### ⭐ Folge 1: `berechnung.py` zieht auf den Server Heute steht dort ausdrücklich *„die einzige Stelle, an der gerechnet wird"*. Zentral gehört sie auf den Server. **Das löst nebenbei die offene Frage aus `AUFGABE_KUNDENSTAMM_UND_WEB.md`:** die zwei Steuerwelten (deutsche Bruttopreise 7/19 % gegen polnische Nettopreise mit Reverse Charge). Weiß der Server, welcher Betrieb anfragt, weiß er auch, wie zu rechnen ist. **Der Client muss davon nichts wissen — und die Frage „beide Welten in einem Programm oder zwei Fassungen" erledigt sich.** ### ⭐ Die Aufgabenteilung im Einzelnen (Andreas, 06.09.2026) > „das tool schickt nur die metadaten, der server rendert die pdf und das tool bekommt den link. > oder halt die vorschau muss es selber machen — das auf dem server ist dumm. und paperless macht > den rest: archivieren und senden an die mitgegebene e-mail, und speichert das unter der > kundennummer." | Wer | Was | |---|---| | **Tool** | schickt die Metadaten · zeichnet die **Vorschau lokal** · bekommt den Link zum fertigen PDF | | **Server (API)** | vergibt die Nummer · rechnet · rendert das endgültige PDF · **verschickt per SMTP** · verteilt | | **Paperless** | archiviert · verschlagwortet (Kundennummer als Korrespondent/Schlagwort) | **Vorschau lokal ist richtig:** ein Netzweg pro Tastendruck wäre sofort träge. ### ⚠️ Die Regel, die dazugehört: EIN Zeichner, zwei Ausführungsorte Zeichnet das Tool die Vorschau und der Server das endgültige Blatt, gibt es **zwei Zeichner — und zwei Zeichner driften auseinander**. Genau davor schützt sich der heutige Code bereits: `berechnung.py` wird von Oberfläche UND PDF benutzt, *„damit Bildschirm und Ausdruck garantiert identisch sind"*. Eine Vorschau, die nicht dem entspricht, was hinausgeht, ist **schlimmer als keine** — sie erzeugt Vertrauen, das nicht gerechtfertigt ist. (Und die Vorschau war seine ausdrückliche Begründung für das Ganze: *„sonst haben die den storno-aufwand"*.) → **`pdf_renderer.py` und `berechnung.py` bleiben EINE gemeinsame Bibliothek**, die an zwei Orten ausgeführt wird. Kein zweiter Code. ### ⚠️ Korrektur: Paperless archiviert, es VERSCHICKT NICHT Paperless-ngx nimmt Dokumente entgegen, erkennt Text, verschlagwortet und lagert ein. **Rechnungen an Kunden mailen kann es nicht.** Der Versand per SMTP gehört auf den Server / in die API. Die Ablage unter der Kundennummer geht dagegen sauber — Paperless kennt Korrespondenten und Schlagworte, die Kundennummer passt in beides. ### ⛔ Verworfen: PDF auf dem Client zeichnen und hochladen Andreas hatte es erwogen (*„ob das schlau ist, weiß ich nicht"*). **Nein**, aus einem Grund: Zeichnet der Client den endgültigen Beleg, entscheidet der Client, was darauf steht — und der Server archiviert blind, was ankommt. Er könnte nicht mehr garantieren, dass zur Nummer, die er vergeben hat, auch das Blatt gehört, das er ablegt. Eine ältere oder veränderte Fassung des Tools erzeugte Dokumente, die niemand prüft. **Der Beleg entsteht dort, wo auch die Nummer entsteht.** Dazu käme: jede künftige Oberfläche (Tablet, Browser) müsste den ganzen Renderer mitschleppen. Die **Vorschau** bleibt lokal — sie ist kein Beleg: ohne Nummer, mit Wasserzeichen, wie heute. ### ⭐ Kundenstamm offline: ein ZWISCHENSPEICHER, kein Sync Seine Frage: *„wenn ein kunde eine kundennummer bekommt, wie willst die wiederfinden? musst die api auch abfragen dafür — heißt, ohne internet wird da eh nichts. sonst musst wieder alles lokal und online speichern, um das schnell zu halten, und dann nur eine art rsync raufpacken."* **Der Instinkt stimmt — nur ist es kein Sync, sondern ein Spiegel.** Der Unterschied ist keine Wortklauberei: | | bedeutet | Folge | |---|---|---| | **Sync** | beide Seiten dürfen ändern | braucht Konfliktauflösung — wer gewinnt bei doppelter Änderung? | | **Spiegel** | nur der Server besitzt die Daten, der Client hält eine Lesekopie | **keine Konflikte**, nur ein Stand, der mal älter ist | **Und die Datenmenge passt:** Kunden sind wenige und ändern sich selten — anders als Rechnungen. Den ganzen Kundenstamm lokal zu halten kostet nichts und macht die Suche sofort schnell, auch ohne Netz. **Sein Wort dafür: „eine Art Zwischenspeicher"** — und das ist ehrlicher als „Spiegel", weil es schon sagt, dass er veralten darf. **Zwei Dinge braucht er, sonst wird er selbst zur Fehlerquelle:** 1. **Er muss sein Alter zeigen.** Klein in der Oberfläche: *„Kundendaten vom 06.09.2026, 15:40"*. Sonst sucht jemand einen Kunden, findet ihn nicht, legt ihn neu an — dabei war er nur seit gestern nicht heruntergeladen. **Ein Zwischenspeicher, dem man sein Alter nicht ansieht, wird irgendwann für die Wahrheit gehalten.** 2. **Er darf nie Quelle für etwas sein, das geschrieben wird.** Lesen und Suchen: ja. Eine Nummer daraus vergeben: nie. Aufgefrischt wird beim Start (wenn Netz da ist) und auf Knopfdruck. **Dieselbe Regel wie bei den Rechnungsnummern:** Ein offline angelegter Kunde bekommt seine Nummer **erst vom Server** — bis dahin ist er ein Entwurf. Sonst vergeben zwei Tablets dieselbe Kundennummer. ### Folge 2: der Client wird schlank Das Tablet beim Kunden braucht kein PDF-Werkzeug, keine Steuerlogik, keinen Nummernkreis. Ein Weg hinein, mehrere hinaus. ### Der Preis **Ohne Server geht nichts außer Entwürfen** (siehe Punkt 1). Bei FiveM ist das dasselbe — nur hängt hier ein Beleg dran, den jemand zehn Jahre aufbewahren muss. ### Sicherheit, weil „Schlüssel zu allem" wörtlich zutrifft Wenn ein Schlüssel alles öffnet, muss er: **je Installation** vergeben sein (nicht einer für alle), **widerrufbar**, **nur über TLS** unterwegs, und die API muss **Missbrauch begrenzen** (Rate-Limit). Sonst ist ein einziger abhandengekommener Schlüssel der Zugang zu allen Gästedaten. ## 5. Offene Entscheidungen - Wer betreibt den Server, und für wen? (nur Bartl, oder mehrere Betriebe) - Ein Mandant je Datenbank oder ein gemeinsames Schema mit Mandantenspalte? - Was passiert mit dem lokalen Betrieb — bleibt SQLite als Offline-Fassung, oder wird alles zentral? - Wie kommt der Bestand in die MySQL, ohne dass Nummern doppelt vergeben werden? --- **Nichts davon beginnen, bevor die Punkte 1 bis 3 entschieden sind** — sie bestimmen den Aufbau, nicht die Ausstattung.