diff --git a/src/lib/customers/20minuten-de.json b/src/lib/customers/20minuten-de.json
new file mode 100644
index 00000000..92de5e28
--- /dev/null
+++ b/src/lib/customers/20minuten-de.json
@@ -0,0 +1,54 @@
+{
+ "title": "bespinian unterstützt 20 Minuten bei der Modernisierung der digitalen Produkte",
+ "logo": {
+ "file": "tx-group.webp",
+ "alt": "TX Group"
+ },
+ "customer": "20 Minuten ist die reichweitenstärkste Medienmarke der Schweiz. Sie gehört wie auch das Medienhaus Tamedia und die Werbevermarkterin Goldbach zur TX Group. 20 Minuten zeichnet sich durch ihre Reichweite in allen Sprachregionen und dem Storymix aus News, Unterhaltung und Inspiration aus. Das 20 Minuten Team war und ist für bespinian ein wichtiger Partner in der Zusammenarbeit bezüglich der Migration der digitalen Produkte auf eine neue Infrastruktur, und anderen Projekten im Rahmen von OAuth2, Cloudifizierung, Containerisierung und Modernisierung von Software.",
+ "background": "20 Minuten ist die schweizweit grösste Pendlerzeitung und eine der meistbesuchten Webseiten der Schweiz. Es ist ein Medienportal mit täglichen Beiträgen aus dem Bereich News, Unterhaltung und Inspiration. 20 Minuten hatte 2019 eine grosse Migration ihrer Applikationen weg von der Legacy-Infrastruktur und dem teilweise fast 20-jährigen Applikationscode geplant. Dabei ging es um eine Migration von bestehenden VMs auf eine moderne Kubernetes-basierte Containerinfrastruktur auf AWS. Das Backend sollte von Perl auf Go migriert und containerisiert werden. Das Frontend wurde ebenfalls von Perl gerendert und sollte in eine moderne Next.js Applikation umgewandelt werden. 20 Minuten hat täglich über eine Million Nutzer:innen. Dies macht eine Migration ohne Downtime besonders anspruchsvoll. Zusätzlich, war es wichtig, die Betriebskosten trotz dieses grossen Loads in einem akzeptablen Rahmen zu halten.",
+ "goal": "Das Ziel des Projekts war die Modernisierung des Setups der Applikation. Dabei sollten die Legacykomponenten und der frühere Code abgelöst werden, um das System stabiler und kosteneffizienter zu machen. AWS wurde als Infrastrukturprovider ausgewählt und die Applikation sollten in Go, Node.js und React Microservices auf einem EKS (Kubernetes) Cluster neu implementiert werden.",
+ "contribution": {
+ "intro": "bespinian hatte eine Schlüsselrolle in den folgenden Themen bezüglich der Applikationsmigration im Sinne von Refactoring / Re-architecting aus den 6 Migrationsstrategien von AWS:",
+ "topics": [
+ {
+ "title": "Infrastruktur auf AWS",
+ "body": "bespinian hat massgeblich zur Provisionierung der Infrastruktur auf AWS beigetragen. Dabei hatten wir eine Schlüsselrolle im Schreiben und Anwenden der entsprechenden Terraform-Module und im Aufsetzen der Kubernetes Cluster, auf denen die verschiedenen Microservices gehostet werden. Ein wichtiger Teil war dabei auch das korrekte Konfigurieren des Caching-Layers (Amazon CloudFront), um bei der grossen Zahl von gleichzeitigen Nutzer:innen von 20 Minuten die Kosten in einem akzeptablen Rahmen zu halten. bespinian leistete einen essenziellen Beitrag bei der Umsetzung und Automatisierung, aber auch bei der effizienten Kommunikation zwischen den Entwicklungs- und den Infrastruktur-Teams."
+ },
+ {
+ "title": "Kubernetes- und Container-Konfiguration",
+ "body": "Eine besonders spannende Aufgabe war die Konfiguration des Kubernetes Clusters (auf Amazon EKS). Die Architektur sowie die Umsetzung davon trägt noch heute die Handschrift von bespinian. Im Mittelpunkt dieser Aufgabe standen die Architekturentscheidungen, aber auch um die Umsetzung der Provisionierung und Konfiguration des Clusters über Terraform. Ein weiterer wichtiger Teil dieser Aufgabe war die Automatisierung der Deployments der einzelnen Services über Helm und GitHub Actions. bespinian spielte eine essenzielle Rolle in allen diesen Teilbereichen. Ferner wurden wir auch mit der Koordination der einzelnen Teams und Applikationen im Sinne einer DevOps Migration betraut."
+ },
+ {
+ "title": "Applikationsentwicklung",
+ "body": "Die diversen Microservices des Backends und das Frontend wurden von bespinian einerseits architektonisch, aber auch bezüglich der Softwareentwicklung mitgestaltet. Als erfahrene Go Entwickler:innen spielten wir eine zentrale Rolle bei der Implementation des Applikationscodes selbst, aber auch bei deren Automatisierung, bei Deployments und bei der Kommunikation der Services untereinander."
+ },
+ {
+ "title": "Monitoring und Alerting",
+ "body": "Die Applikationen im Sinne einer DevOps-Transformation zu monitoren war vor allem in der anfänglichen Phase nach der Migration sehr wichtig. Eine grosse Anzahl Nutzer:innen wurde auf die neuen Applikationen migriert und haben teilweise schwer vorhersehbare Zugriffsmuster produziert. Diese Muster mussten von bespinian analysiert und verstanden werden, um entsprechende Ressourcen zu provisionieren und Bugfixes zu produzieren. Dabei spielten Prometheus und Grafana eine grosse Rolle, um eine Übersicht zu erhalten, was passiert und wo welche Requests gemacht werden."
+ },
+ {
+ "title": "Caching",
+ "body": "Eine weitere wichtige Aufgabe von bespinian war die Konfiguration des CloudFront-Caching-Layers. Durch die hohe Anzahl an Requests, die zumeist lesend sind, konnten wir durch geschickte Nutzung des Caches monatlich sehr hohe Beiträge einsparen. Dadurch konnten die Container in relativ geringer Anzahl an Replicas genutzt werden. Die optimale Konfiguration des Caches bei so vielen verschiedenen Zugriffsmustern und Clients (20 Minuten Website, verschiedene Mobile Applikationen und CMS) war eine grosse Herausforderung, die unter der Anleitung von bespinian gemeistert werden konnte."
+ }
+ ]
+ },
+ "technologies": [
+ "Amazon Web Services (AWS)",
+ "Terraform",
+ "Kubernetes",
+ "Prometheus / Grafana",
+ "Helm",
+ "Go",
+ "React (Next.js)",
+ "MongoDB",
+ "PostgreSQL",
+ "GitHub Actions"
+ ],
+ "quote": {
+ "body": "Die Zusammenarbeit mit bespinian war stets sehr gut. Aufgrund ihrer Expertise hat bespinian einen massgeblichen Anteil an die erfolgreiche Migration der digitalen Produkte von 20 Minuten auf eine neue und moderne Infrastruktur beitragen.",
+ "stakeholder": {
+ "name": "Manuel Sutter",
+ "role": "Product Owner"
+ }
+ }
+}
diff --git a/src/lib/customers/20minuten-en.json b/src/lib/customers/20minuten-en.json
new file mode 100644
index 00000000..2a6bd1bb
--- /dev/null
+++ b/src/lib/customers/20minuten-en.json
@@ -0,0 +1,54 @@
+{
+ "title": "bespinian supports TX Group in modernization of 20 Minuten application",
+ "logo": {
+ "file": "20-minuten.svg",
+ "alt": "20 Minuten"
+ },
+ "customer": "20 Minuten is the media brand with the widest reach in Switzerland. Like the media house Tamedia and the advertising marketer Goldbach, it belongs to the TX Group. 20 Minuten is characterized by its reach in all language regions and the story mix of news, entertainment, and inspiration. The 20 Minuten team was and is an important partner for bespinian in the cooperation regarding the migration of digital products to a new infrastructure, and other projects in the context of OAuth2, cloudification, containerization and modernization of software.",
+ "background": "20 Minuten is Switzerland's largest commuter newspaper and one of the most visited websites in Switzerland. It is a media portal with daily news, entertainment and inspirational articles. In 2019, 20 Minuten had planned a major migration of its applications away from the legacy infrastructure and application code, some of which was almost 20 years old. This involved migrating existing VMs to a modern Kubernetes-based container infrastructure on AWS. The backend was to be migrated from Perl to Go and containerized. The frontend was also rendered by Perl and was to be converted into a modern Next.js application. 20 Minuten has over one million users every day. This makes a migration without downtime particularly challenging. In addition, it was important to keep the operating costs within manageable limits despite this large load.",
+ "goal": "The goal of the project was to modernize the setup of the application. The legacy components and the previous code were to be replaced in order to make the system more stable and cost-efficient. AWS was chosen as the infrastructure provider and the application was to be redeployed in Go, Node.js and React microservices on an EKS (Kubernetes) cluster.",
+ "contribution": {
+ "intro": "bespinian had a key role in the following topics regarding application migration in terms of refactoring / re-architecting from the 6 migration strategies of AWS.",
+ "topics": [
+ {
+ "title": "Infrastructure on AWS",
+ "body": "bespinian has been instrumental in provisioning the infrastructure on AWS. We played a key role in writing and applying the appropriate Terraform modules and setting up the Kubernetes clusters on which the various microservices are hosted. An important part of this was also the correct configuration of the caching layer (Amazon CloudFront) to keep the costs manageable given the large number of concurrent users of 20 Minuten. bespinian did a lot of the technical implementation and automation, but also the communication between the development and infrastructure teams."
+ },
+ {
+ "title": "Kubernetes and container configuration",
+ "body": "An exciting task was the configuration of the Kubernetes cluster (on Amazon EKS). The architecture as well as the implementation of it still bears bespinian's signature. The main focus of this task was making the necessary architectural decisions and implementing the provisioning and configuration of the cluster via Terraform. Subsequently, another key focus of the task was on automating the deployments of the individual services via Helm and GitHub Actions. bespinian played a key role in all of these areas. We also played a major role in coordinating the individual teams and applications in the sense of a DevOps migration."
+ },
+ {
+ "title": "Application Development",
+ "body": "The various microservices of the backend and the frontend were co-designed by bespinian, both architecturally and in terms of software development. As experienced Go developers, we were able to contribute to the design of the application code itself, but also to its automation, deployment and communication between the services."
+ },
+ {
+ "title": "Monitoring and Alerting",
+ "body": "Monitoring the applications in terms of a DevOps transformation was very important, especially in the initial phase after the migration. A large number of users were migrated to the new applications and sometimes produced access patterns which were difficult to predict. These access patterns first needed to be analyzed and understood in order to provision the appropriate resources and produce the appropriate fixes for performance issues and bugs. Prometheus and Grafana played a major role in this process to get an overview of what is happening and where which requests are being made."
+ },
+ {
+ "title": "Caching",
+ "body": "An important part of bespinian's contribution was the configuration of the CloudFront caching layer. Due to the high number of requests, most of which are read-only, we were able to save very large monthly contributions by clever use of the cache. This allowed the containers to be used in relatively small numbers of replicas. The optimal configuration of the cache with so many different access patterns and clients (20 minute website, different mobile applications and CMS) was a big challenge. bespinian was responsible for tackling this challenge and providing a solution to the 20 Minuten team."
+ }
+ ]
+ },
+ "technologies": [
+ "Amazon Web Services (AWS)",
+ "Terraform",
+ "Kubernetes",
+ "Prometheus / Grafana",
+ "Helm",
+ "Go",
+ "React (Next.js)",
+ "MongoDB",
+ "PostgreSQL",
+ "GitHub Actions"
+ ],
+ "quote": {
+ "body": "The collaboration with bespinian has always been very good. Thanks to their expertise, bespinian made a significant contribution to the successful migration of the digital products from 20 Minuten to a new and modern infrastructure.",
+ "stakeholder": {
+ "name": "Manuel Sutter",
+ "role": "Product Owner"
+ }
+ }
+}
diff --git a/src/lib/images/20-minuten.svg b/src/lib/images/20-minuten.svg
new file mode 100644
index 00000000..9bac610d
--- /dev/null
+++ b/src/lib/images/20-minuten.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/lib/images/xovis.svg b/src/lib/images/xovis.svg
index d176cd01..2152fbcd 100644
--- a/src/lib/images/xovis.svg
+++ b/src/lib/images/xovis.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/routes/Customers.svelte b/src/routes/Customers.svelte
index 72f4c12c..55b10719 100644
--- a/src/routes/Customers.svelte
+++ b/src/routes/Customers.svelte
@@ -4,6 +4,7 @@
import { browser } from '$app/environment';
import swisscom from '$lib/images/swisscom.webp';
import txGroup from '$lib/images/tx-group.webp';
+ import twentyMins from '$lib/images/20-minuten.svg';
import ciTechSensors from '$lib/images/citechsensors.webp';
import cometGroup from '$lib/images/comet-group.webp';
import swissSignGroup from '$lib/images/swisssigngroup.svg';
@@ -25,6 +26,7 @@
{ name: 'Swisscom', logo: swisscom, link: 'https://www.swisscom.com' },
{ name: 'Xovis', logo: xovis, link: '/customers/xovis' },
{ name: 'TX Group', logo: txGroup, link: 'https://tx.group' },
+ { name: '20 Minuten', logo: twentyMins, link: '/customers/20-minuten' },
{ name: 'CI Tech Sensors', logo: ciTechSensors, link: '/customers/citech-sensors' },
{ name: 'Comet Group', logo: cometGroup, link: '/customers/comet-group' },
{ name: 'SwissSign Group', logo: swissSignGroup, link: '/customers/swisssign-group' },
diff --git a/src/routes/customers/[slug]/+page.ts b/src/routes/customers/[slug]/+page.ts
index c92f0468..e30c971a 100644
--- a/src/routes/customers/[slug]/+page.ts
+++ b/src/routes/customers/[slug]/+page.ts
@@ -1,4 +1,7 @@
import { error } from '@sveltejs/kit';
+import twentyMinDe from '$lib/customers/20minuten-de.json';
+import twentyMinEn from '$lib/customers/20minuten-en.json';
+import twentyMinLogo from '$lib/images/20-minuten.svg';
import citechEn from '$lib/customers/citechsensors-en.json';
import citechDe from '$lib/customers/citechsensors-de.json';
import citechLogo from '$lib/images/citechsensors-wide.webp';
@@ -15,6 +18,14 @@ import type { PageLoad } from './$types';
export const load: PageLoad = ({ params }) => {
switch (params.slug) {
+ case '20-minuten':
+ return {
+ customer: {
+ en: twentyMinEn,
+ de: twentyMinDe,
+ logo: twentyMinLogo
+ }
+ };
case 'citech-sensors':
return {
customer: {