Hi 👋 I'm Krystof
Fullstack software engineer
I'm a detail-oriented software engineer with 5 years of experience in fullstack web development. I'm targeting roles involving TypeScript, React, Ruby and Go with an opportunity to transfer to North America.
Read about my professional contributions, skills, and more below or see my CV.
Professional contributions
2025-Now
Terminal integrations
I've integrated Portchain's data platform with terminals from Central America and Southern Europe using REST APIs. See more... These integrations periodically check for updates from terminals, match their schedules with Portchain's data and synchronize between the two.
Other
- Implemented MVP features as part of a bet which got us a new major customer.
- Played a role in migration from Heroku to Google Cloud Platform to decrease infrastructure costs.
- Maintained a deployer application used to simplify deployments to various environments on Google Cloud Platform.
- Modernized the codebase by introducing Dependabot and updating dependencies.
2022-2025
Funding rounds calculator
I have driven increased product demand by developing a calculator that helps founders model unpriced funding rounds. See more... The solution involved an RFC-like process to come up with the best solution as this was the first public page (i.e. not behind auth, obviously excluding a sign in/sign up flow). At the time we were also in a rebranding transition where the homepage was already transitioned and the idea was to use the new design on all public facing pages so the calculator should also follow the new design. It uses many primitive components and other more complex components some of which I helped building. Check it out for yourself!
Billing revamp projectwar story
I enabled better sales offering and streamlined customer billing management by revamping billing in a Ruby on Rails app integration with Stripe and HubSpot. See more... This was the longest running project I worked on and wrote around 90% of it when it comes solely to the changes in the app codebase. First step was a migration from one Stripe instance to another. The next step involved changing how the app is interacting with Stripe where previously it was the app recording changes to customer subscriptions using Stripe's API and now the idea was to make these changes from the self-service customer portal and update the app data via webhook events from Stripe. It also involved a change to the pricing packages where there was previously a single package and additional customer features were enabled on an ad-hoc basis and now there would be multiple packages with certain pre-enabled features.
Fundraising for early-stage startups
This project helps early-stage startups in fundraising and offering them inexpensive assistance on tax relief to ensure their success. See more... Services included are round modelling calculator, creating and filing advance assurance, SEIS & EIS, and templates for ASAs & SAFEs. Major challenge in this project was a tight deadline that was agreed on few months in advance and that had to be met which I achieved without sacrificing quality.

In-app workflows
The in-app workflows I implemented increased number of requests for an additional paid service from ~5 to 20+ a month increasing revenue in this area by 300%. See more... These included a backoffice part, where our colleagues fulfilling the request were able to manage and update progress on the requests, and the end customer part, where customers were able to request these services.
Currency exchange rate provider
I provided affordable currency exchange rate solution for 200+ currencies. See more... While the app had a multi-currency support from the time I joined, the currencies that were supported were those available from European Central Bank which contains 30 currencies. Meanwhile, there are 180 currently circulating currencies recognized by UN and some of those started to appear in the app and it became cumbersome to deal with them manually. I used Exchangerates API to get a more comprehensive list of the exchange rates. As we didn't call the API everytime we needed the exchange rate but instead stored it in a database (we also needed historical exchange rates in some cases), new exchange rates were automatically added to the database on a daily basis.
Automated invalid link checker
Addressed invalid links by automatically checking and reporting them. See more... An external link can change and suddenly you're linking to a non-existent page. At some point we encountered a few links that were invalid and instead of just fixing those and moving on with our life I wrote a script to check external links that I set up to run on GitHub Actions on a weekly basis and send a result to an #automated-checks Slack channel. In this way, these issues became more visible and otherwise invalid links that would be in the app for many months were fixed within a week.This check has been implemented for this blog as well.

Improved modal component
Improved both UX and DX by improving a modal component. See more... The way we were writing most of the modals was by directly using the design system components as opposed to a more complete modal implementation. Every colleague therefore had a lot of freedom when it came to implementation of a modal. Properly implementing a modal so that it's consistent with design and behaves in the least obstructive way possible then becomes hard. Our modals were incosistent with how disabled and loading states were handled after clicking cancel and submit buttons, layout of those buttons was sometimes different and when it came to modals with forms, the form being reset after a successful submit caused a flicker while the modal was fading out which was visually distracting. I implemented a modal component to make implementing consistent modals simpler, including support for forms, where all of the aforementioned concerns were handled by default. These models can be seen in action in the funding rounds calculator above.

Data integrity checks
Maintained product quality by implementing data integrity checks. See more... My colleague implemented a framework for adding data integrity checks to notify us of instances where invalid data got into the database and also automatically fix them if an automatic fix is possible. I wrote checks dealing with detecting and autofixing trailing whitespace in attributes like names, emails and domain specific identifiers which could cause subtle bugs in filtering and matching items.

Linter rules
Maintained coding conventions and simplified codebase using linting rules as well as prevented subtle bugs. See more...Before
key :required, [:id, :created_at] property :id do key :type, :integer end property :created_at do key :type, :string key :format, 'date-time' end property :status do key :'$ref', :StatusEnum end property :values do items do key :type, :number end end
After
DocsApiHelper.properties({ id: :integer, created_at: { type: :string, format: 'date-time' }, status?: :StatusEnum, values?: { type: :number, array: true } })
"This::Constant::Exists" ... "But::ThisOne::DoesNot"
Maintained coding conventions and simplified codebase using linting rules as well as prevented subtle bugs. This involved playing around with ASTs. I made linter rules for both frontend (ESLint) and backend (RuboCop). Frontend one was about linting a stylistic error to follow our coding conventions (i.e. no more pointing it out in code reviews). In the backend, I made two linting rules which are a tad more complex:
- OpenAPI helper enforcement - writing the OpenAPI specifications can be a bit cumbersome, there's
a lot of boilerplate that needs to be written making bigger types hundreds
of lines long. I wrote a helper to simplify this where majority of the
use cases that previously took anywhere from 1 to 10 lines could now be
reduced to a single line of code making it more readable. Converting the
whole OpenAPI specification to use this helper would a large effort for
an individual and there would still be the problem with my colleagues not
being aware of this helper and writing new specifications without it. This
linter rule therefore produced warnings (and errors in some cases)
to enforce its usage suggesting fellow colleagues to convert it to use
the helper. The idea was that the warnings would be changed to errors once the conversion is complete so that it would be written in this more
concise and readable format.
Before
key :required, [:id, :created_at] property :id do key :type, :integer end property :created_at do key :type, :string key :format, 'date-time' end property :status do key :'$ref', :StatusEnum end property :values do items do key :type, :number end end
Use DocsApiHelper.properties
After
DocsApiHelper.properties({ id: :integer, created_at: { type: :string, format: 'date-time' }, status?: :StatusEnum, values?: { type: :number, array: true } })
- Check strings looking like constants actually exist - in Ruby, we were sometimes forced to write a constant, such as a class
name, as a string. The static type checker for Ruby, called Sorbet, we
used obviously didn't check strings and such strings sometimes became obsolete
when the class was refactored or removed and could cause an issue. This
linter rule checked that all strings that looked like such constants actually
referred to an existing constant in the codebase.
"This::Constant::Exists" ... "But::ThisOne::DoesNot"
This constant does not exist. Did you make a typo?
Frontend to backend type validation
Increased developer's confidence and prevented minor bugs by ensuring frontend matches backend. See more... The OpenAPI specification was used to generate TypeScript types in the frontend. Since the OpenAPI specification was written by hand, there could be and were discrepancies between what was described in the OpenAPI schema and the actual shape of the response that the server returned. The idea of this initiative was to validate that the types in the frontend, that were generated from the OpenAPI specification manually defined in the backend, matched the actual response from the server and in the case it didn't match, report an error to Sentry which we used for frontend error tracking. As we didn't want to impose the cost of validating the types on every request in production, it was only enabled in our QA environment that we used often enough to catch majority of these errors.
Frontend type:
type Example = { id: number kind: 'good' | 'bad' }
Server response:
{ id: '123' kind: 'neutral' unknown: 'smth' }
Type validation output:
Property 'id' is not of type 'number'.
Property 'kind' does not match allowed values.
Unknown property 'unknown' found.
Conventional commit message auto formatter
- No expected format for branches or commits
- Conventional commits required for features
- Standardized branch names and conventional commits required everything recorded in Jira
- Every code change needs to have a Jira associated and hence will have standardized branch name and conventional commits

The commit message "example message" is autoformatted based on the branch name "feat/JIRA-123-example" to a final message reading "feat(JIRA-123): example message"
2020-2022 (full-time from Feb 2022)
Announce app releases on Slack
Freed up engineering lead time by automating app release announcements in Slack. See more... We used Heroku for hosting and deployed the latest Git main branch on every new change. We had a process in place where once a week one of the engineering leads compiled a list of all the changes with their Jira ID and a short description and posted this in a #release Slack channel. I implemented a task that ran on every deployment to Heroku which compiled a list of Jiras from the last deployment, got the Jira tasks descriptions, the author (developer) of that change, found a related Slack account and tagged them in the automated Slack message (developers were encouraged to provide additional context, especially when it was related to a bug they fixed for someone from a support of other department).

Grammar checker
Improved copy quality through automated grammar and spellchecking. See more... Using LanguageTool I implemented a check in GitHub Actions that checked grammar including spellchecks. This involved compiling the list of translations from a YML file into a human-readable form which is what LanguageTool expects.
Example output for copy "This is highlight by diferent colour.":
highlight - possible grammar mistake highlighted diferent - possible spelling mistake different colour - colour is British English color
Sentry (error tracking)
Enabled proactive identification and resolution of frontend issues by setting up Sentry for error tracking.
OpenAPI
Laid the foundation for future enhancements such as automated TypeScript type generation by adding OpenAPI. See more... Found the tooling and implemented the helpers for adding OpenAPI 2.0 (later upgraded to version 3.0) and implemented it on a few regular cases as well as some exceptional ones. This was used later by the team for generating TypeScript types for frontend which increased our efficiency. It led to other initiatives, such as my work on linters and frontend to backend type validation later on to improve our workflow and get as much as possible from the coupling of backend to frontend this afforded us.

2019-2020 (part-time)
Dependency management
Accelerated developer velocity for hospital task system app for nurses and orderlies by streamlining dependency management and build system. See more... The team had a strict policy for dependency management and actually maintained their own repository of dependencies. This was initially done through quite a large Git submodule. I've made it so that the team was able to use our own repository of dependencies as if they were using the original repository which simplified the workflow to a large extent.
Other
- Gathered data that were previously compiled manually, automated minor tasks.
- Maintained high software quality by participating in acceptance testing.
Skills
Frontend
+ Native


Backend
DevOps
Cloud
+ Actions
Pages
AI & Productivity


Development tools

Meetings & Processes
- Stakeholder demos
- Code reviews
- 1:1s
- Hiring engineers
- Technical design meetings
- Performance reviews
- Pair programming
- Ideation sessions
- RFC-like proposals
- Retrospectives
- Daily standup
- Office hours
- Grooming sessions
- Colleague mentoring
- Stakeholder demos
- Code reviews
- 1:1s
- Hiring engineers
- Technical design meetings
- Performance reviews
- Pair programming
- Ideation sessions
- RFC-like proposals
- Retrospectives
- Daily standup
- Office hours
- Grooming sessions
- Colleague mentoring