Skip to content

How I work

From an unclear brief to software people use

The detail behind the home page: the stages a feature goes through with me, what each capability looks like in practice, and the platform my work runs on. The case studies show the same habits on real projects.

From brief to production

Six stages, in the order they happen. Each names the responsibility I take on, two places I’ve done it and one call I made, with its cost.

  1. Shape the problem

    I turn a request or a product spec into a written plan before I build: who is involved, what each role may do, what must never happen, what done means and the order the work lands in.

    • Audited a two-company workflow against its written spec before it merged, with AI-assisted reviews. Within two days I merged fixes for six of the ten missed acceptance criteria in paired UI and API changes and wrote up the rest.
    • Moved a review team’s question-and-answer process out of a generic task tool into a built-in workflow, with clear roles and states, notifications that never ping the person who acted, and a catch-up view for late answers.

    Decision: I started an internal product-file collector on a written plan that ruled out a backend and AI. The cost: coverage grows one page pattern at a time, each backed by a rule and a test.

  2. Design the interface and the system

    I design the screen and the system under it together: which layer owns each rule, where state lives, how a page loads when the data is large, and what every open screen sees when something changes.

    • Built a manufacturer response grid that behaves like the spreadsheet it writes into: an editor for each data type, arrow-key movement between cells, and autosave that ignores responses arriving out of order.
    • Proposed replacing the five real-time event types of a teammate’s notification engine with one event that tells the client what to do, then built it on the .NET server and the Vue client.

    Decision: I rejected rebuilding that response grid on a virtual-scroller library. It pages from the server and windows the existing table, so sticky headers, column resizing and keyboard movement still work on real rows. The cost: every row shares one fixed height.

  3. Build across the stack

    I build the whole slice a feature needs (interface, endpoints, SQL, background work and integrations) in whatever language that part of the platform runs, and keep the pieces in step through explicit contracts.

    • In 2026 I merged production code into a .NET 10 API, Python workflow workers, Next.js route handlers on Node.js and a Cloudflare Worker, beside the Vue and Nuxt app I’ve worked in day to day since 2023.
    • Built a public Chrome extension and the pieces around it: the React Manifest V3 client, a connect page that trades the web app’s session for a one-hour scoped token, and a .NET endpoint that parses pages with an LLM.

    Decision: The cancel I shipped claimed the row in one transaction and sent notifications, email and live updates only after commit, so a rolled-back write announced nothing. The price: every other writer had to refuse a vanished row.

  4. Prove it works and keep it safe

    Tests ship with the feature, and security is decided on the server: who may act, what a page or a model returned, and where a user-supplied URL is allowed to go.

    • Tests ship with my features, and I built a Playwright harness that scores an extraction tool against frozen ground truth, so every change is measured, not eyeballed.
    • Kept credentials and model calls behind the API: a browser extension gets a short-lived scoped token, and links and images from a model’s answer pass an allow-list before they render.

    Decision: I hand-wrote a same-origin analytics relay with allow-listed headers, methods and paths, so only what the analytics service needs ever leaves the app. The cost: a route to maintain instead of a one-line proxy.

  5. Ship it

    I release through the team’s pipelines and plan risky rollouts with the change: the deploy order between services, a flag or an off switch, and migrations that are safe to re-run. Urgent fixes take the hotfix path.

    • Cut versioned production releases through the pipeline teammates built, wrote the notes for a web and API release shipped together, and ran hotfixes with back-ports.
    • Shipped the frontend of a cross-company workflow dark behind a flag that gated every entry point, background request and live-update handler; it reached internal users first, and I removed another feature’s flag at general release.

    Decision: I added a page scan to an edge service and designed it with its Python callers and review app so each piece could deploy in either order, dark until switched on per site and off again without a deploy. The cost: each caller has to opt in explicitly.

  6. Run and improve it

    After release I stay with the work: I take production errors to root cause, fix the long tail a feature turns up, and measure changes on real data before calling them better.

    • Traced bugs to root cause: unread flags that never cleared (a non-deterministic SQL query), a support button that intermittently died (a start-up race), an empty AI extraction (the model ran out of output budget).
    • Stayed with a cancel feature’s long tail: paging that skipped a row once rows could vanish, readers stranded on a deleted thread, and a resend that created nothing until its idempotency key rotated on cancel.

    Decision: I traded a little precision for coverage in category assignment: on an offline replay of about 26,000 reviewed products, the share with a real category rose from about 19% to 72% while correctness moved from 81–85% to 79%.

Capabilities

Six responsibilities you can hand me, deepest first. “Shipped with” lists tools from production work or my own product. “Working knowledge” is platform technology I work beside and have studied, listed apart because I haven’t owned it.

  • Own the frontend of a complex product

    My deepest area: a large Vue and Nuxt application, plus React and Next.js. I build the screens where a product’s complexity lives (dense data, multi-step workflows, state that changes under the user) and keep them fast by design, with server paging and only the visible rows rendered.

    • Core parts of a spreadsheet-style product schedule: the cell save path, cell types, undo and redo, most of view sharing, and a catalog search that began by moving shared logic into one composable.
    • Keyboard support and screen-reader semantics in complex workflows: an accessible step indicator, dialogs that focus the safe action, errors announced through live regions, and an app-wide contrast regression traced and fixed.
    • Server rendering in Nuxt, with hydration fixes and major contributions to the app’s Nuxt 2 to 3 migration; the rich-text editor I introduced; components for the shared design system; React 19 in two extensions and a Next.js tool.

    Shipped with

    TypeScript, Vue 3, Nuxt, React, Next.js, Pinia, Tailwind CSS, TipTap

  • Build the server half

    I build the endpoints, SQL, migrations and jobs behind the features I ship, inside the architecture a team already has, and keep additions as simple as the problem allows. In 2026 that meant .NET, Python and Node.js.

    • Paginated, filterable .NET endpoints and a dashboard summary that share one access-scope rule, so the summary can never show an item the list would hide.
    • Concurrency-safe PostgreSQL writes (row-locked claims, compare-and-swap status changes) and re-runnable migrations, including a tested reversal of a product-wide rename.
    • Python workflow steps on Hatchet with dry runs, time budgets, jittered retries and writes that never overwrite a reviewer’s later edits; Node.js route handlers with validated filters and streamed CSV export.

    Shipped with

    .NET / C#, PostgreSQL, Node.js, Python, Supabase, Fastify, Cloudflare Workers, Hatchet, Hangfire

    Working knowledge

    • Workflow-engine designorchestration topology, fan-out, concurrency limits
    • MongoDBdocument modeling, read caches
  • Keep connected clients correct

    I keep interfaces correct while data changes underneath them: live presence and cells, notifications that catch up after reconnects, extensions that hand data to web apps, and web and mobile clients on one backend.

    • Schedule presence and live cells with my team, the first notification center’s interface and live updates, and .NET event publishers that fire after the commit on channels whose rules mirror the HTTP API’s.
    • An internal side-panel extension that hands collected product media to the review platform through a versioned clipboard format, golden-tested on both sides with no backend in between.
    • In my own product, a Flutter app and a Next.js web app on one API and database, with push notifications, live tracking and real-time chat, built with AI coding agents under my direction.

    Shipped with

    Pusher, Supabase Realtime, Chrome Manifest V3, Flutter, Riverpod, Firebase Cloud Messaging

    Working knowledge

    • CRDT co-editingYjs, Durable Objects
  • Test and secure what I ship

    I test in every stack I ship in and treat each boundary I touch as a place to check: tokens carry only the scopes they need, access rules fail closed on the server, and untrusted content is checked before it’s stored or rendered.

    • Tests in Vitest, NUnit, pytest and Testing Library, a test-runner change that makes client-only code testable in a server-rendered app, and a fix for a load-dependent test that blocked the team’s pushes.
    • A narrowly scoped token scheme for a browser extension, with an API that refuses to start without its signing key, and production builds of the public extension that ship no source maps.
    • Read-only row-level security with server-only write functions, tested by querying the database as each role, and file serving that renders only known image types and forces a download for the rest.

    Shipped with

    Playwright, Vitest, Vue Test Utils, NUnit, pytest, Testing Library, JWT, Postgres row-level security

    Working knowledge

    • Identity & SSOOIDC, SAML
    • Error tracking & tracingSentry, OpenTelemetry
  • Release safely across runtimes

    My 2026 changes run on several runtimes and ship through pipelines teammates built. My part is making each release safe to take: checks that catch problems before merge, settings ready in every environment, and a known deploy order.

    • Pull-request CI for an internal extension (type-check, unit tests, a production build and a guard that fails if extraction code hard-codes any test site), plus release checklists that confirm dependent server changes are live.
    • A cross-service feature configured for every environment through the existing pipelines, with secrets kept apart from plain settings, and cross-service changes verified on paired frontend and backend previews.
    • Migrations with a documented order against the code that needs them and a lock timeout where a backfill touches a live table, checked first against the platform’s data stores running locally in Docker Compose.

    Shipped with

    GitHub Actions (PR checks), GitHub Releases, Feature flags, Docker Compose, Vite, Vercel

    Working knowledge

    • CI/CD pipeline internalsrelease-triggered deploys, environments, previews
    • Container images for productionmulti-stage builds, registries
    • Serverless containersGoogle Cloud Run
    • Kubernetesdeployments, health probes, Kustomize overlays
    • Infrastructure as codeTerraform, Gateway API
  • Use AI with judgment

    I use coding agents daily and verify what they produce. In products I add a model where it earns its place, treat its output as untrusted input, and use deterministic code where rules do the job.

    • LLM product parsing introduced to a production .NET API, with model output validated and normalized, unsafe links stripped and a per-user rate limit on the endpoint.
    • An offline language guardrail in a teammate-built LLM pipeline that skips non-English pages before any model spend and swaps in a page’s English version when one exists.
    • An agent-run QA campaign I directed on my own product: every user flow listed by role, run on web and mobile, failures confirmed a second way, and each fix re-verified at runtime by an agent that didn’t write it.

    Shipped with

    OpenAI API, Claude Code, Codex

    Working knowledge

    • Agentic LLM featurestool calling, MCP, RAG
    • Hybrid vector & keyword searchpgvector, BM25, rank fusion

The platform I work in

Material Hub runs on far more than a web app, and teammates built most of it. Each row pairs what the platform runs with my part in it: what I built, what I added to, and what I ship through.

  • Clients

    Platform: A large server-rendered Vue and Nuxt web app, a public and an internal Chrome extension, and an internal Next.js review platform for the data team.

    Mine: I’ve built in the web app since 2023 and led the frontend of its cross-company request workflow. I built both Chrome extensions and features across the review platform.

  • Services & APIs

    Platform: A .NET REST API, Python services for search and matching, a small server layer inside the web app, and Node.js route handlers in the review platform.

    Mine: Since mid-2026 I’ve added .NET endpoints, from paged lists and dashboard summaries to server-side permission checks, inside a layering teammates designed. In the review platform I built Node.js route handlers, including a threaded Q&A API.

  • Data & storage

    Platform: PostgreSQL as the system of record, evolved by migrations, plus caching, a database for the data pipeline and object storage.

    Mine: I write the production SQL behind my features, ship re-runnable migrations, and built safe import paths into object storage for the review platform.

  • Real-time & integrations

    Platform: Real-time channels authorized by the API, transactional email, product analytics and feature flags, and third-party integrations.

    Mine: With my team I built presence and live cells, and I built the first notification center’s interface and live updates. I added channel rules and publishers for a cross-company workflow and built the original support-messenger integration.

  • Background jobs & AI pipelines

    Platform: Background jobs inside the API, Python workflows that extract product data with language models for human review, a search service and an in-app assistant.

    Mine: Inside teammates’ Python workflows I added time budgets, jittered retries and writes that keep reviewers’ edits, plus a retry-safe background job in the API. I co-built the assistant’s first chat interface.

  • Delivery & operations

    Platform: Checks on every pull request, preview environments, a shared staging environment, release-triggered production deploys, and error tracking with alerts.

    Mine: Teammates built the pipelines and run monitoring; my changes ship through them, from versioned releases to hotfixes with back-ports. I take what monitoring surfaces to root cause, and wrote the pull-request CI for an internal extension.

Most product companies run this same shape: a web app, an API, a relational database, background workers, a handful of vendors and a release pipeline. I’ve shipped features through every one of those layers, so I can pick up a feature in yours and follow it all the way through.

Habits

  • Own the whole feature. A bulk “report missing products” action, built across the web app, the .NET API and a migration, with a preview step so the confirmation says exactly what will happen. Along the way I fixed the weekly report it feeds.
  • Tests that can fail. When a test guards a fix, I break the code it covers to prove it catches the bug, then put the code back.
  • AI output is a draft. I use coding agents every day. I cross-check their review findings against a second model and the code itself, and I say plainly what I didn’t verify.
  • Decisions in writing. Most of my pull requests state the root cause, what changed and how it was tested, often with before-and-after evidence.

Want to talk it through? Email me, or read the résumé.