Full-stack software engineer
Flutter · React & TypeScript · Node.js · PostgreSQL
Türkiye · UTC+3
I build products end to end: the mobile app, the web client, the service behind them, and the schema they all sit on. That last part is the one most people route around, and it's where I've spent the most time. Three of the six repos below are mostly database.
explain-lens — read a Postgres query plan without squinting
Paste EXPLAIN (ANALYZE, FORMAT JSON) output, get an interactive plan tree back. It runs entirely in the browser, so nothing you paste leaves the tab.
Total time points at whatever sits nearest the root, which is rarely the node doing the damage. The heatmap colours by self time instead. A rules engine names the patterns it recognises: bad row estimates, nested-loop blow-ups, sorts that spill to disk.
→ Try it: osmncnylmz.github.io/explain-lens
React · TypeScript · client-side only
A double-entry ledger where PostgreSQL enforces the accounting. post_entry() validates nothing itself; it writes rows and lets the database refuse them. Two of the three refusals happen on the way in, and the one that has to see the whole entry waits for the transaction to end:
flowchart LR
subgraph stmt["per INSERT, immediate"]
O{"period open?"} --> L{"account is a leaf?"}
end
subgraph tx["at COMMIT, deferred"]
B{"debits = credits?"}
end
P["post_entry()"] --> O
L --> B --> C["committed"]
O -->|no| X["rollback"]
L -->|no| X
B -->|no| X
That last one is a constraint trigger declared deferrable initially deferred. A half-written entry is never wrong, only unfinished. Immutability triggers keep the journal append-only, row-level security separates tenants (forced, so the table owner cannot read past it either), posting is idempotent on a per-tenant key, and the financial statements are recursive CTEs over the account tree. Each of those has a test that attacks it.
PostgreSQL · PL/pgSQL · constraint triggers · row-level security · recursive CTEs
pg-query-lab — slow queries, measured instead of guessed at
The lab runs on PGlite, PostgreSQL compiled to WebAssembly, so there is no container to start and no seed script that only works on one laptop. A Node install reproduces the whole thing. Each scenario ships the naive version, the rewritten version, and the EXPLAIN ANALYZE output of both, checked in next to each other.
PostgreSQL · PGlite · Node.js · EXPLAIN ANALYZE
A Flutter movie browser: routing that follows auth state, and a feed that pages itself. The auth and movies features are split into data / domain / presentation; the rest of the app stays presentation-only, because layering it further would buy nothing.
- One redirect rule gates splash, login, register and home, instead of navigation calls scattered through the widgets.
go_router'srefreshListenableis fed the auth Cubit's stream. - Favourites are optimistic. The visible state is server state, plus a local pending-add set, minus a local pending-remove set. A tap answers immediately and still reconciles honestly when the request lands.
freezedandjson_serializablefor the auth models, an envelope every response has to be unwrapped from first, and aStringOrIntConverterfor a catalogue API that returns ids as strings on one endpoint and integers on another.
The feed asks for its next page two cards from the end. Tokens reach dio through a single interceptor reading flutter_secure_storage, and the tests concentrate on the id converter and the pagination state machine.
Flutter · Dart · flutter_bloc · go_router · get_it + injectable · dio · freezed
pocket-ledger — an offline-first expense tracker on drift/SQLite, no backend anywhere. Amounts are integer minor units so nothing quietly rounds, and a JSON export of the whole database is the only migration path a device-local app gets.
Flutter · drift/SQLite · Riverpod
hana-author-dashboard — list-and-detail over the JSONPlaceholder demo API. Search runs across name and company, the detail route fetches the author and their posts in parallel, and favourites live in a memoised context behind a versioned localStorage key. The Vitest suite spends most of its time on that context, including what it does when the stored value isn't valid JSON.
React · TypeScript · Vite · Tailwind CSS · React Router · axios
A rule that lives in a service layer is a rule the next caller forgets about. The ones that matter go in the schema, where nothing can route around them.
The tests I care about attack the thing they guard and assert that the refusal comes back: an unbalanced posting, a write into a closed period, a read across a tenant boundary, a second post under an idempotency key that has already been used.
The best way to reach me is LinkedIn.