Co-Author: Eugen Timm
Wir beschreiben hierbei die Architekturentscheidungen hinter der Lösung, die wir erarbeitet haben.
Ausgangszustand
Wir haben uns bei Microsoft mit Timeout, unserem SaaS Produkt zur Urlaubs- und Abwesenheitsverwaltung, beworben. Wir haben Timeout nach dem Lean Startup Prinzip entwickelt um möglichst schnell Erfahrungen zu sammeln, wie das Produkt/Konzept am Markt ankommt. Darauf basierend konnten wir wiederum weitere Annahmen für die zukünftige Entwicklung des Produkts treffen. Vor unserem Trip zu Microsoft basierte Timeout auf dem Javascript Full-Stack-Framework Meteor, das sich nach unserer Einschätzung hervorragend zur Entwicklung von Prototypen eignet. Wie sich recht schnell herausstellte, war Meteor jedoch für unseren Anwendungsfall und den geplanten Produktionsbetrieb auf lange Sicht ungeeignet. Die für Meteor typische enge Kopplung zwischen Datenbank, Back- und Frontend, ist einer der Gründe.
Gehostet wurden die einzelnen Timeout-Mandanten auf Azure-VMs in jeweils eigenen Docker-Containern. Die Nutzer-Authentifizierung und Team-Verwaltung war komplett lokal in der Anwendung angesetzt.
Die Konstellation aus Meteor und einzelnen Docker Containern pro Timeout-Mandant war zum schnellen Prototyping und für erste Erkenntnisse bezüglich Nutzerakzeptanz der Anwendung sehr hilfreich. Wir konnten über Online Performance Marketing potenzielle Nutzer adressieren, deren Konversionsrate messen und pro Mandant/Firma schnell eine neue Docker-Instanz hochziehen. Nachdem dieser Test erfolgreich war, haben wir entschieden die Systemarchitektur auf ein stabileres, besser skalierbares Grundgerüst zu stellen und Technologien zu verwenden, bei denen wir uns “mehr zuhause” fühlen.
Ziel
Unser Ziel für das Hackfest war es nun, ein skalierbares Multitenancy-Modell zu erarbeiten und verschiedene Microsoft Services in Timeout zu integrieren.
-
Lose Kopplung der Systemarchitektur
-
Anmeldung via Azure Active Directory
-
Import von Abwesenheitszeiträumen in den Outlook Kalender
-
Team-/Gruppenverwaltung für Timeout basierend auf Office 365 Gruppen/Teams
-
Umzug auf ein (für uns) einfacher wartbares und günstigeres Hosting-Modell
Planung & Architektur
Zusammen mit den Microsoft Experten für Active Directory, Teams und Office 365 haben wir uns für folgenden Aufbau entschieden:
Der erste Schritt zur Integration der Microsoft Services ist das Erstellen und die Integration einer Microsoft App (https://apps.dev.microsoft.com). Über diese Anbindung kann ein Admin einer Organisation, die Office 365 verwendet, Berechtigungen zum Zugriff auf Firmendaten über die Graph API an die Timeout-Anwendung erteilen. Ebenso können sich Mitarbeiter einer Organisation mit ihrem Office-365-Account bei Timeout anmelden.
Eine wichtige und gleichzeitig schwierige Entscheidung ist hierbei, ob man mit Delegated Permissions oder Application Permissions arbeiten möchte.
-
Bei Delegated Permissions werden die Graph-API-Zugriffe aus Sicht des angemeldeten Nutzers durchgeführt. Ressourcen wie E-Mails, Kalender- und Kontakte sind dabei fast uneingeschränkt abrufbar. Demgegenüber stehen Ressourcen wie Gruppen oder Information über das AD, die selbst wenn der Nutzer über die Rechte verfügt, nicht direkt abgerufen werden können. Zwar ist es durch das Geben des Admin-Consents möglich, auch an diese Ressourcen über Delegated Permissions heranzukommen, aber diese Variante stellte sich als zu umständlich für den Endbenutzer heraus.
-
Application Permissions lösen das Problem indem der Admin-Consent nur noch gegenüber eine Anwendung gegeben werden muss. Dies ermöglicht nutzerunabhängige Zugriffe auf die Graph-API, die ein Backend durchführen kann, wann auch immer Daten benötigt werden. Neben der erhöhten Sicherheit, hat sich diese Variante auch als die einfachere Implementierung herausgestellt.
In unserem Fall wollen wir möglichst viele Funktionen in das Backend integrieren, da man so schlankere Clients wie Mobile Apps, Web Apps, Bots, Voice Skills, usw. realisieren kann.
Den Kern des Systems bildet eine API-Anwendung, die auch Zugriff zur Datenbank hat. Dieser Teil sollte robust, skalierbar und flexibel erweiterbar sein. Diese Vorbedingungen erfüllt ASP.NET Core 2. Da wir sehr viel Erfahrung im Team mit ASP.NET MVC als Basis für RESTful APIs haben, fiel uns diese Entscheidung relativ leicht.
Als Datenbank setzen wir Azure SQL DB ein, da wir sehr gute Erfahrungen damit gemacht haben und sich aus unserer Sicht eine relationale Datenstruktur für die Kernfunktionen von Timeout sehr gut eignet.
Bei der Frage der Frontend-Technologie haben wir uns für React entschieden, da wir eine Single-Page-Application (SPA) für eine Anwendung dieser Art als sehr Nutzer freundlich erachten und unser Team aktuell stark in Richtung React tendiert. Sorry Angular…
Umsetzung
API-Anwendung
Die API-Anwendung ist nach einem ASP.NET MVC/Web.API Standardmuster aufgebaut.
Daten aus dem Web-Frontend oder den Bots passieren über die Web API Controller die API-Anwendung. Die Daten aus den Controllern können über Services in tiefere Schichten transportiert werden. Unter den Services liegen die Repositories, die über das Entity Framework Core mit dem der Datenhaltungsschicht interagieren.
Als Dependency Injection Container nutzen wir den von ASP.NET core mitgelieferten DI Container. Fürs Unit-Testen nutzen wir xUnit und Moq.
Sehr hilfreich fürs Unit-Testen von Repositories ist die In-Memory Datenbank des Entity Framework Core. Hiermit können echte Schreib- und Lesezugriffe getestet werden, ohne die langen Wartezeiten einer “echten” Datenbank in Kauf nehmen zu müssen.
Frontend
Im Frontend haben wir zunächst aus Zeitgründen nur die nötigsten Funktionalitäten umgesetzt. Wir haben React, Redux, Redux-Saga und Tailwind CSS eingesetzt. Bis auf Tailwind handelt es sich hier also um einen mittlerweile sehr häufig genutzten und auch gut dokumentierten Frontend-Stack. Tailwind gefällt uns auf den ersten Blick sehr gut, da es recht wenig vordefinierte Styles mitbringt und einem nur die teilweise lästigen, wiederkehrenden Definitionen von Abständen, Rahmen, Farben, Positionen und Größen abnimmt. Jedoch lässt sich unserer Meinung nach ein CSS Framework erst durch längeren Einsatz sinnvoll bewerten.
Sehr spannend fanden wir, dass wir viele Funktionen zur Interaktion mit der API-Anwendung deutlich schneller umsetzen konnten, indem wir für die einzelnen Szenarien einen Teams Bot statt eine Web-UI gebaut haben.
Teams Bot
Wie zuvor erwähnt, haben wir festgestellt, dass (Teams) Bots nicht nur eine nette Spielerei sind, sondern auch eine effiziente und schlanke Benutzerführung ermöglichen.
Auf Anraten unseres Microsoft Hackfest Betreuers nutzen wir die Node.js Implementierung des Microsoft Botframework.
Ein Tutorial zum Aufsetzen der einzelnen Dienste, die zum betreiben eines Teams Bot benötigt werden, findet ihr hier: https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/bots/bots-create
In diesem Artikel werden auch die zum Entwickeln hilfreichen Tools ngrok und der Bot Framework Emulator beschrieben, mit diesen Tools kann man Bots auf einem lokalen Rechner testen, ohne den Bot-Code auf Azure oder in Teams deployen zu müssen.
Unser Bot läuft im Endeffekt innerhalb einer Node.js Server-Anwendung, die wie eine RESTful-API angesprochen werden kann. Der Bot wiederum kann die Timeout-API ebenso ansprechen. Es findet ein sogenannter Dialog zwischen der Timeout-API und der API des Bots statt.
Graph API Integration
Der letzte Schritt im Prozess “Urlaubsantrag erstellen” ist das Speichern des Urlaubszeitraums als Termin im Kalender des Antragstellers.
Mit dem Microsoft Graph API Explorer lassen sich Abfragen gegen die Graph API außerhalb der eigenen Anwendung testen.
Die Graph API ist eine REST-basierte API. In unserem Fall übergeben wir der Graph API die Microsoft Id des Users und die Id des Kalenders in welchen der Eintrag gespeichert werden soll. Ebenso werden u.a. Start- und Enddatum des Urlaubsantrags übergeben und in den entsprechenden User Kalender geschrieben.
Wichtig ist hierbei das Access Token mit entsprechenden Permissions. Das folgende Video zeigt die Zusammenhänge zwischen Delegeted Permissions, Application Permissions und Admin Consent.
Auf Richard diZerga’s Blog, einem der Mentoren beim Hackfest, finden sich noch einige Beispiele bezüglich Azure Authentication. https://blogs.msdn.microsoft.com/richard_dizeregas_blog/
Das folgende Github Repository ist eine Empfehlung von Richard und eine sehr Hilfreiche Sammlung von Code-Snipets und Erklärungen Rund um das Thema Microsoft Graph und Authentifizierung: https://github.com/User1m/microsoft-graph-notes
Fazit
Obwohl wir recht viel Zeit in die Authentifizierung und Recherche des für uns passenden Flows stecken mussten, sind wir sind sehr zufrieden mit dem Stack, für den wir uns entschieden haben. Er besteht aus einer ausgewogenen Mischung aus erprobten Komponenten und Bleeding-Edge Technologien. Die Architektur ist durch die Möglichkeiten des Azure Hosting stabil und skalierbar. Da wir die Multi-Mandantenfähigkeit quasi an Microsoft delegieren, können wir so eine an die Unternehmensstruktur der Kunden angepasste SaaS-Anwendung entwickeln.
Durch die RESTful API, die unsere eigene Businesslogik übernimmt und gleichzeitig einen dünnen Wrapper über die Microsoft Graph API und OAuth Authentifizierung legt, kann die nutzerseitige UI sehr flexibel gestaltet werden. So sind z.B. eine Web-App, native mobile App, Chat Bots, Voice Skills und viele andere nutzerseitige Anwendungen denkbar.
Recht neu für uns war das Botframework. Wir finden diese Form der UI sehr spannend, da man durch den Einsatz von Chat Bots keine eigene UI einwickeln muss und die Anwendung automatisch auf allen Plattformen verfügbar ist, auf denen der jeweilige Messenger läuft. So lässt sich Entwicklungszeit sparen, die man wiederum in neue Features oder Verbesserungen investieren kann.
Nach einer anstrengenden aber spannenden Woche haben wir in einer kleinen Demo vor ca. 20 Microsoft Entwicklern und Managern aus den verschiedenen Produktteams unsere Entwicklungsergebnisse der Woche vorgestellt. Die Demo wurde auch vom Channel 9-Team aufgezeichnet.
Ausblick
Wir haben bei dem Hackfest sehr viele wertvolle Erfahrungen mitgenommen, die wir auch auf weitere Projekte anwenden werden.
Die Graph API bietet sehr interessante Möglichkeiten, die Daten der Microsoft Produktfamilie zu verarbeiten. Wir würden uns hier zwar noch ein paar Features wünschen, wie z.B. verschachtelte Abfragen und erweiterte Filter, aber auch jetzt schon lassen sich mit der Graph API spannende Szenarien entwickeln.
Bezüglich Bots planen wir zeitnah unsere internen Slackbots (zur Essensbestellung, für WLAN Passwörter, Drucker IP) als Teams-Bots zu portieren. Auch für Timeout sehen wir sehr viel Potenzial weitere Prozesse über Bots abzubilden. Z.B. das Erstellen von Urlaubsanfragen.
Azure AD (B2C) setzen wir schon aktiv ein und werden es auch in zukünftigen Projekten als Plattform für Identitäts-/Zugriffsverwaltung nutzen.
Im ersten Teil dieses Posts haben wir ein wenig über unsere Reiseerfahrung nach Redmond zum Microsoft Campus berichtet.
Falls ihr euch für die Verwendung von Timeout in eurem Unternehmen interessiert: http://www.timeoutapp.de/