Der 70-Tabellen Wahnsinn: Eine Kontaktdatenbank im Normalisierungs-Rausch

Oder: Wie man aus einer simplen Adressverwaltung ein akademisches Meisterwerk der Über-Architektur erschafft*

Ein gefährliches Gedankenspiel

Heute Morgen saß ich am Schreibtisch, starrte auf meine FileMaker-Lösung und dachte mir: “Wäre es nicht herrlich, einmal komplett durchzudrehen?” Nicht im Sinne von schlechtem Code oder wilden Skripten, sondern im Sinne von theoretischer Perfektion. Von akademischer Reinheit. Von Normalisierung, die so weit geht, dass selbst Edgar F. Codd sich im Grab umdreht und fragt: “Habe ich das wirklich so gemeint?”

Heute nehme ich euch mit auf eine Reise in die dunkle Seite der Datenbankentwicklung. Wir werden gemeinsam eine Kontaktdatenbank bauen, die so übernormalisiert ist, dass sie in der Praxis völlig unbrauchbar wäre. Wir sprechen von siebzig Tabellen. Siebzig! Für Kontakte, Adressen und ein bisschen Drumherum. Das ist ungefähr so, als würde man einen Nagel mit einem Vorschlaghammer einschlagen, während man auf einem Einrad balanciert und dabei Schach spielt.

Vorweg: Das solltet ihr niemals tun. Aber es macht wahnsinnig viel Spaß, und man lernt dabei eine Menge über Normalisierung, Beziehungen und darüber, wann genug wirklich genug ist.

Die Ausgangslage: Eine ganz normale Kontaktdatenbank

Stellen wir uns vor, wir wollen eine Kontaktdatenbank bauen. Nichts Wildes. Einfach Namen, Adressen, Telefonnummern, E-Mails. Das Zeug, das jeder braucht. In der Praxis würde man vielleicht mit drei, vier Tabellen davonkommen. Kontakte, Adressen, Telefonnummern, E-Mails. Fertig. Schön übersichtlich, performant, wartbar.

Aber wo bleibt da der Spaß? Wo ist die theoretische Eleganz? Wo sind die Normalformen, von denen alle reden, die aber keiner wirklich konsequent durchzieht? Genau hier fängt unser Abenteuer an.

Der Plan: Maximale Normalisierung

Die Idee ist simpel: Wir normalisieren alles, was nicht bei drei auf den Bäumen ist. Jede noch so kleine Information bekommt ihre eigene Tabelle. Jede Redundanz wird gejagt und eliminiert. Jede transitive Abhängigkeit wird aufgelöst. Wir gehen nicht nur bis zur dritten Normalform, nicht mal bis zur BCNF. Wir gehen bis zur fünften, vielleicht sogar sechsten Normalform, wenn wir wirklich übermütig werden.

Das Ergebnis? Eine Datenbank-Struktur, die aussieht wie ein Spinnennetz nach einem Tornado. Oder wie der Stammbaum der britischen Königsfamilie. Oder wie mein Schreibtisch nach einer langen Entwicklungssession.

Die Kontakte: Wo alles beginnt

Fangen wir harmlos an. Ein Kontakt hat einen Vornamen, einen Nachnamen, vielleicht ein Geburtsdatum. In einer normalen Welt würden wir das in eine Tabelle schreiben und fertig. Aber wir sind ja nicht normal.

Ein Kontakt hat eine Anrede. Herr, Frau, Divers. Das kann sich ändern. Das muss zentral verwaltet werden. Also brauchen wir eine Anreden-Tabelle. Klingt noch vernünftig, oder? Gut, dann machen wir weiter.

Ein Kontakt kann einen Titel haben. Dr., Prof., Dipl.-Ing. und all die schönen Dinge, mit denen Menschen sich schmücken. Aber hier wird es spannend: Manche Titel stehen vor dem Namen, manche danach. In Deutschland sagt man “Dr. Müller”, in Österreich manchmal “Müller, Dr.”. Das ist eine Information! Eine strukturierte Information! Also brauchen wir nicht nur eine Titel-Tabelle, sondern auch eine TitelPositionen-Tabelle. Zwei Tabellen, nur damit wir wissen, ob der Doktortitel vor oder nach dem Namen kommt. Herrlich übertrieben, oder?

Die Firmen: Ein Exkurs in die Unternehmensarchitektur

Kontakte arbeiten in Firmen. Das ist nichts Neues. Aber eine Firma ist nicht einfach nur ein Name. Eine Firma hat eine Rechtsform. GmbH, AG, e.K., OHG, KG, und was weiß ich noch alles. Die Rechtsform sagt etwas über die Struktur aus, über Haftung, über steuerliche Behandlung. Das ist wichtig! Also brauchen wir eine Rechtsformen-Tabelle.

Und dann ist da noch die Branche. IT, Maschinenbau, Einzelhandel, Gastronomie. Branchen ändern sich, Branchen haben Hierarchien, Branchen sind komplex. Also brauchen wir eine Branchen-Tabelle. Vielleicht sogar mit Hierarchien, aber das würde jetzt zu weit führen. Wir haben ja erst bei Tabelle Nummer acht oder so.

Und weil ein Kontakt bei mehreren Firmen arbeiten kann, gleichzeitig oder nacheinander, brauchen wir natürlich eine Verknüpfungstabelle. Kontakt_Firma. Mit Position (Geschäftsführer, Angestellter, Freelancer), mit von-Datum und bis-Datum für die Historisierung. Und die Position? Rate mal. Eigene Tabelle. Positionen-Tabelle. Weil sich Positionsbezeichnungen ändern können und wir sie zentral verwalten wollen.

Die Adressen: Ein geografisches Meisterwerk

Jetzt wird es richtig lustig. Adressen sind kompliziert. Wirklich kompliziert. Eine Adresse besteht aus einer Straße, einer Hausnummer, einer Postleitzahl, einem Ort, einem Land. Das würde die meisten zufriedenstellen. Aber nicht uns. Oh nein.

Fangen wir mit der Straße an. Eine Straße hat einen Namen. Aber eine Straße gehört zu einem Ort. Und verschiedene Orte können Straßen mit dem gleichen Namen haben. Die Hauptstraße in Berlin ist nicht die Hauptstraße in München. Also brauchen wir eine Strassen-Tabelle, die zu einem Ort gehört. Schon haben wir eine Redundanz eliminiert.

Die Postleitzahl? Die gehört zur Adresse, nicht zum Ort! Ein großer Ort kann mehrere Postleitzahlen haben. Berlin hat hunderte davon. Also brauchen wir eine PLZ-Tabelle, die wiederum zu einem Ort gehört. Moment, aber eine PLZ kann sich auch über mehrere Orte erstrecken? Stimmt! Also machen wir eine n:m-Beziehung daraus. Ups, schon wieder komplizierter.

Orte gehören zu Regionen. Bundesländer, Kantone, Staaten, je nachdem wo wir sind. Also Regionen-Tabelle. Und Regionen gehören zu Ländern. Also Länder-Tabelle. Und Länder haben ISO-Codes, zweibuchstabig und dreibuchstabig, und Ländervorwahlen für Telefonnummern. Und eine Währung! Also brauchen wir auch noch eine Währungen-Tabelle.

Ach, und ich habe fast die Adresszusätze vergessen. “c/o”, “bei”, “℅”. Das sind strukturierte Informationen! Adresszusätze-Tabelle. Und natürlich brauchen wir eine AdressTypen-Tabelle, denn eine Adresse kann privat, geschäftlich, eine Lieferadresse oder eine Rechnungsadresse sein.

Und weil sowohl Kontakte als auch Firmen mehrere Adressen haben können, brauchen wir Verknüpfungstabellen. Kontakt_Adresse und Firma_Adresse. Mit einem Flag, welche die Hauptadresse ist. Und mit Gültigkeitsdaten, denn Menschen und Firmen ziehen um.

Wir sind jetzt bei ungefähr zwanzig Tabellen. Nur für Kontakte, Firmen und Adressen. Und wir haben noch nicht einmal über Telefonnummern gesprochen.

Die Telefonnummern: Eine Ode an die Verkomplizierung

Telefonnummern sind toll. Man könnte sie einfach als String speichern und gut ist. Aber wo bleibt da die Struktur? Wo ist die Eleganz?

Eine Telefonnummer besteht aus einer Ländervorwahl, einer Ortsvorwahl, einer Rufnummer und vielleicht einer Durchwahl. Das sind vier Felder! Vier strukturierte Informationen! Also brauchen wir eine Telefonnummern-Tabelle mit all diesen Feldern.

Aber die Ländervorwahl? Die gehört zu einem Land! Also brauchen wir eine Ländervorwahlen-Tabelle, die zur Länder-Tabelle verlinkt. Ja, wir haben die Ländervorwahl schon in der Länder-Tabelle gespeichert, aber das wäre ja eine Redundanz! Also machen wir eine eigene Tabelle daraus, damit wir sauber bleiben.

Und dann ist da noch der Typ. Mobil, Festnetz, Fax, VoIP. Das sind strukturierte Kategorien. TelefonTypen-Tabelle. Natürlich.

Und weil wieder sowohl Kontakte als auch Firmen Telefonnummern haben können, brauchen wir Verknüpfungstabellen. Kontakt_Telefon und Firma_Telefon. Mit einem Flag für die Hauptnummer. Mit Gültigkeitsdaten. Ihr kennt das Spiel.

E-Mails, Websites und der Rest: Wir sind noch nicht fertig

E-Mail-Adressen? Eigene Tabelle. Mit einem EmailTyp (privat, geschäftlich, Newsletter). EmailTypen-Tabelle. Und wieder Verknüpfungstabellen für Kontakte und Firmen. Kontakt_Email, Firma_Email.

Websites? Eigene Tabelle. Mit einem WebsiteTyp (Hauptwebsite, Blog, LinkedIn, XING, Facebook, Instagram, TikTok, was auch immer). WebsiteTypen-Tabelle. Und wieder Verknüpfungstabellen. Ihr ahnt es schon.

Bankverbindungen? IBAN, BIC, und eine Referenz zur Bank. Und die Bank? Eigene Tabelle natürlich! Mit Bankname, BLZ und einer Referenz zum Land. Und wieder Verknüpfungstabellen für Kontakte und Firmen.

Steuer-IDs? Eigene Tabelle! Mit einem SteuerTyp (USt-ID, Steuernummer, UID, je nach Land). SteuerTypen-Tabelle. Die wiederum eine Referenz zum Land hat, weil verschiedene Länder verschiedene Steuertypen haben. Und wieder Verknüpfungstabellen.

Wir sind jetzt irgendwo bei vierzig, fünfzig Tabellen. Und ich habe noch ein paar Ideen.

Die Kür: Beziehungen, Sprachen und Tags

Kontakte haben Beziehungen zueinander. Ehepartner, Kinder, Geschwister, Geschäftspartner, Freunde. Das ist eine klassische n:m-Beziehung. Also brauchen wir eine Beziehungen-Tabelle, die zwei Kontakte miteinander verbindet. Und natürlich einen BeziehungsTyp. BeziehungsTypen-Tabelle. Mit einem Datum, seit wann die Beziehung besteht. Man will ja dokumentieren, wann man geheiratet hat oder wann die Geschäftsbeziehung begann.

Kontakte sprechen Sprachen. Und Firmen kommunizieren in Sprachen. Also brauchen wir eine Kommunikationssprachen-Tabelle, die entweder zu einem Kontakt oder zu einer Firma gehört. Und diese Tabelle verweist auf eine Sprachen-Tabelle mit dem Sprachennamen und ISO-Code. Und auf eine Sprachlevel-Tabelle (Muttersprache, Fließend, Grundkenntnisse), weil das Level der Sprachkenntnisse relevant ist.

Und dann sind da noch Tags. Kategorien. Labels. Wie auch immer man sie nennen will. Kontakte und Firmen können mit Tags versehen werden, um sie zu gruppieren, zu filtern, zu organisieren. Also brauchen wir eine Tags-Tabelle. Und weil Tags selbst wieder Kategorien haben können (Marketing-Tags, Projekt-Tags, Status-Tags), brauchen wir eine TagKategorien-Tabelle. Und natürlich Verknüpfungstabellen. Kontakt_Tag und Firma_Tag.

Jetzt sind wir bei siebzig Tabellen. Siebzig! Für eine Kontaktdatenbank!

Das Diagramm: Visuelle Überforderung garantiert

An dieser Stelle sollte ich eigentlich ein Diagramm zeigen, das all diese Tabellen und ihre Beziehungen visualisiert. Aber ehrlich gesagt, das würde diesen Blog-Post sprengen. Ich habe das Diagramm erstellt. Es ist ein Monster. Es sieht aus wie ein Spinnennetz auf Steroiden. Es hat mehr Linien als ein U-Bahn-Plan von Tokio. Es ist wunderschön und schrecklich zugleich.

Wenn ihr das Diagramm sehen wollt, könnt ihr es euch als Mermaid-Datei herunterladen und in einem Tool eurer Wahl anschauen. Ich empfehle mermaid.live, denn dann könnt ihr ordentlich hinein- und herauszoomen. Ihr werdet es brauchen. Glaubt mir.

Das Diagramm zeigt jede einzelne Tabelle mit ihren Attributen, ihren Primary Keys, ihren Foreign Keys. Es zeigt jede Beziehung, jede Kardinalität, jeden Join. Es ist ein akademisches Meisterwerk. Und es ist in der Praxis völlig wahnsinnig.

Die Realität: Warum niemand das tun sollte

Jetzt fragt ihr euch wahrscheinlich: “Warum zum Teufel erzählst du uns das alles, wenn es doch sowieso niemand machen sollte?” Gute Frage. Die Antwort ist zweiteilig.

Erstens: Weil es wichtig ist zu verstehen, wie weit Normalisierung theoretisch gehen kann. Normalisierung ist ein mächtiges Werkzeug. Sie eliminiert Redundanzen, sie sorgt für Datenintegrität, sie macht Updates und Löschungen sicher. Das sind alles gute Dinge. Aber wie bei jedem Werkzeug gibt es einen Punkt, an dem man es übertreibt. Einen Punkt, an dem die Nachteile die Vorteile überwiegen.

Unsere siebzig-Tabellen-Kontaktdatenbank ist so ein Punkt. Sie ist theoretisch perfekt. Sie hat keine Redundanzen. Jede Information ist genau einmal gespeichert. Änderungen an Lookup-Daten wirken sich automatisch überall aus. Historisierung ist eingebaut. Alles ist sauber, strukturiert, elegant.

Aber sie ist auch ein Performance-Albtraum. Um einen einzelnen Kontakt mit allen Details anzuzeigen, müsste man zwanzig, dreißig Tabellen joinen. Jede Abfrage würde ewig dauern. Indizes könnten nur bedingt helfen, weil die Datenbank einfach zu fragmentiert ist. Das Caching würde zum Problem, weil jede kleine Änderung potentiell Dutzende von Caches invalidiert.

Und dann ist da die Wartbarkeit. Stellt euch vor, ihr müsst in diese Struktur eine neue Telefonnummer eintragen. Ihr müsst die Telefonnummer-Tabelle befüllen, die Ländervorwahl nachschlagen, den Telefontyp auswählen, die Verknüpfungstabelle befüllen, das Hauptnummer-Flag setzen. Das sind mindestens fünf verschiedene Operationen, die alle in einer Transaktion laufen müssen. Ein Fehler, und alles ist inkonsistent.

Und die Komplexität für den Entwickler! Jeder neue Entwickler, der in dieses Projekt kommt, würde eine Woche brauchen, nur um die Struktur zu verstehen. Dokumentation? Ja, die wäre nötig. Sehr viel Dokumentation. Und selbst dann würde man ständig nachschauen müssen, welche Tabelle jetzt für was zuständig ist.

Zweitens: Weil es Spaß macht. Ernsthaft. Es macht Spaß, mal theoretisch bis zum Äußersten zu gehen. Es macht Spaß, ein Gedankenexperiment durchzuziehen und zu sehen, wo es hinführt. Und es macht Spaß, am Ende zu sagen: “Okay, das war interessant, aber in der Praxis machen wir es anders.”

Wo liegt die Balance?

Die Frage, die wir uns stellen sollten, ist nicht “Wie weit kann ich normalisieren?”, sondern “Wie weit sollte ich normalisieren?”. Und die Antwort darauf ist, wie so oft in der Softwareentwicklung: Es kommt darauf an.

Für eine Kontaktdatenbank in der Praxis würde ich wahrscheinlich mit zehn bis fünfzehn Tabellen arbeiten. Kontakte, Firmen, Adressen, Telefonnummern, E-Mails, vielleicht Websites. Dazu ein paar Lookup-Tabellen für Länder, Adresstypen, Telefontypen. Vielleicht eine Verknüpfungstabelle für die Kontakt-Firma-Beziehung, wenn das Anforderungen erfordern.

Aber ich würde nicht jede kleinste Information in eine eigene Tabelle auslagern. Ich würde Ortsvorwahlen nicht von der Telefonnummer trennen. Ich würde die Ländervorwahl direkt in der Länder-Tabelle speichern, nicht in einer separaten Tabelle. Ich würde Adresszusätze als Freitextfeld behandeln, nicht als Lookup.

Warum? Weil die Balance wichtig ist. Balance zwischen Normalisierung und Performance. Balance zwischen Datenintegrität und Wartbarkeit. Balance zwischen theoretischer Eleganz und praktischer Brauchbarkeit.

Normalisierung ist kein Selbstzweck. Sie ist ein Mittel zum Zweck. Der Zweck ist eine funktionierende, wartbare, performante Datenbank. Wenn Normalisierung diesen Zweck unterstützt, ist sie gut. Wenn sie ihm im Weg steht, muss man einen Schritt zurücktreten und denormalisieren.

FileMaker-spezifische Überlegungen

Als FileMaker-Entwickler haben wir noch ein paar zusätzliche Dinge zu bedenken. FileMaker ist kein klassisches SQL-Datenbanksystem. Es hat seine eigenen Stärken und Schwächen, seine eigenen Paradigmen.

FileMaker ist visuell. Beziehungen werden im Beziehungsgraphen dargestellt. Ein Beziehungsgraph mit siebzig Tabellen? Das ist kein Graph mehr, das ist ein Chaos. Man würde den Überblick verlieren. Man würde sich permanent verirren. Man würde neue Beziehungen übersehen oder alte falsch verknüpfen.

FileMaker ist portalbasiert. Wenn wir Daten aus verknüpften Tabellen anzeigen wollen, nutzen wir Portale. Aber Portale haben Grenzen. Man kann nicht beliebig tief graben. Jedenfalls nicht ohne verrückt zu werden. Man kann nicht beliebig viele Joins machen, ohne dass die Performance leidet. Eine übernormalisierte Struktur würde uns zwingen, Portale in Portalen zu verwenden (geht nicht), verschachtelte Selects, komplexe Berechnungen. Das würde langsam werden. Sehr langsam.

Und dann ist da noch die Frage der Wertelisten. In unserer übernormalisierten Datenbank haben wir Dutzende von Lookup-Tabellen. AdressTypen, TelefonTypen, EmailTypen, und so weiter. In FileMaker würde man viele davon einfach als Wertelisten implementieren. Wertelisten sind schnell, einfach zu warten, und für die meisten Fälle völlig ausreichend. Man braucht keine eigene Tabelle für drei Werte.

Das heißt nicht, dass Normalisierung in FileMaker unwichtig wäre. Ganz im Gegenteil. Aber es heißt, dass man die FileMaker-spezifischen Werkzeuge und Konzepte berücksichtigen muss. Man muss pragmatisch sein. Man muss die Sprache sprechen, die FileMaker versteht.

Die Lehren: Was wir mitnehmen

Was lernen wir aus diesem Wahnsinn? Was nehmen wir mit aus unserem Ausflug in die Über-Normalisierung?

Erstens: Normalisierung ist wichtig. Sie sorgt für Datenintegrität, sie eliminiert Redundanzen, sie macht unsere Datenbanken robuster. Wir sollten sie nicht ignorieren, nicht aus Bequemlichkeit, nicht aus Unwissenheit.

Zweitens: Normalisierung ist kein Dogma. Es gibt Situationen, in denen Denormalisierung die richtige Wahl ist. Wenn Performance kritisch ist, wenn die Daten sowieso nicht oft geändert werden, wenn die zusätzliche Komplexität den Nutzen übersteigt. Man muss abwägen, Fall für Fall, Tabelle für Tabelle.

Drittens: Theorie und Praxis sind zwei verschiedene Dinge. Was in einem Lehrbuch steht, was in einem Universitätskurs vermittelt wird, muss nicht zwangsläufig eins zu eins in die Praxis übertragbar sein. Man muss verstehen, warum die Theorie so ist, wie sie ist. Und dann muss man entscheiden, wie man sie anwendet.

Viertens: Es macht Spaß, mal über die Stränge zu schlagen. Es macht Spaß, Grenzen auszutesten, Extreme zu erkunden, Gedankenexperimente durchzuziehen. Solange man am Ende weiß, dass es ein Experiment war, und solange man daraus lernt.

Und fünftens: Siebzig Tabellen für eine Kontaktdatenbank sind wirklich, wirklich zu viel. Bitte, bitte macht das nicht in Produktion. Ich bin nicht verantwortlich für die Konsequenzen.

Fazit: Die Kunst des Maßhaltens

Am Ende des Tages ist Datenbankdesign eine Kunst. Es ist kein strikter Prozess, kein Algorithmus, den man einfach abarbeiten kann. Es ist eine Mischung aus Wissen, Erfahrung, Intuition und gesundem Menschenverstand.

Unsere siebzig-Tabellen-Kontaktdatenbank ist ein akademisches Meisterwerk. Sie ist theoretisch perfekt. Sie ist auch praktisch unbenutzbar. Und das ist okay. Denn sie hat uns etwas gelehrt. Sie hat uns gezeigt, wie weit man gehen kann. Und damit hat sie uns auch gezeigt, wie weit man nicht gehen sollte.

Wenn ihr das nächste Mal vor einem Datenbankdesign sitzt, denkt an diese Geschichte. Denkt an die siebzig Tabellen. Lacht ein bisschen. Und dann macht es besser. Macht es praktisch. Macht es wartbar. Macht es so, dass ihr in einem Jahr noch versteht, was ihr euch dabei gedacht habt.

Normalisiert eure Datenbanken. Aber normalisiert sie mit Maß. Findet den Sweet Spot zwischen Theorie und Praxis. Und vor allem: Habt Spaß dabei. Denn am Ende des Tages sollte Entwicklung nicht nur funktional sein, sondern auch ein bisschen Freude bereiten.

Und wenn euer Chef das nächste Mal fragt, warum die Kontaktdatenbank nur zehn Tabellen hat und nicht mehr, zeigt ihm diesen Blog-Post. Sagt ihm, dass ihr wisst, wie es theoretisch geht. Aber dass ihr euch bewusst dagegen entschieden habt. Weil ihr pragmatisch seid. Weil ihr weise seid. Weil ihr keine siebzig Tabellen wollen.

Danke fürs Lesen. Und denkt dran: Normalisierung ist gut. Aber zu viel Normalisierung ist wie zu viel Koffein. Irgendwann zittert man nur noch und fragt sich, wie man hier gelandet ist.

Über z.B. https://mermaid.live könnt Ihr diesen Code Visuell darstellen lassen.

… erDiagram %% ======================================== %% KERN: KONTAKTE & PERSONEN %% ======================================== Kontakte { int KontaktID PK int AnredeID FK int TitelID FK string Vorname string Nachname date Geburtsdatum text Notizen }

Anreden {
    int AnredeID PK
    string Anrede
}

Titel {
    int TitelID PK
    string Titel
    int TitelPositionID FK
}

TitelPositionen {
    int TitelPositionID PK
    string Position
}

%% ========================================
%% FIRMEN
%% ========================================
Firmen {
    int FirmaID PK
    string Firmenname
    int RechtsformID FK
    int BrancheID FK
}

Rechtsformen {
    int RechtsformID PK
    string Rechtsform
}

Branchen {
    int BrancheID PK
    string Branche
}

Kontakt_Firma {
    int Kontakt_FirmaID PK
    int KontaktID FK
    int FirmaID FK
    int PositionID FK
    date von_Datum
    date bis_Datum
}

Positionen {
    int PositionID PK
    string Positionsbezeichnung
}

%% ========================================
%% ADRESSEN & ORTE
%% ========================================
Adressen {
    int AdresseID PK
    int StrasseID FK
    string Hausnummer
    string HausnummerZusatz
    int AdresszusatzID FK
    int PLZID FK
    int AdressTypID FK
}

Strassen {
    int StrasseID PK
    string Strassenname
    int OrtID FK
}

PLZ {
    int PLZID PK
    string PLZ
    int OrtID FK
}

Orte {
    int OrtID PK
    string Ortsname
    int RegionID FK
}

Regionen {
    int RegionID PK
    string Regionsname
    int LandID FK
}

Laender {
    int LandID PK
    string Laendername
    string ISO2
    string ISO3
    string Laendervorwahl
    int WaehrungID FK
}

Waehrungen {
    int WaehrungID PK
    string Waehrung
    string ISO_Code
    string Symbol
}

Adresszusaetze {
    int AdresszusatzID PK
    string Zusatz
}

AdressTypen {
    int AdressTypID PK
    string Typ
}

Kontakt_Adresse {
    int Kontakt_AdresseID PK
    int KontaktID FK
    int AdresseID FK
    bool IstHauptadresse
    date Gueltig_von
    date Gueltig_bis
}

Firma_Adresse {
    int Firma_AdresseID PK
    int FirmaID FK
    int AdresseID FK
    bool IstHauptsitz
    date Gueltig_von
    date Gueltig_bis
}

%% ========================================
%% TELEFON
%% ========================================
Telefonnummern {
    int TelefonID PK
    int LaendervorwahlID FK
    string Ortsvorwahl
    string Rufnummer
    string Durchwahl
    int TelefonTypID FK
}

Laendervorwahlen {
    int LaendervorwahlID PK
    string Vorwahl
    int LandID FK
}

TelefonTypen {
    int TelefonTypID PK
    string Typ
}

Kontakt_Telefon {
    int Kontakt_TelefonID PK
    int KontaktID FK
    int TelefonID FK
    bool IstHauptnummer
    date Gueltig_von
    date Gueltig_bis
}

Firma_Telefon {
    int Firma_TelefonID PK
    int FirmaID FK
    int TelefonID FK
    string Abteilung
    date Gueltig_von
    date Gueltig_bis
}

%% ========================================
%% E-MAIL
%% ========================================
EMail_Adressen {
    int EmailID PK
    string EmailAdresse
    int EmailTypID FK
}

EmailTypen {
    int EmailTypID PK
    string Typ
}

Kontakt_Email {
    int Kontakt_EmailID PK
    int KontaktID FK
    int EmailID FK
    bool IstHauptemail
    date Gueltig_von
    date Gueltig_bis
}

Firma_Email {
    int Firma_EmailID PK
    int FirmaID FK
    int EmailID FK
    string Abteilung
    date Gueltig_von
    date Gueltig_bis
}

%% ========================================
%% WEBSITES
%% ========================================
Websites {
    int WebsiteID PK
    string URL
    int WebsiteTypID FK
}

WebsiteTypen {
    int WebsiteTypID PK
    string Typ
}

Kontakt_Website {
    int Kontakt_WebsiteID PK
    int KontaktID FK
    int WebsiteID FK
}

Firma_Website {
    int Firma_WebsiteID PK
    int FirmaID FK
    int WebsiteID FK
}

%% ========================================
%% BANKING
%% ========================================
Bankverbindungen {
    int BankverbindungID PK
    string IBAN
    string BIC
    int BankID FK
}

Banken {
    int BankID PK
    string Bankname
    string BLZ
    int LandID FK
}

Kontakt_Bankverbindung {
    int Kontakt_BankverbindungID PK
    int KontaktID FK
    int BankverbindungID FK
    bool IstHauptkonto
}

Firma_Bankverbindung {
    int Firma_BankverbindungID PK
    int FirmaID FK
    int BankverbindungID FK
}

%% ========================================
%% STEUERN
%% ========================================
Steuer_IDs {
    int SteuerID_TableID PK
    string Nummer
    int SteuerTypID FK
}

SteuerTypen {
    int SteuerTypID PK
    string Typ
    int LandID FK
}

Kontakt_SteuerID {
    int Kontakt_SteuerID_ID PK
    int KontaktID FK
    int SteuerID_TableID FK
}

Firma_SteuerID {
    int Firma_SteuerID_ID PK
    int FirmaID FK
    int SteuerID_TableID FK
}

%% ========================================
%% BEZIEHUNGEN
%% ========================================
Beziehungen {
    int BeziehungID PK
    int KontaktID_1 FK
    int KontaktID_2 FK
    int BeziehungsTypID FK
    date seit_Datum
}

BeziehungsTypen {
    int BeziehungsTypID PK
    string Typ
}

%% ========================================
%% SPRACHEN
%% ========================================
Kommunikationssprachen {
    int KommunikationsspracheID PK
    int KontaktID FK
    int FirmaID FK
    int SpracheID FK
    int SprachlevelID FK
}

Sprachen {
    int SpracheID PK
    string Sprache
    string ISO_Code
}

Sprachlevel {
    int SprachlevelID PK
    string Level
}

%% ========================================
%% TAGS
%% ========================================
Tags {
    int TagID PK
    string Tagname
    int TagKategorieID FK
}

TagKategorien {
    int TagKategorieID PK
    string Kategoriename
}

Kontakt_Tag {
    int Kontakt_TagID PK
    int KontaktID FK
    int TagID FK
}

Firma_Tag {
    int Firma_TagID PK
    int FirmaID FK
    int TagID FK
}

%% ========================================
%% BEZIEHUNGEN (RELATIONSHIPS)
%% ========================================

%% Kontakte
Kontakte ||--o{ Anreden : "hat"
Kontakte ||--o{ Titel : "hat"
Titel ||--o{ TitelPositionen : "hat"

%% Firmen
Firmen ||--o{ Rechtsformen : "hat"
Firmen ||--o{ Branchen : "hat"
Kontakte ||--o{ Kontakt_Firma : "arbeitet bei"
Firmen ||--o{ Kontakt_Firma : "beschäftigt"
Kontakt_Firma ||--o{ Positionen : "in Position"

%% Adressen
Adressen ||--o{ Strassen : "liegt in"
Adressen ||--o{ PLZ : "hat"
Adressen ||--o{ Adresszusaetze : "hat"
Adressen ||--o{ AdressTypen : "vom Typ"
Strassen ||--o{ Orte : "in"
PLZ ||--o{ Orte : "gehört zu"
Orte ||--o{ Regionen : "in"
Regionen ||--o{ Laender : "in"
Laender ||--o{ Waehrungen : "hat"

Kontakte ||--o{ Kontakt_Adresse : "hat"
Adressen ||--o{ Kontakt_Adresse : "zugeordnet"
Firmen ||--o{ Firma_Adresse : "hat"
Adressen ||--o{ Firma_Adresse : "zugeordnet"

%% Telefon
Telefonnummern ||--o{ Laendervorwahlen : "hat"
Telefonnummern ||--o{ TelefonTypen : "vom Typ"
Laendervorwahlen ||--o{ Laender : "gehört zu"

Kontakte ||--o{ Kontakt_Telefon : "hat"
Telefonnummern ||--o{ Kontakt_Telefon : "zugeordnet"
Firmen ||--o{ Firma_Telefon : "hat"
Telefonnummern ||--o{ Firma_Telefon : "zugeordnet"

%% E-Mail
EMail_Adressen ||--o{ EmailTypen : "vom Typ"
Kontakte ||--o{ Kontakt_Email : "hat"
EMail_Adressen ||--o{ Kontakt_Email : "zugeordnet"
Firmen ||--o{ Firma_Email : "hat"
EMail_Adressen ||--o{ Firma_Email : "zugeordnet"

%% Websites
Websites ||--o{ WebsiteTypen : "vom Typ"
Kontakte ||--o{ Kontakt_Website : "hat"
Websites ||--o{ Kontakt_Website : "zugeordnet"
Firmen ||--o{ Firma_Website : "hat"
Websites ||--o{ Firma_Website : "zugeordnet"

%% Banking
Bankverbindungen ||--o{ Banken : "bei"
Banken ||--o{ Laender : "in"
Kontakte ||--o{ Kontakt_Bankverbindung : "hat"
Bankverbindungen ||--o{ Kontakt_Bankverbindung : "zugeordnet"
Firmen ||--o{ Firma_Bankverbindung : "hat"
Bankverbindungen ||--o{ Firma_Bankverbindung : "zugeordnet"

%% Steuern
Steuer_IDs ||--o{ SteuerTypen : "vom Typ"
SteuerTypen ||--o{ Laender : "in"
Kontakte ||--o{ Kontakt_SteuerID : "hat"
Steuer_IDs ||--o{ Kontakt_SteuerID : "zugeordnet"
Firmen ||--o{ Firma_SteuerID : "hat"
Steuer_IDs ||--o{ Firma_SteuerID : "zugeordnet"

%% Beziehungen zwischen Kontakten
Kontakte ||--o{ Beziehungen : "hat Beziehung zu"
Beziehungen ||--o{ BeziehungsTypen : "vom Typ"

%% Sprachen
Kommunikationssprachen ||--o{ Sprachen : "spricht"
Kommunikationssprachen ||--o{ Sprachlevel : "auf Level"
Kontakte ||--o{ Kommunikationssprachen : "spricht"
Firmen ||--o{ Kommunikationssprachen : "verwendet"

%% Tags
Tags ||--o{ TagKategorien : "in Kategorie"
Kontakte ||--o{ Kontakt_Tag : "hat"
Tags ||--o{ Kontakt_Tag : "zugeordnet"
Firmen ||--o{ Firma_Tag : "hat"
Tags ||--o{ Firma_Tag : "zugeordnet"


KI-gestützte Datensatzerstellung in FileMaker: Als AddOn installierbar

KI-gestützte Datensatzerstellung in FileMaker: Wenn Sprache zu Daten wird !!! (Das System wird als AddOn in ein bestehendes FileMaker-System integriert)

Bildschirmfoto 2025-10-30 um 17.26.42.

Das Problem Jeder FileMaker-Entwickler kennt es: Daten erfassen ist mühsam. Besonders wenn Mitarbeiter unterwegs sind, offline arbeiten oder einfach keine Lust haben, Dutzende von Feldern auszufüllen. Was wäre, wenn man einfach sagen könnte:

“Erstelle einen Auftrag für Pumpe austauschen bei Anlage 2666, Status in Planung, Kategorie Reparatur, im Mai, mit Notiz und Aufgabe für 3 Mitarbeiter” Und das System erstellt automatisch: ✅ Den Master-Datensatz (Auftrag) ✅ Verknüpfte Notizen ✅ Tasks mit Fristen ✅ Automatische Verknüpfungen zu bestehenden Objekten ✅ Alle Felder korrekt befüllt Genau das haben wir gebaut.

Die Lösung: Ein intelligentes KI-Bridge-System Wir haben eine PHP-basierte Middleware entwickelt, die als Brücke zwischen FileMaker und Claude AI (Anthropic) funktioniert. Das Besondere: Das System ist vollständig konfigurierbar über FileMaker, ohne eine Zeile Code zu ändern. Die 3 Kern-Innovationen:

  1. Dynamisches Config-System Statt statischer Workflows werden alle Konfigurationen als JSON in FileMaker gepflegt: Welche Layouts verwendet werden Welche Felder verfügbar sind Welche Item-Typen (Notizen, Tasks, etc.) erstellt werden sollen Spezielle Anweisungen für die KI Diese Configs werden automatisch auf dem Server gespeichert und können von jedem Mitarbeiter wiederverwendet werden.
  2. Intelligente Config-Auswahl Das Geniale: Mitarbeiter müssen keine Config-ID mehr angeben. Das System analysiert ihren Text-Prompt automatisch:
Bildschirmfoto 2025-10-30 um 17.26.57.

Prompt: “Erstelle einen neuen Auftrag…” → System findet automatisch Config “Auftrag anlegen” → Lädt passende Feldnamen & Layouts → Führt aus

Bildschirmfoto 2025-10-30 um 17.28.53.

Über ein Keyword-Scoring-System werden Prompts mit gespeicherten Configs abgeglichen. Je mehr Keywords übereinstimmen, desto höher der Score. 3. Such- & Verknüpfungs-Engine Nicht nur Erstellen, auch Suchen! Das System kann: In bestehenden FileMaker-Datensätzen suchen (z.B. Anlage 2666) Relevante IDs extrahieren Automatisch mit neuen Datensätzen verknüpfen

Bildschirmfoto 2025-10-30 um 17.29.19.

Technische Highlights Intelligentes Field-Mapping Claude AI kennt FileMaker nicht. Aber unser System: Ruft dynamisch verfügbare Felder aus dem FileMaker-Layout ab Sendet sie als Prompt an Claude Claude befüllt nur existierende Felder Case-insensitive Matching (project_name → Project_Name) Automatische Datumskonvertierung (verschiedene Formate → FileMaker-Format) Filterung von AutoEnter/Calculation-Feldern

Multi-Item-Support Ein Prompt kann mehrere Aktionen auslösen:

{ “master”: “Auftrag erstellen”, “items”: [ “Notiz anlegen”, “Task anlegen”, “Objekt zuordnen” ] } Jedes Item kann erstellen oder suchen – automatisch erkannt anhand von Keywords wie “zuordnen”, “verknüpfen”, “finde”.

Das gibt der Mitarbeiter an: Erstelle einen neuen Auftrag und die Notiz -Teste mal die 1372- Der Auftragsname lautet Pumpe ist bald defekt und muss getauscht werden. Der Status lautet -In Planung-, die Kategorie heisst -Reparatur- Als Planungsmonat hinterlege den Mai. Die Anlage ist die 2666. Erstelle auch gleich eine Aufgabe dazu. Hinterlege das Product bzw. Objekt dazu. Für den Auftrag werden 3 Mitarbeiter benötigt.

Prominente Prompt-Hierarchie FileMaker-User können spezielle Anweisungen mitgeben: 🎯 SPEZIELLE ANWEISUNGEN FÜR DEN MASTER:────────────────────────────────────────Planungsmonat immer als 12/2025 formatieren.Anlagennummer in Feld id_anlage eintragen.────────────────────────────────────────BEACHTE DIESE ANWEISUNGEN STRIKT! Diese werden Claude mit visueller Betonung präsentiert, sodass sie nicht übersehen werden.

Use Cases aus der Praxis Szenario 1: Außendienst (Offline-First) Problem: Techniker ist vor Ort, kein Internet, notiert sich 10 Aufträge handschriftlich. Mit unserem System: Notizen in FMGo-App erfassen (offline) Bei Internet: Alle Prompts auf einmal absenden System erstellt automatisch alle Aufträge mit Notizen, Tasks, Verknüpfungen Techniker muss keine Felder ausfüllen Szenario 2: Multi-CRM Umgebung Problem: Firma hat mehrere CRM-Systeme (Vertrieb, Service, Projekte). Mit unserem System: Configs: crm_vertrieb_firma, service_auftrag, projekt_anlegen Automatische Config-Erkennung je nach Prompt Ein System, mehrere Workflows Szenario 3: Sprachbarriere Problem: Internationale Teams, verschiedene Sprachen. Mit unserem System: Prompts in jeder Sprache möglich (Claude versteht 95+ Sprachen) FileMaker-Feldnamen bleiben gleich Nur die Config-Bezeichnung anpassen

Performance & Kosten Geschwindigkeit Config-Laden: < 50ms (lokales JSON) Claude API: ~2-4 Sekunden (abhängig von Komplexität) FileMaker API: ~500ms pro Record Gesamt: 3-5 Sekunden für komplette Workflow-Ausführung API-Kosten (Claude Haiku) Input: ~$0.00025 pro 1K Tokens Output: ~$0.00125 pro 1K Tokens Durchschnitt: ~$0.01-0.03 pro Prompt → Selbst bei 1000 Prompts/Tag: ~$10-30/Monat

Sicherheit & Datenschutz ✅ Kein Datenleck: Nur Feldnamen (nicht Werte) werden im Prompt sichtbar ✅ Verschlüsselte Verbindung: HTTPS zu Claude API ✅ On-Premise möglich: Bei Bedarf mit lokaler AI (z.B. Ollama) ✅ Config-Zugriffskontrolle: FileMaker-Berechtigungen greifen

Technik: Frontend: FileMaker Pro/Go Middleware: PHP 8.x (FileMaker Data API + Anthropic API) AI: Claude 3 Haiku (Anthropic) Storage: JSON-Configs (dateisystembasiert)


Neues Feature: Gap-Report für ZUGFeRD-Mapping (Prüfung auf fehlende Felder)

Neues Feature: Gap-Report für ZUGFeRD-Mapping

Unser KI-gestütztes ZUGFeRD-Mapping hat ein neues Feature bekommen, das die Arbeit noch einfacher macht!

Das Problem

Die KI mappt automatisch ~90% der ZUGFeRD-Felder. Aber was ist mit den fehlenden 10%?
Bisher musste man selbst herausfinden, welche Felder in FileMaker noch fehlen und wie man sie anlegt.

Die Lösung: Gap-Report

Bildschirmfoto 2025-10-10 um 18.37.20.

Ab sofort erstellt die KI einen detaillierten Gap-Report für alle fehlenden Felder:

Was der Gap-Report liefert:

Welches Feld fehlt (z.B. invoiceCurrencyCode)
ZUGFeRD-Code (z.B. BT-5)
Beschreibung (was bedeutet das Feld?)
Pflicht oder Optional? (Priorität HOCH/NIEDRIG)
Konkrete Empfehlung für FileMaker
Beispielwerte zur Orientierung

Beispiel:

❌ invoiceCurrencyCode (BT-5) - PFLICHT
   Beschreibung: Währungscode der Rechnung
   Empfehlung: Textfeld mit Werteliste (EUR, USD, CHF, GBP)
   Beispiel: EUR

❌ unitCode (BT-130) - PFLICHT
   Beschreibung: Einheitencode (UN/ECE)
   Empfehlung: Textfeld mit Werteliste (C62, HUR, MTR, KGM, LTR)
   Beispiel: C62 (Stück), HUR (Stunden)

ℹ️ deliveryTerms (BT-20) - Optional
   Beschreibung: Lieferbedingungen (IncoTerms)
   Empfehlung: Textfeld mit Werteliste (EXW, FOB, CIF, DAP, DDP)
   Beispiel: DAP

Vorteile

Vorher: “15 Felder fehlen” - und jetzt?
Nachher: Konkrete Schritt-für-Schritt-Anleitung, was genau anzulegen ist.

Perfekt für FileMaker-Entwickler ohne ZUGFeRD-Kenntnisse!

Fazit

Das KI-Mapping wird immer intelligenter. Nicht nur automatisch mappen, sondern auch aktiv beim Nacharbeiten helfen.

ZUGFeRD-Compliance wird zum Kinderspiel.


Update: Oktober 2025
Feature: Gap-Report mit konkreten FileMaker-Empfehlungen
Status: Live

#FileMaker #ZUGFeRD #KI #Automatisierung #ERechnung


KI-gestütztes Feld-Mapping in ZUGFeRD Swite , ab morgen Abend verfügbar

Mit ZUGFeRD Swite steht ab sofort ein vollständig automatisiertes, KI-gestütztes Feld-Mapping für FileMaker zur Verfügung. Das System analysiert eigenständig sämtliche FMPXML-Exports aus FileMaker und erstellt innerhalb weniger Sekunden eine komplette Zuordnung zwischen den Quellfeldern und den ZUGFeRD-Zielfeldern. Damit entfällt der aufwendige manuelle Mapping-Prozess, der bislang bei jeder neuen Installation nötig war, Die KI übernimmt die gesamte Arbeit und liefert ein fertiges JSON-Mapping, das sofort in FileMaker übernommen wird. Das ganze erweitert unsere AddOns im Bereich ZUGFeRD. Alle Funktionen bleiben bestehen, das Mapping, mit einem derzeitigen Arbeitsaufwand von ca. 1 Stunde wird auf wenige Minuten reduziert.

Das Problem: Komplexes Field-Mapping überfordert Anwender

Wer schon einmal versucht hat, ZUGFeRD-konforme elektronische Rechnungen aus einem bestehenden ERP- oder Warenwirtschaftssystem zu erzeugen, kennt die Herausforderung: 75+ ZUGFeRD-Felder müssen den vorhandenen Datenfeldern zugeordnet werden. Ein mühsamer, fehleranfälliger Prozess, der für unerfahrene Anwender kaum zu bewältigen ist.

Die klassische Vorgehensweise:

  • Manuelles Durchgehen jedes einzelnen ZUGFeRD-Feldes
  • Suchen des passenden Quellfeldes in verschiedenen Tabellen
  • Copy & Paste von Feldnamen
  • Stundenlange Trial-and-Error-Sessions
  • Häufige Fehler durch Tippfehler oder falsche Zuordnungen

Das Ergebnis: Frustration, Zeitverlust und hohe Fehlerquote.

In unserem Bisherigen AddOn, deshalb das händische Mappen ohne in den FileMaker-Scripten Änderungen vornehmen zu müssen.

Die Lösung: KI macht das Mapping automatisch

Nun aber übernimmt diesen Schritt die KI – Künstlicher Intelligenz (Claude API von Anthropic).

So funktioniert es

Das System besteht aus drei einfachen Schritten:

1. Datenexport aus FileMaker

Der Anwender exportiert 7 XML-Dateien aus seinem System:

  • preferences.xml – Enthält alle ZUGFeRD-Zielfelder (die Referenz)
  • invoice.xml – Rechnungskopfdaten (Rechnungsnummer, Datum, Summen, etc.)
  • buyer.xml – Kundendaten (Name, Adresse, USt-ID, etc.)
  • seller.xml – Verkäuferdaten (Firma, Adresse, Kontakt, etc.)
  • finance.xml – Zahlungsinformationen (IBAN, BIC, Zahlungsbedingungen)
  • payments.xml – Zahlungsdetails und Fälligkeiten
  • items.xml – Rechnungspositionen (Artikel, Mengen, Preise, Steuern)

Diese Dateien werden automatisch nacheinander auf den Server hochgeladen – kein manuelles Handling nötig.

2. KI-gestütztes Mapping

Nach dem Upload wird das KI-Mapping-Script gestartet:

URL: https://ihr-server.de/ki_mapping/start_mapping.php

Was passiert im Hintergrund?

  1. Datenanalyse: Das System liest alle 7 XML-Dateien ein
  2. Feldextraktion: ZUGFeRD-Zielfelder und Quellfelder werden extrahiert
  3. Intelligente Analyse: Die KI analysiert:
    • Feldnamen (semantische Ähnlichkeit)
    • Beispieldaten aus den ersten 3 Datensätzen
    • Datentypen und -strukturen
  4. Automatisches Mapping: Die KI ordnet jedem ZUGFeRD-Feld das passende Quellfeld zu

Dauer: 5-15 Sekunden (abhängig von der Datenmenge)

3. JSON-Response mit fertigem Mapping

Das System gibt eine strukturierte JSON-Antwort zurück:

{
    "success": true,
    "message": "39 von 43 Feldern erfolgreich gemappt",
    "mapping": {
        "buyerName": "buyer.BuyerName",
        "buyerCity": "buyer.BuyerCity",
        "buyerStreet": "buyer.BuyerStreet",
        "invoiceNumber": "invoice.InvoiceNumber",
        "invoiceDate": "invoice.InvoiceIssueDate",
        "totalGrossAmount": "invoice.InvoiceLegalMonetaryTotalTaxInclusiveAmount",
        "payeeIBAN": "finance.payeeIBAN",
        "quantity": "items.LineInvoicedQuantity",
        "priceNet": "items.LineNetPriceAmount",
        ...
    },
    "statistics": {
        "total_zugferd_fields": 43,
        "mapped_fields": 39,
        "unmapped_fields": 4,
        "unmapped_list": ["deliveryTerms", "lieferschein_nr", ...]
    }
}

Diese JSON kann direkt in FileMaker (oder jedem anderen System) weiterverarbeitet werden.

Technische Details

Architektur

Das System besteht aus drei PHP-Scripten:

1. receive_xml.php – XML-Upload-Handler

  • Empfängt die 7 XML-Dateien nacheinander
  • Automatische Reihenfolgen-Erkennung (kein manuelles Benennen nötig)
  • Parst FileMaker FMPXMLRESULT Format
  • Extrahiert Feldnamen und Beispieldaten
  • Speichert XML + JSON-Metadaten

2. process_mapping.php – KI-Mapping-Engine

  • Liest alle 7 XML-Dateien
  • Extrahiert ZUGFeRD-Zielfelder aus preferences.xml
  • Sammelt Quellfelder + Beispieldaten aus den anderen 6 Dateien
  • Erstellt intelligenten Prompt für Claude API
  • Parst KI-Response und validiert Mapping
  • Speichert Ergebnis als JSON mit Timestamp

3. start_mapping.php – FileMaker-Interface

  • Einfacher Endpoint für FileMaker “Aus URL Einfügen”
  • Startet Mapping-Engine
  • Gibt JSON-Response direkt zurück
  • Timeout: 60 Sekunden (ausreichend für alle Fälle)

Keine Dependencies nötig!

Das System nutzt PHP-Bordmittel:

  • SimpleXML für XML-Parsing
  • cURL für API-Kommunikation
  • Keine externen Libraries erforderlich

Der bestehende vendor/-Ordner auf dem Server bleibt unangetastet.

KI-Integration: Claude API

Wir nutzen Claude 3 Haiku von Anthropic:

  • Schnell (5-15 Sekunden Response)
  • Günstig (ca. 0,01-0,05 EUR pro Mapping)
  • Hohe Qualität bei semantischer Analyse
  • Versteht natürliche Sprache UND Datenstrukturen

Die KI erhält:

  • Liste aller ZUGFeRD-Zielfelder
  • Alle Quellfelder mit Beispieldaten
  • Mapping-Regeln (Präzision, Format, etc.)

Und gibt zurück:

  • Vollständiges Mapping als JSON
  • Confidence-Level implizit durch Match-Quality
  • null für nicht zuordenbare Felder

Vorteile des Systems

✅ Für Anwender

  • Keine technischen Kenntnisse erforderlich
  • 90%+ automatische Trefferquote
  • Sekunden statt Stunden
  • Fehlerrate nahezu Null
  • Wiederverwendbare Mappings

✅ Für Entwickler/Administratoren

  • Einfache Installation (3 PHP-Dateien)
  • Keine komplexen Dependencies
  • Vollständig protokolliert (Logs in csv_uploads/)
  • Versionierte Mappings (Timestamp-basiert)
  • Anpassbare Mapping-Regeln (Prompt kann erweitert werden)

✅ Für Unternehmen

  • Drastische Zeitersparnis bei der Implementierung
  • Reduzierte Fehlerkosten
  • Schnellere Onboarding-Prozesse
  • Skalierbar (beliebig viele Mandanten/Systeme)
  • Kosteneffizient (< 5 Cent pro Mapping)

Integration in FileMaker

Script-Aufbau

# Schritt 1-7: XML-Uploads
Aus URL einfügen [
  URL: "https://server.de/ki_mapping/receive_xml.php"
  Daten: $xml_preferences
  Methode: POST
]

# ... weitere 6 Uploads ...

# Schritt 8: KI-Mapping starten
Aus URL einfügen [
  URL: "https://server.de/ki_mapping/start_mapping.php"
  In Variable: $$MappingResponse
  Timeout: 30 Sekunden
]

# Schritt 9: JSON parsen und verwenden
Feld setzen [ feldmapping::json ; $$MappingResponse ]

JSON-Weiterverarbeitung

Das Mapping kann direkt genutzt werden:

  • Import in FileMaker-Tabellen
  • Verwendung für ZUGFeRD-Export
  • Speicherung als wiederverwendbares Template
  • Export für andere Systeme

Fazit

Was früher Stunden manueller Arbeit erforderte, erledigt die KI nun in Sekunden – mit höherer Qualität und weniger Fehlern.

Das System zeigt eindrucksvoll, wie KI komplexe, repetitive Aufgaben übernehmen kann, ohne dass Anwender technisches Spezialwissen benötigen.

ZUGFeRD-Integration war noch nie so einfach.


Technische Anforderungen

  • PHP 7.4+ (SimpleXML, cURL)
  • Anthropic API Account (ab 5 EUR/Monat ausreichend)
  • FileMaker Pro/Server

Unser ZUGFeRD AddOn erhält ein Update

Im Zuge der Zusammenarbeit mit dem geschätzten Entwickler Alexander Lemuth haben wir in den letzten 2 Wochen etliche spannende Änderungen und Verbesserungen vorgenommen. Ursprünglich war geplant, die Implementierung gemeinsam per Zoom durchzuführen. Doch wie es oft bei guter Zusammenarbeit der Fall ist: während der intensiven Auseinandersetzung mit der bestehenden Lösung sind uns immer mehr interessante Details und Optimierungsmöglichkeiten aufgefallen. Was als einfaches Update beginnen sollte, entwickelte sich zu einer grundlegenden Überarbeitung. Die kritischen Fragen von Alexander und seine praktischen Anforderungen haben uns dazu gebracht, tiefer zu graben und das FM ZUGFeRD AddOn kräftig zu überarbeiten. Das Ergebnis ist Version 2.0, eine deutlich flexiblere, intuitivere und mächtigere Lösung, die wir ohne diesen produktiven Austausch nie erreicht hätten. Ein herzliches Dankeschön an dieser Stelle an Alexander für die konstruktiven Impulse, die geduldigen Tests und das ehrliche Feedback!

FM ZUGFeRD 2.0 – Die Evolution der elektronischen Rechnungsstellung in FileMaker

Die elektronische Rechnungsstellung wird in Deutschland und Europa zunehmend zur Pflicht. Mit FM ZUGFeRD 2.0 präsentieren wir die nächste Generation unseres AddOns für FileMaker – komplett überarbeitet, intuitiver und flexibler als je zuvor.

Was ist neu? Die wichtigsten Features im Überblick

🎯 1. Flexible Primärschlüssel-Zuordnung

Bildschirmfoto 2025-09-29 um 18.25.42.

Endlich: Abweichende Primärschlüssel für maximale Flexibilität! Nicht jede FileMaker-Lösung nutzt standardisierte Primärschlüssel. Mit der neuen Funktion können Sie für jeden Bereich (Seller, Buyer, Invoice, Items) einen alternativen Primärschlüssel definieren.

Was bedeutet das für Sie?

  • Keine Anpassung Ihrer bestehenden Datenstruktur nötig
  • Volle Kontrolle über die Datenzuordnung
  • Nahtlose Integration in Ihre vorhandene FileMaker-Lösung

So funktioniert’s: Ein einfacher Dialog ermöglicht die Auswahl eines abweichenden Identifikationsfeldes. Das System nutzt dann automatisch diesen alternativen Schlüssel für die Datenzuordnung – perfekt für komplexe Datenmodelle mit individuellen Beziehungsstrukturen.

🖨️ 2. Erweiterte Drucklayout-Verwaltung

Bildschirmfoto 2025-09-29 um 18.26.50.

Die neue Drucklayout-Funktion bietet Ihnen volle Kontrolle über die Ausgabe Ihrer ZUGFeRD-Dokumente:

Zwei Ansichtsmodi:

  • Formularansicht: Für detaillierte Einzelrechnungen mit allen Informationen
  • Tabellenansicht: Für kompakte Listenansichten und Sammelrechnungen

Intelligente Layout-Zuordnung:

  • Separate Layouts für verschiedene Ausgabeformate
  • Flexible Feldzuordnung pro Ansicht
  • Automatische Anpassung an Ihre Corporate Identity

Das bedeutet: Einmal konfigurieren, mehrfach nutzen – ohne ständige manuelle Anpassungen.

🎨 3. Überarbeitete Benutzeroberfläche

Die komplette Oberfläche wurde von Grund auf neu gestaltet. Moderne, intuitive Navigation durch alle Konfigurationsbereiche:

9 übersichtliche Tabs:

  1. Info – Zentrale URL-Konfiguration für alle Endpunkte
  2. Payments – Rechnungskopf und allgemeine Daten
  3. Buyer – Käufer-/Kundendaten mit vollständiger Adressverwaltung
  4. Seller – Verkäufer-/Firmendaten inkl. Steuer-IDs
  5. Finance – Bankinformationen und Zahlungskonditionen
  6. Invoice – Rechnungsbeträge, Steuern und Totalsummen
  7. Items – Rechnungspositionen mit detaillierten Artikeldaten
  8. Print – Drucklayout-Verwaltung für beide Ansichtsmodi
  9. Testen – Integrierte Demo- und Validierungsfunktionen

Das neue Design punktet mit:

  • Klarer visueller Hierarchie
  • Zweisprachigen Labels (Deutsch/English)
  • Kontextsensitiven Hilfetexten
  • Farblich gekennzeichneten Bereichen für schnellere Orientierung

🔄 4. Intelligentes Feld-Mapping

Das Herzstück von FM ZUGFeRD: Die automatisierte Feldzuordnung.

Wie es funktioniert:

  1. Layout wählen: Dropdown-Auswahl Ihrer FileMaker-Tabellen
  2. Felder zuordnen: Drag & Drop Ihrer FileMaker-Felder zu ZUGFeRD-Standardfeldern
  3. Validieren: Automatische Prüfung auf Vollständigkeit und Konformität
  4. Testen: Sofortige Vorschau der generierten Dokumente

Unterstützte Datenquellen:

  • Beliebige FileMaker-Tabellen
  • Portal-Beziehungen für Positionsdaten
  • Berechnungsfelder für dynamische Werte
  • Globale Felder für Standardwerte

📋 5. EN 16931 Konformität garantiert

Alle generierten ZUGFeRD-Dokumente entsprechen der Europäischen Norm EN 16931 für elektronische Rechnungen.

Technische Details:

  • Format: PDF/A-3 mit eingebettetem XML
  • Profile: BASIC, COMFORT, EXTENDED
  • Standard: ZUGFeRD 2.x / Factur-X
  • Kompatibilität: UBL (Universal Business Language)

Validierung in Echtzeit: Das AddOn prüft kontinuierlich:

  • Pflichtfelder gemäß gewähltem Profil
  • Korrekte Datenformate (Datum, Währung, Steuersätze)
  • Konsistenz zwischen Positionen und Gesamtsummen
  • Gültige ISO-Codes für Länder, Währungen und Einheiten

🧪 6. Integrierte Test- und Demo-Funktionen

Der neue Testen-Tab ist Ihr Playground für ZUGFeRD-Dokumente:

Demo-Funktionen:

  • Create ZUGFeRD Demo: Erstellt Beispielrechnungen zum Testen
  • Create UBL Demo: Generiert UBL-Testdokumente
  • Read ZUGFeRD Demo: Liest und analysiert vorhandene ZUGFeRD-Dateien
  • Read UBL Demo: Importiert UBL-Dokumente zur Validierung

Export/Import von Konfigurationen:

  • Einstellungen exportieren für Backup oder Migration
  • Konfigurationen importieren zwischen Test- und Produktivumgebungen
  • Versionierung Ihrer Mapping-Definitionen

Live-Vorschau: Zwei Container zeigen in Echtzeit:

  • XML-Container: Die generierte ZUGFeRD-XML-Struktur
  • PDF-Container: Das finale PDF/A-3-Dokument mit eingebettetem XML

🌐 7. Nahtlose HTTP-Integration

FM ZUGFeRD arbeitet mit PHP-Scripten (local oder Server) über standardisierte HTTP-Schnittstellen:

Der Workflow:

  1. FileMaker sendet Rechnungsdaten via POST an konfigurierten Endpoint
  2. PHP-Service generiert ZUGFeRD-konforme Struktur
  3. XML wird nach EN 16931 erstellt und validiert
  4. PDF/A-3 wird mit eingebettetem XML erzeugt
  5. Fertiges Dokument wird zum Download bereitgestellt
  6. FileMaker lädt automatisch herunter und speichert in Container-Feld

Ihre Vorteile:

  • Keine lokale PDF-Bibliothek erforderlich
  • Zentrale Verwaltung der Generierungslogik
  • Skalierbar für hohe Dokumentenvolumen
  • Einfache Updates der ZUGFeRD-Spezifikationen

📊 8. Präzise Steuerberechnung

Die Steuerberechnung erfolgt auf zwei Ebenen – vollständig automatisiert:

Positionsebene: Jede Rechnungsposition enthält:

  • Einzelpreis (netto)
  • Menge und Einheit
  • Steuersatz (%)
  • Steuerkategorie (S, Z, E, AE, …)
  • Automatische Berechnung des Zeilentotals

Dokumentebene: Automatische Aggregation zu:

  • Gesamtnettobetrag (Summe aller Positionen)
  • Steuerblöcke pro Steuersatz
  • Steuerbemessungsgrundlage pro Satz
  • Gesamtsteuerbetrag
  • Bruttoendbetrag

Wichtig: Das System stellt sicher, dass Position- und Dokumentsummen immer konsistent sind!

Praktische Anwendungsfälle

Szenario 1: Standardrechnung mit 19% MwSt.

Artikel: "Beratungsdienstleistung"
Menge: 8 Stunden
Einzelpreis: 120,00 EUR (netto)
Steuersatz: 19%

→ Netto: 960,00 EUR
→ MwSt.: 182,40 EUR
→ Brutto: 1.142,40 EUR

FM ZUGFeRD erstellt automatisch ein PDF/A-3 mit eingebettetem XML – bereit für die elektronische Übermittlung.

Szenario 2: Rechnung mit mehreren Steuersätzen

Position 1: Bücher (7% MwSt.) → 100,00 EUR netto
Position 2: Software (19% MwSt.) → 500,00 EUR netto

→ Steuerblock 7%: Basis 100,00 EUR, Steuer 7,00 EUR
→ Steuerblock 19%: Basis 500,00 EUR, Steuer 95,00 EUR
→ Gesamt: 702,00 EUR brutto

Das AddOn erstellt automatisch separate Steuerblöcke für jeden Satz – EN 16931 konform.

Szenario 3: Grenzüberschreitende Rechnung (Reverse Charge)

Verkäufer: Deutschland (DE)
Käufer: Österreich (AT) mit gültiger UID
Steuerkategorie: AE (Reverse Charge)

→ Nettobetrag: 2.500,00 EUR
→ Steuersatz: 0% (Hinweis auf Reverse Charge)
→ Bruttobetrag: 2.500,00 EUR

Perfekt für B2B-Geschäfte innerhalb der EU.

Best Practices für Ihre FileMaker-Lösung

1. Datenstruktur vorbereiten

Empfohlene Felder in Ihrer Rechnungstabelle:

  • rg_nummer (Text): Eindeutige Rechnungsnummer
  • rg_datum (Datum): Rechnungsdatum im Format YYYY-MM-DD
  • rg_faellig (Datum): Fälligkeitsdatum
  • rg_waehrung (Text): ISO-Währungscode (EUR, USD, CHF, …)
  • rg_kunde_id (Zahl): Fremdschlüssel zur Kundentabelle
  • rg_netto (Zahl): Nettosumme (berechnet)
  • rg_steuer (Zahl): Steuerbetrag (berechnet)
  • rg_brutto (Zahl): Bruttosumme (berechnet)

2. Berechnungsfelder nutzen

Steuerbetrag berechnen:

Round ( rg_netto * 0.19 ; 2 )

Bruttobetrag berechnen:

rg_netto + rg_steuer

Aggregation von Positionen:

Sum ( rg_positionen::pos_netto )

3. Validierung implementieren

Prüfen vor Export:

  • Sind alle Pflichtfelder gefüllt?
  • Ist die USt-ID formal korrekt?
  • Stimmen Positions- und Kopfsummen überein?
  • Sind ISO-Codes korrekt (Land, Währung, Einheit)?

FileMaker-Skript Beispiel:

If [ IsEmpty ( rg_nummer ) or IsEmpty ( rg_datum ) ]
    Show Custom Dialog [ "Fehler"; "Pflichtfelder fehlen!" ]
    Exit Script [ Text Result: False ]
End If

# ZUGFeRD Export starten
Perform Script [ "ZUGFeRD - Export Rechnung" ]

4. Layouts strukturieren

Empfohlene Layout-Struktur:

  • Formularansicht: Vollständige Rechnung mit Header, Positionen, Footer
  • Listenansicht: Kompakte Positionsübersicht
  • Druckansicht: Formatiert für PDF-Export mit Corporate Design

5. Fehlerbehandlung einbauen

Typische Fehlerquellen:

  • Leere Pflichtfelder
  • Ungültige Datumsformate
  • Falsche Währungscodes
  • Fehlende Beziehungen zu Stammdaten

Lösung: Validierungs-Skripte vor dem Export ausführen!

Technische Details für Entwickler

Unterstützte Einheitencodes (UN/ECE Recommendation 20)

Die wichtigsten Codes für den deutschen Markt:

Code Bedeutung Verwendung
C62 Stück Einzelne Artikel, Produkte
HUR Stunde Dienstleistungen, Beratung
DAY Tag Tagessätze, Miete
MTR Meter Längenangaben, Textilien
MTK Quadratmeter Flächen, Immobilien
MTQ Kubikmeter Volumen, Baustoffe
KGM Kilogramm Gewichtsangaben
TNE Tonne Schwergewicht, Rohstoffe
LTR Liter Flüssigkeiten
SET Set Produktsets, Bundles
MON Monat Abonnements, Mieten

Steuerkategorien nach EN 16931

Code Bedeutung Anwendung
S Standard rate Regelsteuersatz (19% in DE)
AA Lower rate Ermäßigter Satz (7% in DE)
Z Zero rated 0% (z.B. innergemeinschaftlich)
E Exempt Steuerbefreit (z.B. Kleinunternehmer)
AE Reverse charge Umkehr der Steuerschuldnerschaft
K Intra-Community Innergemeinschaftliche Lieferung
G Free export Export außerhalb EU
O Outside scope Nicht steuerbar

Rechnungstyp-Codes (UNTDID 1001)

Code Typ Verwendung
380 Commercial Invoice Standardrechnung
381 Credit Note Gutschrift/Stornorechnung
384 Corrected Invoice Korrekturrechnung
389 Self-billed Invoice Gutschriftverfahren
751 Invoice Information Rechnungsinformation

Zahlungsarten (ISO 20022)

Code Zahlungsart
58 SEPA-Überweisung
30 Banküberweisung
48 Kreditkarte
49 Lastschrift
97 Verrechnungsscheck

Lizenzierung und Support

COMFORT-Version

FM ZUGFeRD ist als COMFORT-Version lizenziert und bietet:

  • Vollständige EN 16931 Konformität
  • Alle ZUGFeRD 2.x Profile (BASIC, COMFORT, EXTENDED)
  • UBL-Unterstützung
  • Unbegrenzte Dokumentenerstellung
  • Professioneller Support

Updates und Wartung

  • Regelmäßige Updates bei Änderungen der ZUGFeRD-Spezifikation
  • Anpassungen bei gesetzlichen Änderungen
  • Bug-Fixes und Optimierungen
  • Neue Features basierend auf Kundenanforderungen

Support-Kanäle

  • E-Mail Support: support@filemaker-experts.de
  • Dokumentation: Wiki mit ausführlichen Anleitungen
  • Video-Tutorials: Schritt-für-Schritt Konfiguration
  • Community-Forum: Austausch mit anderen Nutzern

Migration von älteren Versionen

Von FM ZUGFeRD 1.x auf 2.0

Die Migration ist einfach:

  1. Backup erstellen: Sichern Sie Ihre aktuelle Konfiguration
  2. Export Settings: Exportieren Sie Ihre Feldzuordnungen
  3. Update installieren: Neue AddOn-Version in FileMaker laden
  4. Import Settings: Importieren Sie Ihre gespeicherte Konfiguration
  5. Test durchführen: Erstellen Sie Test-Dokumente zur Validierung

Was bleibt erhalten:

  • Alle Feldzuordnungen
  • URL-Konfigurationen
  • Layout-Einstellungen

Was ist neu zu konfigurieren:

  • Drucklayout-Zuordnungen (neue Funktion)
  • Alternative Primärschlüssel (falls gewünscht)

Roadmap: Was kommt als Nächstes?

Wir arbeiten bereits an weiteren Verbesserungen:

Geplante Features (Q2-Q4 2025)

  • 🔄 Batch-Verarbeitung: Mehrere Rechnungen auf einmal exportieren
  • 📧 E-Mail-Integration: Direktversand via FM MailBridge AddOn
  • 🗄️ Archivierung: Automatisches Ablegen in revisionssicheren Archiven
  • 📱 Mobile Optimierung: Rechnungserstellung auf iPad
  • 🤖 KI-Unterstützung: Automatische Felderkennung beim Import
  • 🌍 Weitere Formate: X-Rechnung, Peppol BIS
  • 📊 Analytics: Reporting und Statistiken über ZUGFeRD-Nutzung

Fazit: Bereit für die E-Rechnungs-Pflicht

Mit FM ZUGFeRD 2.0 sind Sie bestens gerüstet für die elektronische Rechnungsstellung:

Rechtskonform: EN 16931 zertifiziert
Flexibel: Passt sich Ihrer FileMaker-Lösung an
Intuitiv: Moderne, übersichtliche Benutzeroberfläche
Zuverlässig: Validierung in Echtzeit
Zukunftssicher: Regelmäßige Updates und Erweiterungen

Ab sofort verfügbar!

Jetzt informieren:


Hinweis: Ab 2025 wird die E-Rechnung in Deutschland für B2B-Transaktionen schrittweise verpflichtend. Mit FM ZUGFeRD erfüllen Sie alle gesetzlichen Anforderungen – heute schon für morgen bereit.

#FileMaker #ZUGFeRD #ERechnung #DigitaleTransformation #Automatisierung


ZUGFeRD mit eigenem PDF-Layout, endlich pragmatisch gelöst

ZUGFeRD FileMaker PDF.

Monate lang stand ich vor dem gleichen Problem: Die PHP-Bibliothek horstoeko/zugferd erzeugt zuverlässig die ZUGFeRD-XML, möchte aber idealerweise, dass man das sichtbare PDF mit FPDF neu aufbaut. Für standardisierte Rechnungen ist das akzeptabel; für gewachsene Corporate-Designs mit sauber gesetzten Typografien, Logos, farbigen Flächen und komplexeren Kopf-/Fußbereichen ist es schlicht unpraktikabel. Mein Ziel war daher, ein beliebiges, bereits perfektes Template-PDF (aus FileMaker, InDesign, Word oder einem anderen System) weiterzuverwenden und ausschließlich die ZUGFeRD-XML sauber zu integrieren – ohne das Layout neu zu programmieren.

Ausgangsproblem – warum der reine FPDF-Weg nicht reicht

Sobald es um reale Layouts geht, wird der FPDF-Weg schnell mühsam: Spaltenbreiten, Zeilenabstände, Schriften, Positionierungen, Logos, CI-Farben – alles muss mühsam nachgebaut werden, obwohl das Layout als fertige PDF längst existiert. Hinzu kommt, dass einzelne PDFs wegen Kompressionsarten, PDF-Versionen oder Producer-Spezifika von FPDI nicht immer direkt importierbar sind. Das kostet Zeit, Nerven und bringt keinen fachlichen Mehrwert, wenn das Ziel schlicht „bestehendes Layout beibehalten, ZUGFeRD einbetten“ heißt.

Die Lösung – Template-PDF nutzen, ZUGFeRD einbetten, robustes Fallback

Ich habe ein Template-System mit mehrstufigem Fallback gebaut, das vorhandene PDFs bevorzugt, FPDI nur nutzt, wenn es geht, andernfalls automatisiert konvertiert oder, falls nötig, das Template schlicht als Basis kopiert und anschließend die ZUGFeRD-XML einbettet. Die ZUGFeRD-Erzeugung bleibt sauber im ZugferdDocumentBuilder, das Einbetten erfolgt mit ZugferdDocumentPdfBuilder::fromPdfFile(…). Ergebnis: Das Layout bleibt 1:1 erhalten, und die PDF wird ZUGFeRD-konform.

Kernpunkte des Ansatzes: • Automatische Template-Erkennung im templates/-Ordner, optional mit layout_config.json für kleinere Koordinaten-/Schrift-Tweaks (falls man doch etwas übersteuern möchte). • Mehrstufiger FPDI-Fallback: Direktimport → Konvertierung (Ghostscript) → sichere Kopie. • Robustes Error-Handling & Logging: Jede Stufe wird sauber protokolliert, inklusive Dateigrößen, Rückgaben und etwaigen Ausnahmen. • Saubere Trennung der Verantwortlichkeiten: Der Builder erzeugt die XML; der PDF-Builder fügt sie einem bestehenden PDF hinzu; FPDF kommt nur noch dann zum Einsatz, wenn wirklich ein Basispapier benötigt wird.

Technischer Ablauf – von Template bis ZUGFeRD-PDF 1. Template laden oder Standard-PDF erzeugen (Upload aus FileMaker per aus URL einfügen) Im Projektverzeichnis liegt ein templates/-Ordner. Dort wird automatisch die erste passende PDF als Template ausgewählt. Deshalb wird die Rechnung immer als template.pdf hochgeladen. Möglich ist auch dort schon die Rechnugs-PDF mit eigenem Datei-Namen zu versehen. Dies ist aber nicht notwendig. Ist FPDI verfügbar und kann das Template öffnen, wird die Seite importiert. Schlägt dies wegen Kompressionsdetails fehl, versucht das System eine Konvertierung (via Ghostscript) und importiert erneut. Misslingt auch das, wird das Template als Datei kopiert und danach direkt mit XML versehen. Nur wenn überhaupt kein Template vorhanden/geeignet ist, wird minimal mit FPDF eine neutrale Seite gebaut. 2. ZUGFeRD-XML generieren Die fachlichen Rechnungsdaten kommen wie gehabt per POST (Rechnungsnummer, Datum, Positionen, Summen, Steuerblöcke, Zahlungsbedingungen etc.). Daraus wird mit ZugferdDocumentBuilder die EN16931-konforme XML erzeugt. 3. XML in PDF integrieren Mit ZugferdDocumentPdfBuilder::fromPdfFile($document, $tempPdfPath) wird die XML in das vorbereitete PDF geschrieben und als finale ZUGFeRD-PDF gespeichert.

Ausschnitt: Template-Erkennung mit mehrstufigem Fallback

Im folgenden Ausschnitt ist das Prinzip komprimiert dargestellt. Beachten: Kommentare sind bewusst ausführlich, da sie beim späteren Debuggen Gold wert sind.

// Template-PDF automatisch erkennen
$templatesDir = __DIR__ . '/templates/';
$templatePdfs = glob($templatesDir . '*.pdf');

if (!empty($templatePdfs)) {
    $templatePdf = $templatePdfs[0];

    try {
        // Versuch 1: FPDI nutzen (falls verfügbar)
        if (!class_exists('Fpdi')) {
            throw new Exception('FPDI-Klasse nicht verfügbar');
        }

        $pdf = new Fpdi();
        $pageCount = $pdf->setSourceFile($templatePdf);
        $tpl = $pdf->importPage(1);
        $pdf->AddPage();
        $pdf->useTemplate($tpl, 0, 0);

        // Als temporäre Basis speichern
        $pdf->Output('F', $tempPdfPath);
        // -> ab hier geht es direkt zum Einbetten der XML

    } catch (Exception $e) {
        // Versuch 2: PDF kompatibel machen und erneut probieren
        $converted = $templatesDir . 'converted_template.pdf';
        if (convertPdfForFpdi($templatePdf, $converted)) {
            try {
                $pdf = new Fpdi();
                $pageCount = $pdf->setSourceFile($converted);
                $tpl = $pdf->importPage(1);
                $pdf->AddPage();
                $pdf->useTemplate($tpl, 0, 0);
                $pdf->Output('F', $tempPdfPath);
                @unlink($converted);
            } catch (Exception $e2) {
                @unlink($converted);
                // Versuch 3: Direkte Kopie als Fallback
                copy($templatePdf, $tempPdfPath);
            }
        } else {
            // Falls Konvertierung nicht möglich: Direkte Kopie
            copy($templatePdf, $tempPdfPath);
        }
    }
} else {
    // Kein Template gefunden -> neutrale FPDF-Seite als Minimalbasis
    $pdf = new FPDF();
    $pdf->AddPage();
    // Optional: Logo/Absender, wenn gewünscht; ansonsten blank lassen
    // $pdf->Image('logo.png', 20, 10, 30, 15);
    $pdf->Output('F', $tempPdfPath);
}

Konvertierung für FPDI-Kompatibilität

Manche PDFs scheitern an der Importhürde wegen Kompressionsart oder PDF-Version. Ich reiche deshalb (falls vorhanden) eine Ghostscript-Konvertierung vor. Der Code ist so geschrieben, dass er ohne Ghostscript nicht abstürzt, sondern sauber weiter macht.

function convertPdfForFpdi($inputPdf, $outputPdf) {
    try {
        // Versuch: Ghostscript (falls exec() und gs vorhanden)
        if (function_exists('exec')) {
            $cmd = 'gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 '
                 . '-dPDFSETTINGS=/prepress -dNOPAUSE -dQUIET -dBATCH '
                 . '-sOutputFile="' . $outputPdf . '" "' . $inputPdf . '" 2>&1';
            $out = [];
            $ret = 0;
            exec($cmd, $out, $ret);
            if ($ret === 0 && file_exists($outputPdf)) {
                return true;
            }
        }
        // Fallback: Wenn kompatibel, reicht Kopie
        return copy($inputPdf, $outputPdf);
    } catch (Exception $e) {
        return false;
    }
}

XML erzeugen und in bestehendes PDF einbetten

Der entscheidende Schritt: Wir nutzen die Stärke der Bibliothek – die XML-Erzeugung – und vermeiden, das Layout neu bauen zu müssen. Dazu erstellen wir den ZugferdDocumentBuilder, setzen alle Pflicht- und optionalen Felder (Dokumenttyp, Beträge, Steuern, Zahlungsbedingungen etc.) und übergeben dieses Dokument anschließend an den PDF-Builder.

// 1) ZUGFeRD-XML vorbereiten
$document = ZugferdDocumentBuilder::createNew(ZugferdProfiles::PROFILE_EN16931);
$document->setDocumentInformation($invoiceNumber, $invoiceTypeCode, new DateTime($invoiceDate), $currency);

// Summation/Steuerblöcke etc. setzen ...
// $document->setDocumentSummation(...);
// $document->addDocumentTax(...);
// $document->addDocumentPaymentMeanToCreditTransfer(...);

// 2) XML in das vorhandene (Template-)PDF einbetten
$pdfBuilder = ZugferdDocumentPdfBuilder::fromPdfFile($document, $tempPdfPath);
$pdfBuilder->generateDocument();
$pdfBuilder->saveDocument($outputPath);

Template-Konfiguration: optional, klein, hilfreich

Damit ich bei Bedarf Kleinigkeiten ohne neues Template anfassen kann, lese ich eine layout_config.json ein. Sie enthält vor allem Koordinaten und Schriftgrößen für Textbausteine, die ich optional über FPDF ergänze (z. B. Adressblock, Infospalte, Summenfeld) – praktisch, falls Kundenvarianten leichte Unterschiede verlangen, aber kein komplett eigenes Template rechtfertigen.

Beispielhafte Keys (gekürzt): page_width, margin_left, sender_start_x, right_column_label_x, document_type_y, table_start_y, default_font, header_bg_color, summary_label_x, template_pdf. Fehlt die Datei, läuft das System mit vernünftigen Standardwerten weiter – der ZUGFeRD-Teil ist davon ohnehin unabhängig.

Logging und Fehlertoleranz

Alle wesentlichen Schritte werden in uploads/zugferd_log.txt mit Zeitstempel geloggt: Welche Stufe gegriffen hat, Dateigrößen vor/nach Verarbeitung, gefundene Templates, etwaige Exceptions inklusive Trace. Damit sind Fehlersuche und spätere Betriebsbeobachtung unaufwendig. Auch wenn FPDI oder Ghostscript nicht verfügbar sind, bleibt das System funktionsfähig, da es am Ende immer auf die „Kopie + Einbettung“-Strategie zurückfällt.

Was bleibt von FPDF?

FPDF bleibt im Projekt lediglich als Minimal-Fallback oder für sehr kleine Ergänzungen (z. B. dynamischer Hinweistext) erhalten. Logos, Balken, CI-Elemente usw. kommen aus dem Template, so wie es sein soll. Fazit

Statt aufwendig ein bestehendes Corporate-Design in FPDF nachzubauen, nutze ich jetzt vorhandene PDFs die in FileMaker erzeugt werden unverändert und lasse lediglich die ZUGFeRD-XML sauber einbetten. Die Kombination aus Template-Erkennung, FPDI-Fallback, optionaler Konvertierung und konsequentem Error-Handling führt zu einem robusten, praxistauglichen Workflow: Template bzw. die aktuelle Rechnung hochladen, Daten senden, fertige ZUGFeRD-PDF erhalten. Wenn Sie bereits ein gutes Rechnungslayout in FileMaker haben und nur „ZUGFeRD dazu“ brauchen, ist dieser Ansatz die pragmatische Abkürzung.


FileMaker-Datensätze direkt über eine PHP-API mit KI-Unterstützung erstellen - Direkt in FileMaker speichern: Eigene PHP-API statt n8n & Co

Viele Entwickler suchen nach Wegen, wie sich Notizen, Aufgaben oder Projekte aus natürlicher Sprache direkt in FileMaker übernehmen lassen – ohne Umweg über Integrationsplattformen wie n8n oder Make. Mit einem schlanken PHP-Skript und der FileMaker Data API ist genau das möglich.

Bildschirmfoto 2025-09-13 um 19.36.55.

Idee und Zielsetzung

Der Ansatz ist denkbar einfach: 1. Ein Benutzer spricht oder schreibt einen kurzen Text. 2. Dieser Text wird per JSON-POST an ein PHP-Skript geschickt. 3. Das Skript analysiert den Text mithilfe einer KI (Claude AI oder ChatGPT). 4. Je nach Analyse wird in FileMaker ein neuer Datensatz erstellt oder ein bestehender ergänzt.

So lassen sich Workflows wie “Meeting morgen mit Kunde Müller anlegen” oder “Status-Update für Projekt A-123” in Sekunden automatisieren.

Das PHP-Skript

Das Herzstück ist eine kleine API, die im Webserver läuft, nennen wir sie analyze_text.php.

  1. Empfang der Daten

Das Skript nimmt POST-Anfragen mit JSON entgegen:

{
  "text": "Rückruf morgen für A-123"
}
  1. KI-Analyse

Die KI wird mit einer klaren Vorgabe aufgerufen: sie soll den Text in ein JSON mit festen Feldern zerlegen – darunter action, project_id, date, text und user.

Beispielausgabe:

{
  "action": "create_note",
  "project_id": "A-123",
  "date": "2025-09-14",
  "text": "Rückruf morgen"
}
  1. Verbindung zu FileMaker

Über die FileMaker Data API erfolgt ein Login mit Benutzername und Passwort. Anschließend lassen sich: • bestehende Projekte finden (_find-Abfrage nach Projekt-ID) • Portalzeilen anlegen (z. B. Notizen im Projekt) • neue Projekte erzeugen (wenn keine Referenz existiert)

Dafür verwendet das Skript die REST-Endpunkte wie: • POST /fmi/data/vLatest/databases//sessions → Login • POST /layouts//_find → Projektsuche • PATCH /layouts//records/ → Portalzeile erstellen • POST /layouts//records → neuen Datensatz anlegen

  1. Ergebnis

Das Skript gibt eine JSON-Antwort zurück, z. B.:

{
  "ok": true,
  "original_text": "Rückruf morgen für A-123",
  "extracted": {
    "action": "create_note",
    "project_id": "A-123",
    "date": "2025-09-14",
    "text": "Rückruf morgen"
  },
  "filemaker": {
    "note_created": true,
    "project_record_id": "12345"
  },
  "timestamp": "2025-09-13 16:30:00"
}

Vorteile des Ansatzes • Keine Drittanbieter wie n8n oder Zapier notwendig • Direkter Zugriff auf FileMaker per Data API • Flexibel erweiterbar um eigene Aktionen (Tasks, Kontakte, Termine) • Einfache Integration in FileMaker-Layouts über einen WebViewer oder einen Button mit Insert from URL

Beispielanwendung in FileMaker • Button „Sprachnotiz analysieren“: Aufnahme → Text → POST an analyze_text.php • Automatisches Anlegen von Terminen oder Notizen im Projekt • Projektanlage per Sprache: „Neues Projekt mit Kunde Meier starten“ → neuer Datensatz mit Name und Kunde wird angelegt

Fazit

Mit nur einem PHP-Skript und der FileMaker Data API lässt sich ein eigener Mini-Connector bauen, der Sprache oder Texte in strukturierte FileMaker-Daten verwandelt. Das spart nicht nur Kosten für Integrationsdienste, sondern erlaubt auch maximale Kontrolle und Anpassung.


Tourenplanung in FileMaker, über clustern, Kosten sparen!

Wer schon einmal versucht hat, in FileMaker mit vielen Adressen eine Route über die Google Maps API zu planen, kennt das Problem. Ab einer gewissen Anzahl von Stopps schnellen die Kosten nach oben und die Performance leidet. Aber genau hier setzt mein Ansatz an: -Clustering-.

Warum Clustering?

Google erlaubt pro Request in der Directions API nur 25 Zwischenstopps (plus Start und Ziel). Mehr geht nicht. Mit 80 Kundenadressen wären das also drei bis vier Requests, wenn man clever plant.

Ohne Clustering würde man mit der Distance Matrix API schnell in den vierstelligen Bereich an Elementen kommen (80 × 80 = 6.400), die abgerechnet werden. Mit Clustering dagegen, vier kleine Matrizen a 20 × 20 = 400. Macht in Summe 1.600. Das sind 75 % weniger Kosten und dazu deutlich weniger Wartezeit.

1.	Geocoding – jede Adresse bekommt saubere Koordinaten.
2.	K-Means Clustering – die Adressen werden nach geografischer Nähe in Gruppen aufgeteilt (z. B. vier Cluster mit je 20 Stopps).
3.	Optimierung je Cluster – innerhalb des Clusters wird die Reihenfolge berechnet.
4.	Routes API – für jedes Cluster wird die Route berechnet, nie mehr als 25 Stopps.
5.	FileMaker-Integration – die Ergebnisse landen als einfache JSON-/GET-Antwort wieder in FileMaker, wo sie importiert und angezeigt werden können.

Das Ganze läuft mit Session-IDs, sodass FileMaker volle Kontrolle über den Ablauf hat und wir persistente Daten auch später noch abrufen können.

Demo-Daten für den Praxistest

Für das nächste FileMaker-Magazin haben wir Demo-Daten vorbereitet: • 80 Adressen im Raum Berlin/Brandenburg (kann natürlich geändert werden) • passende Kontaktdaten • und natürlich die fertige Clusterlösung

Damit kann jeder sofort ausprobieren, wie aus einer unübersichtlichen Masse von Stopps überschaubare Touren werden.


Neu: ZUGFeRD/UBL Reader Add-on für FileMaker

Elektronische Rechnungen sind längst Standard, insbesondere im öffentlichen Bereich mit UBL/XRechnung und bei Geschäftspartnern mit ZUGFeRD 2.1.1. Für viele FileMaker-Anwender stellt sich die Frage: Wie lassen sich diese Rechnungen direkt in bestehende Systeme integrieren, ohne jede Datei manuell zu erfassen?

Zugferd Reader.

Genau hier setzt unser neues ZUGFeRD/UBL Reader Add-on an.

Was kann das Add-on? • ZUGFeRD-PDFs einlesen: XML wird automatisch erkannt und verarbeitet • UBL/XRechnung unterstützen: kompatibel mit den gängigen Behörden- und Portallösungen • Strukturierte JSON-Ausgabe: Kopf-, Positions- und Steuerdaten stehen FileMaker-konform bereit • Beispielskripte und Mapping: sofort loslegen mit vorbereiteten Routinen • Flexibel im Einsatz: Einzelplatz oder Serverumgebung

Warum ist das wichtig? • Zeitersparnis: keine manuelle Eingabe von Rechnungsdaten mehr • Rechtssicherheit: Unterstützung aktueller Standards für E-Rechnung • Offen & erweiterbar: klare Dokumentation, kein Vendor-Lock-in • Praxisnah: entwickelt von FileMaker-Experten mit jahrzehntelanger Projekterfahrung

Für wen ist das interessant? • Unternehmen mit Pflicht zur E-Rechnung (öffentlicher Sektor, Lieferanten) • FileMaker-Entwickler, die Buchhaltung oder ERP-Funktionen integrieren möchten • Teams, die Eingangsrechnungen automatisiert verarbeiten wollen


ZUGFeRD nicht nur erstellen, sondern auch lesen

Zugferd lesen.

Die meisten Entwickler verbinden ZUGFeRD oder Factur-X mit dem klassischen Anwendungsfall:

Eine Rechnung in FileMaker erzeugen, die dann als PDF mit eingebettetem XML an den Kunden geht. Doch im täglichen Einsatz ergibt sich oft das umgekehrte Szenario: Eingehende ZUGFeRD-Rechnungen sollen in das eigene System importiert und weiterverarbeitet werden. Genau hier zeigt sich die eigentliche Stärke des Standards, denn er erlaubt eine strukturiert maschinenlesbare Übergabe von Rechnungsdaten ohne dass man auf PDF-Parsing oder OCR-Erkennung angewiesen wäre.

Der Ansatz:

Mein Ziel war es, neben der Erzeugung auch das Einlesen von ZUGFeRD-Dateien in eine FileMaker-Lösung zu integrieren. Der Workflow ist dabei erstaunlich klar: 1. Der Anwender zieht eine ZUGFeRD-PDF in ein Containerfeld. 2. Ein FileMaker-Script übernimmt den Upload und prüft die Datei. 3. Die eingebettete XML-Datei wird mit Hilfe des PHP-Pakets horstoeko/zugferd extrahiert und ausgewertet. 4. Als Rückgabe erhalte ich ein kompaktes JSON, das sich in FileMaker direkt weiterverarbeiten lässt.

Damit ist der Kreis geschlossen: Eingehende Rechnungen können automatisch gelesen, geprüft und in die eigene Datenbank übernommen werden.

Technische Umsetzung

Im einfachsten Fall genügt ein FileMaker-Skript, das den Containerinhalt temporär exportiert und per curl an das Server-Skript übergibt:

Variable setzen [ $filename ; HoleContainerAttribute ( Rechnung::g_pdf ; "filename" ) ]
Variable setzen [ $tmpFS ; Hole ( TemporärerPfad ) & $filename ]
Exportiere Feldinhalt [ Rechnung::g_pdf ; "file:" & $tmpFS ]
Variable setzen [ $url ; "[meine-domain.de/mc/receiv...](https://meine-domain.de/mc/receive_pdf_upload.php)" ]
Variable setzen [ $curl ; "--request POST --upload-file " & Quote ( $tmpFS ) & 
                          " --header \"Content-Type: application/pdf\"" ]
Aus URL einfügen [ Auswahl ; Mit Dialog: Aus ; Ziel: $$response ; $url ; 
                   SSL-Zertifikate verifizieren ; cURL-Optionen: $curl ]

Das PHP-Skript wiederum nimmt die hochgeladene PDF entgegen, übergibt sie an horstoeko und liefert ein strukturiertes JSON zurück:

{
    "ok": true,
    "mode": "raw",
    "file": "/www/htdocs/w01da32b/maps.maro-testserver.de/mc/uploads/upload.pdf",
    "data": {
        "profile": "EN16931",
        "profileId": 2,
        "invoiceNumber": "INV-2025-001",
        "typeCode": "380",
        "issueDateTime": "2025-08-01 18:57:53",
        "currency": "EUR",
        "taxCurrency": null,
        "language": null,
        "isCopy": false,
        "isTest": false,
        "seller": {
            "name": "MaRo-Programmierung GbR",
            "globalId": "16547",
            "description": "Birkenwerder",
            "address": {
                "lineOne": null,
                "lineTwo": null,
                "lineThree": null,
                "postCode": null,
                "city": null,
                "country": null,
                "subdivision": null
            }
        },
        "buyer": {
            "name": "Fensterhaus Ansbach GmbH",
            "globalId": "91522",
            "description": "Ansbach",
            "address": {
                "lineOne": null,
                "lineTwo": null,
                "lineThree": null,
                "postCode": null,
                "city": null,
                "country": null,
                "subdivision": null
            }
        },
        "totals": {
            "grandTotal": 1249.5,
            "duePayable": 1249.5,
            "lineTotal": 1050,
            "taxTotal": 199.5,
            "taxBasisTotal": 1050,
            "chargeTotal": null,
            "allowanceTotal": null,
            "roundingAmount": null,
            "totalPrepaidAmount": null
        },
        "payment": {
            "typeCode": "58",
            "information": null,
            "payeeIban": "DE12345678901234567890",
            "payeeBic": "GENODEF1XYZ",
            "accountName": "Testbank",
            "buyerIban": null,
            "cardType": null,
            "cardId": null,
            "cardHolderName": null
        },
        "tax": [
            {
                "categoryCode": "S",
                "typeCode": "VAT",
                "basisAmount": 1050,
                "calculatedAmount": 199.5,
                "rateApplicablePercent": 19,
                "exemptionReason": null,
                "exemptionReasonCode": null,
                "lineTotalBasisAmount": 0,
                "allowanceChargeBasisAmount": 0,
                "taxPointDate": null,
                "dueDateTypeCode": null
            }
        ],
        "lines": [
            {
                "lineId": "1",
                "name": "Entwicklung und Anpassungen",
                "description": null,
                "sellerId": null,
                "buyerId": null,
                "globalIdType": null,
                "globalId": null,
                "quantity": 10,
                "unitCode": "HUR",
                "unitPrice": 90,
                "netAmount": 900,
                "basisQuantity": null,
                "basisQuantityUnitCode": null,
                "chargeFreeQuantity": null,
                "chargeFreeQuantityUnitCode": null,
                "allowanceChargeAmount": null,
                "taxPercent": 19,
                "taxCategory": "S",
                "taxTypeCode": "VAT",
                "taxCalculatedAmount": null,
                "allTaxes": [
                    {
                        "categoryCode": "S",
                        "typeCode": "VAT",
                        "rateApplicablePercent": 19,
                        "calculatedAmount": null,
                        "exemptionReason": null,
                        "exemptionReasonCode": null
                    }
                ]
            },
            {
                "lineId": "2",
                "name": "Remote-Support pauschal",
                "description": null,
                "sellerId": null,
                "buyerId": null,
                "globalIdType": null,
                "globalId": null,
                "quantity": 1,
                "unitCode": "C62",
                "unitPrice": 150,
                "netAmount": 150,
                "basisQuantity": null,
                "basisQuantityUnitCode": null,
                "chargeFreeQuantity": null,
                "chargeFreeQuantityUnitCode": null,
                "allowanceChargeAmount": null,
                "taxPercent": 19,
                "taxCategory": "S",
                "taxTypeCode": "VAT",
                "taxCalculatedAmount": null,
                "allTaxes": [
                    {
                        "categoryCode": "S",
                        "typeCode": "VAT",
                        "rateApplicablePercent": 19,
                        "calculatedAmount": null,
                        "exemptionReason": null,
                        "exemptionReasonCode": null
                    }
                ]
            }
        ]
    }
}

Dieses JSON ist das ideale Bindeglied: In FileMaker genügt ein Loop über data.lines[], um die einzelnen Positionen anzulegen. Kopf und Summenfelder lassen sich direkt in Variablen schreiben und anschließend auf beliebige Felder mappen.

Warum das spannend ist • Automatisierte Buchung: Eingehende Lieferantenrechnungen können ohne Medienbruch erfasst werden. • Plausibilitätsprüfung: Brutto = Netto + Steuer lässt sich sofort abgleichen. • Flexibilität: Egal ob Erzeugung oder Import dieselbe Technik (PHP + horstoeko) kann beides.

Fazit

Während viele nur an die Ausgabe denken, ist gerade das Einlesen der eigentliche Schlüssel zur durchgängigen Digitalisierung von Rechnungsprozessen. Mit ZUGFeRD lassen sich Daten beidseitig austauschen und mit ein paar Skriptzeilen in FileMaker hat man plötzlich nicht nur ein Export, sondern auch eine Import-Funktion in der Hand.


Endlich ist es fertig: ZUGFeRD in FileMaker – Integration in unter einer Stunde

ZUGFeRD UBL.

Nach intensiver Entwicklung ist es soweit: Unser ZUGFeRD-/Factur-X Add-on für FileMaker ist fertig! 🎉 Wer schon einmal versucht hat, ZUGFeRD in eine FileMaker-Anwendung einzubauen, kennt die Herausforderung: Eigenentwicklungen ziehen sich über Tage oder Wochen, kosten Zeit, Geld und Nerven – und am Ende bleibt die Frage nach der Wartbarkeit.

Mit unserem Add-on gehen wir einen anderen Weg. Keine Programmierung, kein kompliziertes Skripten, stattdessen Mapping.

Mapping statt Programmieren

Die Implementierung basiert auf dem offiziellen COMFORT-Profil von ZUGFeRD/Factur-X. Das bedeutet: Alle relevanten Rechnungsdaten werden abgedeckt, ohne dass man sich selbst tief in Spezifikationen und Normdetails einarbeiten muss.

Anstatt eigene Scripts oder Datenmodelle zu schreiben, werden die bestehenden Felder in FileMaker einfach über ein Mapping den benötigten ZUGFeRD-Feldern zugeordnet. Damit bleibt die eigene Struktur unverändert, und trotzdem erfüllt die Anwendung sofort den Standard.

In weniger als einer Stunde einsatzbereit

Der größte Vorteil: Die Integration dauert in der Regel nicht länger als eine Stunde. Das Add-on klinkt sich direkt in die bestehende FileMaker-Datenbank ein, ohne dass das Rechnungslayout oder vorhandene Scripts angepasst werden müssen.

Wer möchte, kann die Integration jederzeit durch eigenes Skripting erweitern – doch die Grundinstallation läuft komplett ohne Programmieraufwand.

Vorteile gegenüber Eigenentwicklung • Zeitersparnis: statt tagelanger Arbeit → unter einer Stunde fertig. • Kostenreduktion: keine teuren Eigenentwicklungen, kein externer Entwickler notwendig. • Zukunftssicherheit: Nutzung des offiziellen ZUGFeRD-COMFORT-Profils, das in vielen Branchen bereits Standard ist. • Flexibilität: Erweiterungen und Anpassungen sind jederzeit möglich, aber nicht zwingend nötig.

Fazit

Endlich verfügbar! Mit unserem ZUGFeRD-Add-on für FileMaker sparen Sie Zeit, Geld und Ressourcen – und bleiben dabei normenkonform.


Morgen verfügbar: Das FileMaker ZUGFeRD / UBL Add-on – elektronische Rechnungen ohne Umbau der bestehenden Lösung

Ab morgen Abend steht unser neues FileMaker Add-on für ZUGFeRD / UBL zur Verfügung, die wohl einfachste Möglichkeit, elektronische Rechnungen direkt aus einer bestehenden FileMaker-Lösung zu erzeugen.

New ZUGFeRDZ.

Das Besondere daran: Kein Umbau der vorhandenen Lösung nötig. • Keine Änderungen am bestehenden Rechnungslayout – Ihre gewohnten Drucklayouts bleiben, wie sie sind. • Keine Anpassungen an bestehenden Scripts – der Ablauf Ihrer Rechnungserstellung wird nicht verändert. • Alles läuft über ein flexibles Mapping – Sie wählen einfach das Layout aus, auf dem die relevanten Felder zu finden sind, und ordnen diese den vorgegebenen Platzhaltern zu.

Technische Basis: • Läuft über die bewährte PHP-Bibliothek horstoeko/zugferd, aktuell eine der stabilsten und meistgenutzten Open-Source-Lösungen für ZUGFeRD und Factur-X. • Automatische Validierung der erzeugten XML-Struktur, fehlerhafte Daten werden erkannt, bevor die Rechnung erstellt wird. • Keine zusätzlichen Plugins nötig. Das System läuft vollständig mit Bordmitteln von FileMaker und PHP. • Flexibel in der Ausführung: • Lokal z. B. auf einem Einzelplatzrechner mit PHP • Über den FileMaker Server für automatisierte oder geplante Verarbeitung

Unterstützt werden: • ZUGFeRD in den gängigen Profilen (Basic, Comfort …) • UBL als international verbreiteter XML-Standard

Das Add-on übernimmt den Rest: • Erzeugung der XML-Datei • Einbettung in die PDF (ZUGFeRD-konform) • Fertige elektronische Rechnung zum Versand an Kunden, Behörden oder Portale

Startschuss: Morgen Abend. Weitere Informationen, Screenshots und eine ausführliche Dokumentation finden Sie dann hier auf unserer Seite.


Seamless Email Integration for FileMaker – now in English!

Seamless Email Integration for FileMaker – now in English!

Now available: FM MailBridge – the add-on for anyone who wants to integrate email into their FileMaker solutions seamlessly. No external tools. No manual workarounds. Just pure IMAP.

Whether you’re using it as a standalone on your local machine, deploying it on a server, or bundling it into your own commercial FileMaker projects – FM MailBridge makes it possible to process and manage emails directly within FileMaker. Clean, efficient, and fully customizable.

What is FM MailBridge?

FM MailBridge is a standalone PHP-based module that connects directly to IMAP mailboxes and delivers structured email data – including attachments – to FileMaker via Insert from URL. The complete message is returned as JSON, including: • Sender, subject, date • Email body (plain text or HTML) • Attachments (Base64-encoded, with filename & MIME type)

The integration is designed to work with any FileMaker solution – locally, server-side, or as part of a commercial product.

Three license models to fit your needs:

  1. Single User – €49 For local use by developers or single users. Runs via local web server.

  2. Server – €199 For centralized use on a FileMaker Server (via scheduled script or PSOS). No client setup required.

  3. Enterprise – €699 For developers and agencies who want to integrate FM MailBridge into their own FileMaker products and resell it.

Why FM MailBridge? • Direct IMAP access – no Google API or OAuth required • Works with Gmail, Outlook, hosted mailboxes, and more • Returns structured email data as JSON (incl. attachments) • Fully customizable for any FileMaker environment • No external tools – just PHP and FileMaker

Technical Background

The solution relies on a lean PHP script that connects to an IMAP inbox, fetches and processes emails, and returns them as JSON. FileMaker then handles this data within its own table structure. The setup is solid, battle-tested with thousands of messages, and intentionally lightweight.

Product page & download: filemaker-experts.de/applicati…


FM MailBridge ist da, E-Mails direkt in FileMaker integrieren

Image server.

Ab sofort verfügbar: FM MailBridge, das Add-on für alle, die E-Mails nahtlos in ihre FileMaker-Lösungen einbinden möchten ohne externe Tools, ohne manuelle Umwege, direkt per IMAP.

Ob als Einzelplatzversion, für den Servereinsatz oder als Entwicklerlizenz zur Weiterverwertung in eigenen Projekten. FM MailBridge macht es möglich, E-Mails automatisiert in deine FileMaker-Umgebung zu integrieren. Übersichtlich, effizient und vollständig anpassbar.

Was ist FM MailBridge?

FM MailBridge ist ein eigenständiges PHP-basiertes Modul, das sich direkt mit IMAP-Postfächern verbindet und E-Mails samt Anhängen strukturiert an FileMaker übergibt. Dieses erfolgt via Insert from URL. Dabei wird der komplette Mailinhalt als JSON übergeben: Absender, Betreff, Datum, Text (wahlweise HTML oder nur Text) und wenn vorhanden, Base64-kodierte Anhänge inkl. Dateiname und MIME-Typ.

Die Integration ist so konzipiert, dass sie in beliebige FileMaker-Projekte eingebaut werden kann. Entweder lokal, serverseitig oder als Bestandteil einer kommerziellen Lösung.

Drei Lizenzmodelle für jeden Anwendungsfall:

  1. Einzelplatz Für den lokalen Abruf durch einen Entwickler oder Einzelplatznutzer. Einrichtung über lokalen Webserver. -49 €

  2. Server Für den zentralen Einsatz auf einem FileMaker Server (mit Zeitplan oder PSOS). Keine Client-Einrichtung nötig. -199 €

  3. Enterprise Für Entwickler und Agenturen, die FM MailBridge in eigene FileMaker-Projekte einbauen und weiterverkaufen möchten. -699 €

Was macht FM MailBridge besonders?

•	Nutzt reinen IMAP-Zugriff, keine Google API oder OAuth erforderlich
•	Funktioniert mit Gmail, Outlook, Webhostern u. v. m.
•	Übergibt Mails strukturiert als JSON (inkl. Anhänge)
•	Vollständig anpassbar für beliebige FileMaker-Lösungen
•	Keine externen Tools nötig, nur PHP & FileMaker

Technischer Hintergrund

Die Kommunikation erfolgt über ein kompaktes PHP-Skript, das IMAP-Mails abruft, verarbeitet und als JSON zurückliefert. FileMaker verarbeitet diese Daten direkt innerhalb der eigenen Tabellen-Strucktur. Der Aufbau ist stabil, getestet mit tausenden E-Mails und bewusst schlank gehalten.

Produktseite & Download: https://filemaker-experts.de/application.html

Fragen zur Integration, Lizenz oder Sonderfällen? Schreib uns an: support@filemaker-experts.de


Implementierung des IMAP‑AddOns in FileMaker

In unserem neuesten Video zeigen wir Schritt für Schritt, wie Sie unser IMAP‑AddOn in Ihre FileMaker‑Lösung integrieren – von der Einbindung bis zur ersten produktiven Nutzung. Innerhalb von nur zwei Minuten steht Ihnen ein vollwertiger Mail‑Client direkt in Ihrer FileMaker‑Umgebung zur Verfügung. Keine komplizierte Einrichtung, keine zusätzlichen Tools: einfach installieren, konfigurieren und loslegen.

Sehen Sie selbst, wie einfach sich E‑Mails abrufen, durchsuchen und verarbeiten lassen – nahtlos eingebettet in Ihre bestehende Lösung.

Link zum Video auf Canva von FileMaker Experts

Mein kleiner feiner Mail‑Client, auch als Add‑on nutzbar!

In den letzten Wochen habe ich etwas entwickelt, das ich selbst schon lange gebraucht habe: Einen voll anpassbaren Mail‑Client, der sich nahtlos in FileMaker integrieren lässt. Und weil es so gut geworden ist, gibt’s das Ganze jetzt auch als Add‑on für alle, die ähnliche Anforderungen haben. Eigentlich wollte ich nur die Funktionalität des Mail-Abrufes aufzeigen. Nun ist ein kleiner FileMaker-Mail Klient daraus geworden.

Bildschirmfoto 2025-07-15 um 13.10.37.

Was kann das Add‑on? -Durchdachte Ordnerliste, dynamisch per JavaScript erzeugt -Dateianhänge werden automatisch in Containerfelder importiert -Schlank und effizient, keine 2 MB Gesamtgröße -Vollständig anpassbar an eigene Workflows und Layouts -Einfach einzubinden und erweiterbar – auch mit eigenen Skripten oder PHP‑Backends

Damit lassen sich IMAP‑Postfächer direkt aus FileMaker heraus durchstöbern, Mails anzeigen, Anhänge sichern und vieles mehr, ohne zusätzliche schwere Tools.

Warum als Add‑on? Arbeite ich mit einem Plugin, dann wird es oft zeitaufwendig. Tabellen, Layouts, Scripte etc. in die eigene Lösung einbauen. Häufige schnelle Notlösung, die Dateien zum Plugin als weitere FileMaker-Datei einbinden. Das recht sich aber im späteren Prozess fast immer.

Neugierig geworden? Schreib mir gern hier direkt auf LinkedIn oder besuche filemaker-experts.de für weitere Infos. Ich zeige dir gern in einer Erklärung, wie es funktioniert und wie du es in deinem System einsetzen kannst!

#FileMaker #AddOn #MailClient #IMAP #LowCode #Entwicklung #Automation #BusinessTools #FileMakerExperts


Neues FileMaker-Add-on: IMAP-Mailabruf direkt und lokal

Ich habe ein kompaktes Add-on für FileMaker entwickelt, das IMAP-Mails inkl. Anhänge direkt aus FileMaker abrufen kann – komplett lokal, ohne externen Server oder API.

Datenschutzfreundlich: Läuft lokal auf Windows & macOS – kein Hosting, keine Cloud-Abhängigkeit

Technisch gelöst über PHP: Ein integrierter Mini-Server (portable PHP) macht’s möglich. Einfach starten, nutzen, fertig.

Add-on-kompatibel: Einfach in bestehende FileMaker-Lösungen integrierbar

Ideal für: • automatisierte Mail-Importe • Anhänge (z. B. Rechnungen) direkt in FileMaker verarbeiten • vollständige lokale Kontrolle ohne Drittanbieter

Wer Interesse hat: Ich biete auch eine Demo-Version mit 7-Tage-Testlaufzeit an.

Bei Fragen einfach melden – ich freu mich über Austausch!

IMAP FileMaker.

#FileMaker #IMAP #AddOn #PHP #Lokal #Datenschutz #MaRoProgrammierung


E-Mails per IMAP auslesen und an FileMaker übergeben -Ohne Plugin-

In vielen FileMaker-Projekten stellt sich irgendwann die Frage: Wie integriere ich eingehende E-Mails samt Anhängen möglichst flexibel in meine Lösung? Besonders dann, wenn keine Drittanbieter-Dienste gewünscht sind und alles unter eigener Kontrolle laufen soll. In einem aktuellen Projekt habe ich genau das umgesetzt, mit einer simplen, robusten Lösung per PHP und IMAP, die hervorragend mit FileMaker zusammenspielt.

Bildschirmfoto 2025-07-10 um 16.58.22.

Zielsetzung

Das System soll eingehende E-Mails (z. B. aus einem Support-Postfach) auslesen, alle relevanten Felder wie Betreff, Absender, Datum, Text und Anhänge verarbeiten und die Informationen strukturiert an FileMaker übergeben. Das ganze in einem JSON-Format, das sofort weiterverarbeitet werden kann.

Technischer Aufbau

Die zentrale Komponente ist ein PHP-Skript, das per imap_open() auf das Postfach zugreift und wahlweise alle oder nur ungelesene Mails verarbeitet. Um die Performance zu schonen, wird beim ersten Abruf ein Zeitraum (z. B. 30 Tage) berücksichtigt, danach nur noch UNSEEN-Mails. Das Format der zurückgegebenen Daten ist JSON.

[
  {
    "uid": 542,
    "subject": "Neuer Auftrag",
    "from": "info@kunde.de",
    "date": "2025-07-10 09:22:00",
    "body": "Anbei unser Auftrag...",
    "attachments": [
      {
        "filename": "auftrag.pdf",
        "mime_type": "application/pdf",
        "size": 18320,
        "content": "JVBERi0xLjQKJ...(Base64)",
        "disposition": "attachment",
        "url": "[meine-domain.de/mailanhan...](https://meine-domain.de/mailanhang/auftrag.pdf)"
      }
    ]
  }
]

Diese Daten werden dann einfach verarbeitet. In meinem ersten test ist nur ein Anhang möglich, allerdings ist die Anpassung innerhalb von FileMaker nur mit geringem Aufwand verbunden. Um die Verarbeitung von Anhängen so einfach wie möglich zu gestalten, werden die Mail-Anhänge auf dem Server gespeichert. Per JSON wird wie ersichtlich die URL zurückgeliefert. Somit ist es im Anschluss des Skriptes innerhalb von FileMaker möglich, die Dateien in FM-Containern zu speichern.

# MailAbruf in file Mail

# 
# 
Aus URL einfügen [ Auswahl ; Mit Dialog: Aus ; Ziel: $$MAIL_JSON ; "[deine](https://deine)_url_test.de/cap/imap_fetch_mails.php" ]
# 
Variable setzen [ $anzahl ; Wert: ElementeAnzahl ( JSONListKeys ( $$MAIL_JSON ; "" ) ) ]
Variable setzen [ $json ; Wert: $$MAIL_JSON ]
# 
# 
Variable setzen [ $i ; Wert: 0 ]
# 
Schleife (Anfang) [ Flush: Immer ]
	Verlasse Schleife wenn [ $i ≥ $anzahl ]
	Variable setzen [ $uid ; Wert: JSONGetElement ( $json ; "[" & $i & "].uid" ) ]
	Variable setzen [ $subject ; Wert: JSONGetElement ( $json ; "[" & $i & "].subject" ) ]
	Variable setzen [ $from ; Wert: JSONGetElement ( $json ; "[" & $i & "].from" ) ]
	Variable setzen [ $date ; Wert: JSONGetElement ( $json ; "[" & $i & "].date" ) ]
	Variable setzen [ $body ; Wert: JSONGetElement ( $json ; "[" & $i & "].body" ) ]
	Variable setzen [ $mime ; Wert: JSONGetElement ( $json ; "[" & $i & "].mime_type" ) ]
	Variable setzen [ $mime_type ; Wert: JSONGetElement ( $json ; "[" & $i & "].attachments[0].mime_type" ) ]
	# 
	#  Verarbeitung der Anhänge
	Variable setzen [ $anzahl_anhang ; Wert: ElementeAnzahl ( JSONListKeys ( $json ; "[" & $i & "].attachments" ) ) ]
	Wenn [ $anzahl_anhang > 0 ]
		Variable setzen [ $anhang_filename ; Wert: JSONGetElement ( $json ; "[" & $i & "].attachments[0].filename" ) ]
		Variable setzen [ $anhang_base64 ; Wert: JSONGetElement ( $json ; "[" & $i & "].attachments[0].base64" ) ]
		Variable setzen [ $mime_type ; Wert: JSONGetElement ( $json ; "[" & $i & "].attachments[0].mime_type" ) ]
		Variable setzen [ $anhang_url ; Wert: JSONGetElement ( $json ; "[" & $i & "].attachments[0].url" ) ]
	Ende (wenn)
	# 
	# 
	# 
	# 
	# Datensatz anlegen
	Neuer Datensatz/Abfrage
	Feldwert setzen [ Mails::uid ; $uid ]
	Feldwert setzen [ Mails::subject ; $subject ]
	Feldwert setzen [ Mails::from ; $from ]
	Feldwert setzen [ Mails::date ; $date ]
	Feldwert setzen [ Mails::body ; $body ]
	Feldwert setzen [ Mails::anhang_filename ; $anhang_filename ]
	Feldwert setzen [ Mails::anhang_base64 ; $anhang_base64 ]
	Feldwert setzen [ Mails::anhang_mime_typ ; $mime_type ]
	#  Datei als Anhang nach FileMaker
	Variable setzen [ $base64 ; Wert: Mails::anhang_base64 ]
	Variable setzen [ $mime ; Wert: Mails::anhang_mime_typ ]
	Variable setzen [ $name ; Wert: Mails::anhang_filename ]
	#  Data URL vorbereiten
	Feldwert setzen [ Mails::anhang_url ; $anhang_url ]
	Aus URL einfügen [ Auswahl ; Mit Dialog: Aus ; Ziel: Mails::anhang_container ; Mails::anhang_url ]
	Variable setzen [ $i ; Wert: $i + 1 ]
	#  Nun den Dateianhang wieder löschen
	Variable setzen [ $deleteURL ; Wert: "[deine](https://deine)_url_test.de/cap/delete_attachment.php?file=" &Mails::anhang_filename ]
	Scriptpause setzen [ Dauer (Sekunden): 1 ]
	Aus URL einfügen [ Auswahl ; Mit Dialog: Aus ; Ziel: $$ANTWORT ; $deleteURL ]
Schleife (Ende)

Um nicht die Anhänge längerfristig auf dem Server zu speichern, wird nach einer Scriptpause, ein weiteres PHP-Script aufgerufen. Dieses löscht den Anhang und stellt somit sicher, das dieser nicht über eine URL sichtbar gemacht werden kann.

Bildschirmfoto 2025-07-10 um 17.29.15.

Diese Lösung ist ideal für FileMaker-Projekte, bei denen volle Kontrolle über das E-Mail-System gewünscht ist. Sie erfordert kein IMAP-Plugin, kein MBS, keine externen Dienste und ist vollständig serverbasiert. Alles steuerbar über einfache URL-Aufrufe. Der Abruf von E-Mails wird so zum automatisierten Teil des Workflows, vom Posteingang bis zur direkten Weiterverarbeitung in FileMaker.


Mein Artikel ist im FileMaker Magazin erschienen!

Nun noch das aktuelle PDF als Auszug aus dem Magazin.

FMM_202503_9-12.pdf


Mein Artikel ist im FileMaker Magazin erschienen!

Mein Artikel ist im FileMaker Magazin erschienen!

Bildschirmfoto 2025-07-08 um 13.31.54.

Ich zeige darin, wie man eine sequentielle Suche mit PHP und FileMaker umsetzen kann. Eine Lösung, die auch bei großen Datenmengen performant bleibt.

Die Idee entstand, als ein bestehender Ansatz bei einem Kunden plötzlich ins Stocken geriet. Statt den Suchprozess in FileMaker zu quälen, habe ich den Fokus verlagert: -Export per CSV, -Suche in PHP, -Rückgabe der IDs per fmp://URL – und das alles ohne Plugins oder externe Datenbank.

Highlights aus dem Artikel: • FileMaker-Export als Tab-getrennte Datei • Upload via Insert from URL und cURL • serverseitige Verarbeitung mit PHP • blitzschnelle Filterung im WebViewer • Rückübergabe der gefundenen IDs an FileMaker • robust, portabel und unabhängig von der Datenstruktur

Jetzt nachzulesen im FileMaker Magazin, Ausgabe 07/2025: „Sequentielle Suche – Arbeitsteilung zwischen FileMaker und PHP“ (von Ronny Schrader | MaRo-Programmierung GbR)

Wer Interesse an der Lösung oder einer Demo-Datei hat, darf sich gern bei mir melden.