A full-stack warehouse management system covering the complete inbound → storage → outbound lifecycle: product and location master data, lot/expiry tracking, multi-dimensional location capacity, planned putaway and picking, an immutable stock-movement ledger, and an analytics dashboard.
The backend is an ASP.NET Core (.NET 10) Web API built with a clean, layered architecture. The frontend is a Vue 3 single-page app. Data is stored in PostgreSQL.
| Live demo: | https://ambitious-wave-066504303.7.azurestaticapps.net/ |
| Login: | demo@wms.local |
| Password: | 1wFWvd8zrS7! |
Storage / Quarantine / Returns), temperature zone (Ambient / Chilled / Frozen), multi-dimensional capacity (Units / Weight / Volume — each independently capped, most restrictive wins), mixed-SKU / mixed-lot rules, active & blocked states, and per-location preferred products.Draft → Putaway → Completed (cancellable from Draft or Putaway).PreferredLocation, ConsolidateSameLot, ConsolidateSameSku, Proximity, NearestEmpty, NearestAvailable.Draft → Picking → Completed (cancellable).FEFO (first-expired), FIFO, LIFO, LeastQuantity, plus Manual override.StockMovement record, produced as a side effect via domain events — a complete, append-only audit trail.Admin, Manager, Worker. All endpoints require authentication by default; write operations require Admin/Manager.A job-offer aggregator for the Belgian market: a set of scrapers collects postings from five portals, stores them in a shared, deduplicated database and serves them through a single panel with filters. Runs start automatically on a schedule managed from the app, or manually with one button.
Built as a commissioned project for a company — deployed on the client's server (OVHCloud) as a set of Docker containers.
The backend is a FastAPI service (SQLAlchemy + Pydantic, SQLite, Alembic migrations). The frontend is a Vue 3 single-page app with TypeScript and PrimeVue.
source:external_id key with a UNIQUE index — repeated runs only append genuinely new postings.docker compose up; the database and the positions dictionary live in a volume, so rebuilding images leaves them untouched. The schema is created by migrations executed on API startup.Portfolio website template built with the Angular framework. The application has no backend — all content comes from files in the public/assets directory, so creating your own portfolio comes down to replacing them, without touching the source code. The whole thing is built as a static site (SSG): every page, in every language, is rendered to finished HTML at build time and can be served from a CDN, with no application server.
Structured data (profile, experience, projects, technologies, site settings) is described in JSON files, while longer workplace and project descriptions are written in Markdown, in a separate file for each language.
outputMode: static produces static HTML for every route and every language. Search engines and link previews get finished content instead of an empty <app-root>, and in the browser the page hydrates into a full SPA. The JSON data and Markdown descriptions fetched at build time are embedded into the resulting HTML, so the browser never fetches them a second time./pl, /en), and each language version has its own prerendered HTML. Interface texts come from translation files (@ngx-translate), and the list of available languages from the site configuration. On the root address the language is taken from the visitor's earlier choice, falling back to their browser preferences. The switcher in the navigation bar changes language while staying on the same page, without a reload.canonical link and a full set of hreflang links to its counterparts in the other languages (including x-default), and the lang attribute on <html> matches the content being shown. The CV download page is excluded from indexing.body element, with smooth color transitions. The choice is remembered and applied before the page is first painted, so there is no flash of the other theme on load.tools/generate-thumbnails.py script (Pillow, OpenCV) creates optimized JPEG thumbnails for images and from the first frame of videos, following the thumb_<name>.jpg naming convention.technologies.json; labels without an entry fall back to a default color.IntersectionObserver; each element animates once.Desktop application for advanced monitoring of in-game chat in Metin2. Chat is read purely from the screen — the game window is captured every 100 ms and the text is recognized by a custom pixel-based OCR algorithm. The application does not interfere with the game process: no client files are modified, no memory is read, no code is injected.
The client is a Blazor Hybrid app (.NET MAUI, .NET 10) with a MudBlazor UI; screen capture is implemented for Windows (P/Invoke into user32/gdi32: GetDC + BitBlt over the client area of the selected window). The backend is an ASP.NET Core Web API with a PostgreSQL database.
[name]) as separate objects within a messageInstead of an off-the-shelf OCR engine, the app uses bitwise pattern matching, which fits the game's fixed raster font:
charset.bmp plus the character list in charset.txt) is scanned column by column; every glyph is encoded as a UInt128 mask and stored in a two-way dictionary (mask <-> character).UInt128 buffer (|= with a bit shift); an empty column ends the glyph and triggers a dictionary lookup.Private servers differ in font, chat colors, message format, channel count, server start hour, and boss list (name, count, respawn time).
{Channel}, {Player}, and {Boss} placeholders and compiled into regular expressions with named groups, from which kill details are extracted.ASP.NET Core Minimal API (.NET 10), EF Core + PostgreSQL, validation via FluentValidation.
A 2D game engine written in C++ with a graphical editor: OpenGL renderer, Entity Component System (EnTT), physics simulation (Box2D), native scripting, and a custom networking module built on GameNetworkingSockets.
The core architecture is based on the open-source version of the Hazel engine, but it includes numerous modifications and custom-built solutions — the largest being an entirely custom networking module. It is a hobby project in an early stage of development, not intended for commercial game production; development is currently suspended.
As part of the master's thesis, the engine was extended with a networking module, which was then analyzed in terms of the impact of network latency on gameplay simulation quality. In particular, the study examined how different parameter values of the client-side prediction algorithm affect the frequency and scale of desynchronization.
The project is configured with Premake5 (Windows, Visual Studio) and builds in three configurations: Debug, Release (with the editor), and Distribution — an editor-free build that serves as the game runtime.
The engine was previously developed under the name Proton2D — the entire git history lives in the old repository https://github.com/Damian-Zuk/proton2d.
TextureAtlas, Sprite), 9-slice scaling, and atlas-based animations.Scene wraps the EnTT registry; Entity is a pair of an identifier and a scene pointer, with a UUID assigned to every object.AppScript > GameScript > EntityScript (application, game mode, and single object logic), a script factory that instantiates classes by name, and a registration macro.REGISTER_FIELD) show up in the inspector and are serialized together with the scene; supported types include scalars, vectors, strings, and any trivially copyable data.REPLICATED_FIELD) is synchronized over the network automatically, optionally with a callback invoked when a new value arrives.Rigid bodies, box and circle colliders with material parameters and collision filters, sensors, contact listening with a callback into the script, and revolute joints (attaching an object to its parent).
A client-server architecture with a fully authoritative server, running as a listen server, a dedicated server, or a client. All communication goes through a custom binary stream (the header is written back once the payload size is known), and every value read is validated against the remaining buffer size — an inconsistent packet disconnects the client instead of reading out of bounds.
PositionX, PositionY, ScaleX, ScaleY, Rotation), while changes to script fields are detected with a CRC32 checksum computed per client. An object with nothing to report is rolled back out of the stream.The synchronization method is set per object in the inspector, together with the reconciliation and teleport thresholds and the reconciliation duration:
A Python CLI tool that generates a vulnerability (CVE) report for IoT devices. It takes a manually defined device list in JSON format (model, firmware version, MAC address) and/or network scans produced by Nmap (XML). For every identified piece of software — firmware, services on open ports, and the operating system — the script queries the National Institute of Standards and Technology National Vulnerability Database (NIST NVD) and attaches the discovered vulnerabilities to the output report.
Built for the "Security of IoT Systems" course at Rzeszów University of Technology.
devices.json) — manually entered data forms the base of the report and takes precedence over scan data.nmap -A -oX) — hosts are matched to listed devices by MAC address; unknown hosts are added as new entries. Extracted data includes: IPv4 address, vendor (from the MAC), only ports in the open state along with their services, and the OS detection result.model + version, product + version, OS name + family + version). Identifiers in the older CPE 2.2 format are normalized to CPE 2.3.cpeName; when no CPE could be resolved for a device, a keyword search is used instead and the CPE is backfilled from the first matching vulnerability.vulnerabilities section.The report is an array of devices; each entry contains:
firmware, service (keyed by product version), and os (keyed by family version). Each category holds the total number of CVEs found and the list itself, where a single entry carries the CVE identifier, publication date, description, the CVSS metric used, the numeric score, and the severity level (LOW / MEDIUM / HIGH / CRITICAL).config.ini)linux, android), where the number of hits is too large for the result to be useful; the report records a note about the skipped check.A static report-viewer.html page (no backend, no dependencies) — the JSON file is loaded via drag and drop. Devices are presented as collapsible panels, severity levels are color-coded, and CVE and CPE identifiers link directly to the corresponding NVD pages. The same view also handles the input device list, since it shares the exact same structure.
versionEndIncluding) are not evaluated, so a vulnerability described by a range may go undetected.A student project using Ansible to automate the configuration management of virtual machines, installation of system packages, and deployment of a simple LAMP-based application.
The whole setup runs in the AWS cloud — the control node and the managed web servers were launched on separate instances. Playbooks are executed through Ansible Semaphore, a graphical interface for Ansible that provides browser-based task execution, schedules, a key store for access credentials, and a history of runs with their logs.
The core of the project was documenting the configuration of the entire solution — from preparing the instances and SSH access, through installing and configuring Semaphore, to describing how each role works. The repository contains Ansible files only: playbooks, roles, and the inventory.
admin list (with specified UID and description).authorized_keys./etc/sudoers file.memory_limit to 256 MB.posts table if it does not exist.posts table based on an SQL template./var/www directory.config.php configuration file from a Jinja2 template.A web application for creating simple single-question polls and voting on them, inspired by the StrawPoll.com platform.
The backend is a REST API built on FastAPI (SQLAlchemy ORM, PostgreSQL, validation through Pydantic), with Redis acting as the session state store and the rate limit counter. The frontend is a single-page application in React + TypeScript (Vite, Bootstrap). Everything runs through Docker Compose, and the API documentation is generated automatically (Swagger).
Rather than simply issuing tokens, I wrote a separate session management module (fastapi_jwt_redis) that plugs into the FastAPI dependency system:
jti identifier, expiration time, and not-before time.A React application with client-side routing and periodic background session refresh (the access token is exchanged before it expires). A single-poll view under its own address makes polls shareable, and the votes already cast by the logged-in user are fetched in one batched request covering every poll on screen.
An e-commerce application for selling car parts. It was developed in a team of five in collaboration with a management faculty group using the Scrum methodology. The application was created as part of a university project course titled “Software and Database Engineering.”
Built with Django (Python) on a PostgreSQL database, with server-side templates and a Bootstrap-based interface. The application is localized for the Polish market, works as a PWA, and was deployed to Heroku (gunicorn, whitenoise).
My scope of work covered the product catalog and the presentation layer: filtering and sorting of the product list, splitting the assortment into sections and categories along with the navigation bar, pagination, discounted price handling with the sale view and the special offers section, as well as extracting the home view queries into a separate service layer. On the interface side I built, among others, the responsive navigation bar, the floating shopping cart, and the templates for the product page, the product list, login and registration, and the order summary.
Built on an open-source Django module (the comparison list is kept in the session, with items added and removed over AJAX), extended with a parameter table sourced from the JSON field: the attributes of all compared products are merged into a single set and laid out row by row, with missing values marked by a dash. Comparison happens within a single category.
A puzzle game inspired by the classic Sokoban — the goal is to push every crate onto its designated target tile. Written in C++17 with the SFML library and no ready-made engine: the game loop, state system, entities, animations, and UI controls were all implemented from scratch. The in-game interface is in Polish.
The project is built with CMake and targets the Win32 (x86) platform, matching the bundled SFML version.
Header (18 bytes): board dimensions, player start position, and crate count. It is followed by an array of target tile positions (8 bytes each) and the tile grid stored as one byte per field (no tile / floor / wall / crate).
The floor and wall texture variant is drawn from a seed derived from the level dimensions, so the board looks varied yet renders identically on every load.
A console-based client-server chat application for Windows, written in C++ on Winsock sockets (TCP) with no external libraries. The server and the client are two separate command-line applications; all the logic — accounts, ranks, permissions, bans — lives on the server side, while the client is only responsible for displaying output and forwarding whatever the user types.
An early hobby project, born out of a desire to learn network programming and multithreading.
srand seeded with successive characters of the key and mixed into the data with XOR.GUEST (unregistered), USER, VIP (colors in messages), MOD, and ADMIN, compared numerically — a command requires a rank no lower than its threshold.7d, 12h, 30m) and the expiry is stored as a timestamp; once it passes the entry stops applying, and the remaining time is presented in a readable form.A plain console is unsuitable for a chat: text arriving from the network breaks up the line the user is currently typing. A separate component was built for this project to solve that problem:
{number} markers embedded directly in the content — the same string can be printed with colors or stripped of the markers, which is used for the messages of VIP-ranked users, among other things.A clone of Flappy Bird written in Python using the Pygame library. Pygame only handles the window, drawing, and input events — the game layer (objects, scenes, resources, update loop) was built from scratch.
z_index, which establishes the layer order.tap (start screen), playing, died, and died_new_best. Changing the game state comes down to enabling one scene and disabling the others, rather than hiding individual elements by hand.Falling speed builds up to a terminal value, and the acceleration depends on the phase of flight — an ascent is damped more strongly than a free fall, which produces the characteristic jump arc. After a collision the bird switches to a separate falling mode with higher acceleration and a higher terminal speed, stopped only at ground level, while the end screen appears after a short delay.
The record is kept in a binary file preceded by a SHA-256 hash computed from the score and a fixed string embedded in the code. On load the hash is recomputed and compared against the stored one — a mismatch (that is, a hand-edited file) or corruption causes the record to be discarded and the count to start over from zero.
A 2D platformer game written in C++ on the SDL2 library, which only handles the window, texture drawing, and keyboard input — the game loop, objects, physics, camera, and map loading were all written from scratch.
Collisions do not work by pushing an object back once an overlap is detected. For each axis separately, every object lying in the path of movement is scanned and the nearest blocking edge in the direction of travel is determined, with the new position clamped to it. As a result an object never jumps through an obstacle even at high speed, and the map bounds act as a natural limit.
Gravity builds up in proportion to the object's mass until it reaches a set terminal velocity, while contact with the ground or ceiling zeroes the vertical velocity and updates whether the object is airborne — that flag gates the jump, which is only possible while standing on ground.
Horizontal movement accelerates from a starting speed up to a maximum, with lower acceleration in the air than on the ground and a slightly higher top speed while airborne — producing a noticeable difference between running and steering mid-jump. Changing direction in flight slightly adjusts the vertical velocity, and a separate key returns the player to the spawn point.
A roulette simulator inspired by the CSGODouble platform, running entirely in the browser — no backend, built on plain JavaScript with jQuery and Bootstrap. An early project from 2017, created while learning the basics of JavaScript and web development.
The wheel has 15 fields, and a bet is placed on one of three colors:
The algorithm reproduces the "provably fair" scheme used by platforms of this kind — the outcome is fixed before the spin begins and can be verified afterwards. The winning number is derived from three values:
seed — a secret string disclosed the following day so that the previous day's results can be verified (generated as the hash of a random 48–64 character string),public — a public value, which here is the current date in year-month-day form,round — the round number within that day.The values are joined into a single string and passed through the SHA-256 hash function. The first eight characters of the result are read as a hexadecimal number, and its remainder modulo 15 determines the winning field. Further characters of the same hash also produce the offset within the field, so the pointer stops at a different spot of the same field every time — in an equally verifiable way.
The fields sit on a looped strip in alternating order (red and black on both sides of the zero), and a spin comes down to shifting the background by a computed distance. The movement decelerates exponentially — each step covers a fraction of the remaining distance, so the wheel slows down the more gently the closer it gets to its target. The starting distance spans several full revolutions plus the path to the drawn field, and the rate of deceleration is adjustable with a speed control.
A separate panel makes it possible to inspect the generator first-hand: manually set or regenerate the seed, public, and round values, disable the automatic round increment, change the countdown length and the animation speed, lift the free coins limit, and start a spin immediately without waiting for the countdown to finish. By entering the same three values, any earlier spin can be reproduced and confirmed to have not been altered along the way.