Full-stack developer working mostly with Java, TypeScript and Python. I build products end to end, and I like digging into real bugs in open source projects and sending fixes with tests.
Portfolio: dodoshell.vercel.app, with a case study for each project below.
- Poltrona: cloud management for hair salons, where the database itself refuses double bookings (Next.js, Supabase, PostgreSQL). Live
- Corsia: exam prep for taxi and chauffeur drivers, with answers graded on the server and idempotent Stripe webhooks (Next.js, Supabase, Stripe). Live
- Sconti Nova: Amazon deals verified every hour, built with a partner (Next.js, Supabase, PostgreSQL). Live
- iter: leave request management with a state-machine approval workflow (Spring Boot, React, PostgreSQL, Docker). Live demo
- portfolio: the site above, with a three.js shader background (Next.js 16, React 19)
- The-PR-Agent/pr-agent#4425: make the LiteLLM handler the only retry layer, honouring
Retry-After(merged) - doobidoo/mcp-memory-service#1648: report memory load and save status to Codex through
systemMessage(merged) - doobidoo/mcp-memory-service#1676: make the dashboard's Quality tab actually save its settings (merged)
- LearningCircuit/local-deep-research#7886: behaviour tests for the Zotero collection picker (merged)
- btclib-org/btclib#2776: tests for the signature-operation boundaries (merged)
- btclib-org/btclib#2821:
assert_p2trnames the right witness version, with four new refusal tests (merged) - ludo-technologies/pyscn#865: LCOM4 no longer counts inherited method calls as instance state (merged)
- ludo-technologies/pyscn#866: the single-responsibility rule counts sibling modules as one concern (merged)
- Rizzo-AI-Academy/rizzo-pii#141: fix a torch thread leak on Windows
- RailtownAI/railtracks#1734: accept local
.avifattachments (merged) - LearningCircuit/local-deep-research#8124: the PDF export renders a table that directly follows text as a table (merged)
- ludo-technologies/pyscn#874: the deep-nesting suggestion points at the deepest block instead of the
defline (merged) - RailtownAI/railtracks#1765: rewriting a Chroma entry no longer keeps stale chunk metadata (merged)
- LearningCircuit/local-deep-research#8212: hiding the settings JSON editor saves only the keys that were edited (merged)
- LearningCircuit/local-deep-research#8213: a failed theme save from the header puts the previous theme back (merged)
- btclib-org/btclib#2908:
obfuscaterefuses a huge negative offset with btclib's own error (merged) - btclib-org/btclib#2909: the import test also keeps btclib free of
bip32_descriptors(merged) - spring-projects/spring-session#4150: changing a session id removes the old id from the Redis expirations set
- pmd/pmd#7280:
InternalApiUsageno longer flags@VisibleForTestingmembers used inside their own record or enum (merged) - LearningCircuit/local-deep-research#8238: the session-check 503 has the same body whichever check refused the request (merged)
- mojohaus/flatten-maven-plugin#562: parent and imported POMs resolve from repositories declared in the POM chain (merged)
- haydenbleasel/ultracite#864: re-running
initkeeps oxlint'scorepreset first andanti-sloplast (merged) - LearningCircuit/local-deep-research#8274: credentials passed to a log call as bytes or
extrakeys are redacted like the message (merged) - LearningCircuit/local-deep-research#8275: an API key followed by a control character is redacted in logged exceptions (merged)
- btclib-org/btclib#2915: documentation source links point at
maininstead ofmaster(merged) - floci-io/floci-az#630: Container Apps environments report a
customDomainVerificationId(merged) - floci-io/floci-az#631: Append Block answers with
Last-Modifiedandx-ms-request-server-encrypted(merged) - The-PR-Agent/pr-agent#4810: generic
password,secretandtokenassignments in CI artifacts are redacted (merged) - open-constructs/cdk-terrain#592:
replaceTriggeredByreferences render without the${}Terraform rejects (merged) - floci-io/floci-az#649: a plain Container Apps secret no longer keeps an empty
keyVaultUrl(merged) - doobidoo/mcp-memory-service#1932: the startup dependency check accepts the ONNX backend instead of reporting PyTorch as missing (merged)
- LearningCircuit/local-deep-research#8511: a blocked SearXNG URL is warned about once per research instead of at every step (merged)
- LearningCircuit/local-deep-research#8532: the SearXNG warning dedup documents and tests what happens after 256 blocked URLs
- pmd/pmd#7312:
UnusedAssignmentno longer flags the increment in a do-while condition - Pari030/get-ip-by-anydesk#4: the script runs on Linux too and skips every private address range
- KaotoIO/kaoto#4417: the properties count badge is an inline element, so it no longer nests a
<div>inside a<p>(merged) - ArcadeData/arcadedb#11515:
CREATE EDGErendersUNIDIRECTIONALafter itsSET/CONTENTbody, in the order the parser accepts (merged) - LearningCircuit/local-deep-research#8567: a research that finishes just as Cancel is pressed stays completed instead of being marked suspended
- pmd/pmd#7330:
InsecureCryptoIvandHardCodedCryptoKeycatch a hard-coded key or IV passed asthis.field - equinor/ert#14968: the storage server shuts down right away instead of waiting out a TLS timeout
- open-constructs/cdk-terrain#609: a bundled asset whose hash is unchanged reuses its artifact instead of rebuilding on every synth
- open-constructs/cdk-terrain-docs#41: the assets page explains when a bundled asset is rebuilt and how to force a rebuild
- EvoScientist/EvoScientist#810: file tools reach a folder named like the workspace, and deleting the workspace root is refused (merged)
- ludo-technologies/pyscn#889: a package
__init__.pythat only re-exports its submodules is no longer flagged by the single-responsibility rule (merged) - ludo-technologies/pyscn#890: LCOM4 treats a method using a computed
getattrover a class-level name table as stateless - ciscoheat/sveltekit-superforms#707:
superValidate(url)reads only the search params in the schema, so other params don't rerun the load function - apache/maven#13988: an imported BOM keeps its input locations even when an extension imported it first without location tracking
