I build and operate the platform that backend services run on: infrastructure as code, deployment, observability, cost, and security. I come from backend engineering, so I work on both sides of that line.
Platform Engineer & DevOps · 2026-06 – present
- Infrastructure platform — brought a console-built AWS environment under Terraform with OIDC-based workflows
- Observability — monitoring managed as code, alerting moved to SLOs
- Deploy & cost — improved the internal deployment pipeline (blue-green); traced where the cloud bill comes from and cut it
- Security — default-deny authorization, column-level encryption of personal data, ISO 27001 / ISMS-P preparation
TeamBind · Backend Engineer / CTO · 2025-07 – 2026-06
A space-booking and community platform for musicians
- Designed and built a microservices architecture as the sole backend engineer
- Built and operated a self-managed (on-premises) Kubernetes cluster, including incident response
- Designed database schemas and data models for core services
- Developed web and app backends end to end
| Primary | |
| Comfortable |
| Project | Contributions |
|---|---|
| OpenTelemetry Java instrumentation |
• #20845 Fixed the agent no longer propagating context through Reactor operators after the application calls Hooks.resetOnEachOperator(), which broke the context of externally driven Flux.create subscribers• #20659 Fixed @WithSpan on a Flux requesting 32 elements from the source regardless of downstream demand, which dropped queued work on cancel• #20658 Fixed Spring Kafka listeners with async acks or async return types emitting a duplicate Kafka client process span per record (a 2.32.0 regression) • #20660 Fixed MySQL/MariaDB address=(host=..)(port=..) JDBC URLs without a subprotocol losing server.address/server.port• #20661 Fixed the Lettuce library reporting the command name (e.g. BLPOP.) as error.type on client-side timeouts |
| Spinnaker Orca |
#8174 Fixed a race where a duplicate StartExecution delivery could move a completed pipeline back to RUNNING, using a conditional status update (SELECT ... FOR UPDATE) |
| Debezium | #8220 Fixed a regression in the generated MySQL DDL grammar where ALTER DATABASE without a database name failed to parse and stopped the connector |
| ANTLR grammars-v4 | • #5037 Made the schema name optional in the MySQL alterDatabase rule, the upstream source of the Debezium grammar fixed in #8220• #5039 Fixed the MariaDB grammar taking DEFAULT as the database name in ALTER DATABASE DEFAULT CHARSET ..., upstream of one of the two grammars fixed in #8225 (the other, Positive-Technologies, is deprecated upstream and not accepting fixes) |
| Keycloak | #53990 Fixed AccessTokenContext validating grantType twice instead of rawTokenId, so a null token id reached the encoded token id as the literal null rather than failing at construction |
| Lettuce Redis Java client |
• #3952 Fixed DefaultEndpoint validating clientOptions twice so a null clientResources bypassed the null check and surfaced later as an NPE away from the construction site• #3955 Fixed assertion messages that named the wrong argument: a misspelled ReauthenticateBehavior in a public builder, and CompressionCodec reporting a null output stream as the input• #3954 Fixed typos in the Javadoc of the stream XACK and XLEN commands across every API flavor, plus other comment typos |
| Spring Security | #18855 Applied the javadoc-warnings-error policy to the spring-security-aspects module, aligning it with the rest of the build |
| Micrometer | #7256 Documented Jakarta Mail instrumentation and registered it in the Observation instrumented-projects reference |
| Project | Contributions |
|---|---|
| Spinnaker Orca |
• #8208 Made StartExecution's rollback after a failed StartStage push conditional, so a cancel made in that window is no longer overwritten and the redelivered message doesn't start the canceled pipeline (reproduced against MySQL)• #8209 Added a test that depends on the row lock in updateStatusIfExpected; it fails if SELECT ... FOR UPDATE is removed |
| Spring Cloud Config | #3342 Expired the Git refresh rate when /monitor receives a webhook, so refreshed applications get the new commit |
| Debezium | #8225 Fixed the MariaDB and legacy MySQL grammars taking DEFAULT as a database name in ALTER DATABASE DEFAULT CHARSET ..., which silently skipped the charset change (follow-up requested by the maintainer) |
| Spring Batch | #5582 Truncated the execution context SHORT_CONTEXT by UTF-8 length so multibyte contexts no longer fail on Oracle (reproduced on Oracle 23) |
| Spring Boot | #52120 Made Docker Compose support fail fast on unsupported *_FILE credential variables instead of silently falling back to defaults |
| Spring AI | #7125 Added unit tests for ErrorLoggingObservationHandler |
I write up what I learn on my blog: SRE and observability, IaC work logs, incident response and more (180+ posts).



