<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Beiträge von Caroline Labres - Mobile USTP MKL</title>
	<atom:link href="https://mobile.fhstp.ac.at/author/it241502/feed/" rel="self" type="application/rss+xml" />
	<link>https://mobile.fhstp.ac.at/author/it241502/</link>
	<description>Die &#34;Mobile Forschungsgruppe&#34; der USTP, sie  sammelt hier alles zu den Themen Design, UX und Entwicklung mobiler Applikationen</description>
	<lastBuildDate>Sun, 16 Nov 2025 17:20:54 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://mobile.fhstp.ac.at/wp-content/uploads/2025/03/icon-120x120.webp</url>
	<title>Beiträge von Caroline Labres - Mobile USTP MKL</title>
	<link>https://mobile.fhstp.ac.at/author/it241502/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Workshop &#124; Astro</title>
		<link>https://mobile.fhstp.ac.at/workshop/workshop-astro/</link>
		
		<dc:creator><![CDATA[Caroline Labres]]></dc:creator>
		<pubDate>Sun, 16 Nov 2025 17:20:52 +0000</pubDate>
				<category><![CDATA[Webdevelopment]]></category>
		<category><![CDATA[Workshop]]></category>
		<category><![CDATA[Astro]]></category>
		<guid isPermaLink="false">https://mobile.fhstp.ac.at/?p=15111</guid>

					<description><![CDATA[<p>Im 3. Semester habe ich einen Workshop zu Astro gehalten. Dabei habe ich erklärt, was das Webframework ausmacht, und anhand von einem praktischen Beispiel die wichtigsten Kernfunktionen demonstriert. Was ist Astro? Astro ist ein Framework für contentfokussierte Webprojekte, wie z.B. Blogs, E-Commerce- oder Marketing-Websites. Es setzt auf eine komponentenbasierte Web-Architektur, was bedeutet, dass das meiste <a class="read-more" href="https://mobile.fhstp.ac.at/workshop/workshop-astro/">[...]</a></p>
<p>The post <a href="https://mobile.fhstp.ac.at/workshop/workshop-astro/">Workshop | Astro</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Im 3. Semester habe ich einen Workshop zu Astro gehalten. Dabei habe ich erklärt, was das Webframework ausmacht, und anhand von einem praktischen Beispiel die wichtigsten Kernfunktionen demonstriert.</p>



<h2 class="wp-block-heading">Was ist Astro?</h2>



<p class="wp-block-paragraph">Astro ist ein Framework für contentfokussierte Webprojekte, wie z.B. Blogs, E-Commerce- oder Marketing-Websites. Es setzt auf eine <strong>komponentenbasierte Web-Architektur</strong>, was bedeutet, dass das meiste als statische HTML-Seite gerendert wird und man kleine Islands mit JavaScript für Interaktivität hinzufügen kann. Astro verfolgt einen <strong>Server-first-Ansatz</strong> und kommt standardmäßig <strong>ohne JavaScript</strong> am Client aus, liefert aber bei Bedarf <strong>Unterstützung für Frameworks</strong> wie React, Vue, Svelte, Solid etc. Darüber hinaus bietet Astro <strong>Content Collections</strong>, mit denen sich Markdown-Inhalte strukturiert organisieren und mithilfe von TypeScript typsicher validieren lassen.</p>



<h2 class="wp-block-heading">Projekt erstellen</h2>



<p class="wp-block-paragraph"><code>npm create astro@latest</code> (basic, helpful starter Projekt auswählen)</p>



<p class="wp-block-paragraph">In VS Code gibt es eine Extension namens Astro, die hilfreich ist.</p>



<p class="wp-block-paragraph"> Ordnerstruktur (als Beispiel):</p>



<ul class="wp-block-list">
<li>assets</li>



<li>components</li>



<li>content (für Content Collections)</li>



<li>layouts</li>



<li>pages (file-based Routing)</li>



<li>styles</li>
</ul>



<h2 class="wp-block-heading">Dateiaufbau und Astro-Komponenten</h2>



<ul class="wp-block-list">
<li>Dateiendung: .astro</li>



<li>Codeausführung:
<ul class="wp-block-list">
<li>serverseitig: <code>--- ---</code> (Frontmatter)</li>



<li>clientseitig: <code>&lt;script>&lt;/script></code></li>
</ul>
</li>



<li>JSX-ähnliche Ausdrücke
<ul class="wp-block-list">
<li><code>{variable}</code> in HTML</li>



<li>Aber: Funktionen und Objekte können so nicht übergeben werden (wie z.B. bei React), stattdessen mit Script-Tag umsetzbar</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">Beispielsweise MyAstroComp.astro:</p>



<pre class="wp-block-code"><code>---
// Script mit JS, das am Server ausgeführt wird
const text = "Hello World";
---
&lt;!-- Hier Template der Komponente mit HTML, CSS und JS --&gt;
&lt;div&gt;{text}&lt;/div&gt;</code></pre>



<p class="wp-block-paragraph">Was nicht funktioniert:</p>



<pre class="wp-block-code"><code>---
function handleClick() {
  console.log("clicked");
}
---
&lt;button onclick="handleClick()"&gt;{text}&lt;/button&gt;</code></pre>



<p class="wp-block-paragraph">Komponente in index.astro verwenden:</p>



<pre class="wp-block-code"><code>---
import MyAstroComp from "../components/MyAstroComp.astro";
---
&lt;MyAstroComp /&gt;</code></pre>



<ul class="wp-block-list">
<li><code>&lt;slot /></code> für Children (wie {children} in React)</li>



<li>Mit <code>Astro.props</code> auf Properties zugreifen</li>
</ul>



<pre class="wp-block-code"><code>---
interface Props {
  name: string;
}
const { name } = Astro.props;
---
&lt;h2&gt;Hello {name}!&lt;/h2&gt;</code></pre>



<h2 class="wp-block-heading">Unterschiede Astro vs. JSX</h2>



<figure class="wp-block-table"><table class="has-black-color has-text-color has-link-color has-fixed-layout"><thead><tr><th></th><th>Astro</th><th>JSX</th></tr></thead><tbody><tr><td>Attribute</td><td>kebab-case</td><td>camelCase</td></tr><tr><td>Mehrere Elemente</td><td>Ohne Parent zulässig</td><td>Nur in einem einzelnen &lt;div&gt; oder &lt;&gt; zulässig</td></tr><tr><td>Kommentare</td><td>HTML- und JS-Kommentare</td><td>JS-Kommentare</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">React hinzufügen</h2>



<p class="wp-block-paragraph">Interaktivität in Astro Komponenten einzubauen ist mühsam. Um mit einem Buttonklick umgehen zu können, müsste man ein &lt;script&gt; Tag hinzufügen. Stattdessen kann man aber auch ein beliebiges anderes Framework zum Projekt hinzufügen und so auch beispielsweise React-Komponenten bauen und nutzen.</p>



<p class="wp-block-paragraph">Um React als Beispiel hinzuzufügen: <code>npx astro add react</code></p>



<p class="wp-block-paragraph">Achtung: Komponente wird by default nur am Server gerendert!</p>



<p class="wp-block-paragraph">Für Interaktivität braucht es Hydration und eine Client Directive.</p>



<h3 class="wp-block-heading">Client Directives</h3>



<p class="wp-block-paragraph">Die client:* Directive gibt an, wann das JavaScript an den Browser geschickt werden soll. Die Komponente wird zuerst am Server gerendert (außer bei client:only), dann wird das JS gesendet und somit wird die Komponte hydrated und interaktiv.</p>



<ul class="wp-block-list">
<li><code>client: load</code>
<ul class="wp-block-list">
<li>JS: sofort beim Laden der Seite</li>
</ul>
</li>



<li><code>client: idle</code>
<ul class="wp-block-list">
<li>JS: nach initialem Ladeprozess und wenn requestIdleCallback-Event ausgelöst wird</li>
</ul>
</li>



<li><code>client: visible / client:visible={{rootMargin}}</code>
<ul class="wp-block-list">
<li>JS: sobald Komponente bzw. angegebener Margin sichtbar ist</li>
</ul>
</li>



<li><code>client:media={string}</code>
<ul class="wp-block-list">
<li>JS: wenn CSS media query erfüllt wird (z.B. nur für bestimmte Bildschirmgrößen)</li>
</ul>
</li>



<li><code>client:only={string}</code>
<ul class="wp-block-list">
<li>Überspringt SSR und rendert Komponente nur am Client. Framework muss als String übergeben werden.</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">Die Client Directive wird dort hinzufügt, wo die Komponente verwendet wird.</p>



<pre class="wp-block-code"><code>---
import MyReactButton from "../components/MyReactButton";
---
&lt;MyReactButton client:load /&gt;</code></pre>



<h2 class="wp-block-heading">Output Type für Build</h2>



<p class="wp-block-paragraph">In der astro.config Datei kann der Output Type festgelegt werden. Dieser bestimmt, wann die Seiten standardmäßig gerendert werden (beim Builden oder on demand). Das gilt für alle Seiten, außer bei denen eine Ausnahme festgelegt ist.</p>



<p class="wp-block-paragraph">In astro.config.mjs: <code>output: 'static'</code> oder <code>'server'</code></p>



<ul class="wp-block-list">
<li><code>static</code> (default): SSG, Seiten werden vorgerendert (<em>prerendered</em>); Ergebnis: statische Website</li>



<li><code>server</code>: SSR, Seiten werden on demand gerendert; Ergebnis: server-rendered Website</li>



<li>Für einzelne Seite ändern: <code>export const prerender = false</code>
<ul class="wp-block-list">
<li>wenn in config static: <code>false</code></li>



<li>wenn in config server: <code>true</code></li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">Wichtig: Wenn eine Seite SSR verwendet, muss ein <strong>Server-Adapter</strong> (z.B. node) festgelegt werden: <code>npx astro add node</code></p>



<h2 class="wp-block-heading">Blog als Praxisbeispiel</h2>



<p class="wp-block-paragraph">Als Beispiel wird ein kleiner, einfacher Blog programmiert. Dieser beinhaltet zwei Seiten, wobei auf einer alle Einträge mit Bild, Datum und Titel aufgelistet werden (Übersichtsseite) und auf der anderen die Informationen des jeweiligen Eintrags stehen (Detailseite). Die einzelnen Blogbeiträge sollen in Form von Markdown-Dateien erstellt, bearbeitet und verwaltet werden können. Auf das Styling wird bei diesem Beispiel nicht eingegangen.</p>



<h3 class="wp-block-heading">Content Collection erstellen</h3>



<p class="wp-block-paragraph">Content Collections helfen dabei, Markdown-Dateien zu organisieren. Genau das wird für die Blogbeiträge benötigt. Um eine Collection zu erstellen, muss diese in src/content.config.ts definiert werden.</p>



<pre class="wp-block-code"><code>import { glob } from "astro/loaders";
import { defineCollection, z } from "astro:content";

const blog = defineCollection({
  loader: glob({ base: "./src/content/blog", pattern: "**/*.{md,mdx}" }),
  schema: () =&gt;
    z.object({
      title: z.string(),
      date: z.coerce.date(),
      img: z.string(),
    }),
});

export const collections = { blog };</code></pre>



<p class="wp-block-paragraph">Die Funktion <code>defineCollection()</code> verlangt dabei zwei Parameter, einerseits den Loader und andererseits optional das Schema. Der Loader legt fest, wie und von wo die Inhalte der Collection geladen werden. Astro stellt dabei zwei integrierte Varianten zur Verfügung:</p>



<ul class="wp-block-list">
<li><code>glob()</code>: erstellt Einträge aus Ordnern mit Dateien</li>



<li><code>file()</code>: erstellt Einträge basierend auf einer lokalen Datei (z.B. JSON-File)</li>
</ul>



<p class="wp-block-paragraph">Das Schema wird mit zod erstellt. Wird ein Schema definiert, so werden die entsprechenden Markdown-Dateien dahingehend validiert. Außerdem können generierte Types verwendet werden (z.B. <code>type Props = CollectionEntry&lt;"blog"&gt;["data"];</code>). Wichtig ist nur, dass der Dev-Server neu gestartet wird, wenn sich Änderungen am Schema ergeben, sodass Astro das mitbekommt.</p>



<p class="wp-block-paragraph">Ein Blogeintrag soll in diesem Fall immer einen Titel, ein Datum und ein Bild beinhalten, sodass diese Informationen auf der Übersichtsseite angezeigt und auf der Detailseite immer gleich formatiert werden können.</p>



<h3 class="wp-block-heading">Blogbeiträge hinzufügen</h3>



<p class="wp-block-paragraph">Es können jetzt diverse Blogbeiträge in Form von Markdown-Dateien unter content/blog erstellt werden (Pfad in content.config.ts festgelegt).</p>



<p class="wp-block-paragraph">Beispiel: first-entry.md</p>



<pre class="wp-block-code"><code>---
title: "First Entry"
date: "2025-10-30"
img: "/favicon.svg"
---
Hello, this is my first entry.

## H2

This is a paragraph.</code></pre>



<p class="wp-block-paragraph">Im Frontmatter (innerhalb der drei Bindestriche) werden die drei Parameter angegeben, darunter folgt der Inhalt. Als Bild wird der Einfachheit halber das favicon im public-Ordner hergenommen. Der Blogbeitrag kann Überschriften, Absätze, Links, Codeteile, Tabellen und alles, was Markdown zu bieten hat, beinhalten. Wichtig ist nur, dass man das entsprechende Styling dafür definiert (h2, p, code, a etc.).</p>



<h4 class="wp-block-heading">MDX</h4>



<p class="wp-block-paragraph">Es können nicht nur md-Dateien erstellt werden, sondern auch mdx-Dateien, in denen die eigenen Komponenten (egal ob Astro, React etc.) verwendet werden können. Es muss nur die entsprechende Astro-Integration installiert werden (<code>npx astro add mdx</code>) und mdx in der Definition der Content Collection berücksichtigt werden (wurde bereits getan).</p>



<p class="wp-block-paragraph">Beispiel: second-entry.mdx</p>



<pre class="wp-block-code"><code>---
title: "Second Entry"
date: "2025-10-31"
img: "/favicon.svg"
---

This is my second entry.

import MyReactButton from "../../components/MyReactButton"

&lt;MyReactButton client:load /&gt;</code></pre>



<p class="wp-block-paragraph">components/MyReactButton.tsx</p>



<pre class="wp-block-code"><code>export default function MyReactButton(){

    function handleClick(){
        console.log("Hello, you clicked me")
    }

    return (
        &lt;button onClick={handleClick}&gt;Click me&lt;/button&gt;
    )
}</code></pre>



<h3 class="wp-block-heading">Seiten erstellen</h3>



<p class="wp-block-paragraph">Astro verwendet file-based Routing. Die Ordner- und Dateistruktur im pages-Ordner bestimmt somit automatisch, unter welchen URLs die Seiten aufgerufen werden können. Im pages-Ordner wird ein Unterordner blog und darin index.astro und [slug].astro angelegt. Der Blog ist somit unter /blog erreichbar. index.astro ist eine statische Route, während [slug].astro eine dynamische Route ist. Der Parameter slug kann dabei durch eine beliebige andere Bezeichnung ersetzt werden. Für mehr Tiefe kann auch ein Rest-Parameter verwendet werden: [&#8230;path].astro. </p>



<h4 class="wp-block-heading">Übersichtsseite</h4>



<p class="wp-block-paragraph">Für die index Seite wird zuerst ein Layout erstellt. Ein Layout ist dabei nichts anderes als eine normale Astro-Komponente.</p>



<p class="wp-block-paragraph">layouts/Layout.astro</p>



<pre class="wp-block-code"><code>---<br>import "../styles/global.css";<br>---<br><br>&lt;!doctype html&gt;<br>&lt;html lang="en"&gt;<br>  &lt;head&gt;<br>    &lt;meta charset="UTF-8" /&gt;<br>    &lt;meta name="viewport" content="width=device-width" /&gt;<br>    &lt;link rel="icon" type="image/svg+xml" href="/favicon.svg" /&gt;<br>    &lt;meta name="generator" content={Astro.generator} /&gt;<br>    &lt;title&gt;My Blog&lt;/title&gt;<br>  &lt;/head&gt;<br>  &lt;body&gt;<br>    &lt;slot /&gt;<br>  &lt;/body&gt;<br>&lt;/html&gt;<br><br>&lt;style&gt;<br>  html,<br>  body {<br>    margin: 0;<br>    width: 100%;<br>    height: 100%;<br>  }<br>&lt;/style&gt;</code></pre>



<p class="wp-block-paragraph">Für den Header kann ebenso eine Astro-Komponente erstellt werden (components/Header.tsx).</p>



<pre class="wp-block-code"><code>&lt;header&gt;
  &lt;nav&gt;
    &lt;a href="/blog"&gt;My Blog&lt;/a&gt;
  &lt;/nav&gt;
&lt;/header&gt;
</code></pre>



<p class="wp-block-paragraph">Nun kann index.astro befüllt werden:</p>



<pre class="wp-block-code"><code>---
import { getCollection } from "astro:content";
import Header from "../../components/Header.astro";
import Layout from "../../layouts/Layout.astro";

const posts = (await getCollection("blog")).sort((a, b) =&gt; {
  return b.data.date.valueOf() - a.data.date.valueOf();
});
---

&lt;Layout&gt;
  &lt;Header /&gt;
  &lt;ul&gt;
    {
      posts.map((post) =&gt; (
        &lt;li&gt;
          &lt;a href={"/blog/" + post.id}&gt;
            &lt;div&gt;
              &lt;img src={post.data.img} /&gt;
            &lt;/div&gt;
            &lt;div&gt;{post.data.title}&lt;/div&gt;
            &lt;div&gt;{post.data.date.toLocaleDateString()}&lt;/div&gt;
          &lt;/a&gt;
        &lt;/li&gt;
      ))
    }
  &lt;/ul&gt;
&lt;/Layout&gt;</code></pre>



<p class="wp-block-paragraph">Mithilfe von <code>getCollection()</code> kann eine Collection, sprich ein Array von Einträgen, geholt werden. In diesem Beispiel werden die Einträge von der Blog-Collection zusätzlich nach dem Datum sortiert.</p>



<h4 class="wp-block-heading">Detailseite</h4>



<p class="wp-block-paragraph">Für die Detailseite wird ebenso ein Layout erstellt, das den Titel, das Bild und das Datum übergeben bekommt und anzeigt.</p>



<p class="wp-block-paragraph">layouts/BlogLayout.astro</p>



<pre class="wp-block-code"><code>---
import type { CollectionEntry } from "astro:content";
import Header from "../components/Header.astro";

type Props = CollectionEntry&lt;"blog"&gt;&#91;"data"];

const { title, date, img} = Astro.props;
---

&lt;!doctype html&gt;
&lt;html lang="en"&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;meta name="viewport" content="width=device-width" /&gt;
    &lt;link rel="icon" type="image/svg+xml" href="/favicon.svg" /&gt;
    &lt;meta name="generator" content={Astro.generator} /&gt;
    &lt;title&gt;My Blog&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;Header /&gt;
    &lt;main&gt;
      &lt;article&gt;
        &lt;div&gt;
          &lt;img src={img} /&gt;
        &lt;/div&gt;
        &lt;div&gt;{date.toLocaleDateString()}&lt;/div&gt;
        &lt;h1&gt;{title}&lt;/h1&gt;
        &lt;div&gt;
          &lt;slot /&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/main&gt;
  &lt;/body&gt;
&lt;/html&gt;

&lt;style&gt;
  html,
  body {
    margin: 0;
    width: 100%;
    height: 100%;
  }
&lt;/style&gt;</code></pre>



<p class="wp-block-paragraph">Die Detailseite muss nun den Parameter slug auslesen und die entsprechenden Informationen dem BlogLayout übergeben. Es gibt zwei Varianten, das zu tun, je nachdem ob man SSR oder SSG verwenden möchte.</p>



<p class="wp-block-paragraph"><strong>Variante 1: SSR (on demand Rendering)</strong></p>



<pre class="wp-block-code"><code>---
import { render } from "astro:content";
import { getEntry } from "astro:content";
import BlogLayout from "../../layouts/BlogLayout.astro";

export const prerender = false;
const { slug } = Astro.params;

if (!slug) {
  return Astro.rewrite("/404");
}

const entry = await getEntry("blog", slug);

if (!entry) {
  return Astro.rewrite("/404");
}

const { Content } = await render(entry);
---

&lt;BlogLayout {...entry.data}&gt;
  &lt;Content /&gt;
&lt;/BlogLayout&gt;
</code></pre>



<p class="wp-block-paragraph">Mithilfe von <code>Astro.params</code> kann der Parameter slug ausgelesen werden. Mit <code>getEntry()</code> wird dann der entsprechende Eintrag geholt. Wenn es keinen passenden Eintrag gibt, wird 404 angezeigt. Um den Inhalt der Zielseite anzuzeigen, ohne die URL zu verändern, wird <code>Astro.rewrite()</code> genutzt.</p>



<p class="wp-block-paragraph"><strong>Variante 2: SSG (statische Seite)</strong></p>



<pre class="wp-block-code"><code>---
import type { GetStaticPaths } from "astro";
import { render } from "astro:content";
import BlogLayout from "../../layouts/BlogLayout.astro";
import { getCollection } from "astro:content";

export const getStaticPaths = (async () =&gt; {
  const entries = await getCollection("blog");

  return entries.map((entry) =&gt; ({
    params: { slug: entry.id },
    props: entry,
  }));
}) satisfies GetStaticPaths;

const entry = Astro.props;

const { Content } = await render(entry);
---

&lt;BlogLayout {...entry.data}&gt;
  &lt;Content /&gt;
&lt;/BlogLayout&gt;
</code></pre>



<p class="wp-block-paragraph">Soll eine dynamische Route statisch sein, so muss sie eine Funktion namens <code>getStaticPaths()</code> exportieren, die ein Array an Objekten mit dem property <code>params</code> zurückgibt. So werden alle möglichen Paths vordefiniert. In diesem Beispiel holt man sich also alle Einträge der Blog-Collection in der <code>getStaticPaths()</code>-Funktion und über die Properties (<code>Astro.props</code>) können dann die Informationen des einzelnen Eintrags ausgelesen werden.</p>



<h2 class="wp-block-heading">Fazit</h2>



<p class="wp-block-paragraph">Mit Astro können schnelle Websites erstellt werden. Wenn man bereits Erfahrung mit HTML, JSX oder React hat, so fällt einem der Einstieg in das Framework besonders leicht, da man viele vertraute Konzepte wiederfindet. Nur bei komplexeren Websites stößt Astro irgendwann auf seine Grenzen.</p>



<h2 class="wp-block-heading">Quelle</h2>



<p class="wp-block-paragraph"><a href="https://docs.astro.build/en">https://docs.astro.build/en</a></p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://mobile.fhstp.ac.at/workshop/workshop-astro/">Workshop | Astro</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>TFG &#124; Erika CMS</title>
		<link>https://mobile.fhstp.ac.at/allgemein/tfg-erika-cms/</link>
		
		<dc:creator><![CDATA[Caroline Labres]]></dc:creator>
		<pubDate>Mon, 07 Jul 2025 21:01:17 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Forschung]]></category>
		<category><![CDATA[Projekte]]></category>
		<category><![CDATA[Studium]]></category>
		<category><![CDATA[Webdevelopment]]></category>
		<category><![CDATA[Erika]]></category>
		<category><![CDATA[Forschungsprojekt]]></category>
		<category><![CDATA[TFG]]></category>
		<guid isPermaLink="false">https://mobile.fhstp.ac.at/?p=14567</guid>

					<description><![CDATA[<p>Im Rahmen der Lehrveranstaltung „Tun Forschen Gründen“ arbeitete ich 80 Stunden beim Forschungsprojekt Erika mit. Das Hauptziel des Forschungsprojekts besteht darin, mittels einer App klimafreundliches Verhalten zu fördern und passende regionale Aktivitäten (sogenannte Initiativen) zu präsentieren. Die App Erika soll informieren, durch spielerische Elemente motivieren und belohnen. Das Forschungsprojekt erfolgt am Beispiel der Region Waidhofen <a class="read-more" href="https://mobile.fhstp.ac.at/allgemein/tfg-erika-cms/">[...]</a></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/tfg-erika-cms/">TFG | Erika CMS</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Im Rahmen der Lehrveranstaltung „Tun Forschen Gründen“ arbeitete ich 80 Stunden beim Forschungsprojekt Erika mit.</p>



<p class="wp-block-paragraph">Das Hauptziel des Forschungsprojekts besteht darin, mittels einer App klimafreundliches Verhalten zu fördern und passende regionale Aktivitäten (sogenannte Initiativen) zu präsentieren. Die App Erika soll informieren, durch spielerische Elemente motivieren und belohnen. Das Forschungsprojekt erfolgt am Beispiel der Region Waidhofen a/d Ybbs, weshalb auch eine Integration in die vorhandene Waidhofen-App vorgesehen ist.</p>



<p class="wp-block-paragraph">In der App können Nutzer*innen an Initiativen teilnehmen, Aufgaben erfüllen und Belohnungen erhalten. Zusätzlich können sie Vorschläge für Initiativen machen und die von anderen bewerten.</p>



<h2 class="wp-block-heading">Zielsetzung</h2>



<p class="wp-block-paragraph">Meine Aufgabe war es, ein funktionsfähiges CMS laut vorhandenem Prototyp umzusetzen. Dazu zählten sowohl die Umsetzung des Frontends als auch Anpassungen und Ergänzungen im bestehenden Backend. Das CMS sollte vor allem diverse Daten von Nutzer*innen, Initiativen etc. anzeigen, ein Login beinhalten und die Möglichkeit bieten, Inhalte für die App erstellen, bearbeiten und löschen zu können. Zudem sollten mit dem CMS PDFs generiert werden können, die für Initiativen und Belohnungen benötigt werden.</p>



<h2 class="wp-block-heading">Vorgehensweise</h2>



<p class="wp-block-paragraph">Die genauen Funktionen des CMS wurden anfangs definiert und priorisiert, und später leicht angepasst. Zu Priorität 1 zählten vor allem die Authentifizierung, die Anzeige der verschiedenen Daten (Nutzer*innen, Initiativen und Belohnungsmöglichkeiten) und die Generierung von PDFs. Im nächsten Schritt lag der Fokus auf den Vorschlägen für Initiativen, die angezeigt und freigegeben werden können. Zum Schluss wurden die Funktionalitäten ergänzt, Initiativen anlegen, bearbeiten und löschen zu können.</p>



<p class="wp-block-paragraph"><strong>Verwendete Technologien:</strong></p>



<ul class="wp-block-list">
<li>Frontend: Low-Code-Framework Luisa, Vue.js und Axios</li>



<li>Libraries für die PDF-Generierung (inkl. QR-Code): pdf-lib, qrcode und file-saver</li>



<li>Prototyp: QuantUX</li>



<li>Backend: Express Framework, Effect Library und Swagger</li>
</ul>



<p class="wp-block-paragraph">Während der Mitarbeit beim Forschungsprojekt teilte ich mir die Zeit selbst ein, machte mit dem Projektleiter Dipl.-Ing. Gernot Rottermanner vor allem separate Meetings aus und nahm vereinzelt am wöchentlichen Jour Fixe teil. Für das Frontend war ich allein zuständig, während ich beim Backend zusammen mit Dipl.-Ing. Ramon Brullo arbeitete, der vor allem die Funktionen für die App selbst und später das Erstellen und Bearbeiten von Initiativen umsetzte. Den Prototypen für das CMS hatte Dipl.-Ing. Gernot Rottermanner bereits entwickelt. Durch die Verwendung des Low-Code-Frameworks Luisa konnte ich das Design sofort übernehmen, mich auf die Funktionalität konzentrieren und musste in QuantUX nur noch an manchen Stellen Anpassungen vornehmen.</p>



<h2 class="wp-block-heading">Ergebnisse</h2>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="2902" height="1890" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/07/Initiativen.jpg" alt="Screenshot der Initiativen-Seite, die eine Seitennavigation und eine Tabelle mit allen Initiativen beinhaltet. Rechts oben befindet sich ein Button, um eine neue erstellen zu können." class="wp-image-14572" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/07/Initiativen.jpg 2902w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/07/Initiativen-1536x1000.jpg 1536w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/07/Initiativen-2048x1334.jpg 2048w" sizes="(max-width: 2902px) 100vw, 2902px" /><figcaption class="wp-element-caption"><em>Initiativen-Seite</em></figcaption></figure>



<p class="wp-block-paragraph">Hier können alle Initiativen eingesehen, bearbeitet und neue erstellt werden. Für jede Initiative lässt sich ein PDF und ein QR-Code generieren.</p>



<figure class="wp-block-image size-full"><img decoding="async" width="2880" height="1984" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/07/Initiativen_erstellen.png" alt="Screenshot der Seite, wo eine neue Initiative erstellt werden kann. Sie enthält eine Seitennavigation, einen Button rechts oben, um eine vorhandene Initiative beim Bearbeiten löschen zu können, ein großes Textfeld und zwie weitere Buttons zum Formatieren und Speichern." class="wp-image-14578" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/07/Initiativen_erstellen.png 2880w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/07/Initiativen_erstellen-1536x1058.png 1536w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/07/Initiativen_erstellen-2048x1411.png 2048w" sizes="(max-width: 2880px) 100vw, 2880px" /><figcaption class="wp-element-caption"><em>Seite, um eine neue Initiative anzulegen</em></figcaption></figure>



<p class="wp-block-paragraph">Auf dieser Seite kann eine neue Initiative mittels JSON erstellt und die Eingabe formatiert werden. Das Textfeld wird je nachdem, ob eine Initiative erstellt oder bearbeitet wird, mit einer Vorlage oder den richtigen Daten befüllt. Eine bestehende Initiative kann hier ebenso gelöscht werden.</p>



<figure class="wp-block-image size-full"><img decoding="async" width="2880" height="2316" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/07/Ideen.jpg" alt="Screenshot der Ideen-Seite, die eine Seitennavigation und zwei Tabellen mit allen Ideen-Bewertungen und eingereichten Ideen beinhaltet." class="wp-image-14591" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/07/Ideen.jpg 2880w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/07/Ideen-1536x1235.jpg 1536w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/07/Ideen-2048x1647.jpg 2048w" sizes="(max-width: 2880px) 100vw, 2880px" /><figcaption class="wp-element-caption"><em>Ideen-Seite</em></figcaption></figure>



<p class="wp-block-paragraph">Auf dieser Seite lassen sich alle eingereichten Ideen (Vorschläge für Initiativen) einsehen und freigeben, sowie alle Bewertungen der freigegeben Ideen nachsehen.</p>



<p class="wp-block-paragraph">Die Benutzer:innen- und Einlösemöglichkeiten-Seite ähneln dem Rest. Auf ersterer werden alle Nutzer*innen inklusive ihrem Erstelldatum, der Anzahl der angemeldeten und teilgenommenen Initiativen und ihrem &#8220;Spielstatus&#8221; angezeigt. Auf zweiterer werden alle Einlösemöglichkeiten, sprich mögliche Belohnungen, aufgelistet. Für jede lässt sich ebenso ein entsprechender QR-Code und ein PDF generieren.</p>



<h2 class="wp-block-heading">Retrospektive</h2>



<p class="wp-block-paragraph">Durch meine Mitarbeit bei Erika konnte ich meine Programmier-Kenntnisse erweitern und viele neue Technologien kennenlernen. Sowohl die komplette Backend-Struktur als auch das Low-Code-Framework Luisa waren neu für mich. Anfangs war das durchaus herausfordernd, doch schnell bekam ich einen Überblick und konnte alles wie geplant umsetzen. Die Verwendung von Luisa hat die Entwicklung des Frontends erheblich beschleunigt und es mir erlaubt, mich vor allem auf das Backend zu konzentrieren. Bei einfachen Projekten ist das Low-Code-Framework sehr praktisch, bei höheren Anforderungen wie z.B. responsive Tabellen stößt es jedoch an seine Grenzen. Insgesamt war das Projekt abwechslungsreich und ließ sich gut im Rahmen der vorgegebenen 80 Stunden umsetzen.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">Link zum Forschungsprojekt: <a href="https://research.fhstp.ac.at/projekte/erika">https://research.fhstp.ac.at/projekte/erika</a></p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/tfg-erika-cms/">TFG | Erika CMS</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Luisa &#8211; Einführung in das Low-Code JS Framework</title>
		<link>https://mobile.fhstp.ac.at/allgemein/luisa-einfuehrung-in-das-low-code-js-framework/</link>
		
		<dc:creator><![CDATA[Caroline Labres]]></dc:creator>
		<pubDate>Tue, 17 Jun 2025 18:28:44 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<guid isPermaLink="false">https://mobile.fhstp.ac.at/?p=14448</guid>

					<description><![CDATA[<p>Den typischen Prozess zuerst Design, dann Implementierung kennt jeder. Bei der Implementierung gilt es dann, zuerst das Design in vorm von beispielsweise HTML nachzubauen. Doch was ist, wenn es viel schneller gehen könnte? Mittels Low-Code Frameworks wie Luisa ist das möglich. In diesem Blogartikel wird das Framework kurz beschrieben und eine kleine Anwendung als Beispiel <a class="read-more" href="https://mobile.fhstp.ac.at/allgemein/luisa-einfuehrung-in-das-low-code-js-framework/">[...]</a></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/luisa-einfuehrung-in-das-low-code-js-framework/">Luisa &#8211; Einführung in das Low-Code JS Framework</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Den typischen Prozess zuerst Design, dann Implementierung kennt jeder. Bei der Implementierung gilt es dann, zuerst das Design in vorm von beispielsweise HTML nachzubauen. Doch was ist, wenn es viel schneller gehen könnte? Mittels Low-Code Frameworks wie Luisa ist das möglich. In diesem Blogartikel wird das Framework kurz beschrieben und eine kleine Anwendung als Beispiel durchgemacht.</p>



<h2 class="wp-block-heading">Was ist Low-Code?</h2>



<p class="wp-block-paragraph">Wie der Begriff schon verrät, ist das Ziel wenig Code selbst schreiben zu müssen. Nützlich ist das vor allem für Personen mit geringen Programmierkenntnissen. Die Idee ist, dass Fachleute sich um den visuellen Teil der Anwendung kümmern, der dann zur Laufzeit durch Softwarekomponenten interpretiert wird. Es gibt verschiedenste Frameworks, die unterschiedliche Ansätze verfolgen. Wichtig ist jedoch, das richtige Verhältnis zwischen Modellierung und Code zu finden, sodass im Endeffekt die Komplexität verringert und nicht erhöht wird.</p>



<h2 class="wp-block-heading">Luisa</h2>



<p class="wp-block-paragraph">Luisa verfolgt den Ansatz, dass nur der Frontend-Code generiert wird, sprich HTML und CSS, die Businesslogik hingegen ist Aufgabe des Programmierers bzw. der Programmiererin. Zurzeit werden Figma und Quant-UX als Design-Tools und Vue.js als Framework unterstützt. Luisa ist Open Source und kann kostenfrei genutzt werden. </p>



<p class="wp-block-paragraph">In seinem Code muss nur die Luisa-Komponente eingebaut werden, die dann den Rest erledigt. Im Development kann man Luisa mit dem Design-Projekt verbinden, sodass Design-Änderungen sofort in der Anwendung sichtbar sind. Für Production kann das Design-File auch heruntergeladen und eingebunden werden. Ändert sich etwas am Design muss das File erneut heruntergeladen werden. Um Logik hinzufügen zu können, werden Data- und Method-Binding benutzt. In Figma benötigt man dazu das Figma-Low-Code Plugin, in Quant-UX steht einem diese Funktion von Haus aus zur Verfügung. Im Code können ebenso Anpassungen beim Design gemacht und benutzerdefinierte Komponenten verwendet werden. </p>



<h2 class="wp-block-heading">Beispiel</h2>



<p class="wp-block-paragraph">Nachfolgend wird ein kleines Beispiel durchgemacht, um zu sehen, wie Luisa eingebunden und verwendet wird. Die Applikation soll nach Eingabe eines Datums, die restlichen Tage bis dahin ausgeben. Hierbei wird Quant-UX verwendet.</p>



<h3 class="wp-block-heading">Design erstellen</h3>



<p class="wp-block-paragraph">Zuallererst wird ein neues Projekt in Quant-UX erstellt und ein Screen hinzugefügt. Auf diesem wird nun ein Date Picker, ein Button und ein Text platziert. </p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="2482" height="1420" data-id="14457" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-161327.png" alt="Screenshot der Quant-UX Komponenten" class="wp-image-14457" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-161327.png 2482w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-161327-1536x879.png 1536w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-161327-2048x1172.png 2048w" sizes="auto, (max-width: 2482px) 100vw, 2482px" /></figure>
</figure>



<p class="wp-block-paragraph">Dann sieht es in etwa so aus:</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="902" height="752" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-163732.png" alt="Screenshot des Beispielscreens mit Überschrift, Datumseingabe, Button und Text" class="wp-image-14455" style="width:400px"/></figure>



<p class="wp-block-paragraph">Hinweis: Ich habe die Schriftgröße auf 16 px erhöht.</p>



<h3 class="wp-block-heading">Projekt Setup</h3>



<p class="wp-block-paragraph">Da in diesem Beispiel ein neues Projekt erstellt wird, ist es am einfachsten das Starterprojekt zu klonen.</p>



<pre class="wp-block-code"><code>git clone https://github.com/KlausSchaefers/luisa-vue3-starter.git</code></pre>



<p class="wp-block-paragraph">Anschließend nicht vergessen, die node modules zu installieren.</p>



<pre class="wp-block-code"><code>npm install</code></pre>



<p class="wp-block-paragraph">In Home.vue muss nun der richtige Token zum Design-Projekt eingetragen werden. Diesen bekommt man in Quant-UX indem man auf das Projekt klickt und dann Share auswählt.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="758" height="762" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-151103.png" alt="Screenshot der Share-Funktion, um zum Token zu kommen" class="wp-image-14462" style="width:300px" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-151103.png 758w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-151103-150x150.png 150w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-151103-120x120.png 120w" sizes="auto, (max-width: 758px) 100vw, 758px" /></figure>



<pre class="wp-block-code"><code>data: function () {
    return {
      design: "<strong>token...</strong>",
      viewModel: {
        date: '',
        result: defaultText
      },
      config: {
      }
    }
  },</code></pre>



<p class="wp-block-paragraph">Bei Quant-UX wird der Token so eingetragen. Bei Figma müssen sowohl die Figma File ID, welche man aus der URL herauslesen kann, als auch der Access Key, welchen man in den Settings bekommt, eingetragen werden.</p>



<p class="wp-block-paragraph">Nun heißt es, Projekt starten und testen, ob das Design aus dem Quant-UX Projekt angezeigt wird.</p>



<pre class="wp-block-code"><code>npm run serve</code></pre>



<p class="wp-block-paragraph">Die Applikation sieht schon mal schön aus. Nun fehlt nur noch die Logik.</p>



<h3 class="wp-block-heading">Logik hinzufügen</h3>



<p class="wp-block-paragraph">Um Daten auslesen und der Applikation sagen zu können, was sie beim Klick auf den Button tun soll, müssen in Quant-UX Variablen- und Methodennamen hinzugefügt werden. Dazu klickt man beispielsweise auf die Datumsauswahl, wählt auf der rechten Seite &#8220;Prototype&#8221; und fügt mit &#8220;Add Data Binding&#8221; eine neue Variable hinzu.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="1384" height="922" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-163839.png" alt="Screenshot von Quant-UX, wie Data Binding hinzugefügt werden kann" class="wp-image-14464" style="width:600px"/></figure>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="1646" height="426" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-163855.png" alt="Screenshot von Quant-UX, wie der Name der Variable angegeben wird" class="wp-image-14465" style="width:600px" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-163855.png 1646w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-163855-1536x398.png 1536w" sizes="auto, (max-width: 1646px) 100vw, 1646px" /></figure>



<p class="wp-block-paragraph">Um eine onClick-Methode hinzuzufügen, wählt man den Button aus und gibt unter &#8220;Low Code &#8211; Callbacks&#8221; den Methodennamen an.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="1386" height="1276" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-163922.png" alt="Screenshot von Quant-UX, wie Method Binding hinzugefügt werden kann" class="wp-image-14498" style="width:600px"/></figure>



<p class="wp-block-paragraph">Danach sollte es im Prototype-Modus ungefähr so aussehen:</p>



<ul class="wp-block-list">
<li>Date Picker: date</li>



<li>Text: result</li>



<li>Button: calculate</li>
</ul>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="796" height="704" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-16-163948.png" alt="Screenshot des Beispielscreens mit zugehörigem Data und Method Binding" class="wp-image-14499" style="width:400px"/></figure>



<p class="wp-block-paragraph">Nun kann wieder in das Vue.js Projekt gewechselt und anfangen werden, die Variablen zu verwenden und die Methode hinzuzufügen.</p>



<p class="wp-block-paragraph">In Home.vue kann man unter &#8220;data&#8221; die verwendeten Variablen mit einem Defaultwert auflisten.</p>



<pre class="wp-block-code"><code>data: function () {
    return {
      design: "token...",
      viewModel: {
        date: undefined,
        result: "Select a date to calculate the remaining days"
      },
      config: {
      }
    }
  },</code></pre>



<p class="wp-block-paragraph">Die calculate Mathode kann man dem &#8220;methods&#8221; Objekt beifügen. Um zu sehen, ob alles funktioniert, kann man sich hier erstmal das Datum ausgeben lassen. Variablen können über das &#8220;viewModel&#8221; Objekt verwendet werden.</p>



<pre class="wp-block-code"><code>methods: {
    calculate() {
      console.log(this.viewModel.date)
    }
  }</code></pre>



<p class="wp-block-paragraph">Startet man das Projekt mit <code>npm run serve</code> bzw. läuft es noch, sollte man nachdem man ein Datum ausgewählt und auf den Button geklickt hat, dieses in der Konsole des Browsers sehen.</p>



<p class="wp-block-paragraph">Nun kann der eigentliche Code geschrieben werden. Die Rechnung der übrigen Tage lässt sich der Übersicht halber in eine andere Funktion auslagern.</p>



<pre class="wp-block-code"><code>function calcRemaining(date) {
  const diff = new Date(date) - new Date()
  return diff > 0 ? Math.ceil(diff / (1000 * 60 * 60 * 24)) : 0;
}</code></pre>



<pre class="wp-block-code"><code>methods: {
    calculate() {
      if (this.viewModel.date) {
        const days = calcRemaining(this.viewModel.date)
        this.viewModel.result = `${days} days left`
      } else {
        this.viewModel.result = "Select a date to calculate the remaining days"
      }
    },
  }</code></pre>



<p class="wp-block-paragraph">Gibt es ein Datum, so sollen die übrigen Tage bis dahin angezeigt werden, ansonsten soll den User*innen mitgeteilt werden, dass zuerst ein Datum ausgewählt werden muss.</p>



<h2 class="wp-block-heading">Weitere nützliche Infos</h2>



<p class="wp-block-paragraph">Möchte man, dass sich der Button im gehoverten Zustand vom normalen unterscheidet, so kann man einfach in Quant-UX den Hover-State bearbeiten. Dafür wählt man den Button aus und ändert im Design-Fenster unten unter &#8220;Hover&#8221; beispielsweise die Hintergrundfarbe.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="1376" height="1408" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-17-173654.png" alt="Screenshot von Quant-UX, wie der Hover State eines Buttons bearbeitet werden kann" class="wp-image-14512" style="width:598px"/></figure>



<p class="wp-block-paragraph">Was die Responsiveness betrifft, haben alle Komponenten von Haus aus eine relative Breite. Man kann im Design-Fenster allerdings auch festlegen, dass die Höhe und/oder die Breite fix sein soll (unter &#8220;Fixed Size&#8221;).</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="1370" height="632" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/Screenshot-2025-06-17-180644.png" alt="Screenshot von Quant-UX, wie das Layout für Luisa bearbeitet werden kann" class="wp-image-14515" style="width:600px"/></figure>



<p class="wp-block-paragraph">Ebenso kann man angeben, inwiefern das Element an das übergeordnete Element angeheftet werden soll, sodass es beispielsweise immer links, rechts oder mittig platziert wird (unter &#8220;Pin&#8221;).</p>



<p class="wp-block-paragraph">Benutzerdefinierte Komponenten kann man in Quant-UX, wenn ein Element ausgewählt ist, unter &#8220;Prototype&#8221; &#8211; &#8220;Low Code &#8211; Rendering&#8221; angeben. Im Code muss dann das main.js File bearbeitet werden. Hat man beispielsweise MyTextComponent in Quant-UX hinterlegt und zum Vue-Projekt hinzugefügt, so würde man die Komponente in main.js so registrieren.</p>



<pre class="wp-block-code"><code>createApp(App)
    .use(router)
    .use(Luisa)
    .component('MyTextComponent', MyTextComponent)
    .mount('#app')</code></pre>



<h2 class="wp-block-heading">Fazit</h2>



<p class="wp-block-paragraph">Luisa beschleunigt den Entwicklungsprozess erheblich. Man muss keine Zeit mit HTML und CSS vergeuden, sondern kann direkt mit der Implementierung der Logik starten. Dadurch hat man genau eine Basis für das Design und sobald sich etwas am Prototyp ändert, ändert sich das auch im Projekt. Für einfache Anwendungen ist Luisa sehr praktisch. Bei komplexeren Projekten, speziellen Anforderungen oder einem hohen Bedarf an Individualisierung stößt das Framework jedoch an seine Grenzen. Im Bereich des Responsive Designs stößt man ebenfalls rasch an Einschränkungen. Verwendet man beispielsweise eine Tabelle, so ist diese immer gleich hoch und die Höhe der Zeilen variiert je nach Anzahl. An dieser Stelle sei erwähnt, dass ich noch nicht versucht habe, das CSS manuell anzupassen, und eventuell bietet Figma hier mehr Flexibilität. Das müsste noch genauer getestet werden. Die Dokumentation fällt insgesamt recht knapp aus. Es lohnt sich aber dennoch einmal hineinzuschauen und Luisa auszuprobieren.</p>



<h2 class="wp-block-heading">Quellen</h2>



<p class="wp-block-paragraph"><a href="https://luisa.cloud/">https://luisa.cloud/</a></p>



<p class="wp-block-paragraph"><a href="https://javascript.plainenglish.io/luisa-the-low-code-ui-framework-5aad9a8bbf50">https://javascript.plainenglish.io/luisa-the-low-code-ui-framework-5aad9a8bbf50</a></p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/luisa-einfuehrung-in-das-low-code-js-framework/">Luisa &#8211; Einführung in das Low-Code JS Framework</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Projekt &#124; TripSync</title>
		<link>https://mobile.fhstp.ac.at/allgemein/projekt-tripsync/</link>
		
		<dc:creator><![CDATA[Caroline Labres]]></dc:creator>
		<pubDate>Mon, 16 Jun 2025 10:39:18 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Cross Plattform]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Projekte]]></category>
		<category><![CDATA[Studium]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[Semesterprojekt]]></category>
		<guid isPermaLink="false">https://mobile.fhstp.ac.at/?p=14392</guid>

					<description><![CDATA[<p>Im Zuge der Masterklasse Mobile im 2.Semester habe ich ein neues Semesterprojekt umgesetzt. TripSync soll die Urlaubsplanung vereinfachen und alle wichtigen Funktionen in einer App vereinen. Im Zuge der vorgegebenen 82 h habe ich mich dabei auf die wichtigsten Funktionen und Screens fokussiert. Screens und deren Features Die App beinhaltet eine Authentifizierung, sodass die Funktionen <a class="read-more" href="https://mobile.fhstp.ac.at/allgemein/projekt-tripsync/">[...]</a></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/projekt-tripsync/">Projekt | TripSync</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Im Zuge der Masterklasse Mobile im 2.Semester habe ich ein neues Semesterprojekt umgesetzt. TripSync soll die Urlaubsplanung vereinfachen und alle wichtigen Funktionen in einer App vereinen. Im Zuge der vorgegebenen 82 h habe ich mich dabei auf die wichtigsten Funktionen und Screens fokussiert.</p>



<h2 class="wp-block-heading">Screens und deren Features</h2>



<p class="wp-block-paragraph">Die App beinhaltet eine Authentifizierung, sodass die Funktionen erst nach dem Login bzw. der Registrierung genutzt werden können.</p>



<h3 class="wp-block-heading">Profil</h3>



<p class="wp-block-paragraph">Hat man sich eingeloggt, kann man in seinem Profil alle seine geplanten Urlaube verwalten. Hier lässt sich einer der aufgelisteten Urlaube auswählen, der dann für alle anderen Tabs bzw. Screens gilt. Man kann einen neuen erstellen, einem beitreten oder einen löschen bzw. verlassen. Im Profil gibt es außerdem die Möglichkeit sich über das Menü wieder abzumelden.</p>



<p class="wp-block-paragraph">Um einem Urlaub beizutreten, benötigt man den zugehörigen Code. Dem bzw. der Ersteller*in wird nach dem Erstellen des Urlaubs die Möglichkeit geboten, den Code mittels der „Share“-Funktion zu teilen.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1377" height="660" data-id="14396" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/TripSync_Profile.png" alt="Sceens vom Profil. Diese zeigen die aufgelisteten Urlaube, das Bottom Sheet zum Erstellen und zum Beitreten." class="wp-image-14396"/></figure>
</figure>



<h3 class="wp-block-heading">Info</h3>



<p class="wp-block-paragraph">Auf dem Info-Screen werden alle Informationen zum aktuellen Urlaub angezeigt. Dazu gehören Titel, Zeitraum, Beschreibung und die Teilnehmer*innen. Hierbei kann man die Informationen auch bearbeiten und den Code nochmals teilen, falls man noch wen hinzufügen möchte.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1377" height="660" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/TripSync_Info.png" alt="Sceens von der Infoseite. Diese zeigen alle Informationen vom Urlaub, das Bottom Sheet zum Bearbeiten und zum Teilnehmer hinzufügen." class="wp-image-14397"/></figure>



<h3 class="wp-block-heading">Packliste</h3>



<p class="wp-block-paragraph">Die Packliste ermöglicht es mehreren Personen, gemeinsam eine Urlaubscheckliste zu erstellen und direkt zuzuweisen, wer was mitnimmt. Dabei gibt es oben den allgemeinen Bereich mit noch nicht zugeordneten Gegenständen und nachfolgend für jedes Mitglied einen eigenen, angefangen mit sich selbst. Es können Einträge hinzugefügt, gelöscht, in den eigenen oder in den allgemeinen Bereich verschoben und als eingepackt markiert werden.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1377" height="660" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/TripSync_Packliste.png" alt="" class="wp-image-14398"/></figure>



<h3 class="wp-block-heading">Restliche Screens</h3>



<p class="wp-block-paragraph">Es soll auch noch weitere Screens bzw. Tabs geben, die beispielsweise einen Kostenrechner oder gemeinsame Notizen beinhalten. Im Zuge der 82 h wurden diese aber nicht umgesetzt.</p>



<h2 class="wp-block-heading">Technologien</h2>



<h3 class="wp-block-heading">Backend</h3>



<ul class="wp-block-list">
<li>NestJS</li>



<li>Prisma</li>



<li>Zod und zod-prisma-type für Type Generation</li>



<li>Swagger</li>



<li>Docker</li>
</ul>



<h3 class="wp-block-heading">Frontend</h3>



<ul class="wp-block-list">
<li>React Native mit Expo</li>



<li>Native Wind (Tailwind für React Native)</li>



<li>Zustand für State Management</li>



<li>OpenAPI Generator</li>



<li>Libraries: react-native-bottom-sheet, react-native-elements, react-native-bouncy-checkbox etc.</li>
</ul>



<h2 class="wp-block-heading">Challenges und Learnings</h2>



<h3 class="wp-block-heading">Backend</h3>



<p class="wp-block-paragraph">Im Backend interessierte mich die Verwendung von Prisma. Dabei hat man ein zentrales Schema-File und kann sich die Types generieren lassen. Zusätzlich zu den generierten Types brauchte ich jedoch eigene DTOs, die ich mittels zod Schemas und Helper Methods umsetze. Ich habe auch auf eine ordentliche Swagger Dokumentation geachtet, sodass ich dann im Stande war, OpenAPI Generator für das Frontend zu verwenden. Es war einerseits sehr praktisch sich darum nicht kümmern zu müssen, andererseits wurde es mühsam, wenn man beispielsweise den Typ eines Objekts brauchte, welches nur innerhalb eines Arrays vorkommt. Diese stehen einem zwar auch zur Verfügung, doch die Namen werden immer länger und unleserlicher. Ich habe dann in solchen Fällen begonnen, eigene Types zu erstellen, die dann auf die generierten verweisen.</p>



<p class="wp-block-paragraph">Es war anfangs eine Challenge herauszufinden, wie man bei zod Schemas Beispielwerte für Swagger mitgibt. Die Library @anatine/zod-openapi bietet hierbei mittels Methoden wie extendApi die Lösung.</p>



<p class="wp-block-paragraph">Nachdem wir dieses Semester einen Docker-Workshop hatten, entschied ich mich dafür Docker auch für dieses Projekt zu verwenden und setzte erstmals alles selbst auf.</p>



<h3 class="wp-block-heading">Frontend</h3>



<p class="wp-block-paragraph">Im Frontend musste ich mich erstmal zurechtfinden, da ich zwar bereits React verwendet hatte, aber nicht React Native. Anfangs war für mich klar, dass ich auch Native Wind einbaue, da ich sehr oft Tailwind CSS nutze. Bei Komponenten aus Libraries ist jedoch das Problem, dass viele (noch) kein Native Wind unterstützen, und somit musste ich oftmals auf gutes altes CSS zurückgreifen. Allgemein hatte ich das Gefühl, dass man bei React Native sehr oft auf Libraries der Community angewiesen ist, da React Native selbst nicht viele vorgestylte Komponenten bietet. Das ist ein Unterschied zu Ionic, den ich bemerkt habe.</p>



<p class="wp-block-paragraph">Unter anderem verwendete ich das UI-Toolkit React Native Elements. Dieses kommt mit der Option, ein Theme zu erstellen, wobei neben Farben auch die default Styles der Komponenten festgelegt werden können, was sehr hilfreich war. React Native selbst bietet auch ein Color Theme, wodurch ich im Endeffekt beide nutze. Man müsste sich hier noch besser einlesen, was hierbei die Best Practice Lösung ist.</p>



<p class="wp-block-paragraph">An der Kombination React Native mit Expo war sehr praktisch, dass man Änderungen mittels der Expo Go App schnell auf seinem Handy testen konnte. Das war auch sehr nötig, denn schnell wurde klar, es ist nicht so einfach die App bzw. die externen Komponenten auf jeder Plattform zum Laufen zu bringen, ohne dass unerwartete Verhaltensweisen auftreten. Manchmal gibt es auch Libraries, die nur Komponenten für iOS und Android zur Verfügung stellen, wodurch das Testen im Web schwierig wird.</p>



<p class="wp-block-paragraph">Neben React Native habe ich mich im Rahmen des Projekts intensiv mit Zustand beschäftigt. Im Vergleich zu Redux ist es eine einfachere State Management Lösung, welche aber trotzdem eine Vielzahl nützlicher Features bietet. Um Logik zu trennen, habe ich meinen Store in Slices unterteilt. Zustand bietet außerdem die Funktion, den Store zu persistieren, wodurch ich manche Daten, wie z.B. den bzw. die User*in, den aktuellen Urlaub etc., zusätzlich lokal speichern konnte.</p>



<h2 class="wp-block-heading">Fazit</h2>



<p class="wp-block-paragraph">Das Projekt hat mir vor allem einen Einblick in React Native mit Expo gegeben. Das Framework ist einerseits sehr mächtig, auf der anderen Seite können die vielen externen Komponenten mühsam werden. Ich habe aber auch viel Neues in Bezug auf Zustand und Prisma in Kombination mit zod gelernt. Auch die gesehenen Vor- und Nachteile von OpenAPI Generator werden hilfreich für weitere Projekte sein.</p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/projekt-tripsync/">Projekt | TripSync</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Blog &#124; MoveMates</title>
		<link>https://mobile.fhstp.ac.at/development/blog-movemates/</link>
		
		<dc:creator><![CDATA[Caroline Labres]]></dc:creator>
		<pubDate>Wed, 11 Jun 2025 18:34:10 +0000</pubDate>
				<category><![CDATA[Cross Plattform]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Dokumentation]]></category>
		<category><![CDATA[Projekte]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Studium]]></category>
		<category><![CDATA[Tests]]></category>
		<category><![CDATA[Workshop]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[Extreme Programming Week]]></category>
		<category><![CDATA[Gitlab]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[Sensoren]]></category>
		<category><![CDATA[websockets]]></category>
		<category><![CDATA[Wild Week]]></category>
		<guid isPermaLink="false">https://mobile.fhstp.ac.at/?p=14255</guid>

					<description><![CDATA[<p>Am Anfang des 2. Semesters des Master-Studiengangs Interactive Technologies (Masterklasse Mobile) fand die “Extreme Programming Week” statt (auch “Wild Week” genannt). Für diese Woche bekamen wir die Challenge, als ganze Masterklasse gemeinsam (insgesamt 8 Personen) innerhalb von 5 Tagen (Montag bis Freitag) eine App zu entwickeln. Die konkrete Aufgabenstellung erhielten wir erst am Montag, und <a class="read-more" href="https://mobile.fhstp.ac.at/development/blog-movemates/">[...]</a></p>
<p>The post <a href="https://mobile.fhstp.ac.at/development/blog-movemates/">Blog | MoveMates</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Am Anfang des 2. Semesters des Master-Studiengangs Interactive Technologies (Masterklasse Mobile) fand die “Extreme Programming Week” statt (auch “Wild Week” genannt). Für diese Woche bekamen wir die Challenge, als ganze Masterklasse gemeinsam (insgesamt 8 Personen) innerhalb von 5 Tagen (Montag bis Freitag) eine App zu entwickeln. Die konkrete Aufgabenstellung erhielten wir erst am Montag, und am Freitagnachmittag sollte die MVP-Version präsentiert werden.</p>



<h2 class="wp-block-heading">Aufgabenstellung</h2>



<p class="wp-block-paragraph">Die Aufgabenstellung und das MVP wurde uns größtenteils vorgegeben, wobei wir vor allem bei den optionalen zusätzlichen Features mitreden konnten. Prinzipiell war die Idee, eine App zu entwickeln, über die man gewisse Echtzeitdaten wie Standort, Geschwindigkeit, Herzfrequenz etc. mit einer Gruppe austauscht. Einsatzbereiche gibt es dabei mehrere. Beispielsweise könnte man sich auf den Sport- (Laufen, Radfahren etc.) oder auf den Gesundheitsbereich (inkl. Fallerkennung) fokussieren. Letztendlich haben wir uns für den Bereich &#8220;gegeneinander Laufen&#8221; entschieden.</p>



<h3 class="wp-block-heading">MVP (Minimum Viable Product)</h3>



<p class="wp-block-paragraph">Um am Ende sagen zu können, dass wir die Aufgabe gemeistert haben, wurde ein MVP (Minimum Viable Product) mit den grundlegendsten Funktionen definiert. Was den Client betrifft, waren das Auslesen und sinnvolle Übertragen von Sensor-Daten, Login und Teambildung aber auch eine “coole Darstellung” wichtig. Vor allem beim letzten Punkt sollten wir uns wirklich Gedanken machen, was im Kontext gut funktioniert, anstatt einfach nur alle Daten in Zahlenform anzuzeigen.<br>Serverseitig lag der Fokus auf der Verteilung der Daten in Echtzeit im Team.<br>Außerdem sollte die App auf mindestens einer Plattform nativ im Testmodus verfügbar sein.</p>



<h3 class="wp-block-heading">NTH (Nice to Have)</h3>



<p class="wp-block-paragraph">Neben dem MVP wurden auch optionale Features notiert, genannt “Nice to Haves”, die dann umgesetzt werden sollten, sobald das MVP fertig ist. Diese Liste wurde auch während der Woche erweitert.<br>Dazu gehörte die Distribution auf beiden Plattformen (iOS und Android) oder das Einführen eines Handicaps, welches dazu genutzt werden kann, dass unterschiedlich starke Leute in einer Sportart gegeneinander antreten können. Eine History vergangener Sessions, eine Exportmöglichkeit der Daten, Gamification, das Laufen der App im Hintergrund, Micro-Interactions und Vibration waren ebenso Punkte auf dieser Liste. Andere Ideen waren die Berechnung eines Leistungswerts, Tests oder die Verwendung eines QR-Codes zur Gruppenbildung.</p>



<h2 class="wp-block-heading">Verwendete Technologien</h2>



<p class="wp-block-paragraph">Im Projekt setzten wir auf Technologien, die wir bereits im vorherigen Semester kennenlernen durften bzw. mit denen einige unserer Gruppenmitglieder*innen bereits Erfahrung hatten. Von Anfang an war klar, dass sich eine native Umsetzung unserer App für sowohl Android als auch iOS wohl zeitlich nicht ausgehen würde, weshalb wir im Frontend auf eine Cross-Plattform Technologie setzten.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="5831" height="1080" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/tech_stack_diagram.jpg" alt="" class="wp-image-14288" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/tech_stack_diagram.jpg 5831w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/tech_stack_diagram-1536x284.jpg 1536w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/tech_stack_diagram-2048x379.jpg 2048w" sizes="auto, (max-width: 5831px) 100vw, 5831px" /><figcaption class="wp-element-caption"><strong>Zusammenspiel der verwendeten Technologien und Infrastruktur</strong></figcaption></figure>



<h3 class="wp-block-heading">Frontend</h3>



<p class="wp-block-paragraph">Im Frontend arbeiteten wir mit dem Cross-Platform Framework Ionic (Capacitor), in Kombination mit der Frontend-Technologie React &#8211; geschrieben in Typescript. Die Wahl fiel darauf, da wir im 1. Semester unseres Studiums sowohl ein Projekt mit React umsetzen mussten, als auch in unserer Masterklasse mit dem Ionic Framework arbeiteten.</p>



<p class="wp-block-paragraph">Die ersten Screen-Prototypes designten wir mit der Design-Software Figma.</p>



<h3 class="wp-block-heading">Backend</h3>



<p class="wp-block-paragraph">Im Backend verwendeten wir NestJS, ebenfalls in Kombination mit Typescript, da wir diese Backend-Technologie ebenfalls im 1. Semester unserer Masterklasse in einem Projekt verwendeten und so die Einstiegshürde wegfiel.</p>



<p class="wp-block-paragraph">Da unsere App sehr stark auf Live-Daten angewiesen ist (sowohl das Senden der aktuellen Sensordaten eines Users, als auch das Erhalten der Live-Daten anderer User während einer Aktivität), entschieden wir uns, hierfür auf Websockets zurückzugreifen, welche nahtlos in NestJS unterstützt wurden. Beim Erstellen einer Session für alle Teilnehmer*innen wurde ein Websocket &#8220;Topic&#8221; erstellt, welches in den Apps aller Nutzer*innen subscribed werden konnte und mit welchem immer die aktuellen Live-Daten in einem fest definierten Intervall ausgetauscht wurden.</p>



<h4 class="wp-block-heading">Datenbank</h4>



<p class="wp-block-paragraph">Für die Persistenz unserer Daten setzten wir auf eine PostgreSQL Datenbank, ergänzt durch den Object-Relational Mapper (ORM) TypeORM. Wir wählten PostgreSQL aufgrund seiner Zuverlässigkeit und weiten Verbreitung als relationale Datenbank, was uns eine solide Basis für unsere Anwendung bot und zukünftige Skalierbarkeit ermöglichte. Ein weiterer ausschlaggebender Faktor war die exzellente Kompatibilität mit NestJS und die vorhandene Teamerfahrung mit TypeORM.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1111" height="651" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/06/ER-Modell-Komplett.drawio-1.png" alt="" class="wp-image-14372"/><figcaption class="wp-element-caption"><strong>ER-Diagramm der movemates DB</strong></figcaption></figure>



<p class="wp-block-paragraph">Die Struktur unserer Datenbank wird ist in diesem ER-Diagramm veranschaulicht. Die Kernentitäten bilden  User, Session und Messerwerte. Zwischen :</p>



<ul class="wp-block-list">
<li>User<strong>:</strong> Hier hinterlegen wir alle notwendigen Benutzerinformationen, darunter Id, Vorname, Nachname, Email, Passwort und physiologische Daten wie Geburtsdatum, Groesse, Gewicht und Geschlecht. Diese Informationen sind essenziell, insbesondere das Geburtsdatum für die Berechnung der individuellen Herzfrequenzzonen.</li>



<li>Session<strong>:</strong> Diese Entität verwaltet die Details der Lauf-Sessions, wie Id, Status, Enddatum, Typ und Startdatum.</li>



<li>User_Session<strong>:</strong> Als Verbindungstabelle stellt sie die Beziehung zwischen Benutzern und Sessions dar und speichert die Rolle des Teilnehmers innerhalb einer Session.</li>



<li>Messwerte<strong>:</strong> Diese zentrale Entität ist für die Speicherung der während einer aktiven Session gesammelten Sensordaten zuständig. Dazu gehören Zeitstempel, Geschwindigkeit, Breitengrad, Längengrad, Lage, Richtung, Herzfrequenz und Schrittfrequenz. Diese Daten bilden die Grundlage für unsere Echtzeitanzeigen und potenzielle historische Analysen.</li>
</ul>



<p class="wp-block-paragraph">Mit unserer PostgreSQL DB wird somit das Rückgrat unserer App, indem alle statischen Benutzer- und Sitzungsdaten sowie die dynamischen Sensordaten gespeichert sind, die für die Kernfunktionen und die Visualisierung notwendig sind, gebildet.</p>



<p class="wp-block-paragraph">Um diese DB stabil und einfach zu handhaben, nutzten wir Docker. Das erlaubte uns, die PostgreSQL-Datenbank in einem eigenen, isolierten &#8220;Container&#8221; laufen zu lassen. Dies vereinfacht nicht nur die Einrichtung erheblich, sondern stellt auch sicher, dass die Datenbank immer in einer konsistenten Umgebung läuft und ihre Daten sicher verwahrt bleiben. Dank dieser Docker-Einrichtung konnte sich unser Backend-Service problemlos und zuverlässig mit der Datenbank verbinden, sobald diese bereit war. Die Konfiguration mit TypeORM wiederum sorgte dafür, dass unsere App die Daten korrekt lesen, schreiben und verwalten konnte. Besonders wichtig dabei waren unsere TypeORM Datenbank-Migrationen. Diese funktionieren wie kleine, versionierte Skripte, die es uns ermöglichten, die Struktur der Datenbank (wie z.B. neue Spalten hinzufügen oder bestehende ändern) im Laufe der Entwicklung schrittweise und kontrolliert anzupassen, ohne Daten zu verlieren.</p>



<h4 class="wp-block-heading">OpenAPI</h4>



<p class="wp-block-paragraph">Damit wir in unserem Frontend nicht noch einmal alle Backend Objekte doppelt anführen müssen und um Zeit zu sparen, haben wir uns dazu entscheiden, den OpenAPI Generator zu verwenden. Die grundsätzliche Funktion von diesem ist, dass man im Backend mithilfe eines Decorators, wie Swagger, die Endpunkte definiert und dokumentiert. Mithilfe dieser Dokumentation, kann man dann für das Frontend Client-Funktionen erstellen lassen, welche mit dem Backend konsistent und typensicher sind. In unserem Backend haben wir Swagger verwendet, um per Decorator die Endpoint Spezifikationen anzugeben. Im Frontend haben wir dann die <em>@openapitools/openapi-generator-cli</em> installiert, welche einen Befehl bereitstellt, mit welchem man die API erstellen kann. Davor ist noch eine OpenAPI Spec Datei benötigt, welche openapitool.json heißt, in welcher man die Einstellungen für die API angibt. Danach kann man jederzeit die API generieren lassen und sie verwenden.</p>



<h3 class="wp-block-heading">CI/CD</h3>



<p class="wp-block-paragraph">Für unsere Backend-Applikation wurde uns ein Server auf unserer FH-Cloud zur Verfügung gestellt. Haben wir nun unsere NestJS Applikation per FTP auf diesen Server geladen? Natürlich nicht! Haben wir stattdessen viel Zeit in Continuous Integration und Deployment (CI/CD) investiert? Selbstverständlich! Schon am ersten Tag der Woche haben wir ein docker-compose.yml geschrieben. Damit ließ sich die Backend-Applikation mit einer Postgres Datenbank starten. Mit&nbsp;der Unterstützung unseres Masterklassenleiters Armin haben wir am Morgen des zweiten Tages Docker auf unserem Server installiert. Dann haben wir einen GitLab Runner mit dem Shell Executor eingerichtet und das .gitlab-ci.yml geschrieben. Darin haben wir einen Deploy Job definiert, der bei einem Commit auf den “main” Branch docker-compose ausführt und damit die neueste Version der Anwendung auf unserem Server startet. Ebenfalls haben wir den Build unserer Android-App automatisiert. Dafür brauchte es einen Job um die Dependencies der Ionic App zu installieren, einen Job um die Frontend-Applikation zu bauen, einen um das .apk zu bauen und schließlich einen Job um das .apk zu publishen. Damit wir reproduzierbare Builds und einen sauberen Server haben, wollten wir all diese Jobs in Containern ausführen. Dazu mussten wir einen weiteren GitLab Runner aufsetzen, der dieses Mal den Docker Executor verwendet. Der Build der Android App verwendet das Image alvrme/alpine-android und die anderen ein simples Node.js Image. Continuous Deployment war geschafft, Continuous Integration folgte.</p>



<p class="wp-block-paragraph">Wenn man ein neues NestJS-Projekt startet, werden automatisch <a href="https://eslint.org/">Eslint</a> mit <a href="https://prettier.io/">Prettier</a> und <a href="https://jestjs.io/">Jest</a> eingerichtet. Damit das Code-Linting/Formatting und die Tests auch in der Pipeline ausgeführt werden, haben wir dafür jeweils einen Job in einem “test” Step in unsere Pipeline erstellt. Vorgelagert findet ein Job statt, der die Dependencies installiert. Alle drei Jobs werden in einem Node.js Image ausgeführt. Hätten wir noch mehr Zeit gehabt, hätten wir noch für das Frontend einen Linting- und Test-Job erstellt.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1383" height="158" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/image2.png" alt="" class="wp-image-14285" style="object-fit:cover"/><figcaption class="wp-element-caption"><strong>Visualisierung unserer GitLab CI/CD Pipeline</strong></figcaption></figure>



<p class="wp-block-paragraph">Im Hinblick auf CI war zwar die Basis für Unit Tests im Backend gelegt, aber leider fehlten uns die Tests, um wirklich Nutzen davon zu haben. Der <a href="https://docs.gitlab.com/ci/testing/unit_test_reports/">GitLab Test Reporter</a> zeigt die traurige Situation unserer Unit Tests (siehe folgenden Screenshot). Um das zu kompensieren, haben wir End-To-End-Tests geschrieben, die zumindest einen Teil der User Flows abdecken. Mit <a href="https://www.cypress.io/">Cypress</a> durchlaufen wir den Registrierungs- und Anmeldeprozess und starten einen neuen Gruppenaktivität. Die Cypress Tests werden leider nicht in der Pipeline ausgeführt, da unsere GitLab Runner mit den existierenden Jobs bereits alle Hände voll zu tun hatten. Gegen Ende der Woche, als der Zeitdruck stieg, mussten wir sogar manche Pipeline Steps deaktivieren, um das Deployment zu beschleunigen.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="952" height="615" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/image3.png" alt="" class="wp-image-14286"/><figcaption class="wp-element-caption"><strong>Erfolgreich durchgelaufene Pipeline (32 Minuten!)</strong></figcaption></figure>



<h4 class="wp-block-heading">Internes App-Publishing</h4>



<p class="wp-block-paragraph">Eine der Anforderungen unserer Auftraggeber war es, die fertige App auch auf zumindest einer der beiden Plattformen auf eine beliebige Weise öffentlich zur Verfügung zu stellen. Wir entschieden uns dafür Firebase App Distribution zu verwenden, um unsere Android App einer fest definierten Personengruppe ausliefern zu können. Es wurde ein Build Job in unserer GitLab Pipeline eingerichtet, der uns ein APK-File gebaut hat und dieses über die Firebase CLI in einen geschlossenen Test hochgeladen hat, in denen sowohl alle Teammitglieder*innen als auch unsere Dozenten eingeladen wurden. So wurde nach jedem Commit auf unseren master-branch eine neue App-Version veröffentlicht, die mit einem Klick in der Firebase App Distribution App heruntergeladen werden konnte.</p>



<h3 class="wp-block-heading">Sensoren</h3>



<p class="wp-block-paragraph">In Bezug auf Sensoren wurden wir mit verschiedenen Heart Rate Monitors (HRMs) wie Wahoo Tickr Fit und einem Modell von Moofit ausgestattet. Um diese Daten auslesen zu können, haben wir das Capacitor Community Plugin “Bluetooth Low Energy” verwendet.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="3024" height="4032" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/hrm-rotated.jpeg" alt="" class="wp-image-14278" style="width:auto;height:400px" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/hrm-rotated.jpeg 3024w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/hrm-1152x1536.jpeg 1152w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/hrm-1536x2048.jpeg 1536w" sizes="auto, (max-width: 3024px) 100vw, 3024px" /><figcaption class="wp-element-caption"><strong>Beispiel: Einer der verwendeten Herzfrequenzsensoren</strong></figcaption></figure>



<h2 class="wp-block-heading">Arbeitsablauf</h2>



<p class="wp-block-paragraph">Generell haben wir beschlossen, dass wir jeden Tag um 9 Uhr mit der Arbeit beginnen werden. Wir haben auch die gesamte Woche vor Ort gearbeitet, da wir es als die bessere Option empfunden haben und gehört haben, wie schlecht es der Gruppe ging, welche nur im Home Office gearbeitet hat. Um uns besser organisieren zu können, haben wir jeden Tag um 10:00 ein Daily Standup abgehalten, wo wir unseren derzeitigen Stand den Dozenten gezeigt und erklärt haben und wir Feedback auf diesen erhalten haben. Bei diesen Standups haben wir auch unsere Ziele für den Tag festgelegt, damit wir wissen, auf was wir uns fokussieren werden.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-3 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="4624" height="3468" data-id="14281" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/standup1.jpg" alt="" class="wp-image-14281" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/standup1.jpg 4624w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/standup1-1536x1152.jpg 1536w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/standup1-2048x1536.jpg 2048w" sizes="auto, (max-width: 4624px) 100vw, 4624px" /></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="3472" height="4624" data-id="14282" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/standup2.jpg" alt="" class="wp-image-14282" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/standup2.jpg 3472w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/standup2-1153x1536.jpg 1153w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/standup2-1538x2048.jpg 1538w" sizes="auto, (max-width: 3472px) 100vw, 3472px" /></figure>
<figcaption class="blocks-gallery-caption wp-element-caption"><strong>Daily Standup: Zieldefinition für den Arbeitstag</strong></figcaption></figure>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Ziel des ersten Tages war es, ein Monorepo auf GitLab anzulegen und das Projekt zu initialisieren. Im Frontend beschäftigten wir uns mit den ersten Sensoren, und im Backend wurde die Datenbank aufgesetzt und mit den Websockets begonnen. Weiters richteten wir Firebase App Distribution für die Android Plattform ein.</p>



<p class="wp-block-paragraph">Am Dienstag besprochen wir, wie unsere Entities/Daten aussehen würden. Das Feature “User Registrierung und Login” wurde implementiert, und wir machten uns Gedanken über das UI-Konzept und die Datenvisualisierung. Zusätzlich überlegten wir uns die Verwendung und Berechnung der Rohdaten der Sensoren, und implementierten automatisierte Android Builds.</p>



<p class="wp-block-paragraph">Am Mittwoch, nachdem wir Feedback zu unserem UI-Konzept erhielten, verfeinerten wir dieses und überlegten uns ein bestimmtes Szenario für die Datenvisualisierung. Danach machten wir uns daran, die UI umzusetzen, ClientSDK zu generieren und Endpoints und Services im Backend zu erstellen. Weitere Ziele waren, Sensordaten über Websockets schicken und empfangen zu können, und eine Session sowohl im Frontend als auch im Backend erstellen zu können.</p>



<p class="wp-block-paragraph">In den letzten beiden Tagen ging es darum, alle Features des MVP fertigzustellen und letzte Bugs zu fixen. Dazu gehörten: Auth (Route Guard, Token, …), alles rund um Sessions (Create, Join, End, Leave), die Kommunikation der Daten über Websockets, Edit Profile, Datenvalidierung (null, -1, …), Loading Indicator, und mehr.</p>



<p class="wp-block-paragraph">Am Freitagnachmittag wurde das Endprodukt präsentiert &#8211; mehr dazu etwas später in diesem Blogbeitrag.</p>



<p class="wp-block-paragraph">Neben der Arbeit kam aber auch nicht der Spaß zu kurz. Darum nutzten wir als Team am 4. Tag der Wild Week (Donnerstag) die Möglichkeit, beim FH internen “IMFix” Event vorbeizuschauen. Neben Snacks, Bier und guter Laune konnten wir uns bei mehreren Multiplayer Spielen entspannen, bevor es dann in die heiße Endphase des Projektes ging.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-4 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1080" height="1920" data-id="14259" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/imfix_1.jpg" alt="" class="wp-image-14259" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/imfix_1.jpg 1080w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/imfix_1-864x1536.jpg 864w" sizes="auto, (max-width: 1080px) 100vw, 1080px" /></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="3024" height="4032" data-id="14262" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/imfix_2-2-rotated.jpeg" alt="" class="wp-image-14262" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/imfix_2-2-rotated.jpeg 3024w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/imfix_2-2-1152x1536.jpeg 1152w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/imfix_2-2-1536x2048.jpeg 1536w" sizes="auto, (max-width: 3024px) 100vw, 3024px" /></figure>
<figcaption class="blocks-gallery-caption wp-element-caption"><strong>Kurze Verschnaufpause beim IMFix Event &#8211; <em>&#8220;Don&#8217;t drink and drive&#8221;</em> wurde hier ausnahmsweise mal nicht ganz ernst genommen.</strong></figcaption></figure>



<h2 class="wp-block-heading">Abgeliefertes Endprodukt</h2>



<p class="wp-block-paragraph">Unsere App ist in mehrere übersichtliche Screens unterteilt, die den User Schritt für Schritt durch den gesamten Ablauf führen. Von der Anmeldung über die Erstellung oder Teilnahme an einer Session bis hin zur aktiven Nutzung während eines Laufs sind alle Funktionen klar strukturiert. Im Mittelpunkt stehen dabei das Dashboard als zentrale Steuerzentrale, der WaitingScreen zur Organisation der Teilnehmer*innen, sowie das Userprofil, in dem persönliche Daten verwaltet werden können. Während einer aktiven Session rücken das Leaderboard und die Kartenansicht in den Vordergrund. Hier werden in Echtzeit alle relevanten Informationen der Teilnehmer*innen angezeigt.&nbsp;<br>Bevor jedoch der eigentliche Ablauf startet, erfolgt der Einstieg über den Login oder die Registrierung.</p>



<h3 class="wp-block-heading">Login und Registrierung</h3>



<p class="wp-block-paragraph">Beim ersten Öffnen der App wird der User auf den Login-Screen weitergeleitet. Hier kann man sich entweder mit bestehenden Zugangsdaten anmelden oder sich neu registrieren. Die Registrierung erfolgt über ein kurzes Formular, bei dem grundlegende Daten wie Benutzername, E-Mail-Adresse und Passwort abgefragt werden.</p>



<h3 class="wp-block-heading">Dashboard</h3>



<p class="wp-block-paragraph">Sobald der Login oder die Registrierung abgeschlossen ist, gelangt der User auf das Dashboard. Hier stehen zwei Optionen zur Verfügung: Entweder eine neue Session zu erstellen oder einer bestehenden Session beizutreten. Diese Optionen sind jedoch zu Beginn ausgegraut dargestellt und können erst genutzt werden, wenn bestimmte Voraussetzungen erfüllt sind.</p>



<p class="wp-block-paragraph">Auf dem Dashboard befinden sich drei Buttons zur Aktivierung der benötigten Sensoren:</p>



<ul class="wp-block-list">
<li><strong>GPS</strong></li>



<li><strong>Herzfrequenzsensor</strong> (inkl. Bluetooth-Verbindung zu einem Wearable)</li>



<li><strong>Heading-Sensor</strong></li>
</ul>



<p class="wp-block-paragraph">Zu Beginn sind alle drei Buttons rot eingefärbt, um anzuzeigen, dass die jeweiligen Sensoren noch nicht aktiv sind. Nach dem erfolgreichen Aktivieren – sei es durch das Einschalten eines Gerätesensors oder die Herstellung einer Verbindung – wechselt die Farbe auf grün, was visuell signalisiert, dass der jeweilige Sensor nun einsatzbereit ist.</p>



<p class="wp-block-paragraph">Erst wenn entweder das GPS-Signal oder der Herzfrequenzsensor aktiviert wurde, werden die beiden Optionen „Session erstellen“ und „Session beitreten“ freigeschaltet und können ausgewählt werden. Optional kann zusätzlich der Heading-Sensor aktiviert werden, der später auf der Karte eine genauere Bewegungsrichtung ermöglicht.</p>



<p class="wp-block-paragraph">Beim Beitritt zu einer Session muss zuvor die Session-ID, die man über einen QR-Code oder eine Nachricht erhalten hat, in ein Inputfeld eingegeben werden. Danach geht es automatisch weiter zum nächsten Screen.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="1170" height="2532" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/dashboard.png" alt="" class="wp-image-14272" style="width:auto;height:400px" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/dashboard.png 1170w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/dashboard-710x1536.png 710w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/dashboard-946x2048.png 946w" sizes="auto, (max-width: 1170px) 100vw, 1170px" /><figcaption class="wp-element-caption"><strong>Screenshot: Dashboard</strong></figcaption></figure>



<h3 class="wp-block-heading">WaitingScreen</h3>



<p class="wp-block-paragraph">Am WaitingScreen wird die aktuelle Teilnehmerliste angezeigt. Dort sieht der User, wer sich bereits angemeldet hat. Die Liste aktualisiert sich automatisch, sobald weitere Personen hinzukommen.</p>



<p class="wp-block-paragraph">Über den Abmelde-Button kann sich der User jederzeit wieder von der Session entfernen. Man wird dabei direkt zurück ins Dashboard geleitet. Sollte jedoch der Host selbst auf „Abmelden“ klicken, wird nicht nur die eigene Verbindung getrennt, sondern die komplette Session gelöscht, inklusive aller Teilnehmerinnen. Auch in diesem Fall gelangen alle automatisch zurück ins Dashboard.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="1170" height="2532" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/waitingscreen.jpg" alt="" class="wp-image-14273" style="width:auto;height:400px" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/waitingscreen.jpg 1170w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/waitingscreen-710x1536.jpg 710w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/waitingscreen-946x2048.jpg 946w" sizes="auto, (max-width: 1170px) 100vw, 1170px" /><figcaption class="wp-element-caption"><strong>Screenshot: WaitingScreen</strong></figcaption></figure>



<h3 class="wp-block-heading">QR-Modal</h3>



<p class="wp-block-paragraph">Für den Ersteller der Session gibt es die Möglichkeit, einen QR-Code zu generieren. Dieser Button befindet sich oberhalb der Teilnehmerliste. Nach dem Klick öffnet sich ein Modal, in dem der QR-Code angezeigt wird. Dieser enthält die Session-ID und kann über einen Button ebenso in die Zwischenablage kopiert werden. Zusätzlich gibt es die Möglichkeit, die Session-ID direkt per Nachricht oder Social Media zu teilen. Wenn der Host entscheidet, dass alle bereit sind, kann die Session jederzeit über den Start-Button gestartet werden.</p>



<p class="wp-block-paragraph">Sobald der Host einer Session auf “Start” klickt, kommen alle User*innen einer Session auf das Leaderboard. Dort befindet sich das Grundkonzept unserer App. Ganz oben am Screen findet man zwei Tabs, um zwischen 2 Ansichten zu wechseln: das Leaderboard und die Kartenansicht.</p>



<h3 class="wp-block-heading">Leaderboard</h3>



<p class="wp-block-paragraph">Oben am Bildschirm findet der*die User*in die Ranganzeige. Der eigene Rang wird ziemlich groß dargestellt, damit man sofort erkennt, wo man sich am Leaderboard befindet. Gleich darunter findet sich das eigentlich wichtigste Feature unserer App, nämlich die visuelle Anzeige der Herzfrequenz und der Geschwindigkeit. Die Herzfrequenz wird bei uns in 3 Zonen eingeteilt. In der mittleren Zone befindet sich die &#8220;ideale Herzfrequenz&#8221; für den*die User*in für die aktuelle Aktivität. Sobald man sich in der linken oder in der rechten Zone befindet, bedeutet das, dass die Herzfrequenz zu niedrig bzw. zu hoch ist. Die &#8220;ideale Herzfrequenz&#8221; berechnet sich aus dem Alter des Users bzw. der Userin, damit die Fairness bei Teilnehmer*innen unterschiedlichen Alters erhalten bleibt. Die visuelle Darstellung wurde als Balken gelöst, da wir so die 3 Zonen in Farben unterteilen konnten und die aktive Herzfrequenz auf diesem Balken hin- und herwandern kann. Innerhalb der Balken befindet sich auch die Anzahl der Punkte, die man bekommt, je nachdem, in welcher Zone man sich befindet. Das Punktesystem für die Herzfrequenz wurde so gelöst, dass nur die mittlere Zone, also Zone 2, die meisten Punkte (+5 Punkte) bekommt. Die anderen zwei Zonen bekommen jeweils +2 Punkte. Somit bekommt der*die Nutzer*in alle 3 Sekunden, je nach Zone, die Punkte gutgeschrieben.&nbsp;</p>



<p class="wp-block-paragraph">Unterhalb des Herzfrequenz-Balkens befindet sich der Geschwindigkeits-Balken, dieser basiert auf dem gleichen Prinzip. Je nach Geschwindigkeit gehen die Punkte nach oben, je schneller desto mehr Punkte. Auch hier wurde der Balken in mehrere Zonen unterteilt, die farblich markiert sind.</p>



<p class="wp-block-paragraph">Unterhalb der beiden Balken befindet sich auch schon das Leaderboard. Dort werden alle Teilnehmer*innen angezeigt, sowie deren Punktzahl. Alle Punkte werden permanent alle 3 Sekunden geupdatet, damit das Board ständig in Bewegung ist. Wenn sich Plätze ändern, passiert dies in einer überlappenden Animation. Außerdem werden Plätze 1-3 in den klassischen Farben Gold, Silber, Bronze dargestellt.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="1170" height="2532" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/leaderboard.jpg" alt="" class="wp-image-14274" style="width:185px;height:auto" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/leaderboard.jpg 1170w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/leaderboard-710x1536.jpg 710w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/leaderboard-946x2048.jpg 946w" sizes="auto, (max-width: 1170px) 100vw, 1170px" /><figcaption class="wp-element-caption"><strong>Screenshot: Leaderboard</strong></figcaption></figure>



<h3 class="wp-block-heading">Kartenansicht</h3>



<p class="wp-block-paragraph">Auf dieser Seite befindet sich eine Karte von &#8220;Leaflet&#8221;, die in voller Bildschirmgröße dargestellt wird. Sie dient dazu, dass man jederzeit alle Teilnehmer*innen aktiv auf der Karte verfolgen kann, sollte sich beispielsweise ein*e User*in in einer anderen Stadt befinden. Alle Teilnehmer*innen werden jeweils als Dreieck, in einer individuellen Farbe, dargestellt. Wir haben uns für Dreiecke entschieden, weil wir so die Richtung anzeigen können, in die sich ein*e Nutzer*in bewegt. Aufgrund zeitlicher Begrenzung war das auch schon die Funktion unserer Karte.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="1170" height="2532" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/map.jpg" alt="" class="wp-image-14275" style="width:auto;height:400px" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/map.jpg 1170w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/map-710x1536.jpg 710w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/map-946x2048.jpg 946w" sizes="auto, (max-width: 1170px) 100vw, 1170px" /><figcaption class="wp-element-caption"><strong>Screenshot: Kartenansicht</strong></figcaption></figure>



<h3 class="wp-block-heading">User-Profil</h3>



<p class="wp-block-paragraph">Das Userprofile ist sehr simpel gehalten und bietet nur die Möglichkeit, Daten der Nutzer*innen zu ändern, wie zum Beispiel das Alter. Außerdem befindet sich dort der Logout Button.</p>



<h2 class="wp-block-heading">Endpräsentation und Feedback</h2>



<h3 class="wp-block-heading">Ablauf der Präsentation / Abgabe</h3>



<p class="wp-block-paragraph">Am Nachmittag des fünften und letzten Tags der Extreme Programming Week war es soweit: das Produkt der Woche sollte präsentiert werden. Kurz vor dem ausgemachten Termin mit unseren Masterklasseleitern war es noch recht stressig, da noch einige kleine Bugs aufkamen, die gefixt werden mussten. Trotzdem schafften wir es recht pünktlich, mit der App-Demo anzufangen.</p>



<p class="wp-block-paragraph">Zuerst installierten wir die App auf unseren Handys: auf Android via Firebase App Distribution und für iOS direkt von Xcode am Laptop auf das iPhone via USB-Kabel. Danach zeigten wir unseren Masterklasseleitern, wie man sich in der App registrieren und einloggen kann, und wie das Dashboard und die Account-Seite aussehen, sobald man eingeloggt ist. Die Herzfrequenz-Sensoren, welche wir zur Verfügung hatten, wurden unterschiedlichen Personen angelegt und mit Handys verbunden.</p>



<p class="wp-block-paragraph">Schließlich war es Zeit für eine Demonstration der App in einem echten Szenario: eine Person unter uns erstellte eine Session und alle anderen traten dieser bei. Sobald alle drinnen waren, machten wir uns auf den Weg. Während einem Spaziergang rund um das Gebäude (der Rückweg wurde sogar gelaufen!) probierten wir die App aus und beobachteten dabei unsere eigenen Werte (Herzfrequenz, Position, Geschwindigkeit), sowie die Punkte auf dem Leaderboard.</p>



<p class="wp-block-paragraph">Als wir zu dem Raum der Lehrveranstaltung zurückkehrten, gaben unsere Masterklasseleitern ihr Feedback zu unserem Endprodukt. Dadurch, dass wir die Anforderungen des MVP erfüllten, und auch noch einige Nice-To-Have-Funktionalitäten einbauten, war unser Projekt erfolgreich. Wir freuten uns über die positiven Rückmeldungen und über Ideen für mögliche Erweiterungen und Verbesserungen der App.</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-5 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="4032" height="3024" data-id="14267" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/demo1.jpg" alt="" class="wp-image-14267" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/demo1.jpg 4032w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/demo1-1536x1152.jpg 1536w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/demo1-2048x1536.jpg 2048w" sizes="auto, (max-width: 4032px) 100vw, 4032px" /></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="3024" height="4032" data-id="14268" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/demo2.jpg" alt="" class="wp-image-14268" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/demo2.jpg 3024w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/demo2-1152x1536.jpg 1152w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/demo2-1536x2048.jpg 1536w" sizes="auto, (max-width: 3024px) 100vw, 3024px" /></figure>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="3024" height="4032" data-id="14269" src="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/demo3.jpg" alt="" class="wp-image-14269" srcset="https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/demo3.jpg 3024w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/demo3-1152x1536.jpg 1152w, https://mobile.fhstp.ac.at/wp-content/uploads/2025/05/demo3-1536x2048.jpg 1536w" sizes="auto, (max-width: 3024px) 100vw, 3024px" /></figure>
<figcaption class="blocks-gallery-caption wp-element-caption"><strong>Interaktive Live-Demo am Parkplatz der FH St. Pölten</strong></figcaption></figure>



<h3 class="wp-block-heading">Erhaltenes Feedback: Verbesserungspotenzial</h3>



<p class="wp-block-paragraph">Im Laufe der interaktiven Live-Demo und im Anschluss zur Präsentation erhielten wir folgendes Feedback:</p>



<ul class="wp-block-list">
<li>Die WebSocket-Verbindung bricht öfters ab (z.B. beim Wechsel von WLAN zu Mobilen Daten, und auch nach einer Weile von Inaktivität). Eine Möglichkeit, sich (automatisch) wieder verbinden zu können, sollte implementiert werden.</li>



<li>Die Berechnung der Daten (Punkte für das Leaderboard) wird momentan clientseitig durchgeführt. Die Berechnung sollte serverseitig passieren.</li>



<li>Wenn sowohl die Herzfrequenz, als auch die GPS-Daten, null sind, verschwindet der visuelle Balken dieser Person im Leaderboard.</li>



<li>Der Code, der eingegeben werden muss, um einer Session beizutreten, sollte kürzer sein. Zusätzlich wäre ein eingebauter QR-Code-Reader cool. (Dies hatten wir eigentlich vor, es ist sich zeitlich aber leider nicht ganz ausgegangen)</li>



<li>Es wäre gut, während der Session sehen zu können…
<ul class="wp-block-list">
<li>…wie akkurat die Daten sind (z.B. Position).</li>



<li>…ob eine Person einen Herzfrequenz-Sensor verbunden hat. (Zusätzlich wäre es von Vorteil, sich während der Session auch später noch mit einem Herzfrequenz-Sensor verbinden zu können.)</li>



<li>…ob eine Person momentan disconnected ist.</li>
</ul>
</li>



<li>Ein Nice-To-Have wäre noch, dass man in dem Leaderboard während der Session auf einzelne User*innen draufklicken kann, um Detaildaten zu der Person zu sehen. Eventuell könnten in der View die Daten der anderen Person auch gleich mit den eigenen verglichen werden.</li>
</ul>



<h2 class="wp-block-heading">Fazit aller Teilnehmer*innen</h2>



<p class="wp-block-paragraph">Im folgenden Abschnitt möchten wir noch unser Fazit und unsere Erfahrungen teilen, die wir während der Extreme Programming Week sammeln konnten.</p>



<h3 class="wp-block-heading">Katharina</h3>



<p class="wp-block-paragraph">Ich bin sehr stolz auf das, was wir in diesen fünf Tagen geleistet haben. Die Extreme Programming Week hat nicht nur unsere Zeitmanagement-Skills, sondern auch zum ersten Mal unsere koordinierte Zusammenarbeit als Team auf die Probe gestellt. Ich war positiv überrascht, wie gut dies funktioniert hat &#8211; ich glaube, die täglichen Meetings haben sehr stark zu unserem Erfolg beigetragen.</p>



<p class="wp-block-paragraph">Meine Aufgaben während der Woche waren unter anderem das Leiten der Meetings, das Testen und Debuggen der nativen Funktionalitäten (insbesondere auf dem iPhone) und Frontend Development. Dabei habe ich mich zum Beispiel intensiv mit Device-Daten (Geolocation, Accelerometer, Gyroskop, etc.) beschäftigt, um diese einerseits in der App anzuzeigen, und andererseits, um sie zur Berechnung von Herzfrequenzzonen, Kalorienverbrauch und sogar einem Schrittzähler zu verwenden. Letzteres hat es aus Zeitgründen leider nicht in das Endprodukt geschafft, aber die Erfahrungen, welche ich dabei gesammelt habe, bleiben mir erhalten.</p>



<p class="wp-block-paragraph">Im Laufe der Woche hatte ich auch die Möglichkeit, gemeinsam mit Caro im Pair-Programming-Stil an der Authentifizierung im Frontend zu arbeiten. Diese Art des Arbeitens war recht neu für mich, aber ich muss sagen, dass ich eine sehr positive Erfahrung damit gemacht habe &#8211; wenn zwei kreative Köpfe zusammenkommen, kann so einiges entstehen!</p>



<p class="wp-block-paragraph">Zusammenfassend kann man sagen, dass die Woche recht stressig war, besonders gegen Ende hin, aber ich habe sehr viel dabei gelernt. Vom technischen Know-how bis hin zu Leadership, Zeitmanagement und Team-Skills war alles dabei. Ich wünschte, ich hätte noch mehr Einblick in das Backend und den CI/CD-Prozess bekommen können, aber aus Zeitgründen war das nicht möglich. Alles in allem blicke ich positiv auf die Extreme Programming Week zurück: es war eine spannende Woche voller wertvoller Erfahrungen, welche uns als Team noch enger zusammengeschweißt hat, und aus der ich viel neues Wissen für die Zukunft mitnehme.</p>



<h3 class="wp-block-heading">David</h3>



<p class="wp-block-paragraph">Ich blicke gerne auf die Wild Week zurück und bin stolz auf das Endprodukt, das wir als Team in der Woche geschaffen haben. Es war schön zu sehen, wie jedes Teammitglied seine bisherigen technischen Erfahrungen bei den verschiedenen Teilaufgaben des Projekts einbringen konnte. Durch das Setup (alle Teammitglieder ständig in einem Raum) konnten wir das Know-How auch sehr gut mit allen teilen.</p>



<p class="wp-block-paragraph">Sehr motivierend fand ich auch die Aufteilung in tägliche Sprints mit einem Meeting in der Früh, in dem wir immer die Aufgaben definierten und zwischen den Teammitgliedern verteilten, da man so ein festes Ziel für den Tag vor Augen hatte, auf das man hinarbeiten konnte.</p>



<p class="wp-block-paragraph">Ich konnte auf jeden Fall ein paar persönliche Learnings aus der Wild Week mitnehmen: Da das zu entwickelnde Produkt ja am Freitag zu präsentieren war und dadurch die Zeit ein extrem limitierender Faktor, war es essentiell, sich auf das MVP zu konzentrieren und sich nicht in Details zu verlieren. Das hat im Laufe der Woche mal mehr, mal weniger gut geklappt. Es ist auch gar nicht so leicht, stets den Fokus auf die Grundfunktionalität zu behalten, da man bei Projekten mit kompletter Entscheidungsfreiheit als Entwickler automatisch darüber nachdenkt, welche Features man nicht noch hinzufügen könnte. Gegen Ende der Woche hat sich das Pareto-Prinzip aus meiner Sicht auch wieder zum Teil bewahrheitet. Durch Erfolgsmomente am Anfang des Projekts ist man leicht dazu verleitet anzunehmen, dass die Entwicklungsgeschwindigkeit im selben Tempo bis zum Abschluss beibehalten werden kann &#8211; was sich nicht bewahrheitet hat. In einem zukünftigen Projekt dieser Art wäre es für mich wichtig, mehr Fokus darauf zu legen, wirklich beim MVP zu bleiben und den ganzen Entscheidungsprozess über zusätzliche Features erst gar nicht aufkommen zu lassen.</p>



<p class="wp-block-paragraph">Aus technischer Sicht fand ich super, mich wieder mehr mit React beschäftigen zu können. Hier habe ich einiges an Know-How aus der Woche mitnehmen können. Zusätzlich fand ich die Diskussionen mit meinen TeamkollegInnen über Architekturentscheidungen sehr spannend und fand es super, das ganze Tech Setup inkl. CI/CD für ein Projekt dieser Art von Grund auf einzurichten. Es war auch das erste Mal, dass ich an einer App gearbeitet habe, die hauptsächlich Websockets als Kommunikationskanal verwendet &#8211; es war spannend, mal mit einem anderen Schnittstelle als REST zu arbeiten.</p>



<h3 class="wp-block-heading">Andreas</h3>



<p class="wp-block-paragraph">8 Teammitglieder, fast 5 Tage Entwicklungszeit und eine gemeinsame App-Idee realisieren – das war unser intensives und lehrreiches Projekt am Anfang des 2. Semesters, aus dem ich persönlich viel mitnehmen konnte. Die Woche war geprägt von enger Teamkommunikation, klarer Aufgabenverteilung und vielen kleinen Abstimmungen, die am Ende zu einem funktionierenden Gesamtprodukt geführt haben. Besonders interessant war für mich, wie unterschiedlich einzelne Teammitglieder an Aufgaben herangegangen sind – sowohl inhaltlich als auch methodisch. Dabei habe ich nicht nur verschiedene Denkansätze kennengelernt, sondern auch praktische Coding-Tipps und Lösungsstrategien aufgeschnappt, die mir in Zukunft sicher weiterhelfen werden.</p>



<p class="wp-block-paragraph">Mein Fokus lag zu Beginn auf der Planung unserer Datenbank. Zusammen mit Matthias habe ich verschiedene Datenbanktypen – wie z.B. relationale, NoSQL und Time-Series DBs – hinsichtlich ihrer Eignung für unseren Use Case bewertet. Auf Basis dieser Überlegungen sind wird bei einer klassischen relationalen DB geblieben, für die Matthias und ich ein erstes ER-Diagramm entworfen haben, das wir anschließend im Team besprochen und gemeinsam überarbeitet haben. Auch wenn dieser Prozess Zeit gekostet hat, konnten wir dadurch eine saubere, tragfähige Struktur aufsetzen, die sich später fast vollständig problemlos in NestJS integrieren ließ. Im weiteren Verlauf (nachdem der technische Aufbau der DB gestanden ist) habe ich mich verstärkt dem Frontend gewidmet, insbesondere der Nebenmaske für die User*innendaten, die noch nicht von meinen Kolleg*innen bearbeitet wurden. Dort konnte ich eigenständig erste Komponenten entwickeln, gerade bei Bereichen mit direktem Bezug zur Datenbank. Bei komplexeren Problemen habe ich auf Pair Programming gesetzt, um gemeinsam mit dem gebündelten Stärken meiner Kolleg*innen gezielte Lösungen zu finden.</p>



<p class="wp-block-paragraph">Eine besondere Herausforderung war auch für mich der Umgang mit dem begrenzten Zeitrahmen bei gleichzeitigem Anspruch auf sauberen, wartbaren Code. Ich habe gelernt, wie entscheidend es ist, in der Entwicklung frühzeitig sinnvolle Prioritäten zu setzen – also die „richtige“ Reihenfolge zu finden: Was muss funktionieren, was ist optional, und was kann man notfalls zurückstellen? Diese Balance war nicht immer einfach, aber essenziell, um alle Kernfunktionen zuverlässig umzusetzen. Mein Versuch, am Ende noch die Safe-Area technisch sauber zu integrieren, ist trotz mehrerer Ansätze gescheitert – aber genau daraus habe ich am meisten gelernt: Nicht jede Idee lässt sich unter Zeitdruck noch sinnvoll umsetzen, und pragmatisches Handeln ist oft wichtiger als Perfektion im Detail.<br><br>Um mein Fazit abzurunden, möchte ich gerne festhalten, dass dieses Projekt nicht nur meine technischen Fähigkeiten weiterentwickelt, sondern auch mein Verständnis für effiziente Teamarbeit unter Druck geschärft hat. Besonders der Umgang mit begrenzter Zeit und die bewusste Fokussierung auf das Wesentliche haben mir gezeigt, worauf es in realen Entwicklungsprozessen wirklich ankommt.</p>



<h3 class="wp-block-heading">Felix</h3>



<p class="wp-block-paragraph">Die Programming Week war für mich auf jeden Fall ein Highlight. In einer relativ großen Gruppe so ein Projekt in nur 5 Tagen umzusetzen war nicht nur super anstrengend, sondern auch spannend und lustig. Ich muss echt sagen, dass ich sehr viel gelernt habe, auch wenn ich leider von manchen Bereichen des Projekts nicht so viel mitbekommen habe, was aber durchaus verständlich ist, wenn man unter diesem Zeitdruck steht.</p>



<p class="wp-block-paragraph">Ich habe viel im Pair-Programming gearbeitet und das vor allem am Frontend. Das war für mich echt nützlich, da ich so schneller in das Projekt und in React reinfinden konnte. Ich habe mit Caro zuallererst begonnen, dass wir den Heart-Rate-Sensor mit Bluetooth verbinden können und die Daten auslesen können, das hat Anfangs ein bisschen schwierig funktioniert, aber dann haben wir zusammen auch schnell eine Lösung gefunden, was gerade am ersten Tag super motivierend war. Auch sonst war das gesamte Projekt sehr gut aufgebaut, weil wir jeden Tag mit einem Meeting begonnen haben, um die heutigen Ziele festzulegen. Anfangs dachte ich, dass wird ja dann echt einfach am Freitag fertig zu werden, wenn alles so schnell weitergeht, aber wie so oft unterschätzt man dann den Stress der letzten Tage. Wie ich schon einmal erwähnt habe, hätte ich noch sehr gerne mehr in das Backend und in die Websockets geschaut, aber leider war das zeitlich nicht mehr ganz möglich, aber dafür konnte ich im Frontend fast überall mitarbeiten, was natürlich auch dort mein Wissen verbessert hat.</p>



<p class="wp-block-paragraph">Das gesamte Projekt haben wir echt gut als Gruppe gemeistert. Wir hatten Spaß, waren gestresst und haben alle glaube ich sehr viel dabei gelernt. Das Endprodukt konnte sich bei der Präsentation auch sehen lassen, außer vielleicht ein paar kleine Bugs. Ich konnte auf jeden Fall sehr viel lernen und würde diese Art von Projekt gerne wiederholen, auch wenn eine Pause nach dieser Woche sehr gut getan hat. </p>



<h3 class="wp-block-heading">Caroline</h3>



<p class="wp-block-paragraph">Es war sehr spannend zu sehen, wie viel man zu acht in einer Woche bzw. 5 Tagen schafft zu entwickeln. Ich habe mich vor allem mit dem Frontend beschäftigt und dabei meist Pair Programming mit verschiedenen Personen betrieben. Dieses Konzept ist mir bereits aus dem Bachelor bekannt und mir persönlich gefällt es sehr gut, da man so schneller Fehler bemerkt.</p>



<p class="wp-block-paragraph">Montags habe ich mich mit Felix um die Verbindung zum Heart Rate Sensor gekümmert. Anfangs gab es ein paar Schwierigkeiten, doch dann folgte das Erfolgserlebnis. Die Verwendung von HRMs und Bluetooth LE war für mich neu, aber sehr interessant. Dienstags habe ich mich vor allem mit dem Login- und Registrierungs-Screen beschäftigt und dafür anfangs Farben und Schriftarten global definiert und Tailwind aufgesetzt. In Bezug auf die Formulare auf den zwei Screens nutze ich React Hook Form, wobei ich die Library zu einem späteren Zeitpunkt ersetzt habe, da der State nicht immer aktualisiert wurde. Nachdem wir am Mittwoch unser UI-Konzept und die Datenvisualisierung überarbeitet hatten, habe ich mit Felix die Umsetzung des LiveActivity-Screens begonnen. Donnerstags war ich mit Katharina für den Authentifizierungscheck beim Aufruf gewisser Routen verantwortlich und habe Andi beim Bearbeiten der Profilinformationen geholfen. Am letzten Tag war Endspurt angesagt und somit auch Bug Fixing. Dabei habe ich einerseits David bei der Verwendung der WebSockets im Frontend unterstützt, andererseits Matthias bei der Session Erstellung/Teilnahme.</p>



<p class="wp-block-paragraph">Ich finde, wir haben das als Gruppe sehr gut gemeistert, mit dem Daily Planning am Anfang war klar definiert, was gemacht wird, und das Endprodukt (bis auf die paar Bugs) kann sich sehen lassen. Vor allem was die Verbindung mit den Sensoren und die Erstellung eigener sogenannter Guarded Routes betrifft, habe ich einiges gelernt, was auch in Zukunft hilfreich sein könnte. Neben den technischen Aspekten habe ich nochmals gesehen, wie wichtig es ist, sich zuerst auf das MVP zu konzentrieren und sicherzustellen, dass das die anderen auch tun, da man sonst Zeit verliert und sich verrennen kann.</p>



<h3 class="wp-block-heading">Sebastian</h3>



<p class="wp-block-paragraph">Die Wild Week war ein wirklich interessantes und spannendes Erlebnis. Ein ganzes Projekt in nicht einmal 5 Tagen auf die Beine zu stellen war extremst stressig, aber auch wirklich toll zu sehen, was man eigentlich in so kurzer Zeit auf die Beine stellen kann, wenn man sich wirklich ins Zeug lägt. Auch konnte ich einiges aus dieser Woche mitnehmen.</p>



<p class="wp-block-paragraph">Zum einen hatte ich bisher noch keine Erfahrung mit Ionic in Verbindung mit React. Ich habe nur Ionic und Angular oder React Native verwendet, aber nicht beide zusammen. Auch habe ich einiges über die Verwendung von Herz Sensoren erfahren, auch wenn meine Erfahrung hier etwas kurz gekommen ist, da ich größtenteils im Backend zuständig war. Ich hätte sehr gerne auch andere Bereiche mir angeschaut, aber aufgrund des Zeitstresses ist es verständlich, dass dies nicht wirklich möglich war. In der Woche habe ich manchmal allein gearbeitet, zum Beispiel für die Erforschung, wie das Accelerometer im Handy funktioniert oder im Backend die Datenspeicherung über die passenden Endpoints zu ermöglichen, habe aber auch einiges im Pair Programming gemacht. Auf beiden Seiten. Auch wenn ich diese Technik schon aus dem Bachelor kannte, ist es trotzdem immer interessant zu sehen, wie gut Pair Programming funktioniert. Eine weitere Person neben sich zu haben, die sich nur darauf konzentrieren kann, was geschrieben wird und sofort erkennen kann, wenn man eine Sache vergisst oder welche einem bei Problemen hilft, ist sehr wertvoll, vor allem wenn nicht jede Person im Team an einer eignen Sache arbeiten kann.</p>



<p class="wp-block-paragraph">Im großen und ganzem finde ich das die Wild Week wirklich toll gelaufen ist. Wir haben uns viel vorgenommen, dies aber auch toll hinbekommen. Mit den Daily Stand-ups, welche wir immer in der Früh gemacht haben, konnten wir uns jeden Tag auf unsere Ziele festlegen und auf diese fokussieren. Man konnte auch wirklich gut erkenne, weshalb das Prinzip eines MVPs existiertet. Ich hätte nichts dagegen, einmal wieder so ein Projekt zu wiederholen.</p>



<h3 class="wp-block-heading">Jan</h3>



<p class="wp-block-paragraph">Es war eine spannende Woche! In fünf Tagen haben wir viel diskutiert, Entscheidungen getroffen und fleißig in die Tasten gehauen. Das Ergebnis ist ein Proof of Concept, der unsere interessante App-Idee greifbar macht. Mit diesem Ergebnis sind wir insgesamt sehr zufrieden. Allerdings schwingt beim „insgesamt“ auch ein kleiner Vorbehalt mit: Hätten wir vielleicht noch mehr aus dieser Woche herausholen können?</p>



<p class="wp-block-paragraph">Viel Zeit hat unser Team zur Konzeption der App aufgewendet. Diese Zeit scheint mir rückblickend gut investiert. Es war wichtig, eine Idee auszuarbeiten, die wir spannend und sinnvoll fanden. Erst mit dieser klaren Vorstellung konnten wir mit Elan loslegen. Unsere Schwächen sehe ich eher bei der Aufteilung und Priorisierung der Arbeit. Die Features der App haben wir in Backend und Frontend unterteilt und zu unabhängig voneinander umgesetzt. Das führte dazu, dass im Backend Funktionen implementiert wurden, die im Frontend letztlich keine Verwendung fanden. Wie im Kapitel zu CI/CD erwähnt, haben wir außerdem zu viel Energie in unsere Pipelines gesteckt. Ein weiteres Problem der Aufteilung war, dass das Zusammenführen der Arbeiten erst spät erfolgte, wodurch wir auch erst spät auf Probleme aufmerksam wurden. Sinnvoller wäre es wohl gewesen, wenn Sub-Teams End-to-End an einzelnen Features gearbeitet hätten, sodass die App schrittweise gewachsen wäre.</p>



<p class="wp-block-paragraph">Insgesamt war es jedoch eine produktive Woche, in der wir als Team nicht nur viel geschafft, sondern auch viel Spaß gehabt haben. Es war wirklich schön, sich fünf Tage lang intensiv in ein völlig neues Thema zu vertiefen – eine willkommene Abwechslung! Die Erfahrungen aus dieser Woche und das gestärkte Teamgefühl werden uns im nächsten Projektsemester mit Sicherheit zugutekommen.</p>
<p>The post <a href="https://mobile.fhstp.ac.at/development/blog-movemates/">Blog | MoveMates</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Prisma ORM: Ein Überblick über die moderne ORM-Lösung für TypeScript und Node.js</title>
		<link>https://mobile.fhstp.ac.at/allgemein/prisma-orm-ein-ueberblick-ueber-die-moderne-orm-loesung-fuer-typescript-und-node-js/</link>
		
		<dc:creator><![CDATA[Caroline Labres]]></dc:creator>
		<pubDate>Wed, 22 Jan 2025 02:04:52 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<guid isPermaLink="false">https://akirchknopf-21110.php.fhstp.cc/?p=13704</guid>

					<description><![CDATA[<p>Datenbanken sind in vielen modernen Anwendungen nicht wegzudenken – doch SQL-Abfragen können schnell komplex und Datenbank-Migrationen können auf Dauer mühsam werden. Hier kommt Prisma ORM ins Spiel: Ein innovatives Tool, das die Arbeit mit Datenbanken erheblich vereinfacht. Prisma verbindet Typsicherheit, Automatisierung und Benutzerfreundlichkeit und bietet damit alles, was für eine effiziente Entwicklung benötigt wird. Dieser <a class="read-more" href="https://mobile.fhstp.ac.at/allgemein/prisma-orm-ein-ueberblick-ueber-die-moderne-orm-loesung-fuer-typescript-und-node-js/">[...]</a></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/prisma-orm-ein-ueberblick-ueber-die-moderne-orm-loesung-fuer-typescript-und-node-js/">Prisma ORM: Ein Überblick über die moderne ORM-Lösung für TypeScript und Node.js</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Datenbanken sind in vielen modernen Anwendungen nicht wegzudenken – doch SQL-Abfragen können schnell komplex und Datenbank-Migrationen können auf Dauer mühsam werden. Hier kommt <strong>Prisma ORM</strong> ins Spiel: Ein innovatives Tool, das die Arbeit mit Datenbanken erheblich vereinfacht. Prisma verbindet Typsicherheit, Automatisierung und Benutzerfreundlichkeit und bietet damit alles, was für eine effiziente Entwicklung benötigt wird. Dieser Beitrag soll nach einer kurzen theoretischen Einführung vor allem praktisch erklären wie Prisma ORM beispielhaft innerhalb eines NestJS-Projekts verwendet werden kann.</p>



<h2 class="wp-block-heading">Was ist Prisma ORM?</h2>



<p class="wp-block-paragraph">Prisma ORM ist, wie der Name schon verrät, ein ORM (object-relational mapping), also eine Objektrelationale Abbildung für TypeScript und Node.js. ORMs abstrahieren die Komplexität der Datenbank, indem sie über Objekte eine Schnittstelle zum Holen, Erstellen, Bearbeiten und Löschen von Daten bieten. Es werden Modelle bzw. Klassen geschrieben, die den Tabellen in der Datenbank entsprechen. Prisma ORM verfolgt dabei allerdings einen schema-first Ansatz. Das bedeutet, dass es ein zentrales Schema-File gibt, auf dem alles basiert. Außerdem ist Prisma ORM open-source (bis auf Prisma Sudio &#8211; siehe nächster Abschnitt). </p>



<h2 class="wp-block-heading">Bestandteile</h2>



<p class="wp-block-paragraph">Prisma besteht aus folgenden drei Teilen:</p>



<ul class="wp-block-list">
<li>Prisma Client</li>



<li>Prisma Migrate</li>



<li>Prisma Studio</li>
</ul>



<h3 class="wp-block-heading">Prisma Client</h3>



<p class="wp-block-paragraph">Der Prisma Client ist eine automatisch basierend auf dem Prisma-Schema generierte, typsichere API, mit der Datenbankabfragen durchgeführt werden können. Es muss also nicht manuell SQL geschrieben werden und durch die Typsicherheit werden Fehler frühzeitig vermieden. Dieser Bestandteil ist der Teil von Prisma ORM, der am häufigsten vorkommt, weshalb er oftmals auch nur Prisma genannt wird.</p>



<h3 class="wp-block-heading">Prisma Migrate</h3>



<p class="wp-block-paragraph">Prisma Migrate ist ein Tool zum Verwalten von Datenbankschemas. In Form von Migrationen können leicht Änderungen an der Struktur der Datenbank vorgenommen werden. Dadurch können Code und Datenbank synchron gehalten werden.</p>



<h3 class="wp-block-heading">Prisma Studio</h3>



<p class="wp-block-paragraph">Prisma Studio bietet einen grafische Benutzeroberfläche, um die Datenbank durchsuchen zu können und die Daten verwalten zu können. Auf diesen Teil wird in dem Blogartikel nicht genauer eingegangen.</p>



<h2 class="wp-block-heading">Erste Schritte</h2>



<p class="wp-block-paragraph">Im folgenden Abschnitt wird nun erklärt wie Prisma ORM beispielhaft in einem NestJS Projekt installiert und verwendet werden kann.</p>



<h3 class="wp-block-heading">1. Projekt aufsetzen</h3>



<p class="wp-block-paragraph">Zuerst muss NestJS CLI installiert und ein neues Projekt erstellt werden. Wenn ein bestehendes Projekt verwendet wird, kann dieser Schritt übersprungen werden</p>



<pre class="wp-block-code"><code>npm i -g @nestjs/cli
nest new prisma-test</code></pre>



<p class="wp-block-paragraph">Im Ordner des Projekts, muss nun Prisma CLI installiert und ein neues Prisma-Projekt initialisiert werden.</p>



<pre class="wp-block-code"><code>npm i prisma --save-dev
npx prisma init</code></pre>



<p class="wp-block-paragraph">Nun muss die Datenbankverbindung hergestellt werden. Dazu muss im .env File die richtige URL gesetzt (siehe dazu <a href="https://www.prisma.io/docs/orm/reference/connection-urls">https://www.prisma.io/docs/orm/reference/connection-urls</a>) und in der schema.prisma Datei der provider im datasource Block angepasst werden. Ich arbeite lokal mit XAMPP und einer MySQL Datenbank. Prisma ORM kann aber mit PostgreSQL, MySQL, MariaDB, SQLite, MongoDB, Supabase und vielen weiteren Datenbanken genutzt werden.</p>



<h3 class="wp-block-heading">2. Tabellen erstellen</h3>



<p class="wp-block-paragraph">Um Tabellen zu erstellen, müssen zuerst Models im Prisma Schema erstellt werden. Das prisma.schema File könnte beispielsweise so aussehen:</p>



<pre class="wp-block-code"><code>model User {
  id       Int    @id @default(autoincrement())
  username String @unique
  posts    Post&#91;]
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  text      String?
  published Boolean? @default(false)
  author    User?    @relation(fields: &#91;authorId], references: &#91;id])
  authorId  Int?
}</code></pre>



<p class="wp-block-paragraph">Zuerst wird der Name des Feldes definiert, dann der Typ (? für optional) angegeben und abschließend die Eigenschaften angeführt.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph"><strong>Hinweis zu VS Code:</strong></p>



<p class="wp-block-paragraph">Arbeitet man in VS Code, so empfiehlt es sich, die Extension &#8220;Prisma&#8221; von Prisma selbst herunterzuladen, um die Lesbarkeit des Schemas durch Syntax Highlighting zu verbessern.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">Nachdem die Datei gespeichert wurde, können nun mittels Prisma Migrate die Migration Files erstellt werden, die dann unter <code>prisma/migrations</code> zu finden sind.</p>



<pre class="wp-block-code"><code>npx prisma migrate dev --name init</code></pre>



<h3 class="wp-block-heading">3. Prisma Client installieren und verwenden</h3>



<pre class="wp-block-code"><code>npm i @prisma/client</code></pre>



<p class="wp-block-paragraph">Mit der Installation wird auch schon <code>prisma generate</code> ausgeführt. In der Zukunft muss nach jeder Änderung am Model dieser Befehl ausgeführt werden, um den Prisma Client up-to-date zu halten.</p>



<p class="wp-block-paragraph">Nun erstellen wir ein Prisma Service (prisma.service.ts) im <code>src</code> Ordner, welches wir dann in anderen Services verwenden können.</p>



<pre class="wp-block-code"><code>import { Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect();
  }
}</code></pre>



<p class="wp-block-paragraph">Um ein Module, ein Service und einen Controller in NestJS zu erstellen werden folgende Befehle benötigt:</p>



<pre class="wp-block-code"><code>nest g mo user
nest g s user
nest g co user</code></pre>



<p class="wp-block-paragraph">Dasselbe macht man für die Posts. Dann kann das User Service erweitert werden. Um das Prisma Service verwenden zu können, muss es im App Module und jedem weiteren wie z.B. User Module unter Providers hinzugefügt werden.</p>



<p class="wp-block-paragraph">So könnte das User Service aussehen:</p>



<pre class="wp-block-code"><code>import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma.service';
import { Prisma, User } from '@prisma/client';

@Injectable()
export class UserService {
    constructor(private prisma: PrismaService) { }

    async findUserById(
        id: number,
    ): Promise&lt;User | null&gt; {
        return this.prisma.user.findUnique({
            where: { id },
        });
    }

    async findAllUsers(): Promise&lt;User&#91;]&gt; {
        return this.prisma.user.findMany();
    }

    async createUser(data: Prisma.UserCreateInput): Promise&lt;User&gt; {
        return this.prisma.user.create({
            data,
        });
    }

    async updateUser(params: {
        id: number;
        data: Prisma.UserUpdateInput;
    }): Promise&lt;User&gt; {
        const { id, data } = params;
        return this.prisma.user.update({
            where: { id },
            data: data
        });
    }

    async deleteUser(id: number): Promise&lt;User&gt; {
        return this.prisma.user.delete({
            where: { id }
        });
    }
}</code></pre>



<p class="wp-block-paragraph">Das Prisma Service (bzw. der Prisma Client) stellt einem die CRUD Methoden zur Verfügung und auch die Types können direkt von Prisma übernommen werden. Nach demselben Prinzp kann das Post Service erweitert werden.</p>



<p class="wp-block-paragraph">Möchte man beim Laden eines Posts auch die Informationen des Autors bzw. der Autorin mitgeben, so kann <code>include</code> oder <code>select</code> verwendet werden.</p>



<pre class="wp-block-code"><code>async findPostById(
        id: number,
    ): Promise&lt;Post | null&gt; {
        return this.prisma.post.findUnique({
            where: { id },
            include: {
                author: true
            }
        });
    }</code></pre>



<p class="wp-block-paragraph">Es gibt unzählige Query Optionen, die verwendet werden können um nach bestimmten Daten zu suchen, sortieren, filtern etc. Siehe <a href="https://www.prisma.io/docs/orm/prisma-client/queries">https://www.prisma.io/docs/orm/prisma-client/queries</a>.</p>



<h3 class="wp-block-heading">4. Endpoints definieren</h3>



<p class="wp-block-paragraph">In den Controllern definiert man dann seine Endpoints und ruft die Methoden des spezifischen Services auf. </p>



<pre class="wp-block-code"><code>import { Body, Controller, Get, Post } from '@nestjs/common';
import { UserService } from './user.service';
import { User } from '@prisma/client';

@Controller('user')
export class UserController {
    constructor(
        private readonly userService: UserService,
    ) { }

    @Post()
    async createUser(
        @Body() userData: { username: string; },
    ): Promise&lt;User&gt; {
        return this.userService.createUser(userData);
    }

    @Get()
    async getAllUsers(): Promise&lt;Array&lt;User&gt;&gt; {
        return this.userService.findAllUsers();
    }
}
</code></pre>



<p class="wp-block-paragraph">Da dies NestJS spezifisch ist und nichts direkt mit Prisma zu tun hat, wird darauf hier nicht näher eingegangen.</p>



<p class="wp-block-paragraph">Mit <code>npm run start:dev</code> kann die Applikation gestartet werden.</p>



<h2 class="wp-block-heading">Fazit</h2>



<p class="wp-block-paragraph">Prisma ORM vereinfacht den Umgang mit der Datenbank erheblich und ist leicht zu erlernen. Im Vergleich zu anderen ORMs wie zum Beipsiel TypeORM werden die Models genau in einem File, dem Prisma Schema, definiert und alles andere wird basierend darauf generiert. Bei TypeORM hingegen definiert man zuerst die Entity-Klassen in mehreren Dateien und versieht die enthaltenen Properties mit Decoratorn, woraufhin TypeORM diese in Datenbank Informationen verwandelt. Prisma ORM unterstützt automatische Datenbank-Migrationen, ohne eigene Befehle im package.json ergänzen zu müssen. Außerdem sind die automatisch generierten Types sehr praktisch und allgemein ist die Typsicherheit höher (z.B. bei den Relationen und beim Filtern), wodurch Fehler bereits zur Kompilierzeit erkannt werden. Und was dabei aber nie verloren geht, sind die Personalisierungsmöglichkeiten bei den Queries. Bei sehr komplexen Abfrageszenarien bietet TypeORM mit dem QueryBuilder wiederum Unterstützung bei Raw-SQL-Abfragen.</p>



<p class="wp-block-paragraph">Die Wahl eines ORMs hängt somit unter anderem davon ab, wie man sein Schema definieren und verwalten möchte und wie feingranular die Kontrolle über Datenbankabfragen sein muss. Hier spielen aber vor allem auch persönliche Präferenzen eine große Rolle.</p>



<h2 class="wp-block-heading">Quellen</h2>



<p class="wp-block-paragraph"><a href="https://www.prisma.io/docs/orm/overview/prisma-in-your-stack/is-prisma-an-orm">https://www.prisma.io/docs/orm/overview/prisma-in-your-stack/is-prisma-an-orm</a></p>



<p class="wp-block-paragraph"><a href="https://medium.com/@binayakgourishankar/getting-started-with-prisma-orm-89c2fcda5026">https://medium.com/@binayakgourishankar/getting-started-with-prisma-orm-89c2fcda5026</a></p>



<p class="wp-block-paragraph"><a href="https://docs.nestjs.com/recipes/prisma">https://docs.nestjs.com/recipes/prisma</a></p>



<p class="wp-block-paragraph"><a href="https://dev.to/afl_ext/prisma-vs-typeorm-description-and-comparison-4bob">https://dev.to/afl_ext/prisma-vs-typeorm-description-and-comparison-4bob</a></p>



<p class="wp-block-paragraph"><a href="https://www.prisma.io/docs/orm/overview/databases">https://www.prisma.io/docs/orm/overview/databases</a></p>



<p class="wp-block-paragraph"><a href="https://www.prisma.io/docs/orm/more/comparisons/prisma-and-typeorm">https://www.prisma.io/docs/orm/more/comparisons/prisma-and-typeorm</a></p>



<p class="wp-block-paragraph"><a href="https://spin.atomicobject.com/prisma-vs-typeorm/ ">https://spin.atomicobject.com/prisma-vs-typeorm/ </a></p>



<h3 class="wp-block-heading">Logo vom Beitragsbild</h3>



<p class="wp-block-paragraph"><a href="https://github.com/prisma/presskit">https://github.com/prisma/presskit</a></p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/prisma-orm-ein-ueberblick-ueber-die-moderne-orm-loesung-fuer-typescript-und-node-js/">Prisma ORM: Ein Überblick über die moderne ORM-Lösung für TypeScript und Node.js</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>SOTA &#124; Versteckte Beeinflussung: Deceptive Patterns in beliebten mobilen Applikationen</title>
		<link>https://mobile.fhstp.ac.at/allgemein/sota-versteckte-beeinflussung-deceptive-patterns-in-beliebten-mobilen-applikationen/</link>
		
		<dc:creator><![CDATA[Caroline Labres]]></dc:creator>
		<pubDate>Mon, 20 Jan 2025 12:39:22 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Wissenschaftliche Arbeit]]></category>
		<category><![CDATA[SOTA]]></category>
		<guid isPermaLink="false">https://akirchknopf-21110.php.fhstp.cc/?p=13664</guid>

					<description><![CDATA[<p>ABSTRACT Manipulative Designstrategien, bekannt als Dark oder Deceptive Patterns, finden häufig Verwendung in digitalen Medien, um Nutzer*innen zu unbewussten Entscheidungen zu verleiten. Ziel des Artikels ist zu erforschen, inwiefern die verschiedenen Typen dieser Muster in bekannten mobilen Applikationen zum Einsatz kommen und welche Auswirkungen sie allgemein auf das Nutzungsverhalten haben. Die Ergebnisse zeigen, dass diese <a class="read-more" href="https://mobile.fhstp.ac.at/allgemein/sota-versteckte-beeinflussung-deceptive-patterns-in-beliebten-mobilen-applikationen/">[...]</a></p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/sota-versteckte-beeinflussung-deceptive-patterns-in-beliebten-mobilen-applikationen/">SOTA | Versteckte Beeinflussung: Deceptive Patterns in beliebten mobilen Applikationen</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-file"><a id="wp-block-file--media-4519a0b8-41b9-49a1-bd35-8358bdeb9fef" href="https://akirchknopf-21110.php.fhstp.cc/wp-content/uploads/2025/01/SOTA_it241502_Versteckte_Beeinflussung.pdf">SOTA_it241502_Versteckte_Beeinflussung</a><a href="https://akirchknopf-21110.php.fhstp.cc/wp-content/uploads/2025/01/SOTA_it241502_Versteckte_Beeinflussung.pdf" class="wp-block-file__button wp-element-button" download aria-describedby="wp-block-file--media-4519a0b8-41b9-49a1-bd35-8358bdeb9fef">Herunterladen</a></div>



<h2 class="wp-block-heading">ABSTRACT</h2>



<p class="wp-block-paragraph">Manipulative Designstrategien, bekannt als Dark oder Deceptive Patterns, finden häufig Verwendung in digitalen Medien, um Nutzer*innen zu unbewussten Entscheidungen zu verleiten. Ziel des Artikels ist zu erforschen, inwiefern die verschiedenen Typen dieser Muster in bekannten mobilen Applikationen zum Einsatz kommen und welche Auswirkungen sie allgemein auf das Nutzungsverhalten haben. Die Ergebnisse zeigen, dass diese jedenfalls einen Einfluss auf die Nutzer*innen haben, die diese Strategien wiederum nicht erkennen. In der Praxis treten die verschiedenen Muster, zu denen Nagging, Obstruction, Sneaking, Interface Interference und Forced Action zählen, oft in Kombination miteinander auf. In den Bereichen Bildung, soziale Netzwerke und E-Commerce stößt man vor allem auf visuell hervorgehobene Optionen, zu denen Nutzer*innen tendieren sollen, oder Maßnahmen, die die Löschung des Accounts oder die Kündigung des Abonnements erschweren.</p>



<h2 class="wp-block-heading">1 Einleitung</h2>



<p class="wp-block-paragraph">In der digitalen Welt von heute spielen mobile Anwendungen eine zentrale Rolle im Alltag vieler Menschen. Gleichzeitig wächst die Zahl an Strategien, die nicht darauf abzielen, den Nutzer*innen einen Mehrwert zu bieten, sondern sie gezielt zu täuschen oder zu manipulieren. Derartige manipulative Designstrategien werden als Deceptive Patterns (oder auch Dark Patterns) bezeichnet. Sie nutzen irreführende Gestaltungselemente, Verschleierung und psychologische Schwächen, um zu Entscheidungen zu verleiten, die im Interesse der Betreiber und nicht der Nutzer*innen sind (Brignull, 2023; Gray et al., 2018).</p>



<p class="wp-block-paragraph">Ziel dieses Artikels ist aufzuzeigen, welche verschiedenen Deceptive Patterns existieren und wie diese in der Praxis verwendet werden, um so ein Bewusstsein für die versteckten Beeinflussungs-techniken zu schaffen. Zunächst wird definiert, was Deceptive Patterns sind und welche verschiedenen Typen existieren, beispielsweise Roach Motel oder Forced Continuity. Anschließend werden die drei Apps Duolingo, Instagram und Amazon auf Grundlage von einschlägiger Literatur und eigenen Beobachtungen analysiert, um die Verbreitung solcher Muster in den Bereichen Bildung, soziale Netzwerke und E-Commerce zu beleuchten. Zuletzt werden die Wirkung und Erkennung von Deceptive Patterns angeschnitten.</p>



<h2 class="wp-block-heading">2 Definition</h2>



<p class="wp-block-paragraph">2010 definierte Brignull (2023) den Begriff Dark Pattern. Darunter versteht man, dass Nutzer*innen durch bestimmte Tricks im User Interface zu Interaktionen und Handlungen bewegt werden, die nicht in ihrem Interesse sind. Beispielsweise werden sie zum Abschluss eines Abonnements verführt oder ihnen wird mehrmals die Möglichkeit von In-App-Käufen angeboten. (Brignull, 2023; Gray et al., 2018, S. 1). Nun empfindet Brignull diesen Begriff allerdings als veraltet und verwendet in seinen neuesten Werken stattdessen die Bezeichnung Deceptive Pattern (zu Deutsch trügerische Muster), welche eine Kurzform für Deceptive or Manipulative Pattern ist (Brignull, 2023).</p>



<h2 class="wp-block-heading">3 Arten von Deceptive Patterns</h2>



<p class="wp-block-paragraph">In der Literatur tauchen mehrere Möglichkeiten auf, wie Dark Patterns kategorisiert werden können. Conti und Sobiesk (2010) gehen von elf Kategorien aus, darunter Verwirrung, Ablenkung, Verschleierung, Ausnutzung von Fehlern und Schock, während Brignull et al. (2023) auf ihrer Webseite 16 Arten aufzählen (Confirmshaming, Fake Scarcity, Fake urgency, Hard to cancel etc.). Gray et al. (2018) teilen Deceptive Patterns wiederum in fünf Kategorien ein: Nagging, Obstruction, Sneaking, Interface Interference und Forced Action. Diese Einteilung findet sich öfters in der Literatur und wird als aktuell bezeichnet, weshalb diese auch in diesem Artikel herangezogen wird.</p>



<h3 class="wp-block-heading">3.1 Nagging</h3>



<p class="wp-block-paragraph">Beim Nagging wird der oder die Nutzer*in bei einer Interaktion einmal oder mehrmals durch eine andere Aufgabe unterbrochen, die nicht mit der Interaktion im Zusammenhang steht. Beispiele hierfür sind Pop-Ups oder ablenkende Audiosignale, wodurch die Aufmerksamkeit in eine andere Richtung gelenkt wird (Gray et al., 2018, S. 5).</p>



<h3 class="wp-block-heading">3.2 Obstruction</h3>



<p class="wp-block-paragraph">Obstruction bedeutet, dass den Nutzer*innen die Durchführbarkeit einer Aufgabe oder Interaktion erschwert wird, um sie davon abzuhalten. Hierbei gibt es drei Unterkategorien (Gray et al., 2018, S. 5-6):</p>



<p class="wp-block-paragraph"><em>3.2</em><em>.1</em><em> Roach Motel (Kakerlakenfalle).</em><em> </em>Es ist zwar leicht in eine Situation zu kommen, doch umso schwerer ist es hinauszugelangen. Zum Beispiel ist das Löschen eines Accounts im Vergleich zu dessen Erstellung viel schwieriger oder sogar unmöglich, weil zum Beispiel eine Telefonnummer angerufen werden muss.</p>



<p class="wp-block-paragraph"><em>3.2</em><em>.2</em><em> Price Comparison Prevention (Verhinderung von Preisvergleichen).</em> Dem oder der Nutzer*in wird der Preisvergleich von Dienstleistungen oder Produkten erschwert.</p>



<p class="wp-block-paragraph"><em>3.2.3 Intermediate Currency (Zwischenwährung).</em> Hierbei wird mittels echten Geldes eine virtuelle Währung in der Applikation gekauft, die gegen Dienstleistungen oder Waren getauscht werden kann (z.B. In-App-Käufe). Den Nutzer*innen soll somit das Gefühl für den echten Geldwert genommen werden.</p>



<h3 class="wp-block-heading">3.3 Sneaking</h3>



<p class="wp-block-paragraph">Oftmals werden den Nutzer*innen relevante Informationen verheimlicht, verschleiert oder erst verzögert mitgeteilt, sodass diese veranlasst werden, bestimmte Handlungen auszuführen, die sie mit vollem Wissensstand nicht durchführen würden. Beispielsweise treten unvorhergesehen Kosten auf oder unerwünschte Auswirkungen der Handlung machen sich im Nachhinein bemerkbar. Dies wird unter dem Begriff Sneaking zusammengefasst und dabei unterscheidet man vier verschiedene Arten (Gray et al., 2018, S. 6-7):</p>



<p class="wp-block-paragraph"><em>3.3</em><em>.1</em><em> Forced Continuity (Erzwungene Kontinuität).</em><em> </em>Nach dem Ablaufdatum eines zeitlich begrenzten Diensts oder einer kostenlosen Testphase werden dem oder der Nutzer*in Kosten verrechnet. Es wird die Versäumnis ausgenutzt und davon ausgegangen, dass der Service weiterhin oder nun eine gebührenpflichtige Version genutzt werden möchte.</p>



<p class="wp-block-paragraph"><em>3.3</em><em>.2</em><em> Hidden Costs (Versteckte Kosten).</em><em> </em>Hierbei werden bestimmte Kosten erst später offengelegt. Eine Dienstleistung oder Ware wird im ersten Moment mit einem speziellen Preis beworben, der sich durch hohe Versandkosten, eine zeitliche Begrenzung oder zusätzliche Gebühren dann allerdings erhöht.</p>



<p class="wp-block-paragraph"><em>3.3</em><em>.3</em><em> Sneak into Basket (In den Warenkorb schleichen).</em><em> </em>Es werden Artikel in den Warenkorb gelegt, die dann unwissentlich von den Nutzer*innen gekauft werden. Argumentiert wird, dass die Artikel Vorschläge basierend auf den vorherigen Käufen sind.</p>



<p class="wp-block-paragraph"><em>3.3</em><em>.4</em><em> Bait and Switch (Lockvogeltaktik).</em><em> </em>Auf eine bestimmte Handlung des oder der Nutzer*in folgt ein unvorhergesehenes und womöglich unerwünschtes Ereignis, welches nicht den Erwartungen entspricht. Beispielsweise wird beim Klick auf das rote „X“ nicht das Dialogfenster geschlossen, sondern die Webseite der Marke geöffnet.</p>



<h3 class="wp-block-heading">3.4 Interface Interference</h3>



<p class="wp-block-paragraph">Unter Interface Interference versteht man jegliche Manipulation des User Interfaces (Benutzeroberfläche), sodass bestimmte Interaktionen wahrscheinlicher auftreten als andere. Dabei soll der oder die Nutzer*in verwirrt werden und die Auffindbarkeit von gewissen Interaktionsmöglichkeiten eingeschränkt werden. Diese Täuschungen lassen sich in drei Kategorien einteilen (Gray et al., 2018, S. 7-8):</p>



<p class="wp-block-paragraph"><em>3.4</em><em>.1</em><em> Hidden Information (Versteckte Informationen).</em><em> </em>Den Nutzer*innen werden wichtige Handlungsmöglichkeiten verschwiegen, indem sie schwer oder nicht sofort zugänglich gemacht werden. Ziel ist, diese irrelevant erscheinen zu lassen. Die Informationen oder Optionen können sich beispielsweise im Kleingedruckten, in Form eines verfärbten Texts oder in den AGBs verstecken.</p>



<p class="wp-block-paragraph"><em>3.4</em><em>.2</em><em> Preselection (Vorauswahl). </em>Hierbei wird eine Option vorausgewählt, die aus der Sicht des Betreibers die gewünschte Wahl ist, jedoch nicht aus der Sicht der Nutzer*innen. Dadurch akzeptieren sie diese Standardoption eher, denn sie denken, dass in ihrem Interesse gehandelt wird.</p>



<p class="wp-block-paragraph"><em>3.4.3 Aesthetic Manipulation (Ästhetische Manipulation). </em>Durch gewisse Designentscheidungen wird die Aufmerksamkeit der Nutzer*innen in eine bestimmte Richtung gelenkt, sodass sie davon überzeugt sind oder von anderen Informationen abgelenkt werden. Innerhalb dieser Kategorie gibt es vier genauere Unterteilungen (Gray et al., 2018, S. 7-8):</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:3%"></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<p class="wp-block-paragraph"><em>3.4.3.1 Toying with Emotion<a> </a>(Spiel mit Gefühlen). </em>Der oder die Nutzer*in wird von einer Emotion, die durch Sprache, Farbe, Stil etc. hervorgerufen wird, zu einer Handlung oder Interaktion verleitet. Neben niedlichen Bildern oder einer beängstigenden Sprache kann auch ein Timer ein Auslöser sein, um Druck auszuüben.</p>



<p class="wp-block-paragraph"><em>3.4.3.2 False Hierarchy<a> </a>(Falsche Hierarchie). </em>Hier wird die Auswahl einer Option durch Hervorhebung beeinflusst. Bei den Nutzer*innen soll das Gefühl entstehen, die beste oder einzige Wahl getroffen zu haben.</p>



<p class="wp-block-paragraph"><em>3.4.3.3 Disguised Ad (Getarnte Werbung). </em>Anzeigen werden als Download-Button, interaktives Spiel oder auf eine andere Art und Weise getarnt.</p>



<p class="wp-block-paragraph"><em>3.4.3.4 Trick Questions (Fangfragen). </em>Zu dieser Kategorie zählen Fragen, die auf den ersten Blick klar erscheinen, in Wirklichkeit aber eine andere Bedeutung haben. Dabei wird mit verwirrender Formulierung, Doppelverneinungen oder manipulativer Sprache gearbeitet.</p>
</div>
</div>



<h3 class="wp-block-heading">3.5 Forced Action</h3>



<p class="wp-block-paragraph">Die letzte Kategorie an Deceptive Patterns umfasst Aktionen, die der oder die Nutzer*in ausführen muss, um den Zugriff zu speziellen Funktionen zu erhalten oder aufrechtzuerhalten. Diese können als letzter Schritt eines Vorgangs oder als vorteilhafte Option getarnt sein. Hierbei wird nochmal zwischen drei verschiedene Arten unterschieden (Gray et al., 2018, S. 8):</p>



<p class="wp-block-paragraph"><em>3.5</em><em>.1</em><em> Social Pyramid (Soziale Pyramide).</em><em> </em>Der oder die Nutzer*in muss weitere Personen einladen, ebenfalls die Applikation zu nutzen, um Vorteile zu erhalten oder exklusive Funktionen nutzen zu können. Häufig sieht man dieses Muster in Online-Spielen oder sozialen Medien.</p>



<p class="wp-block-paragraph"><em>3.5</em><em>.2</em><em> Privacy Zuckering.</em><em> </em>Darunter fallen verwirrende Privatsphäre-Einstellungen, wodurch die Nutzer*innen mehr Informationen von sich preisgeben, als sie eigentlich möchten. Ein Beispiel dafür ist der in den AGBs oder Datenschutzrichtlinien verankerte Verkauf von Nutzerdaten an Dritte.</p>



<p class="wp-block-paragraph"><em>3.5.3 Gamification. </em>Allgemein versteht man unter Gamification, dass Elemente aus Videospielen außerhalb des spielerischen Kontexts verwendet werden, um das Nutzungserlebnis zu verbessern (Deterding et al., 2011). Zu dieser Untergruppe von Deceptive Patterns zählen Situationen, in der sich wiederholende, meist unerwünschte Aufgaben erledigt werden müssen, um sich bestimmte Aspekte des Services zu verdienen. Oftmals können In-App-Käufe genutzt werden, um dies zu beschleunigen (Gray et al., 2018, S. 8).</p>



<h2 class="wp-block-heading">4 Deceptive Patterns in mobilen Applikationen</h2>



<p class="wp-block-paragraph">Di Geronimo et al. (2020) untersuchten 240 kostenlose Apps aus den acht beliebtesten Kategorien aus dem Google Play Store, darunter Amazon, Netflix, Facebook und Spotify. Dabei fanden sie heraus, dass 95% der Apps mindestens ein Deceptive Pattern enthalten. Insgesamt wurden bei der Analyse 1.787 Deceptive Patterns gefunden, was bedeutet, dass eine App durchschnittlich sieben verschiedene Arten verwendet. Die häufigsten Strategien sind Nagging, False Hierarchy und Preselection (Di Geronimo et al., 2020). In den folgenden Unterkapiteln werden beispielhaft Apps aus drei Kategorien angeführt und beschrieben, wie diese Deceptive Patterns verwenden.</p>



<h3 class="wp-block-heading">4.1 Duolingo &#8211; Bildung</h3>



<p class="wp-block-paragraph">Duolingo ist eine beliebte gamifizierte Sprachlern-App, bei der Vokabel und Grammatik in immer schwieriger werdenden Lektionen erlernt werden. Wird eine Frage falsch beantwortet, so verliert der oder die Nutzer*in ein Herz. Sind alle Herzen verbraucht, so muss er oder sie einen bestimmten Zeitraum abwarten oder kann durch In-App-Käufe die Herzen wieder auffüllen. Dabei wird eine virtuelle Währung namens „Gems“ verwendet, mit denen Power-Ups und Herzen erkauft werden können, sodass die Nutzer*innen das Gefühl für den tatsächlichen Geldwert verlieren (Intermediate Currency). Das Forced Action Deceptive Pattern zeigt sich durch die Möglichkeit, ein Werbevideo anzuschauen, um eine Truhe mit Gems zu erhalten (Peter, 2023). Wird die App für mindestens zehn Minuten verwendet, so fallen noch weitere Muster auf. Es werden wiederholt für mehrere Sekunden andauernde Werbevideos oder interaktive Anzeigen geschaltet (Nagging und Disguised Ad), wobei der oder die Nutzer*in bei einer Interaktion unerwarteterweise zum App Store geleitet wird (Bait and Switch). Außerdem kann ein kostenpflichtiges Abonnement („Super Duolingo“) abgeschlossen werden, welches keine Werbung, unbegrenzte Herzen und vieles mehr enthält. Dabei werden vor allem Deceptive Patterns aus der Kategorie Interface Interference genutzt (siehe Abbildung 1). Es wird das Jahres-Einzelabo vorselektiert (Preselection) und es scheint so, als gäbe es nur zwei Möglichkeiten. Hinter dem Button „Alle Abos anzeigen“ versteckt sich allerdings eine dritte Option, die monatlich gezahlt wird (Hidden Information). Allgemein findet man in der App oft visuell hervorgehobene Auswahlmöglichkeiten (siehe Abbildung 1), wodurch der oder die Nutzer*in zu bestimmten Aktionen gedrängt wird (Aesthetic Manipulation: Toying with Emotion und False Hierarchy). Was das Abonnement betrifft, so wird es nach der kostenlosen Testphase automatisch verlängert (Forced Continuity).</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:20%"></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1434" height="1180" src="https://akirchknopf-21110.php.fhstp.cc/wp-content/uploads/2025/01/Duolingo_Screenshots.jpg" alt="Zwei Screenshots der App Duolingo. Auf erstem sieht man die aufgelisteten Abos Familienabo und Einzelabo, wobei Einzelabo mittels einer Umrandung und einem Hakerl vorselektiert ist. Es gibt außerdem eine Option, alle Abos anzeigen zu können, die nicht als Button erkennbar ist. Zeiter Screenshot zeigt einen Text, der den User auffordert die Benachrichtigungen zu aktivieren. Dabei ist erstere Option, die sie aktiviert, blau hinterlegt und zweitere, die das ablehnt, weiß hinterlegt." class="wp-image-13678"/><figcaption class="wp-element-caption">Abbildung 1: Screenshots der App Duolingo, die Preselection, Hidden Information und Aesthetic Manipulation beinhalten</figcaption></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:20%">
<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>
</div>
</div>



<h3 class="wp-block-heading">4.2 Instagram &#8211; Soziale Netzwerke</h3>



<p class="wp-block-paragraph">In sozialen Netzwerken wie Instagram lassen sich mehrere Deceptive Patterns finden. Ein Account lässt sich leicht erstellen, die Funktion, diesen wieder zu löschen, ist allerdings versteckt. Diese Aktion wird den Nutzer*innen somit erschwert, was auf die Verwendung des Roach Motels hindeutet (Di Geronimo et al., 2020, S. 6). Oftmals wird bei Dialogfenstern eine von zwei Optionen hervorgehoben (z.B. der Button zum Erlauben des Zugriffs auf die Kontakte), was dem Interface Interference entspricht. Weiters wird das Privacy Zuckering angewendet (Mildner, Freye, et al., 2023, S. 2367). Laut Mildner, Savino et al. (2023) lassen sich alle fünf Arten aus Kapitel 3 in der App finden. Auch andere soziale Netzwerke wie Facebook, X und TikTok verwenden vor allem Deceptive Patterns wie Interface Interference, Obstruction und Privacy Zuckering (Mildner, Freye, et al., 2023, S. 2366).</p>



<h3 class="wp-block-heading">4.3 Amazon &#8211; E-Commerce</h3>



<p class="wp-block-paragraph">Das Roach Motel Deceptive Pattern wird auch von der beliebten E-Commerce-Plattform Amazon genutzt. Die Kündigung einer Prime-Mitgliedschaft ist im Vergleich zu dessen Abschluss schwieriger aufzufinden und durchzuführen (Di Geronimo et al., 2020, S. 6). Weiters spielt Amazon mit den Gefühlen der Nutzer*innen, indem ihnen klargemacht wird, dass sie sofort alle Vorteile verlieren würden, und zählt diese erneut auf (Toying with Emotion) (siehe Abbildung 2). Allgemein werden bestimmte Farben und Formulierungen genutzt, um die Nutzer*innen davon abzuhalten die Mitgliedschaft zu kündigen (Aesthetic Manipulation) (Verbraucherzentrale Bundesverband e.V., 2022, S. 2-3). Aesthetic Manipulation wird auch, wie bei vielen anderen Webseiten und Applikationen, im Cookie-Banner verwendet (siehe Abbildung 2).</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:20%"></div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1024" height="856" src="https://akirchknopf-21110.php.fhstp.cc/wp-content/uploads/2025/01/Amaron_Screenshots.jpg" alt="Zwei Screenshots der App Amazon. Erster zeigt den Screen, wenn man seine Prime Mitgliedschaft kündigen möchte. Dabei werden nochmal alle Vorteile aufgezählt. Zweiter Screenshot zeigt den Cookie-Banner mit der hervorgehobenen Option, sie zu akzeptieren." class="wp-image-13687"/><figcaption class="wp-element-caption">Abbildung 2: Screenshots der App Amazon, die Toying with Emotion und False Hierarchy beinhalten</figcaption></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:20%">
<div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>
</div>
</div>



<h2 class="wp-block-heading">5 Wirkung und Erkennung</h2>



<p class="wp-block-paragraph">Luguri und Strahilevitz (2021) erforschten die Wirkung von milden und aggressiven Deceptive Patterns. Die Ergebnisse zeigen, dass beide einen Einfluss auf das Verhalten der Nutzer*innen haben. &nbsp;Die Wahrscheinlichkeit, sich für einen bedenklichen Service zu registrieren, war in dem durchgeführten Experiment bei den Nutzer*innen, die mit milden Deceptive Patterns konfrontiert wurden, doppelt und bei denen, die aggressiven Deceptive Patterns ausgesetzt wurden, viermal so hoch wie bei der Kontrollgruppe. Die aggressiven Formen wurden allerdings auch als störender empfunden als die milderen. Zu den Deceptive Patterns, die am meisten Wirkung zeigten und die Nutzer*innen manipulierten bestimmte Entscheidungen zu treffen, die nicht in ihrem Interesse sind, zählen Hidden Information, Trick Questions und Obstruction.</p>



<p class="wp-block-paragraph">Di Geronimo et al. (2020) untersuchten mittels einer Online-Umfrage die Erkennung von fünf bzw. sechs Deceptive Patterns: Nagging, Intermediate Currency, Sneak into Basket in Kombi-nation mit Preselection, False Hierarchy und Forced Action. Dabei stellten sie fest, dass Nutzer*innen diese Muster oft nicht erkennen, und sprechen deshalb von einer DP-Blindheit (DP-blindness).</p>



<h2 class="wp-block-heading">FAZIT</h2>



<p class="wp-block-paragraph">Es gibt viele verschiedene Arten von Deceptive Patterns, die häufig in mobilen Applikationen zum Einsatz kommen. 95% der Apps im Google Play Store nutzen mindestens eines dieser Muster. Diese können in fünf Kategorien eingeteilt werden, nämlich Nagging, Obstruction, Sneaking, Interface Interference und Forced Action. Viele davon finden auch in den Bereichen Bildung, soziale Netzwerke und E-Commerce Verwendung. In der gamifizierten Sprachlern-App Duolingo findet man beispielsweise In-App-Käufe mit einer eigenen virtuellen Währung, freiwillige und unfreiwillige Werbe-Unterbrechungen und visuell hervorgehobene Buttons. Bei der Bewerbung des kostenpflichtigen Abonnements wird wiederum eine Option vorselektiert und andere versteckt. Sowohl hier als auch bei Amazon wird das Abo bzw. die Mitgliedschaft nach Ablauf verlängert, was den Betreibern zugutekommt. Die Kündigung der Mitgliedschaft bzw. die Löschung des Accounts wird den Nutzer*innen auf Plattformen wie Amazon oder Instagram ebenso erschwert. Allgemein kann gesagt werden, dass viele der Deceptive Patterns in gewissen Kombinationen auftreten und dass vor allem oft Aesthetic Manipulation genutzt wird, genauer gesagt Toying with Emotion und False Hierarchy. Während die einen Deceptive Patterns als störend empfunden werden, fallen andere den Nutzer*innen gar nicht auf. Jedenfalls haben sie einen gewissen Einfluss auf ihre Handlungsentscheidungen, weshalb es umso interessanter ist, spezifische Apps hinsichtlich der Verwendung und Wirkung solcher Muster noch genauer zu untersuchen. Hinzu kommen Fragen nach ethischen Grundsetzen und der Erkennung solcher Muster, mit denen man sich beschäftigen muss, wenn die Häufigkeit von Deceptive Patterns in Zukunft weiter zunimmt.</p>



<h2 class="wp-block-heading">LITERATUR</h2>



<p class="wp-block-paragraph">Brignull, H. (2023). <em>Deceptive Patterns: Exposing the Tricks Tech Companies Use to Control You</em>. Testimonium Ltd.</p>



<p class="wp-block-paragraph">Brignull, H., Leiser, M., Santos, C., &amp; Doshi, K. (2023, 25. April). <em>Deceptive patterns – user interfaces designed to trick you</em>. https://www.deceptive.design/ (Abgerufen am 23.11.2024)</p>



<p class="wp-block-paragraph">Conti, G., &amp; Sobiesk, E. (2010). Malicious interface design: Exploiting the user. <em>Proceedings of the 19th international conference on World wide web</em>, 271–280. https://doi.org/10.1145/1772690.1772719</p>



<p class="wp-block-paragraph">Deterding, S., Dixon, D., Khaled, R., &amp; Nacke, L. (2011). From game design elements to gamefulness: Defining „gamification“. <em>Proceedings of the 15th International Academic MindTrek Conference: Envisioning Future Media Environments</em>, 9–15. https://doi.org/10.1145/2181037.2181040</p>



<p class="wp-block-paragraph">Di Geronimo, L., Braz, L., Fregnan, E., Palomba, F., &amp; Bacchelli, A. (2020). UI Dark Patterns and Where to Find Them: A Study on Mobile Applications and User Perception. <em>Proceedings of the 2020 CHI Conference on Human Factors in Computing Systems</em>, 1–14. https://doi.org/10.1145/3313831.3376600</p>



<p class="wp-block-paragraph">Gray, C. M., Kou, Y., Battles, B., Hoggatt, J., &amp; Toombs, A. L. (2018). The Dark (Patterns) Side of UX Design. <em>Proceedings of the 2018 CHI Conference on Human Factors in Computing Systems</em>, 1–14. https://doi.org/10.1145/3173574.3174108</p>



<p class="wp-block-paragraph">Luguri, J., &amp; Strahilevitz, L. J. (2021). Shining a Light on Dark Patterns. <em>Journal of Legal Analysis</em>, <em>13</em>(1), 43–109. https://doi.org/10.1093/jla/laaa006</p>



<p class="wp-block-paragraph">Mildner, T., Freye, M., Savino, G.-L., Doyle, P. R., Cowan, B. R., &amp; Malaka, R. (2023). Defending Against the Dark Arts: Recognising Dark Patterns in Social Media. <em>Proceedings of the 2023 ACM Designing Interactive Systems Conference</em>, 2362–2374. https://doi.org/10.1145/3563657.3595964</p>



<p class="wp-block-paragraph">Mildner, T., Savino, G.-L., Doyle, P. R., Cowan, B. R., &amp; Malaka, R. (2023). About Engaging and Governing Strategies: A Thematic Analysis of Dark Patterns in Social Networking Services. <em>Proceedings of the 2023 CHI Conference on Human Factors in Computing Systems</em>, 1–15. https://doi.org/10.1145/3544548.3580695</p>



<p class="wp-block-paragraph">Peter, M. (2023, 6. Februar). Dark Patterns in Popular Mobile Apps. <em>Medium</em>. https://medium.com/@marcpeter1997/dark-patterns-in-popular-mobile-apps-296011029579</p>



<p class="wp-block-paragraph">Verbraucherzentrale Bundesverband e.V. (2022). <em>Dark Patterns—Manipulatives Design im Internet: Fallsammlung aus dem Verbraucheraufruf „Dark Patterns“ der Marktbeobachtung Digitales (Stand: 09.02.2022)</em>. https://www.edpb.europa.eu/system/files/2022-05/2021-02-09_fallsammlung_verbraucheraufruf_dark_patterns.pdf</p>
<p>The post <a href="https://mobile.fhstp.ac.at/allgemein/sota-versteckte-beeinflussung-deceptive-patterns-in-beliebten-mobilen-applikationen/">SOTA | Versteckte Beeinflussung: Deceptive Patterns in beliebten mobilen Applikationen</a> appeared first on <a href="https://mobile.fhstp.ac.at">Mobile USTP MKL</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
