Here you can find a part of the software projects I developed.

Further down you can find the projects I developed as part of my training as a full-stack web developer.

Currently I work as a consultant at Woodmark Consulting AG.

Tech stack I have used so far:
Frontend: HTML, CSS, JavaScript, React.js, Vue.js, Nuxt.js, QML, LiveScript, jQuery
Backend: Node.js/Express, Python, Java, Spring Boot
Databases: PostgreSQL, SQLite
Cloud Computing: AWS (ECR, EC2, S3, CloudWatch, CodePipeline, Lambda, ParameterStore), Terraform
CICD: GitHub Actions, AWS
Testing: Jest, jUnit, PyTest, unittest
Monitoring/Alerting: DataDog
IDE's: IntelliJ, PyCharm, Visual Studio Code, QtCreator
Version Control: Git, GitHub, GitLab


App for copying files and creating graphs

Tech stack: Python 3.8, Matplotlib, Pandas, NumPy, PySimpleGUI, poetry, pyinstaller
Version control: Git, GitLab
IDE: PyCharm

Features: graphical user interface, search for patients, copy all relevant local files to server with modified folder structure and create graphs with a simple click, feedback of the processing status, extensive error display, create debug logfile

The code on GitLab

Show gif

  • To find out exactly what the employees of Charité need and to develop a customer-centric software (the app emerged from these discussions in several iterations)
  • The app should copy reliably, quickly and completely
  • The app should be easy to use
  • The app should create beautiful .svg graphs
Task Description
  • Write software that copies local data from different computers to a server, creating a specific folder structure on the server and changing the date folder from 8 to 6 digits
  • Create .svg graphs from .csv file(s) if available, additionally using xml layout files
  • User-friendly graphical interface
  • Create a JSON file with relevant values for later use
  • App must run in a Windows environment, create an .exe file
The App

GRAIL_upload copies the local data from GRAIL-computer and Vicon-computer to the BeMoveD-server of Charité Berlin and creates .svg-graphs if it finds the correct .csv-file.

If the app runs, a (German-speaking) GUI opens and the user is prompted to input a patient ID. The app checks if the patient exists (e.g. P100). If they are found, the GUI shows source and destination path and if .csv-files are found.

If the button is pushed and there is a .csv-file, the app

  • copies the .layout files into each date-directory, cleans them (deletes all the HTML-tags), replaces the arrows with better-looking ones and renames them ('walk.layout', 'run.layout')
  • creates a .json-file for later use with the keys 'title', 'graphname' und 'channelname' from the .csv-file
  • creates a directory 'cascade-graphs' and a subdirectory for each time (e.g. '1013') that is in the filename of the .csv-file
  • creates from each .csv-file (usually) 89 .svg-graphs and saves them into the corresponding time-subdirectory
  • writes a readme-file in each time-subdirectory
  • creates 3 directories on the server: 'Dokumente', 'GRAIL', 'Vicon'
  • copies everything from the local patient data (e.g. P100/20211016) into the GRAIL-subdirectory on the server ('P100/211016/GRAIL'). This includes the patient-data, the .layout-files, the .json-file, and the graphs if there is a .csv-file.
  • copies every file from the local Vicon path 'D:/BeMovedDB/gait analysis bemoved/P100/New Session' into the corresponding Vicon-directory on the server ('P100/211016/Vicon'). 'Corresponding' means here that the creation date of the file has to match the date (e.g. created on October 16th 2021 is put into 'P100/211016/Vicon'). Since creation dates differ on Windows OS and Linux/Mac OS, there is first a check for the OS in use.
  • shows the user that it is still copying. When done it shows the user that it is done.

When there is no .csv-file, steps a-e are skipped.

Dates and times are found with regular expressions.

Error Handling

GRAIL_upload's GUI shows the user a variety of possible errors:

  • When the user inputs anything else than digit
  • When the user inputs less than 3 or more than 4 digits
  • When the patient does not exist
  • When there is no .csv-file
  • When the .csv-file is wrong (first box does not contain the string 'left')
  • When there is no local date-directory
  • When the local date-directory does not have exactly 8 digits
  • If the .layout-file does not exist at the given path
  • When copying fails

Additionally, a logfile for debugging is created.

  • Greatest success: Feedback from Charité employees that the app saves them 2-5 minutes per patient and that they use it daily
  • Differentiated error handling with precise feedback to the user
  • Desire to develop more with Python 😊

Scraping WGcompany

Automated e-mail for new housing offers

Tech stack: Python 3.10, selenium, chromedriver-autoinstaller, chromedriver-py, dateparser, poetry, python-dotenv
Version control: Git, GitHub
IDE: PyCharm

Features: The app scrapes the newest entries on and emails them automatically to a given email address.

The code on GitHub

Show gif

Get local environment variables or GitHub secrets (remote) for GitHub Actions, headless selenium chrome webdriver, match version of Chrome browser and chromedriver, assertions that the page to be scraped is correct, fetch relevant data with XPath and RegEx patterns, change date patterns, send email through SSL-connection with all relevant info in utf-8 encoding, functions: typing of parameters and return values and extensive explanator docstrings.

Social Network

screenshot of social Network Kite.Inc displaying some search results

Facebook-inspired single-page-application (SPA)

Tech stack: React & Redux, Node, Express, PostgreSQL,, Amazon S3 and SES, CSS, HTML

Features: Registration, login, a personal profile with bio and image upload, sending, receiving and accepting friend requests, unfriend, having conversations in a chat room, display of last 3 registered users, searching for users by first and last name, showing friends of friends, logout

The code on GitHub

Show gif

Users can join a social network, in this case focusing on inclusive kitesurfing communities.

A high priority is on conditional rendering, security issues (password hashing, protection against SQL-injection, CSRF- and XSS-attacks, reset code by email) and a differentiated error handling (different error messages get displayed, e.g. if the email is not in the database, the retyped password does not match the first password or the input fields are left empty) in the register, login, and reset password components.


screenshot of petition against algorithmic bias displaying the register site

Online-petition against algorithmic bias

Tech stack: Express handlebars, Node, PostgreSQL, jQuery, CSS, HTML

Features: Supporters can register, login, update their profile information, sign, unsign, view fellow signees sorted by location, logout

The code on GitHub

Show gif

This petition advocates for signing the Algo.Rules and against algorithmic bias. Depending on whether users register and sign, they get served different sites. If they sign, other signees, their homepages, age and city are displayed.

I learned about dataflow, working with session-cookies, get- and post-routes and how to test them with supertest. I was also working with promises, password hashing and inserts, updates, upserts and deletes in the database. Getting the signature on a canvas and conditionally editing the profile I found particularly challenging.

The site has a differentiated error-handling and is protected against SQL-injection, clickjacking, XSS- and CSRF-attacks.

up-arrow to jump to the top of the page


screenshot of imageboard graffiti and street art displaying landing page

Instagram-inspired single-page-application (SPA)

Tech stack: Vue, Node, Express, PostgreSQL, Amazon S3, Jest, CSS, HTML

Features: Upload of images with title, description and username, each image can be clicked and displayed in large with more info and the possibility to comment and also delete the image, more images can be loaded

The code on GitHub

Show gif

Anyone can upload images of their choosing; the theme of this imageboard is graffiti and street art.

I learned about Vue.js and working with state, un/mounting, dynamic routing, click handlers, event-emitters and watchers. The imageboard is protected against SQL-injection, clickjacking, XSS- and CSRF-attacks.


screenshot of Kaleidoscope displaying the landing page with all the projects

My smaller and medium-sized projects

Tech stack: Express handlebars, CSS, HTML

Features: Display of all projects, description-site for each project

The code on GitHub

Resizable Panes

screenshot of resizable panes

Features: Resize pane with slider, display one image or the other

2 images blending into each other, usually used for before-after-images. I used it to commemorate my great-grandmother Emilie Rau. If you click on the white slider in the middle and slide it to the left you will see more of the image on the right-hand side and vice versa. Programming-wise I used mousedown, mousemove and mouseup events and offset().left became a good friend. It was difficult to end the sliding within the boundaries of the pane.

Spotify Search

screenshot of spotify search, displaying search results for 'monae'

Features: Search Spotify database through API, display album/artist with hyperlinked cover and name, load more through button click or infinite scroll

Still not having a Spotify account myself, nonetheless I programmed a user interface to search via an API the spotify database. When you search for an artist or album the first 20 search items are displayed with an image of the album and the name of the artist. If you've reached the bottom, you can click 'More' to load the next 20 items. I also added infinite scroll. I used jQuery, clickhandlers, several ajax 'GET'-requests, CSS flexbox and played with pseudo-selectors - fun! I found it quite difficult to figure out the order when to call which function and that they don't interfere with each other. In the end I managed and if you click on the link below you have an unlimited supply of search results - hopefully YOU have a spotify account...

screenshot of kitty carousel displaying one kitty sliding to the left and one another coming in from the right

Features: Watch kitties carouseling, pick a specific image to be displayed again

4 kitty-images move from right to left in an endless loop, one image per second. You can also pick a specific image by clicking on the corresponding white dot. Timing and space was important to program the carousel, including the addition and removal of querySelectors, eventListeners and clickHandlers. It was the first time I worked with CSS-transitions. It's cute, ain't it? Click on the link to watch the kitties carouseling...


screenshot of ticker running

Features: Get the latest news displayed, click if you are interested

Tickers are a bit outdated, but a good programming exercise. Mine runs from right to left, and if you mouseover on one of the titles the ticker stops running, the hyperlink becomes blue and underlined and if clicked the desired information opens in a new tab. The programming is in vanilla JavaScript with event listeners, mouseovers, mouseouts, offsetWidth and AnimationFrames among other things. If you wanna deep dive into my ticker you get to read all my texts that got translated into English... In a later exercise we added a backend and fetched live data from existing twitter-accounts through the twitter-API using tokens.

Local Storage

screenshot of local storage project

Features: Write a message and save it in local storage, display and/or delete message

Working with local storage was fun. If you write something in the text field and click the button 'Keep it a secret!' the text disappears and the button cannot be clicked again (to keep what was saved to local storage). The button left to this ('Tell me the secret!') reveals what was saved, even after the browser was closed. The last button ('I don't trust you anymore - forget my secret!') clears the local storage and the console. I worked with jQuery using click handlers and try-catch error-handling.


screenshot of JSON-validator displaying vald JSON in green

Features: Test if data is JSON or not

This simple validation test tells you if you have JSON or not. Simply copy-paste in the textfield and hit the 'Validate JSON' button. If you have JSON, the border of the textfield turns into green and a 'Valid JSON!' text blinks at the bottom of the textfield. If you don't have valid JSON, the border turns red and it will let you know that you do not have valid JSON. 'Clear textarea' to test some more... Done with jQuery with the parse()-method and flexbox and keyframes in CSS.

Connect 4

screenshot of connect four, both colors in the game

Features: 2 players can play against each other, horizontal, vertical or diagonal victories, animation when one player wins, winning color gets displayed, play again

I loved playing Connect 4 as a child - and I still do today! I never thought I would build one as a computer game. The hardest part was figuring out and programming the diagonal victories. You can either pick dark-red or pink to play. Every move is accompanied by a sound. When one color wins, the whole board expands and the winning color fills the screen. This animation I did with jQuery. Additionally, there is a winning-message blinking - I programmed this in CSS with animations and keyframes. The 'Play again' button restarts a new game - you should give it a shot!

Spiced Homepage

screenshot of spiced homepage

Features: Pop-up modal, hamburger menu with navigation sliding in from the right, also suited for smaller screens

An exercise in building a homepage for Spiced with HTML, CSS and JavaScript/jQuery without flexbox or grid - quite challenging! I added a pop-up modal and a menu that slides in from the right. It is also designed for a smaller screen with @media screen. I used animations, click handlers and (dis)played (with) in/visibility.

Features: Search countries, use either mouse or keys

I have used incremental searches many times in my life and did not even know this term until I had to build one... I never thought about all the different steps that need to be programmed. I learned how to work with mouseovers, mousedowns and key-commands and how to highlight a search result, all programmed with jQuery. I also used focus and blur when a user's attention blurs (pun intended 😉) and after all it was my first ajax 'GET'-request to search from an API serving over 200 countries.