Types before tests
Most of the bugs a test suite would catch never get written if the types make the wrong state impossible to represent. TypeScript in strict mode is the cheapest quality tool available.
I build web and mobile products end to end — React and Next.js on the front, Node.js and a properly designed database behind it, Flutter when it needs to be an app. Typed, tested against real use, and shipped.
I am a full-stack developer working across React, Next.js, TypeScript and Node.js, with Flutter for mobile and SQL and NoSQL databases underneath. I take a product from an interface sketch through the API and schema that make it work.
I got into software because I liked the feeling of turning a rough problem into something real that other people could use. That mindset stayed with me: I care about making products that are useful, dependable, and clear to maintain.
Most of my work sits in the JavaScript and TypeScript ecosystem: React and Next.js for interfaces, Node.js for the services behind them, and Tailwind or Bootstrap for the styling layer depending on what the project already uses. When something needs to be a real mobile app rather than a responsive site, I build it in Flutter.
I am equally interested in the layer underneath. Most product bugs turn out to be schema bugs wearing a costume, so I spend real time on the data model — in PostgreSQL and MySQL where the relationships matter, in MongoDB where the shape genuinely varies.
I work with AI tooling every day — Cursor and similar assistants are part of how I write and review code now. It makes the boring parts faster; it does not replace knowing why the code is shaped the way it is.
Most of the bugs a test suite would catch never get written if the types make the wrong state impossible to represent. TypeScript in strict mode is the cheapest quality tool available.
Interfaces get redesigned; data models get migrated. I spend the time up front on relationships and constraints, because that is the decision that is expensive to change later.
Software earns its keep in production. I build the smallest honest version, put it in front of real usage, and let evidence drive the next iteration instead of opinion.
A stack is a set of trade-offs, not a trophy cabinet. Hover or focus any item to see where it earns its place.
A filled dot marks the tools reached for first.
Eight stages, in order. The early ones are cheap and decide most of the cost; the late ones are where everyone else starts.
Understand the business outcome, the users, the constraints, and which deadline is real versus aspirational.
Scope the smallest version that proves the thesis, then sequence everything else behind it. Cut before building, not after.
Decide the data model, the service boundaries and the failure modes. Most of the lifetime cost of a system is committed here.
Turn flows into interfaces — states, empty cases, errors and responsive behaviour, not just the happy-path screen.
Build in reviewable increments against a working trunk. Every branch deploys to a preview URL you can click.
Automate the paths that would embarrass us in production, and manually probe the ones that are hard to describe to a machine.
Ship behind flags, migrate forward-compatibly, watch the dashboards, and keep the rollback one command away.
Let real usage set the priorities. Profile the slow thing, cache the hot thing, delete the thing nobody used.
No headcounts, no invented percentages. These are commitments about method — the kind you can hold someone to.
I ask what a feature is for before asking how to build it. You get pushback when the spec and the goal disagree — which is more often than anyone expects.
Clear module boundaries and a data model that makes illegal states unrepresentable.
Designed for the traffic you expect and instrumented for the traffic you do not.
AI assistants make the mechanical work faster. Every line still gets read before it lands, so you inherit code someone can actually maintain.
A Next.js front end and a Flutter app against the same API, without coordinating two contractors.
Plain-language updates on a fixed cadence, in writing. You hear about slippage while it is still cheap to fix, not at the deadline.
Handover means documentation, runbooks and a maintenance window — not a zip file and silence.
Budgets set up front and enforced in CI, so it stays fast on the devices your users actually own.