<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>UX |</title><link>https://aretascodes.dev/de/tags/ux/</link><atom:link href="https://aretascodes.dev/de/tags/ux/index.xml" rel="self" type="application/rss+xml"/><description>UX</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>de-DE</language><lastBuildDate>Wed, 20 May 2026 00:00:00 +0000</lastBuildDate><image><url>https://aretascodes.dev/media/icon_hu_2ab4f4763b27c75b.png</url><title>UX</title><link>https://aretascodes.dev/de/tags/ux/</link></image><item><title>Teil 7 · Gamifying Learning: 25 Badges, Idle-Gap Sessions und eine 90-Tage-Heatmap</title><link>https://aretascodes.dev/de/blog/gamifying-learning-badges-heatmap/</link><pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate><guid>https://aretascodes.dev/de/blog/gamifying-learning-badges-heatmap/</guid><description>
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;Teil einer Serie über die Entwicklung von
. Zuvor:
.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote class="border-l-4 border-neutral-300 dark:border-neutral-600 pl-4 italic text-neutral-600 dark:text-neutral-400 my-6"&gt;
&lt;p&gt;Alle Abkürzungen werden im Anhang unten auf der Seite vollständig erklärt.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ich habe acht Jahre lang ICT an weiterführenden Schulen unterrichtet, bevor ich zum Full-Stack-Developer gewechselt bin. Die zuverlässigste Lektion aus dieser Zeit war unangenehm einfach: &lt;strong&gt;Schüler, die beständig da waren, haben gelernt. Die anderen nicht.&lt;/strong&gt; Talent, Vorwissen, sogar die Motivation an einem bestimmten Tag – all das war der bloßen Anwesenheit nachgelagert.&lt;/p&gt;
&lt;p&gt;Der &amp;ldquo;Dashboard&amp;rdquo;-Tab in CogniVault ist ein kleiner Versuch, genau das zu fördern. Es ist keine Duolingo-Streak-Panikmaschine. Es sind drei Dinge:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hero-Statistiken&lt;/strong&gt; – gesamte Lernzeit, gesamte Sessions, aktueller Streak.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;25 Erfolgs-Badges&lt;/strong&gt; – automatisch erfasst über Chat, Quizzes, Workshops, Flashcards und Mindmaps hinweg.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Eine 90-Tage-Aktivitäts-Heatmap&lt;/strong&gt; – im GitHub-Stil, mit fünf lila Intensitätsstufen.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Das Ganze besteht nur aus einem kleinen Satz von SQLite-Tabellen und ein paar React-Komponenten. Der interessante Teil ist aber nicht der Code – es sind die Designentscheidungen.&lt;/p&gt;
&lt;h2 id="idle-gap-sessions"&gt;Idle-Gap Sessions&lt;/h2&gt;
&lt;p&gt;Die schwerste Frage klang eigentlich am einfachsten: &lt;strong&gt;Was zählt als eine Lern-Session?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Die naive Antwort ist: &amp;ldquo;Alles, was zwischen dem Öffnen und Schließen der App passiert.&amp;rdquo; Aber das ist falsch. Leute lassen Tabs offen. Leute gehen für eine Stunde weg und kommen dann wieder. Leute öffnen die App um 9 Uhr morgens, machen nichts und schauen um 14 Uhr wieder rein.&lt;/p&gt;
&lt;p&gt;Die Antwort, bei der ich gelandet bin: Eine Session endet, wenn du &lt;strong&gt;15 Minuten lang inaktiv&lt;/strong&gt; warst. Stellst du eine Frage und bist dann 16 Minuten inaktiv – das ist eine Session. Kommst du zurück und stellst eine weitere Frage – beginnt eine neue. Der Schwellenwert ist über &lt;code&gt;STUDY_SESSION_IDLE_GAP_SECONDS=900&lt;/code&gt; konfigurierbar.&lt;/p&gt;
&lt;p&gt;Die Uhr richtet sich nach den &lt;strong&gt;Chat-Nachrichten&lt;/strong&gt; – dem konversationellen Kern des Lernens in CogniVault. Jede Nachricht verlängert entweder die offene Session (indem sie den &lt;code&gt;ended_at&lt;/code&gt;-Zeitstempel und die Nachrichtenanzahl erhöht) oder, falls die Pause seit der letzten Aktivität den Schwellenwert überschreitet, schließt sie diese implizit ab und eröffnet eine neue:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Simplified from backend/services/progress_tracker.py&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;record_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idle_gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;most_recent_session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ended_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;idle_gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ended_at&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# same session continues&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;open_session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;started_at&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ended_at&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# new session begins&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Zwei Schreibvorgänge pro Nachricht. Die Dauer einer Session ist &lt;code&gt;ended_at - started_at&lt;/code&gt;, was bedeutet, dass &amp;ldquo;Gesamtzeit&amp;rdquo; die &lt;em&gt;aktive&lt;/em&gt; Zeit widerspiegelt, nicht &amp;ldquo;hatte einen Tab offen&amp;rdquo;. Das ist die einzige Zahl, die wirklich etwas aussagt. (Aktionen im Study Hub – Quizversuche, Karteikarten umdrehen, Mindmap-Exporte – werden als eigene Events erfasst und fließen in die Badge-Metriken unten ein; die Session-Uhr selbst bleibt nachrichtengetrieben und ehrlich.)&lt;/p&gt;
&lt;h2 id="25-badges-nicht-250"&gt;25 Badges, nicht 250&lt;/h2&gt;
&lt;p&gt;Die meisten gamifizierten Apps überfluten dich regelrecht mit Erfolgen. Es gibt einen Grund dafür: mehr Badges, mehr Dopamin, mehr täglich aktive Nutzer. Der Preis dafür ist, dass jedes Badge weniger bedeutet – irgendwann wird die ganze Schicht nur noch zur Tapete.&lt;/p&gt;
&lt;p&gt;Ich habe CogniVault auf &lt;strong&gt;25&lt;/strong&gt; limitiert, aufgeteilt auf die fünf Aktivitätsbereiche:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;10 für &lt;strong&gt;Chat &amp;amp; Lerngewohnheiten&lt;/strong&gt; (erste Frage, 10 Nachrichten an einem Tag, 100 insgesamt, eine Stunde Gesamtlernzeit, 3- und 7-Tage-Streaks, eine 30-minütige Deep-Dive-Session, Night-Owl- und Early-Bird-Sessions, erste Nutzung des Scope-Filters)&lt;/li&gt;
&lt;li&gt;4 für &lt;strong&gt;Quizzes&lt;/strong&gt; (erstes Quiz, perfektes Ergebnis, Bestehen auf fortgeschrittenem Schwierigkeitsgrad, 10 Quizzes)&lt;/li&gt;
&lt;li&gt;4 für &lt;strong&gt;Workshops&lt;/strong&gt; (erste Outline, erste abgeschlossene Lektion, erster abgeschlossener Workshop, 5 abgeschlossen)&lt;/li&gt;
&lt;li&gt;4 für &lt;strong&gt;Flashcards&lt;/strong&gt; (erstes Deck, 50 umgedrehte Karten, ein Deck komplett gemeistert, 5 Decks)&lt;/li&gt;
&lt;li&gt;3 für &lt;strong&gt;Mindmaps&lt;/strong&gt; (erste Mindmap, erster Export, 5 Mindmaps)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Jedes Badge hat ein einzeiliges Freischaltkriterium, das bei relevanten Events automatisch ausgewertet wird. Nichts Manuelles, nichts, was der Nutzer &amp;ldquo;einfordern&amp;rdquo; muss. Sie tauchen einfach auf.&lt;/p&gt;
&lt;p&gt;Und die Definitionen sind gar kein Code – sie sind &lt;strong&gt;Daten&lt;/strong&gt;. Alle 25 leben in einer JSON-Datei. Jeder Eintrag benennt die Metrik, die er beobachtet, und das zu erreichende Ziel:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;code&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;card_reviewer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Card Reviewer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;icon&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;🃏&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;metric&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;total_card_flips&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;target&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ein einzelner Evaluator liest die aktuellen Statistiken aus, vergleicht jede Definition mit ihrer Metrik, gleicht sie mit bereits verdienten Badges ab und fügt neue Freischaltungen in die &lt;code&gt;progress.db&lt;/code&gt; ein. Ein 26. Badge hinzuzufügen, bedeutet, einen JSON-Eintrag hinzuzufügen, nicht neue Logik zu schreiben. Mehrere Badges bilden Leitern – jedes weiß, welches Badge das &amp;ldquo;nächste Level&amp;rdquo; ist, was den Schubs in der Detailansicht zum nächsten Ziel antreibt.&lt;/p&gt;
&lt;h2 id="die-heatmap"&gt;Die Heatmap&lt;/h2&gt;
&lt;p&gt;Auf die 90-Tage-Heatmap bin ich am meisten stolz, und sie ist gleichzeitig das Einfachste. Es ist ein 13×7-Raster aus Zellen, eine pro Tag, farblich markiert nach der Gesamtlernzeit an diesem Tag.&lt;/p&gt;
&lt;p&gt;Fünf Intensitätsstufen:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;level 0 — no activity
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;level 1 — under 15 minutes (a quick check-in)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;level 2 — 15-60 minutes (a focused session)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;level 3 — 1-3 hours (substantial study)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;level 4 — 3+ hours (a marathon)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Die Daten sind konzeptionell eine einzige Aggregation über die Sessions-Tabelle:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;started_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;day&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ended_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;started_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;study_sessions&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;started_at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;now&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-90 days&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;GROUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;day&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Das Backend füllt die fehlenden Tage mit Nullen auf, sodass das Frontend immer genau 90 Einträge erhält. Eine kleine clientseitige Funktion ordnet die Tagessummen in die fünf Level ein. Wenn du auf eine beliebige Zelle klickst, öffnet sich ein &lt;code&gt;DayDetailModal&lt;/code&gt; mit den Zahlen dieses Tages – Lernzeit, Sessions, Nachrichten – sowie allen Badges, die an diesem Tag verdient wurden.&lt;/p&gt;
&lt;p&gt;Der Grund, warum ich diese Komponente liebe: Sie macht die &lt;em&gt;Textur&lt;/em&gt; einer Lerngewohnheit sichtbar. Streaks sind toll, aber ein Streak ist nur eine Zahl. Eine Heatmap zeigt dir, dass du am Wochenende härter lernst, oder dass du den ganzen Monat über langsam abgebaut hast, oder dass die Lücke zwischen deinem letzten &amp;ldquo;Level 4-Tag&amp;rdquo; und heute größer ist, als du dachtest. Sie spiegelt etwas wider, worauf der Nutzer reagieren kann.&lt;/p&gt;
&lt;h2 id="was-ich-bewusst-weggelassen-habe"&gt;Was ich bewusst weggelassen habe&lt;/h2&gt;
&lt;p&gt;Drei Dinge, die du in den meisten gamifizierten Apps finden würdest, fehlen in CogniVault absichtlich:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Streak-Panik.&lt;/strong&gt; Kein &amp;ldquo;Dein Streak ist in Gefahr!&amp;quot;-Popup. Keine Regeln für Streak-Freezes. Keine gelben Ausrufezeichen. Der Streak wird angezeigt – das ist der gesamte Feedback-Loop. Wenn ein Nutzer seinen Streak bricht, dann bricht er ihn eben. Erwachsene brauchen keine Shaming-UX.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Leaderboards.&lt;/strong&gt; Das ist eine lokale Einzelnutzer-App. Es gibt keinen globalen Vergleich. (Und den sollte es auch nicht geben – Leaderboards optimieren beim Lernen das Falsche.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Konfetti, Fanfaren, Push-Benachrichtigungen.&lt;/strong&gt; Ein neu verdientes Badge taucht auf dem Quiz-Ergebnisbildschirm und im Dashboard-Raster auf. Das ist die ganze Feier. Alles, was größer ist, stiehlt dem Nutzer die Aufmerksamkeit zum Nutzen der App, nicht zu seinem eigenen.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Das allgemeine Prinzip: &lt;strong&gt;Miss, was wichtig ist, mach es sichtbar, aber ohne zu nerven.&lt;/strong&gt; Registriere, dass du wiedergekommen bist. Spiegele dir das wider. Tu nicht so, als ob es dich mehr interessiert, als es das tatsächlich tut.&lt;/p&gt;
&lt;h2 id="was-das-dashboard-nicht-zu-optimieren-versucht"&gt;Was das Dashboard &lt;em&gt;nicht&lt;/em&gt; zu optimieren versucht&lt;/h2&gt;
&lt;p&gt;Eine häufige Falle bei diesen Dashboards ist die umgekehrte Kausalität: Der Nutzer fängt an, die Metrik zu spielen, anstatt die eigentliche Sache zu tun. Ein täglicher Fragenzähler zum Beispiel führt dazu, dass Nutzer eine irrelevante Frage pro Tag stellen, um ihren Streak am Leben zu halten.&lt;/p&gt;
&lt;p&gt;Deshalb ist die Hürde absichtlich an genau einer Stelle sehr niedrig und überall sonst hoch. Es gibt &lt;em&gt;ein&lt;/em&gt; Badge, das keinen Aufwand erfordert – &amp;ldquo;Erste Frage&amp;rdquo;, das man für die allererste Nachricht bekommt –, weil jedes Spiel eine Einstiegsrampe braucht, die beweist, dass das System funktioniert. Danach werden die Metriken schwer zu manipulieren, ohne die eigentliche Arbeit zu tun:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gesamtlernzeit&lt;/strong&gt; – sammelt sich nur während aktiver Nutzung an, mit Idle-Gap-Abschaltungen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sessions&lt;/strong&gt; – um mehr hinzuzufügen, muss man tatsächlich separate Arbeitsphasen starten.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Badges&lt;/strong&gt; – fast alle erfordern Tiefe (100 Nachrichten, ein Quiz meistern, ein Deck perfekt beherrschen, 5 Workshops abschließen), nicht nur oberflächliches Antippen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Heatmap-Intensität&lt;/strong&gt; – erfordert anhaltendes Engagement an einem bestimmten Tag.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="implementierung-bewusst-klein"&gt;Implementierung: bewusst klein&lt;/h2&gt;
&lt;p&gt;Der Gamification-Kern besteht aus drei SQLite-Tabellen –&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;study_sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;started_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ended_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;message_events&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sent_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;had_scope_filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;had_attachments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;achievements_earned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;earned_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;— plus die JSON-Badge-Definitionen, ein Evaluator-Modul und eine Handvoll React-Komponenten (&lt;code&gt;SummaryCards&lt;/code&gt;, &lt;code&gt;AchievementGrid&lt;/code&gt;, &lt;code&gt;ActivityHeatmap&lt;/code&gt;, &lt;code&gt;DayDetailModal&lt;/code&gt;). Die gleiche &lt;code&gt;progress.db&lt;/code&gt;-Datei hat mittlerweile weitere Tabellen für die gespeicherten Quizzes, Workshops, Decks und Mindmaps des Study Hubs bekommen – aber die Badge-und-Session-Maschinerie selbst ist nur ein paar hundert Zeilen lang geblieben.&lt;/p&gt;
&lt;p&gt;Daran ist nichts Ausgefallenes. Das Dashboard funktioniert, weil die &lt;em&gt;Designentscheidungen&lt;/em&gt; richtig sind, nicht weil die Implementierung raffiniert ist.&lt;/p&gt;
&lt;h2 id="fazit"&gt;Fazit&lt;/h2&gt;
&lt;p&gt;Wenn du ein Lern-Tool baust – oder ein beliebiges Tool, das von den Gewohnheiten der Nutzer lebt –, dann setze Gamification &lt;em&gt;bewusst&lt;/em&gt; ein. Wähle die Metriken, die das widerspiegeln, was du wirklich fördern willst. Begrenze die Anzahl der Erfolge. Verzichte auf die Streak-Panik-UX. Mach die Textur der Nutzung sichtbar, ohne dass die App verzweifelt wirkt.&lt;/p&gt;
&lt;p&gt;Oder direkter gesagt: Bau kein Duolingo. Bau ein Dashboard, auf das der Nutzer ab und zu schaut und das er dann wieder schließt, mit dem leichten Gefühl, weitermachen zu wollen. Das ist der ganze Job.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="anhang-abkürzungen-in-diesem-beitrag"&gt;Anhang: Abkürzungen in diesem Beitrag&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Abkürzung&lt;/th&gt;
&lt;th&gt;Vollform&lt;/th&gt;
&lt;th&gt;Bedeutung&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UX&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;User Experience&lt;/td&gt;
&lt;td&gt;Wie sich das Produkt anfühlt – genau das, was durch Streak-Panik-Mechaniken geopfert wird&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ICT&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Information and Communications Technology&lt;/td&gt;
&lt;td&gt;Das Fach, das ich acht Jahre lang unterrichtet habe, bevor ich zum Full-Stack gewechselt bin&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SQLite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;(SQL = Structured Query Language)&lt;/td&gt;
&lt;td&gt;Eine komplette relationale Datenbank in einer einzigen Datei, &lt;code&gt;progress.db&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;JSON&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;JavaScript Object Notation&lt;/td&gt;
&lt;td&gt;Das Datenformat, in dem die 25 Badge-Definitionen liegen&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;User Interface&lt;/td&gt;
&lt;td&gt;Die Dashboard-Oberfläche: Statistiken, Raster, Heatmap&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Als Nächstes:&lt;/strong&gt;
.&lt;/p&gt;</description></item></channel></rss>