14 KiB
Finanzen: Stripe-Rechnungen und Finom-Konto im Ticketsystem
Stand: 2026-10-01 · Status: Entwurf zur Freigabe
Grundlage: Recherche /root/reports/Finanzübersicht für kleine Webagentur.md (Notizen in
/root/research_notes/Finanzübersicht für kleine Webagentur/) und die Machbarkeitsprüfung vom
30.09./01.10.2026 (Enable Banking produktiv getestet: Finom-Konto, Salden, Umsätze).
Ziel
Die Seite „Finanzen“ im Ticketsystem (WOMS, ticket.webklar.com/finance) zeigt nicht mehr
InvoiceNinja, sondern Stripe-Rechnungen und das Finom-Geschäftskonto. Sie beantwortet beim
wöchentlichen Blick drei Fragen: Wie viel Geld ist wirklich frei? Was muss ich heute tun? Reicht das
Geld die nächsten 30 Tage? Projektrechnungen werden direkt aus WOMS über Stripe geschrieben und
verschickt.
Erfolg: Kein Zahlungseingang bleibt unzugeordnet, keine überfällige Rechnung bleibt unbemerkt, und der Bankzugang läuft nie unbemerkt ab.
Feststehende Rahmenbedingungen (geprüft)
- WEBklar GbR, Kleinunternehmer nach § 19 UStG (Impressum, Stripe-Rechnungsfuß im Portal). Daraus folgt: keine Umsatzsteuer auf Rechnungen, keine USt-Voranmeldung, keine USt-Rücklage, keine E-Rechnungspflicht beim Ausstellen – das Stripe-PDF genügt. Einkommensteuer zahlen die Gesellschafter privat; Gewerbesteuer erst über 24.500 € Gewinn.
- Bank: Enable Banking, App „WEBklar Finanzen“, ID
b2582270-11bf-4489-affb-1a151f076c07, Produktion, nur Kontoinformationen (AIS). Schlüssel auf dem Server erzeugt (/home/webklar/apps/ticket-integrations/enablebanking.pem, verlässt den Server nie). Sitzung zum Finom-Konto „Webklar“ besteht, gültig bis 29.03.2027; Sitzungs-ID und Konto-UID in/home/webklar/apps/ticket-integrations/enablebanking-session.txt. Finom liefert bei Eingängen Zahlername, IBAN und Verwendungszweck; Kartenzahlungen haben eine Händlerkategorie (MCC). PSD2-Grenzen: etwa 4 automatische Abrufe pro Tag, Umsätze nur der letzten ~90 Tage, Zugang höchstens 180 Tage. - Enable Banking ohne Vertrag ist nur zur Erprobung erlaubt („solely for evaluation purposes or for the personal use of private individuals“, Terms → Restriction of Use). Für den Dauerbetrieb braucht es einen Vertrag (support.api@enablebanking.com). Bauen und testen ist gedeckt.
- Stripe ist im Kundenportal eingerichtet (Live-Schlüssel, Abos per Karte und SEPA-Lastschrift, Rechnungsfuß § 19 UStG). Bisher hat noch keine Stripe-Auszahlung das Finom-Konto erreicht.
- InvoiceNinja bleibt installiert und unverändert in Betrieb, verschwindet aber aus der WOMS-Oberfläche. Einzige relevante Altrechnung: 0005 (EWV Software GmbH, 168,79 €), am 05.08.2026 per Überweisung bezahlt und in InvoiceNinja seit 01.10.2026 als bezahlt markiert.
- Die Kundenstammdaten (
customersinwoms-database) teilen sich WOMS und Portal; Stripe-Kunden hängen übermetadata.webklarCustomerIddaran (getOrCreateStripeCustomerim Portal).
Entscheidungen (Standardwerte zur Freigabe)
- Backend im Kundenportal-Server unter
/api/admin/finanzen/*, geschützt mitrequireAppwriteStaff(Appwrite-JWT, Labeladmin, Sitzung mit zweitem Faktor). Dort liegen schon Stripe, Jobs, Mails, Appwrite-Setup-Skripte und Tests.ticket-integrationsbleibt unverändert. - Nur Admins sehen „Finanzen“ (Menüpunkt und Seiten). Justin braucht als Gesellschafter das Label
admin(Prüfung beim Livegang). - Schlüssel wandert nach
/home/webklar/apps/secrets/enablebanking/und wird schreibgeschützt in den Portal-Container eingebunden. Die Sitzungs-ID steht in Appwrite (ohne Schlüssel wertlos). - Bankdaten werden dauerhaft gespeichert (Collection
bankTransactions), weil die Bank nur 90 Tage liefert. Abruf automatisch alle 6 Stunden (4× täglich) und per Knopf „Aktualisieren“ (höchstens alle 10 Minuten; mit PSU-Kopfzeilen, damit es nicht auf das Tageslimit zählt). - Bankzugang erneuern direkt aus WOMS: Knopf → Finom-Freigabe → Rückkehr auf
https://ticket.webklar.com/finanzen/bank-callback(bereits als Redirect-URL registriert). Hinweis in „Zu erledigen“ ab 30 Tagen vor Ablauf, Team-Mail (Vorlage T18) bei 30, 14 und 3 Tagen. - Projektrechnungen entstehen in WOMS über Stripe: Kunde wählen, Positionen (Beschreibung, Menge, Einzelpreis), Zahlungsziel 14 Tage, Versand per Stripe-Mail mit PDF und Zahlungsseite. Zahlarten stellt der Nutzer im Stripe-Dashboard ein (Empfehlung: Karte und SEPA-Lastschrift). Im Rechnungsfuß stehen der § 19-Hinweis und die Bankverbindung mit der Bitte, die Rechnungsnummer als Verwendungszweck anzugeben. Entwürfe lassen sich löschen, versendete Rechnungen nur stornieren.
- Zahlungsabgleich als Vorschlag mit Bestätigung, nie still automatisch: Eine Bestätigung markiert
die Stripe-Rechnung „außerhalb von Stripe bezahlt“ (
paid_out_of_band, nicht umkehrbar) und merkt sich die Bankbuchung. Stripe-Auszahlungen werden der Auszahlung zugeordnet (Umbuchung, kein Umsatz). Teilzahlungen werden nicht unterstützt (Hinweis: in Stripe direkt erfassen). - Fixkosten pflegt der Nutzer als Liste (Name, Betrag, Rhythmus, nächstes Datum, Suchbegriff für die Gegenpartei). Erkannte wiederkehrende Ausgaben werden nur vorgeschlagen (mindestens 3 Buchungen).
- Vorschau 30 Tage mit zwei Linien: „nur sicher“ (Kontostand, unterwegs befindliche Stripe-Auszahlungen, Fixkosten, ESt-Vorauszahlungen) und „erwartet“ (zusätzlich offene Rechnungen und Abo-Verlängerungen). Kein Konfidenzkegel, eine Annahmezeile in Klartext.
- Steuer: Rücklage = einstellbarer Prozentsatz (Standard 30 %) vom Gewinn des laufenden Jahres (Einnahmen minus Ausgaben laut Bank). Kleinunternehmer-Zähler nach Zahlungseingang: laufendes Jahr gegen 25.000 € (Status im Folgejahr) und 100.000 € (harte Grenze), Vorjahr als Einstellung. ESt-Vorauszahlungen als optionale Einstellung (Betrag je Quartal, fällig 10.3./10.6./10.9./10.12.).
- Kundenansicht: Der Kunden-Tab „Rechnungen“ zeigt Stripe-Rechnungen des Kunden und „Rechnung schreiben“. Der Ticket-Tab „Rechnungen“ entfällt.
- Nicht im Umfang: Kundenportal-Tab „Rechnungen“ (zeigt weiter InvoiceNinja, eigener Folgeschritt), Stundenguthaben je Kunde, Projektmarge, Kundenkonzentration, Angebote, Teilzahlungen, E-Rechnung, Ausgabenbelege, mehrere Bankkonten.
Seitenaufbau (WOMS /finance)
Reihenfolge von oben nach unten; Blöcke 0–2 stehen im ersten Bildschirm. Beträge in de-DE
(1.234,50 €, rechtsbündig, tabular-nums), Daten 01.10.2026, Farbe nie allein als Signal.
| Nr. | Block | Inhalt |
|---|---|---|
| 0 | Statuszeile | „Bank: Stand vor 3 Std. · jüngste Buchung 29.09. · Zugang bis 29.03.2027“, „Stripe: Stand …“; bei Fehler „Abruf fehlgeschlagen: …“; Knopf „Aktualisieren“ |
| 1 | Liquiditätskopf | Kontostand (gebucht), „Verfügbar nach Rücklagen“ (Kontostand − Steuer-Rücklage − Fixkosten der nächsten 30 Tage − Mindestpuffer; negativ erlaubt; Aufschlüsselung per Klick), „Tiefster Stand in 30 Tagen“ (nur sicher / erwartet, jeweils mit Datum) |
| 2 | Zu erledigen | Höchstens 7 Zeilen, je mit genau einer Aktion; Leerzustand „Nichts offen“ |
| 3 | Vorschau 30 Tage | Tabelle nach Datum: Posten, sicher/erwartet, Betrag, laufender Saldo beider Linien; Annahmezeile |
| 4 | Steuer | Rücklage (Betrag, Prozentsatz, Gewinn lfd. Jahr), Kleinunternehmer-Zähler, nächste ESt-Vorauszahlung (falls eingestellt) |
| 5 | Abos | Monatliche Abo-Einnahmen (aktive + past_due, Jahrespreise ÷ 12), Anzahl zahlender Kunden, gefährdete Einnahmen (past_due), Liste der Abos |
| 6 | Rechnungen | Filter Offen / Überfällig / Bezahlt / Entwürfe / Alle; Altersgruppen (nicht fällig, 1–30, 31–60, über 60 Tage) mit Summe und Anzahl; Tabelle Nr., Kunde, Datum, Fällig, Betrag, Offen, Status, Aktionen (PDF, Zahlungsseite, Senden, Stornieren, Löschen); Knopf „Rechnung schreiben“ |
| 7 | Buchungen | Alle gespeicherten Buchungen, neueste zuerst, 50 je Seite: Datum, Gegenpartei + Verwendungszweck, Betrag mit Vorzeichen, Zuordnung (Rechnung, Stripe-Auszahlung, Fixkosten, Einnahme ohne Stripe-Rechnung, Privat/Umbuchung, Sonstiges, offen) |
Unterseite /finance/einstellungen: Mindestpuffer, Rücklage-Prozentsatz, Vorjahresumsatz,
ESt-Vorauszahlung je Quartal, Bankverbindungstext für den Rechnungsfuß, Fixkostenliste, Bankzugang
(Status, „Neu verbinden“).
Mobil: Blöcke gestapelt in derselben Reihenfolge, Tabellen als zweizeilige Zeilen.
„Zu erledigen“ – Arten
| Art | Wann | Aktion | Dringlichkeit |
|---|---|---|---|
bank-zugang |
Zugang läuft in ≤ 30 Tagen ab oder ist abgelaufen | Neu verbinden | hoch ab ≤ 14 Tagen |
bank-abruf |
Letzter erfolgreicher Abruf älter als 24 h | Aktualisieren | mittel |
ueberfaellig |
Offene Rechnung, Fälligkeit < heute | Zahlungsseite öffnen / Erinnerung über Stripe senden | hoch ab 30 Tagen (Verzug) |
zuordnung |
Eingang (Betrag > 0) ohne Zuordnung | Zuordnen (mit Vorschlag, falls vorhanden) | mittel |
abo-zahlung |
Abo im Status past_due oder unpaid |
Kunde öffnen | hoch |
entwurf |
Rechnungsentwurf älter als 3 Tage | Öffnen | info |
fixkosten-vorschlag |
Wiederkehrende Ausgabe erkannt, nicht in der Fixkostenliste | Übernehmen | info |
kleinunternehmer |
Einnahmen lfd. Jahr ≥ 70 % von 25.000 € | Einstellungen | mittel, hoch ab 100 % |
Sortierung: hoch vor mittel vor info, innerhalb nach Datum (älteste zuerst).
Datenmodell (Appwrite, woms-database)
bankConnections– ein Dokumentfinom:status(aktiv|abgelaufen|fehler),sessionId,accountUid,accountIdHash,ibanMasked,iban,validUntil(ISO),lastSyncAt,lastSyncOk(bool),lastError,lastManualSyncAt,balanceBookedCents,balanceAvailableCents,balanceDate,latestBookingDate,authState,authStartedAt,warnedThresholds(z. B.30,14).bankTransactions– Dokument-ID = erste 36 Zeichen des SHA-256 ausentry_reference(sonsttransaction_id, sonst Datum|Betrag|Gegenpartei|Verwendungszweck):accountUid,status(BOOK/PDNG),bookingDate,valueDate(YYYY-MM-DD),amountCents(Integer, Eingang +, Ausgang −),currency,counterpartyName,counterpartyIban,remittance,mcc,entryReference,category(leer |rechnung|rechnung-extern|stripe-auszahlung|fixkosten|privat|sonstiges),matchedInvoiceId,matchedInvoiceNumber,matchedPayoutId,fixedCostId,note,syncedAt.financeSettings– ein Dokumentmain:minBufferCents(0),taxReservePercent(30),previousYearRevenueCents(leer),estPrepaymentCents(0),bankDetailsText.financeFixedCosts:name,amountCents(positiv),interval(monat|quartal|jahr),nextDate,counterpartyMatch,active.
Stripe-Rechnungen, -Auszahlungen und Abos werden nicht gespiegelt: Rechnungen und Auszahlungen
liest der Server live (Zwischenspeicher 60 s, nach eigenen Änderungen geleert), Abos kommen aus der
vorhandenen Collection subscriptions.
Schnittstellen (/api/admin/finanzen)
| Methode, Pfad | Zweck |
|---|---|
GET /uebersicht |
Alles für Blöcke 0–6 in einer Antwort (Status, Kopf, Aufgaben, Vorschau, Steuer, Abos, Rechnungs-Altersgruppen) |
GET /rechnungen?status=&kunde= |
Stripe-Rechnungen (status: offen, ueberfaellig, bezahlt, entwurf, alle) |
POST /rechnungen |
Rechnung anlegen ({ customerId, items, daysUntilDue, memo, senden }) |
POST /rechnungen/:id/senden |
Entwurf festschreiben und senden |
POST /rechnungen/:id/stornieren |
Offene Rechnung stornieren |
DELETE /rechnungen/:id |
Entwurf löschen |
GET /buchungen |
Gespeicherte Buchungen (höchstens 1000, neueste zuerst; die Oberfläche blättert in 50ern) mit Zuordnungsvorschlägen für offene Eingänge |
POST /buchungen/:id/zuordnen |
{ invoiceId } oder { payoutId } oder { fixedCostId } oder { category } |
DELETE /buchungen/:id/zuordnung |
Zuordnung lösen (nicht bei Rechnungen, die schon als bezahlt markiert sind) |
POST /bank/aktualisieren |
Sofortabruf |
POST /bank/verbinden |
Freigabe starten → { url } |
POST /bank/rueckkehr |
{ code, state } oder { error, state } → neue Sitzung |
GET, PATCH /einstellungen |
Einstellungen |
GET, POST /fixkosten; PATCH, DELETE /fixkosten/:id |
Fixkostenliste |
Zuordnungsregeln (Vorschläge, höchstens 3 je Buchung)
- Stripe-Auszahlung (hoch): Gegenpartei oder Verwendungszweck enthält „stripe“, Betrag = Betrag
einer Auszahlung, Buchungsdatum höchstens 3 Tage von
arrival_dateentfernt. - Rechnungsnummer (hoch / mittel): normalisierter Verwendungszweck (Großbuchstaben, ohne Leerzeichen und Bindestriche) enthält die normalisierte Stripe-Rechnungsnummer. Betrag = offener Betrag → hoch, sonst mittel mit Hinweis „Betrag weicht ab“.
- Betrag und Name (mittel): Betrag = offener Betrag und ein Wort (≥ 4 Zeichen, ohne GmbH, UG, GbR, AG, KG, e.K., und, der, die) aus Firmen- oder Kundenname kommt im Zahlernamen vor.
- Nur Betrag (niedrig): Betrag = offener Betrag genau einer offenen Rechnung.
Bestätigen mit Rechnung ist nur möglich, wenn der Betrag dem offenen Betrag entspricht.
Fehlerverhalten
- Bankabruf scheitert: alte Daten bleiben sichtbar und werden als veraltet markiert;
lastErrorin der Statuszeile; kein Datenverlust. - Zugang abgelaufen (Enable Banking 401/403 oder Sitzung
EXPIRED): Statuszeile + Aufgabebank-zugang(hoch), Abrufe pausieren bis zur Neuverbindung. - Stripe nicht erreichbar: Übersicht liefert Bankteil trotzdem; Stripe-Blöcke zeigen „Stripe nicht erreichbar“.
- Rückkehr mit falschem
stateoder Fehler von Finom: Meldung auf der Rückkehrseite, bestehende Sitzung bleibt gültig.
Livegang (Reihenfolge)
- Schlüssel nach
secrets/enablebanking/verschieben, Compose: Mount und UmgebungsvariablenENABLE_BANKING_APP_ID,ENABLE_BANKING_KEY_PATH. - Setup-Skript legt Collections an und übernimmt die bestehende Sitzung (kein neuer Finom-Login).
- Portal
mainpushen (Nutzer-OK), Container neu starten, erster Abruf prüfen. - Stripe-Dashboard: Rechnungsnummern fortlaufend auf Kontoebene, Zahlarten für Rechnungen (Karte, SEPA-Lastschrift) – Nutzer.
- WOMS
testpushen (Nutzer-OK). - Buchung „Rechnung 0005“ als „Einnahme ohne Stripe-Rechnung“ zuordnen.
- Vor dem Dauerbetrieb: Vertrag mit Enable Banking (Nutzer).