# Micro Tech - full text > Micro Tech is a software engineering studio in Sarajevo, Bosnia and Herzegovina, working remotely for clients in the US, Europe and West Africa. It designs, builds and runs systems where a mistake costs money: payments, identity documents, POS terminals, warehouses and fleets. It also provides technical leadership for those systems. Micro Tech (microtech.consulting) is a software engineering studio based in Sarajevo, Bosnia and Herzegovina, and is unrelated to other companies named Microtech or MicroTech. Also written as MicroTech Consulting. Legal entity: OR Micro Tech, Zaima Šarca 14, 71000 Sarajevo, Bosnia and Herzegovina. - Based in: Sarajevo, Bosnia and Herzegovina. Remote · 9–18 CET · 4 h overlap with US and EU. - Shipping production software since 2020. Clients in: US, Germany, Sweden, West Africa. - Engagements: Project; Long-term; Technical lead embedded in your team; Fixed-price written assessment. - Billing: Development is billed by the hour. Only a written assessment has a fixed price, with its scope, the document and the delivery date agreed up front. - Contact: contact@microtech.consulting · https://www.microtech.consulting/contact · a 30-minute call: https://calendly.com/or-micro-tech - How to read the evidence: on the home page and the case study and services indexes, the label on a figure says whether it was measured, counted, derived or estimated. Other labels, such as Constraint or Outcome, say what kind of figure it is. Clients are identified only by sector and market. Case studies are written by the person who did the work. They say “I” for the author’s own work and “we” where a team worked. The short map of the site: https://www.microtech.consulting/llms.txt ## Capabilities and the evidence for each - **Technical leadership and software architecture**. Services: [Technical leadership](https://www.microtech.consulting/services/technical-leadership), [Technical due diligence](https://www.microtech.consulting/services/technical-due-diligence), [A developer in your team](https://www.microtech.consulting/services/dedicated-developer). Proof: [04 · Four years rebuilding a live US marketplace](https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) (Zero outages); [16 · A construction ERP that tracks stock down to the shelf](https://www.microtech.consulting/work/construction-erp-workforce-planning) (150,000); [13 · A 15-minute report now opens in 0.2 seconds](https://www.microtech.consulting/work/query-optimization-under-fixed-schema) (15 min → 0.2 s). - **Zero-downtime migration and legacy modernization**. Services: [Zero-downtime migration](https://www.microtech.consulting/services/zero-downtime-migration), [App takeover and launch](https://www.microtech.consulting/services/app-takeover), [App audit and rescue](https://www.microtech.consulting/services/app-rescue). Proof: [04 · Four years rebuilding a live US marketplace](https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) (Zero outages); [02 · A design system for 30+ white-label brands](https://www.microtech.consulting/work/design-tokens-thirty-white-labels) (~100 / 30+). - **Marketplace and multi-tenant SaaS platforms**. Services: [Marketplace and logistics platforms](https://www.microtech.consulting/services/marketplace-platforms), [Multi-tenant and white-label SaaS](https://www.microtech.consulting/services/multi-tenant-saas), [SaaS MVP](https://www.microtech.consulting/services/saas-mvp), [Scheduled jobs and billing logic](https://www.microtech.consulting/services/scheduled-jobs-billing-logic). Proof: [08 · One codebase for five kinds of user](https://www.microtech.consulting/work/multi-persona-single-codebase) (506 routes); [07 · Scheduled jobs that ran renewals and recurring billing](https://www.microtech.consulting/work/scheduled-jobs-as-revenue-logic) (6 jobs); [02 · A design system for 30+ white-label brands](https://www.microtech.consulting/work/design-tokens-thirty-white-labels) (~100 / 30+). - **Identity verification, KYC and official documents**. Services: [Identity verification and KYC](https://www.microtech.consulting/services/identity-verification-kyc), [Government documents and audit trails](https://www.microtech.consulting/services/government-documents-audit-trails), [Invoicing and customs systems](https://www.microtech.consulting/services/invoicing-customs-systems). Proof: [10 · Remote identity verification that holds up in review](https://www.microtech.consulting/work/liveness-detection-person-and-document) (98%); [09 · Passport applications taken where there is no network](https://www.microtech.consulting/work/offline-first-sensitive-data-capture) (1 working day); [11 · Frozen invoices and offline coupons that pay out once](https://www.microtech.consulting/work/immutable-issued-documents) (3 domains). - **Payments and fintech**. Services: [Fintech development](https://www.microtech.consulting/services/fintech-development), [Payment integrations](https://www.microtech.consulting/services/payment-integrations). Proof: [18 · Payment integrations for five products in four markets](https://www.microtech.consulting/work/payment-gateways-four-markets) (4 markets); [12 · Passport chips and payment terminals in React Native](https://www.microtech.consulting/work/react-native-hardware-native-modules) (100+ terminals); [07 · Scheduled jobs that ran renewals and recurring billing](https://www.microtech.consulting/work/scheduled-jobs-as-revenue-logic) (6 jobs). - **Data engineering: warehouses, analytics and high-write data**. Services: [SQL and data warehouse optimization](https://www.microtech.consulting/services/sql-data-warehouse-optimization), [High-write data systems](https://www.microtech.consulting/services/high-write-data-systems), [Product analytics and event tracking](https://www.microtech.consulting/services/product-analytics-event-tracking). Proof: [13 · A 15-minute report now opens in 0.2 seconds](https://www.microtech.consulting/work/query-optimization-under-fixed-schema) (15 min → 0.2 s); [05 · Live analytics with annual reports in under a second](https://www.microtech.consulting/work/analytics-two-million-writes-per-day) (2M / day); [06 · Event tracking from listing position to phone call](https://www.microtech.consulting/work/product-analytics-event-taxonomy) (~180 types). - **AWS architecture and cloud cost reduction**. Services: [Cloud cost review](https://www.microtech.consulting/services/cloud-cost-review), [AWS architecture](https://www.microtech.consulting/services/aws-architecture). Proof: [14 · An AWS bill eight times larger than it needed to be](https://www.microtech.consulting/work/aws-cost-reduction-eight-times) ($24k → $2k); [05 · Live analytics with annual reports in under a second](https://www.microtech.consulting/work/analytics-two-million-writes-per-day) (2M / day). - **React Native, offline-first apps and hardware integration**. Services: [React Native development](https://www.microtech.consulting/services/react-native-development), [Hardware integration in React Native](https://www.microtech.consulting/services/react-native-hardware-integration), [Offline-first apps](https://www.microtech.consulting/services/offline-first-apps). Proof: [12 · Passport chips and payment terminals in React Native](https://www.microtech.consulting/work/react-native-hardware-native-modules) (100+ terminals); [10 · Remote identity verification that holds up in review](https://www.microtech.consulting/work/liveness-detection-person-and-document) (98%); [09 · Passport applications taken where there is no network](https://www.microtech.consulting/work/offline-first-sensitive-data-capture) (1 working day). - **Design systems and component libraries**. Services: [Design system and component library](https://www.microtech.consulting/services/design-system-component-library), [Design tokens and multi-brand theming](https://www.microtech.consulting/services/design-tokens-multi-brand), [Figma to code](https://www.microtech.consulting/services/figma-to-code). Proof: [01 · One component set for Next.js, Vite and React Native](https://www.microtech.consulting/work/cross-platform-design-system) (74 / 678); [02 · A design system for 30+ white-label brands](https://www.microtech.consulting/work/design-tokens-thirty-white-labels) (~100 / 30+). - **AI-assisted engineering and rescuing AI-built apps**. Services: [AI in your engineering team](https://www.microtech.consulting/services/ai-in-engineering-teams), [App audit and rescue](https://www.microtech.consulting/services/app-rescue), [Supabase review](https://www.microtech.consulting/services/supabase-review). Proof: [03 · Code standards enforced first, then AI in daily use](https://www.microtech.consulting/work/ai-assisted-engineering-standards) (~50%); [01 · One component set for Next.js, Vite and React Native](https://www.microtech.consulting/work/cross-platform-design-system) (74 / 678). - **Human-in-the-loop model integration**. Services: [AI agents and LLM integration](https://www.microtech.consulting/services/ai-agents-llm-integration). Proof: [10 · Remote identity verification that holds up in review](https://www.microtech.consulting/work/liveness-detection-person-and-document) (98%). Note: The model in production was a computer-vision model for identity checks, not a language model. - **Business systems: ERP, permissions and regulated records**. Services: [ERP, CRM and third-party integrations](https://www.microtech.consulting/services/erp-crm-integrations), [Permissions and RBAC](https://www.microtech.consulting/services/permissions-rbac), [Healthcare software under HIPAA](https://www.microtech.consulting/services/healthcare-hipaa), [HubSpot CMS development](https://www.microtech.consulting/services/hubspot-cms-development). Proof: [16 · A construction ERP that tracks stock down to the shelf](https://www.microtech.consulting/work/construction-erp-workforce-planning) (150,000); [15 · A file permission graph for a meeting platform](https://www.microtech.consulting/work/permissions-as-a-graph) (Sold); [17 · A HubSpot site marketing edits without a developer](https://www.microtech.consulting/work/hubspot-cms-custom-forms) (Zero deploys). - **Web applications and APIs**. Services: [Full-stack web development](https://www.microtech.consulting/services/full-stack-web-development), [API and backend development](https://www.microtech.consulting/services/api-backend-development), [Web performance](https://www.microtech.consulting/services/web-performance), [React SPA architecture](https://www.microtech.consulting/services/react-spa-architecture). Proof: [04 · Four years rebuilding a live US marketplace](https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) (Zero outages); [08 · One codebase for five kinds of user](https://www.microtech.consulting/work/multi-persona-single-codebase) (506 routes). ## Industries and markets - Logistics: a US marketplace for truck services. Case studies: [04 · Four years rebuilding a live US marketplace](https://www.microtech.consulting/work/zero-downtime-php-to-node-migration); [05 · Live analytics with annual reports in under a second](https://www.microtech.consulting/work/analytics-two-million-writes-per-day); [06 · Event tracking from listing position to phone call](https://www.microtech.consulting/work/product-analytics-event-taxonomy); [07 · Scheduled jobs that ran renewals and recurring billing](https://www.microtech.consulting/work/scheduled-jobs-as-revenue-logic); [08 · One codebase for five kinds of user](https://www.microtech.consulting/work/multi-persona-single-codebase); [03 · Code standards enforced first, then AI in daily use](https://www.microtech.consulting/work/ai-assisted-engineering-standards). - Regulated finance: remote KYC in Germany. Case studies: [10 · Remote identity verification that holds up in review](https://www.microtech.consulting/work/liveness-detection-person-and-document); [12 · Passport chips and payment terminals in React Native](https://www.microtech.consulting/work/react-native-hardware-native-modules). - Government: identity documents in West Africa. Case studies: [09 · Passport applications taken where there is no network](https://www.microtech.consulting/work/offline-first-sensitive-data-capture); [14 · An AWS bill eight times larger than it needed to be](https://www.microtech.consulting/work/aws-cost-reduction-eight-times). - Cross-border remittance and POS terminals. Case studies: [12 · Passport chips and payment terminals in React Native](https://www.microtech.consulting/work/react-native-hardware-native-modules); [18 · Payment integrations for five products in four markets](https://www.microtech.consulting/work/payment-gateways-four-markets); [11 · Frozen invoices and offline coupons that pay out once](https://www.microtech.consulting/work/immutable-issued-documents). - Healthcare and finance: meetings under HIPAA. Case studies: [15 · A file permission graph for a meeting platform](https://www.microtech.consulting/work/permissions-as-a-graph). - Construction: ERP and white-label estimating software. Case studies: [16 · A construction ERP that tracks stock down to the shelf](https://www.microtech.consulting/work/construction-erp-workforce-planning); [02 · A design system for 30+ white-label brands](https://www.microtech.consulting/work/design-tokens-thirty-white-labels). - Retail data: BI reporting for a US-market supplier. Case studies: [13 · A 15-minute report now opens in 0.2 seconds](https://www.microtech.consulting/work/query-optimization-under-fixed-schema). - B2B SaaS: a Swedish code-analysis company. Case studies: [17 · A HubSpot site marketing edits without a developer](https://www.microtech.consulting/work/hubspot-cms-custom-forms). ## Technologies named in the case studies Node.js (04, 05, 06, 07, 08, 10, 11, 14, 18); MySQL (04, 05, 06, 07, 08, 13); AWS (04, 05, 09, 10, 14); Next.js (01, 04, 09, 16); React (04, 08, 09, 15); InfluxDB (04, 05, 06); PostgreSQL (09, 11, 16); React Native (01, 10, 12); Android (02, 12); CSS (02, 17); Expo (04, 09); Figma (02, 03); JavaScript (02, 17); Kotlin (11, 12); NFC / ICAO 9303 (10, 12); S3 (13, 14); TypeScript (01, 03); WebRTC (10, 15); Amazon Redshift (13); Apple Pay (18); AWS Lambda (07); AWS Transcribe (15); biometrics (09); CI (03); Claude Code (03); custom ESLint plugin (01); design tokens (02); DocuSign (15); ESLint (03); Express (08); Fabric.js (11); Figma MCP (01); Google Pay (18); Handlebars (07); HubL (17); HubSpot CMS (17); Java (12); materialized views (13); national gateways (18); Neo4j (15); NestJS (16); npm (02); offline-first (09); OpenSearch (04); PayPal (18); pnpm workspaces (01); pre-commit hooks (03); Redis (04); Redux (08); SAP (16); SCSS (02); SQS (07); Stripe (18); styled-components (01); Swift (12); TensorFlow (10); Turbo Modules (12); Turborepo (16); Vite (01); WebSockets (05). ## Case studies in full ### Case study 01: A design system that keeps web and mobile in sync - URL: https://www.microtech.consulting/work/cross-platform-design-system - Domain: Platforms and design systems - Engagement: Own product · 6 months, ongoing · solo · this site runs on it - Published: 2026-09-11 - Stack: TypeScript, Next.js 16, React Native 0.87, Vite, styled-components, pnpm workspaces, Figma MCP, custom ESLint plugin - What could not change: The same components had to run on Next.js, Vite and React Native without the web and mobile versions drifting apart. - Headline number: 74 / 678 I built CDS after running into the same five problems on eleven projects. It has 74 components and 678 tests, and this site runs on it. #### Summary Web and mobile versions of a product start out identical, and two years later they share nothing but a name. Figma is one source of truth and the code is another, and nobody knows which one is correct. Conventions live in a README and are followed until someone gets busy. Every new product builds its component layer from zero. And a product sold under other companies' brands either has design tokens or ends up as thirty copies that nobody can maintain. In CDS, design tokens arrive from Figma automatically over an MCP server. A theme token resolves differently on each platform: on the web it becomes a CSS variable, and on native it becomes a sentinel value that the native resolver then replaces. That keeps the platform split one layer below the call site, so it never reaches the code that uses a component. The conventions are checked automatically: ~2,450 lines of verification make the build fail as soon as one of them is broken. The system has 74 components and 678 tests, and its 81-page catalog is generated from the source code. #### The five problems I ran into each of these problems on a real project before I started building CDS. ##### 1. Web and mobile drift apart On a meeting platform, five people spent eight months building, each in their own direction, and no shared component layer ever emerged. The codebase ended up with three UI frameworks and four dropdown libraries. On a marketplace, the dashboards and the mobile app did share a library, but the public site went its own way. The usual tools make divergence free. `Platform.select` puts a branch wherever it is convenient, and conditional imports let any file diverge. Neither leaves a trace, and nothing fails when they multiply. **What CDS does:** it moves the platform split one layer below the call site, so the code that uses a component never has to check the platform. `createTheme()` turns a token into a string that resolves per platform, so `${theme.color.fg.default}` behaves the same everywhere. Shared style recipes sit above that layer and both platforms apply them; they differ only in the trigger, `:hover` on the web and `pressed` on native. There is one definition of each color, so colors cannot drift apart. The login screen shows the result: its component call is byte-identical in all three apps. ``` b768aa14a346 apps/web/app/LoginScreen.tsx Next.js 16, RSC b768aa14a346 apps/spa/src/routes/LoginRoute.tsx Vite SPA b768aa14a346 apps/mobile/App.tsx React Native 0.87 ``` `LoginForm.tsx` is a single file of 135 lines with no native twin. It is assembled from `Box`, `Button`, `Card`, `Input` and `Text`, and the platform split happens inside those primitives. The wrapper around it differs: on the web a `Box` centers the form, on the phone a `SafeAreaView` holds it, and the API URL is different. Those differences come from the platform and the product, and the design system adds none of its own. --- ##### 2. Figma and the code are two sources of truth I have run into this everywhere. On a white-label product with thirty brands, a plugin exported the tokens from Figma. That was automated, but it worked in one direction only, and the tokens easily fell behind the design. On most projects, the only link between Figma and the code is a person copying hex values. Design changes on its own schedule and code on another, and without a mechanism between them the two are correct at the same moment only by accident. **What CDS does:** design tokens arrive from Figma automatically over an MCP server, with a manual path as a fallback. The token layer is a package: `core` depends on `tokens`, and `ui` depends on `core`, so a change enters in one place and nobody has to search and replace it across the code. --- ##### 3. Conventions written in a README stop being followed On a marketplace with nineteen repositories, the same queue helper had been copied into seven of them, and nothing in the setup prevented it. Nothing enforces a convention that is only written down, so it lasts until the first week nobody has time for a careful review. **What CDS does:** every invariant has a check, and the build fails as soon as one is broken. | Script | Lines | Checks | |---|---|---| | `verify-tokens` | 902 | token integrity | | `verify-conventions` | 1,056 | orphan-native, twin-exports, use-client, shared-platform-import | | `verify-katalog` | 485 | 10 hard checks on the catalog | That is ~2,450 lines of verification, plus an ESLint plugin with four rules. The rule that holds the architecture together is that a pattern must not have a `.native` variant. It is checked by `pattern-native` in `verify-conventions.ts`, which fails CI across 11 subjects. That rule is why the login screen stayed shared, and it will keep the screen shared after I stop paying attention. CI runs the same chain instead of reimplementing it: `pnpm verify` plus three real builds, for Next, Vite and Metro. The real builds are there because `next build` is the only place where the `'use client'` rule is actually verified, and a check that runs only in a script could pass while the real build fails. --- ##### 4. Every new product starts its component layer from zero I hit this while building three products of my own. Without a shared library, each of them would grow its own buttons, forms and modal, and the three products would end up with three sets of bugs. **What CDS does:** it is a package that my financial platform already uses, and this site is built on it too. It is a full component set: primitives (Box, Text, Button, Input, Switch, Slider), forms (Form, Field, Select, RadioGroup, OTPInput, PasswordField), overlays (Modal, Popover, Menu, Drawer, Tooltip, Toast), navigation (Link, Tabs, AppBar, TabBar, Breadcrumbs) and data (Table, Pagination, Accordion). I measured what `sideEffects: false` does: an entry that imports only `Box` went from 253,075 B to 241,309 B. The trap is documented next to that setting. `@cds/tokens` must not be marked false, because then `reset.css` is dropped and the layout collapses without a single error. Nothing in the toolchain reports that failure, so the note sits where the next person will look. --- ##### 5. Naive multi-brand theming multiplies the variants One construction product is sold under more than thirty brands. Built naively, with a separate version of every component for each brand, its hundred components would become three thousand variants to keep up to date. **What CDS does:** components refer to colors only through token names. A brand is added by supplying a new set of token values, and no component changes. The approach was proven on that construction product, and in CDS it has been part of the architecture since the first commit. #### The derived principle: split the reason, not the component 38 of 74 components have a native twin, which sounds as if half the system had diverged. In fact, the twins sit almost entirely in one layer: | Layer | Twins | |---|---| | `primitives/` | 27 | | `overlay/` | 8 | | `form/` | 2 | | `navigation/` | 1 | | `patterns/` | **0 of 26** | **33 of the 38 twins import no other component.** They are leaves that translate a single platform element, `div` to `View` or `input` to `TextInput`, and do nothing more. The split sits at the bottom of the tree, which is why nothing above it needs to know about it. A twin is allowed for only three reasons, and two of them have nothing to do with elements. **A different element.** This covers 33 of the 38 twins. The change is mechanical and contained, and the components above never see it. **A different event.** `Tooltip.native` exists because there is no hover on a touch screen, so the trigger is a long press, deliberately without a delay. On the web, `delayShow` prevents flicker while the cursor crosses a row of icons. A long press already signals intent, so a delay would only make the tooltip feel broken. **A different window.** `NativeSelect.native` exists because a system picker must sit above the keyboard, and the only way to a separate native window is an RN `Modal`. The shared `Portal` hands the tree to the host, which would leave the list underneath the keyboard. That failure shows only on a device, and only inside a form. The remaining three twins import exactly one component each and do not change the picture. No pattern has a twin at all, and that is enforced: `pattern-native` in the verification layer fails CI across 11 subjects as soon as one appears. `Modal` shows that a hard case can stay shared, with its portal, focus management and measurement, and `LoginForm` shows that a whole screen can. When a pattern needed a split, I left the pattern shared, extracted the primitive whose only difference was the element and gave that primitive the twin. It happened four times under pressure, which is why I treat it as a principle. The extracted primitives include `PositionedLayer`, `DialogActionsRow` and `MenuSeparator`. #### Numbers | | | |---|---| | Components | **74** | | With native twins | **38**, roughly half of them literally the same file | | Test cases | **678** across 62 suites | | Catalog pages | **81**, props tables generated from source | | Verification tooling | **~2,450 lines** plus 4 ESLint rules | | Bundle, Box-only entry | 253,075 B → **241,309 B** | | Duration | 6 months, ongoing | | In use by | this site, and my financial platform | #### The review, and the three causes behind it I reviewed all 75 components the system had at the time and found 188 issues. They came down to three root causes, and the toolchain catches none of them: the typecheck, ESLint and the build all pass. **A label on an element with no role.** `accessibilityLabel` on a node with no role is announced by neither platform. On the web, `aria-label` on a bare `div` does nothing, because the ARIA specification does not let a generic role take an author-supplied name. On native, `accessibilityLabel` without `accessible` is never read at all. Nine components had this bug, and the correct pattern already existed in the same package, where `Icon` always pairs its label with `role="img"`. **An inherited prop that never reaches the element.** `Omit` leaves `id`, `a11yRole`, `accessibilityLabel` and `pointerEvents` in the contract, but a branch that does not destructure them passes them into `...box`, and from there into a style helper that returns only `$` props. Nothing complains, because an omitted prop is simply `undefined`, which is valid. Four sibling components wired three different subsets of these props: one wired all four, two wired two each, and one wired none. **A comment describing an earlier version of the system.** A note describes a limitation, the limitation is later removed, and the note stays. This is the most insidious class, because a reader trusts the comment and never tries what has been possible for months. A worse variant is a JSDoc block shifted by one prop, so one prop carries two descriptions and its neighbor carries none. That text is generated into the catalog, where it becomes the public documentation. Knowing why the three tools stayed silent matters more than the count of 188, because it decides whether the next bug of the same kind gets caught. Two of the three causes are now covered by verification rules, so catching them no longer depends on a review. If I did it again, I would run that review when the system had 30 components, long before it reached 75. The same three causes were already present then, and correcting them would have cost an order of magnitude less. All 188 issues are fixed; coverage for `aria-label` and `tabindex` is still open. ### Case study 02: A design system for 30+ brands, and a client who came back - URL: https://www.microtech.consulting/work/design-tokens-thirty-white-labels - Domain: Platforms and design systems - Engagement: 2022: design system, solo, 2 months · 2025: Android, team of 3, 6 months · returning client - Published: 2026-09-11 - Stack: JavaScript, CSS, SCSS, design tokens, Figma, npm, Android - What could not change: More than thirty construction companies each needed their own colors, logos and imagery from the same set of about a hundred components. - Headline number: ~100 / 30+ I built about a hundred components for 30+ white-label brands. Three years later the client brought me back when their Android app would no longer install. #### Summary The client's software turns a photograph of a floor plan into a cost estimate and a phased work plan, and the client sells it under other companies' brands. In 2022 I built their central design system alone, in two months. Three years later they brought me back for something entirely different: their Android app could no longer be installed on current devices. #### The constraint In 2022 the product was white-label: more than thirty construction companies each got their own colors, logos and imagery. With that many brands, the product could not work without design tokens. Implemented naively, a hundred components for thirty brands would mean three thousand variants that nobody would maintain. In 2025 the app could no longer be installed on current Android versions, because its libraries had been abandoned and the APIs it relied on were deprecated. An app in that state disappears without an error: new users simply cannot install it, and existing users lose it the moment they change phones. At the same time, a large share of the phones on a construction site are several years old, so the fix could not leave them behind. #### What I did, and what we did **The design system (2022, alone).** I exported the design tokens from Figma into JSON, generated SCSS from them and built about a hundred components on top, organized by size, type and kind. The library is versioned and distributed as a package, with its own documentation. No component knows its own color, only the name of a token. A new client is a new set of values, not new code, and that is what keeps thirty brands maintainable. I made the library framework-agnostic on purpose, because two different products use it. Tied to one framework, it would force every consumer outside that framework to build its own implementation of the same design, which is the problem a design system exists to solve. With a hundred components, the organization by size, type and kind has a practical purpose. Without consistent organization, a library that size turns into a search through file names: a developer who does not find what they need in thirty seconds concludes it does not exist and writes their own CSS, and the design system ends up bypassed without anyone deciding to drop it. **The Android app (2025, three of us).** We got the app running again on both current and older devices. We brought camera permissions into compliance after a store policy change, upgraded the dependencies used for viewing documents and moved work off the main thread. #### Result - **~100 components carrying 30+ white labels**, built solo in two months - A versioned package with documentation, used by two products - The Android app installs and runs again on both new and old devices - **The same client, back after three years, on an unrelated discipline** #### What I would do differently The documentation was custom-made, without a standard tool, so it became one more thing to maintain and one more thing every new developer had to learn. For a library that thirty brands depend on, I would choose a standard documentation tool, even though it is the boring option. ### Case study 03: Code standards that made AI-generated code cheap to accept - URL: https://www.microtech.consulting/work/ai-assisted-engineering-standards - Domain: Platforms and design systems - Engagement: Technical Lead · US marketplace for truck services · 2026 · team of 12 · same engagement, fourth year - Published: 2026-09-11 - Stack: Claude Code, pre-commit hooks, CI, ESLint, TypeScript, Figma - What could not change: Generated code arrives faster than a person can carefully read it. - Headline number: ~50% We turned the team's standards into checks that run before every commit and in CI. Throughput rose roughly 50%, estimated from ticket cycle time. #### Summary By 2026 the team used Claude Code every day for components, tests and integrations, and design was connected to Figma. Throughput rose by roughly 50%, estimated from ticket cycle time, and the team stopped writing tests by hand. AI moves work from writing code to reviewing it, and it does not reduce the total. If review is already the bottleneck, generating more code makes things worse, so review had to get cheaper before AI arrived. We started with the rules: engineering standards written as executable checks, enforced before every commit and again in CI, with a separate set for each codebase, because a backend and a component library need different rules. #### The constraint A convention with no owner is a suggestion: it holds while someone has time to review carefully, and it stops the first week nobody does. Conventions fade on disciplined teams too, because nothing enforces the agreement. On a system of nineteen repositories, with four developers in a team of twelve, "we agreed to do it this way" has a half-life of about a quarter. I had already seen where that leads: the same queue helper copied into seven repositories, because nothing stopped it. With AI in the workflow, a soft standard gets weaker still: generated code arrives faster than a person can carefully read it, and the standard becomes decoration. The requirement was to make the standards mechanical, checked by tools, so that accepting code would cost less than writing it. #### What we did ##### Rules written as code We wrote the standards as checks that the tooling runs, so none of them depended on anyone remembering a style guide. They included: - No `any`, with a prescribed way of declaring types - A component may not exceed 200 lines - Every API call must have a request type and a response type ##### A different set per codebase The web app, the backend and the component library each had their own set of rules. One set for both a backend and a design system would be loose enough to be useless for one or strict enough to be routinely bypassed in the other. Deciding which rules mattered in which codebase was part of my job as Technical Lead. ##### Three severity levels, by stage The same rule had a different severity at each stage: | Stage | Severity | Why | |---|---|---| | While developing | **warning** | tells you without interrupting the work | | Pre-commit hook | **error** | stops the problem before it becomes shared | | CI | **error** | the gate nobody can skip | Escalating the severity by stage keeps a rule present the whole way through and makes it block only where blocking is cheap. Most teams pick one severity and get one of two failures: if it is too strict, people fight the tooling or switch it off, and if it is too soft, the rule gradually stops being followed. This is the part of the setup I would recommend to any team. Which checks run where follows the same logic. Formatting and linting run in the hook because they are fast and local, and types and tests run in CI because they are slow and definitive. A hook that takes thirty seconds gets bypassed within a week. ##### AI in daily use With the checks in place, Claude Code went into daily use for components, tests and integrations, and design was connected to Figma. The order mattered because generated code is cheap only when accepting it is cheap, and that requires something other than a person to check the boring half. #### Result - Team throughput up roughly **50%**, estimated from ticket cycle time - **Tests stopped being written by hand**: the team generated them with Claude Code, and that matters because tests are the first thing dropped under deadline pressure - The standards were enforced the same way no matter who reviewed the code, or whether anyone did In hindsight, the most valuable rule was the 200-line limit on components, more than the type rules or the API contracts. It pays back over years, because it forces decomposition the moment something starts to sprawl, while splitting it is still easy. #### What I'd do differently The 50% figure is an estimate from ticket cycle times, not a controlled measurement. In July 2025, METR ran a randomized controlled trial with 16 experienced developers working on 246 real tasks in repositories they had worked in for years. The developers predicted that AI would make them 24% faster, and afterwards they reported being 20% faster. Measured, they were 19% slower, a gap of 39 percentage points between how fast they felt and how fast they were. METR has since revised the study's design and treats the result as historical, partly because in a follow-up many developers declined to take part if they had to work without AI. The main finding still stands as a warning: speed that people report themselves is unreliable, including when the report is flattering. The team's setup differed from the study's in ways that plausibly matter. METR measured individual developers in codebases they had known for five years, using AI ad hoc in an editor with early-2025 tools. This team was building a product in active development, with rules enforced automatically and 2026 tooling. Those differences are reasons to think the 50% might be real, but they do not prove it. I would measure cycle time properly: three months before and three months after, from data the team already had. It was available, and I estimated instead. ### Case study 04: Moving a US marketplace from PHP to Node with no downtime - URL: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration - Domain: Marketplace and revenue - Engagement: Technical Lead · Jul 2022 – 2026 · direct client · team of 12 · I owned architecture, roadmap, hiring and the client relationship - Published: 2026-09-08 - Stack: Node.js, React, Next.js, Expo, MySQL, OpenSearch, InfluxDB, Redis, AWS - What could not change: The marketplace was the client's only source of revenue, so nothing could be taken offline or rewritten in place. - Headline number: Zero outages We took over a marketplace that kept crashing on shared hosting and rebuilt it on AWS in four phases over four years, with me as Technical Lead. #### Summary The product is a US marketplace that connects truck drivers and fleets with repair, towing and tire services. When we took it over, it ran on PHP on shared hosting that did not scale, it went down regularly, and SQL injection was reaching production. The work ran in four phases: two months of stabilization, two years of rebuilding, a shared design system, and then AI built into how the team works. The product never went down in any of them. The part of this work I am proudest of is the analytics, even more than the migration. The platform took over two million writes a day, advertisers read them live in their dashboard, and annual reports came back in under a second even for the largest accounts. #### The constraint The marketplace was live and was the client's only source of revenue. Advertisers pay to be visible, so they pay for every hour of downtime and get nothing for it. We could not take anything offline, and we could not rewrite the system in place. The mobile apps shaped the whole rebuild, because we controlled the web but not the phones. A web user gets the new version on their next page load. A mobile user updates whenever they feel like it, and shutting down the old backend breaks an app that is already installed on someone's phone. #### What we did **Phase 1: stabilize (2 months).** We moved the existing PHP application onto AWS without rewriting it. We added a firewall, closed the inherited security holes, moved images to object storage and mail into a queue, and indexed the twenty slowest queries, which made them 90% faster. Rewriting straight away was tempting, but we stabilized what was earning money first and spent the next two years on the rewrite. **Phase 2: rebuild (2 years).** The backend moved from PHP to Node and later to a typed framework, the dashboards to React, the public site to Next.js, the mobile apps to Expo, and the hosting to containers with autoscaling. We deliberately kept MySQL as the one fixed point, the only thing that was not allowed to move. When language, framework, hosting and mobile stack all change at once, you need one thing that stays the same to prove the new version behaves like the old one. Data moved through a script that remapped the schema, and triggers kept the old and new databases synchronized in both directions for over a year. An ad created in the new system appeared in the old one, and the other way round. We shut the old system down only when analytics showed that its last user had left. Rollback was a change of origin at the CDN: seconds, no deploy. After the public site moved to Next.js, Lighthouse performance went from 60 to over 90, and SEO from 30 to over 90. The platform lives on organic search, so those scores feed straight into revenue. Amazon measured in 2006 that every 100 ms of added load time cost it 1% of sales, and Walmart found that every second of improvement raised conversion by 2%. **Phase 3: design system.** We built over 200 components in a monorepo, shared between the dashboards and the mobile app. Only side effects differ per platform, so web and mobile cannot drift apart. **Phase 4: AI in the process (2026).** We wrote the engineering standards as executable rules, checked before every commit and again in CI. Each codebase got its own rule set, because a single set for a backend and a component library would be too loose for one or too strict for the other. Claude Code was in daily use for components, tests and integrations, and design was connected to Figma. **Analytics, across all four phases.** This part of the system had to absorb over two million writes a day, keep each advertiser's dashboard live and produce a full year's report in under a second, even for accounts with more than 900 listings. One database rarely manages all three, because a database built for fast writes tends to be slow at complex queries, and a year of raw data at this volume runs to hundreds of millions of rows. We split the work between two databases. Writes went into a time-series database whose index we kept small on purpose. Once a day, each listing's events were summarized into a row in MySQL, and the dashboard and the invoices read those rows. Raw events stayed for seven days before going to the archive. The annual report never read them at all: it added up 365 daily rows per listing. #### Result - Four phases in four years, **zero downtime**: no outage was recorded in the logs or reported - Lighthouse performance **60 → 90+** and SEO **30 → 90+** after the public site moved to Next.js - Twenty slowest queries **90% faster** - Analytics at **2M+ writes/day** with live reads, and an **annual report under one second** at 900+ listings - Team throughput up roughly **50%** after AI was built into the process, estimated from ticket cycle - 19 repositories, 506 API routes, 100 data models and 194 migrations, five user types on a single codebase, and four databases, each chosen for its purpose #### What we would do differently We let the system spread across nineteen repositories with no shared package. The same queue helper ended up copied into seven of them, so changing a message format means changing it in seven places. A shared internal package should have come before the fifth service rather than after the fifteenth. ### Case study 05: Live analytics for advertisers at two million writes a day - URL: https://www.microtech.consulting/work/analytics-two-million-writes-per-day - Domain: Marketplace and revenue - Engagement: Technical Lead · US marketplace for truck services · 2022–2026 · team of 12 · same engagement - Published: 2026-09-11 - Stack: InfluxDB, MySQL, WebSockets, Node.js, AWS - What could not change: The analytics layer had to take writes at volume, serve live reads and aggregate a whole year quickly, all at once. - Headline number: 2M / day I built the analytics layer of an advertising marketplace. Each customer's annual report came back in under a second, even for accounts with 900+ listings. #### Summary I designed and built the analytics layer for an advertising marketplace. It took over two million writes a day, fed a dashboard that updated live, and returned a full year of history in under a second. High-volume writes, live reads and fast yearly reports normally exclude one another. A database that ingests quickly is slow at complex queries, and a year of raw data at that rate is hundreds of millions of rows. No single database does all three jobs, so I split them between two. #### The constraint On an advertising platform, what a customer pays for is proof that their listing was seen. When a repair shop pays for a listing, the only question that matters at renewal is how many people saw it and how many called. The analytics are what justifies the invoice, which rules out buying an off-the-shelf tool. General web analytics measures traffic to a site. It does not measure the value delivered to one advertiser, and it cannot put that number back into the advertiser's account, in their dashboard, next to their renewal. The system had to take writes at volume, serve live reads and aggregate a whole year quickly, all at the same time. Each of these is easy on its own. #### What I did **A time-series database for ingest, with a deliberately small index.** I put identifiers such as listing, user and device into fields. In a time-series store tags are indexed and fields are not, so putting a listing ID in a tag means every new listing creates a new series, and eventually the index suffocates. This is the single most common way these installations fail. Keeping listing IDs out of the index meant the time-series store could not group by listing efficiently, so that grouping was done in the relational database. **Daily rollups in the relational database.** Raw events were kept for seven days, with a daily export to object storage as the archive. A daily summary per listing landed in the relational database, and that is what the dashboard and the invoices queried. Because of the rollups, the annual report never touched a raw row: it read 365 summarized rows per listing. **Speed measured on the largest accounts.** The under-one-second figure holds for accounts with over 900 listings, where a year of daily rollups is roughly 330,000 rows aggregated in a single query. A report that returns in under a second on an account with three listings proves nothing about the architecture, so I measured at the worst case rather than the average. **Total and unique views in separate buckets.** I counted unique views by session and by page URL, so someone who searched in two cities was not counted as one view: they were looking for two different things. Totals are the bigger number and look better, while uniques tell an advertiser how many different people saw them. I kept both, so neither number had to be hidden. **Bot filtering at three layers.** I filtered bots at the firewall, by known addresses and by user agent. On an advertising platform an inflated view count damages trust, because an advertiser who sees five hundred views and no calls stops believing the number, and then stops believing the invoice. #### Result - **2M+ writes per day** into the time-series database - Advertisers read their numbers live in the dashboard - **Annual report under one second at 900+ listings**, reading 365 daily rollups per listing - The same data feeds the yearly report sent before each renewal #### What I'd do differently Seven days of raw retention was chosen early and never revisited. It was almost certainly right, but I never checked what we lost by it: whether anyone ever needed to reprocess a window longer than a week, and what it would have cost to keep thirty days. I picked a number and moved on. ### Case study 06: Event tracking that measures what advertisers pay for - URL: https://www.microtech.consulting/work/product-analytics-event-taxonomy - Domain: Marketplace and revenue - Engagement: Technical Lead · US marketplace for truck services · 2022–2026 · same engagement - Published: 2026-09-11 - Stack: InfluxDB, MySQL, Node.js - What could not change: Standard web analytics measures neither the position an advertiser pays for nor the calls they get. - Headline number: ~180 types An advertiser pays for a listing's position and gets value from the calls it brings. I designed about 180 event types to measure both and each step in between. #### Summary The platform tracked around 180 event types. The number is large because the taxonomy maps how the business makes money, from the position an advertiser paid for to the phone call that came from it. Designing the taxonomy was much more a product decision than a technical one, and it is the part of the analytics work I would point to first. #### The constraint In a directory business the advertiser buys position and receives calls. Anything that happens between the two is an assumption until someone measures it. Standard web analytics measures neither position nor calls. It counts sessions, pageviews and bounce rates, which describe the website and say nothing about the value delivered to one advertiser on it. You cannot take a bounce rate to a repair shop and explain why the invoice is what it is. The taxonomy follows the value chain from position to call, while standard tools are organized by page. #### What I did **Position as a first-class event.** The events `top1`, `top3`, `top5` and `top10` were recorded at the moment a listing appeared instead of being derived afterwards. A premium listing is sold as better placement, so placement has to be demonstrable, and that means recording it when it happens. I split the chain into stages: position → impression → interest → intent → contact. Interest was deliberately granular: opening hours, services, amenities, rates and reviews were tracked separately. Each of those is a different question, and a system that lumps them together as "engagement" throws the answer away. **Intent and contact as separate events.** Revealing a phone number is recorded as intent, and placing the call as contact. The gap between them is a conversion rate that no general-purpose tool would produce, because none of them knows that revealing a number is the meaningful moment in this business. **Primary, secondary and after-hours numbers.** Each was tracked separately. In truck repair the difference matters: a call at three in the morning means a different kind of urgency and a different kind of job. **The sales funnel.** I also measured which package a visitor chose and which tier of listing they created. That way the system describes how an advertiser decided what to buy as well as what they receive. #### Result - ~180 event types covering the whole chain from placement to call - Yearly reports that answer the one question an advertiser has at renewal: how many people saw the listing and how many called - A conversion rate from number reveal to call, which no off-the-shelf tool would have produced #### What I'd do differently Over four years the platform tracked 180 event types, and there was never a scheduled review of which ones anyone still looked at. Some certainly stopped being used and kept being written. We had a naming convention for events but no habit of pruning them, and a taxonomy needs both. I would review the event types on a schedule. ### Case study 07: Renewals and payment reminders handled by six daily jobs - URL: https://www.microtech.consulting/work/scheduled-jobs-as-revenue-logic - Domain: Marketplace and revenue - Engagement: Technical Lead · US marketplace for truck services · 2022–2026 · same engagement - Published: 2026-09-11 - Stack: AWS Lambda, SQS, MySQL, Handlebars, Node.js - What could not change: Every customer renewed on a different date, and nobody could watch several thousand expiry dates by hand. - Headline number: 6 jobs The marketplace sold annual advertising, so several thousand customers renewed on different dates. Every day the jobs applied the same rules to each account. #### Summary On this platform, the revenue depended on six scheduled jobs that ran every day. Scheduled jobs usually handle maintenance, such as cleanup, expiry and digests, but these handled renewals and payments. Between them, the six jobs reminded advertisers before their listings expired, downgraded listings that fell too far behind on payment, processed recurring charges, chased unverified listings, ran a re-engagement campaign timed to the annual cycle and warned fleet operators about upcoming vehicle inspections. #### The constraint The product sold annual advertising, so revenue came in on each customer's renewal date, and every customer had a different one. If that date passed unattended, the money did not come in at all. Nobody could watch several thousand expiry dates by hand. The rule to downgrade a listing after non-payment also could not be left to someone's judgment, because a rule applied to some late accounts and skipped for others is worse than having no rule. It had to apply the same way to every account. The commercial rules therefore had to be written in code and run on a schedule, without anyone deciding each day to run them. #### What I did **I made renewal the central job.** It found listings approaching expiry and sent reminders. When a listing was more than seven days late, the job downgraded it automatically, updated the invoice and re-indexed the record, so search showed the change immediately. Without the re-indexing, the downgrade would have existed only in the database, and the advertiser would have kept the placement they had stopped paying for. **Recurring payments had three outcomes.** A successful charge, a failed charge and an upcoming charge each had their own message. I treated a failed payment as a reason to contact a customer who probably wanted to keep the service. **Re-engagement followed the annual cycle.** A three-step campaign went out at roughly 179, 182 and 186 days after a listing's last update. About half a year before renewal, stale information in a listing is a sign that the owner has stopped thinking about it, and those owners are the ones who fail to renew. **I chose the channel for each job.** Reminders about unfinished draft listings appeared in the app instead of arriving by email, so someone halfway through creating a listing found the reminder where they had left off. **All mail went through one sending service.** Every job followed the same steps: query the database, take a template from object storage, write a record and put a message on a queue. Outside production, that service redirected all mail to a test address, so there was no way for staging to email a real customer. #### Result - Six daily jobs that ran renewal, downgrade, dunning and re-engagement - The same commercial rules applied to every account, without anyone having to decide to apply them - 55 email templates, all going out through a single sending service #### What I'd do differently The jobs ran daily and reported only their errors. There was no way to see how many listings had been downgraded in a given week, or whether the re-engagement campaign changed anything at all. I would add a business-level report next to the error log that answers those two questions. Without it, a job that stopped working would only have come to light when someone asked why revenue dipped. ### Case study 08: Five kinds of user in one codebase, separated by route - URL: https://www.microtech.consulting/work/multi-persona-single-codebase - Domain: Marketplace and revenue - Engagement: Technical Lead · US marketplace for truck services · 2022–2026 · team of 12 · same engagement - Published: 2026-09-11 - Stack: React, Redux, Node.js, Express, MySQL - What could not change: Five kinds of user did different work on the platform, but every payment, branding or security change had to reach all five. - Headline number: 506 routes Service vendors, fleet carriers, owner operators, company drivers and a call center each had their own dashboard, with permissions set by user type and role. #### Summary The platform served five kinds of user who did different work on it. A vendor managed listings, invoices and renewals. A driver had recent searches, preferred vendors, call logs, trucks and repair tickets. A call center operator worked on behalf of other users. One codebase served all five, and the company's own team used a separate internal CRM. #### The constraint Building five separate applications looks cleaner, and for about six months it is faster. With five applications, every shared change, such as a payment flow, a branding update or a security fix, has to be made five times. It will be made four times, and nobody will notice which one was missed until a customer does. A single application with role conditions scattered through the interface is the opposite mistake, and just as common. That version cannot be audited, because the only way to answer "what can a driver actually do?" is to read the entire codebase looking for conditionals. #### What I did **I separated the user types by route.** Each type had its own set of routes under `/dashboard/{user_type}/{page}`, so the vendor's routes showed everything a vendor could do. **Permissions resolved as user type plus role.** Every user type had at least two roles, such as admin, owner and operator, and a permission depended on the combination. A vendor's operator was a different subject from a fleet carrier's operator, even though both were called "operator." **The backend checked permissions too.** Separate routes in the client only organized the code, so the API checked every permission independently. A rule enforced only in the interface can be bypassed by anyone who calls the API directly. **I split the API in two.** Public routes and admin routes were two separate sets instead of one set with checks inside. The internal CRM was, in effect, a separate product with its own API surface. #### Result - Five user types and their roles served from one codebase - 506 API routes in two separate sets - Permissions that could be audited by reading one set of routes #### What I'd do differently The permission model existed in the routing and in the API, but it was never written down anywhere a person could read it as a whole. Each new developer had it explained verbally, and verbal explanations of an authorization model drift. I should have generated a single table of user types against actions. It would have taken a day and answered the question for good. ### Case study 09: Capturing passport applications and biometrics offline - URL: https://www.microtech.consulting/work/offline-first-sensitive-data-capture - Domain: Identity and documents - Engagement: Full-stack engineer · 2024 · 6 months · direct client · involved in every feature - Published: 2026-09-11 - Stack: React, Next.js, Expo, PostgreSQL, AWS, offline-first, biometrics - What could not change: The applications included biometrics, and the people the agents visited often had no connection. - Headline number: 1 working day For a national identity authority in West Africa, we built the app its agents use to take passport and ID applications in villages with no signal. #### Summary For a national identity authority in West Africa, we built the system for applications, biometrics, fee payment, national registry checks and status tracking. The same flow issues both passports and ID cards, and only the price differs. The system is in production, and the app is published on Google Play. The hard part was deciding which problem we did not need to solve. #### The constraint The authority sends agents out to people, and the people they visit often have no connectivity. Passport applications with biometrics, the most sensitive data a government holds, therefore have to be captured on a phone in a village and uploaded later. Requiring a connection, the usual answer, was not an option. Working offline also raises problems an online system never has: what is stored on the device, what happens if the device is lost, and how to know that the same application was not submitted twice. #### What we did We limited the offline window to one working day. Agents return their devices to the office at the end of each day, so synchronization only ever has to cover one day. Because no device comes back after weeks away, there are no merge conflicts or divergent copies to reconcile. We designed for that one-day window instead of for offline sync in general, and that is what kept the system simple enough to trust. Applications and biometrics are held in secure storage on company-issued phones that can be wiped remotely, and they upload when connectivity returns. **Company-issued phones only.** Keeping biometrics on a phone is acceptable only if the phone belongs to the organization and can be wiped remotely. If agents had used their own phones, the same design would not have passed, however well the data was encrypted. **Duplicates are caught on the server.** A device that has been offline cannot know what another device did. Only the server, which every device eventually talks to, can decide whether an application already exists, and it does so before the application is accepted. **Fee payment.** Fees are collected through the national payment gateway, with PayPal for applicants abroad. In the public sector, regulation decides which payment provider you use. **Registry access.** Calls to the national registry are secured with keys, digest authentication, single-use tokens and IP allow-listing, so a stolen key on its own opens nothing. #### Result - Applications, photographs and biometrics captured without a connection, on devices that can be wiped remotely - Duplicate submissions caught on the server before acceptance - The system in production, with the app published on Google Play #### What we would do differently We never tested what happens when a device does not come back: an agent who does not return at the end of the day, or a phone that stays out for a week. The one-day window was the right design, but a design that depends on a working habit should define what happens when the habit fails. A hard expiry on unsynced data would have cost an afternoon. ### Case study 10: Liveness checks on both the person and their passport - URL: https://www.microtech.consulting/work/liveness-detection-person-and-document - Domain: Identity and documents - Engagement: Full-stack engineer · 2020 · 6 months · via agency · I built the web app, the mobile app and the API - Published: 2026-09-08 - Stack: TensorFlow, WebRTC, React Native, Node.js, AWS, NFC / ICAO 9303 - What could not change: Regulation required video identification, and each session's record had to hold up in a review years later. - Headline number: 98% We built remote identity verification for a German financial institution. A model was confident in about 98% of cases, and an operator confirmed every case. #### Summary We built remote identity verification as infrastructure to be resold to other institutions, separate from any one bank's app. Customers went through six steps, randomized so that no session could be prepared in advance. The model produced a confident recommendation in about 98% of cases, and a person confirmed every case. The product was sold at MVP stage. #### The constraint Regulation required video identification, and that one requirement shaped the rest of the design. It is why the video was kept, why an operator confirmed every case and why the system recorded gestures as well as checking the face. Each session had to produce the same evidence as a conversation with a human agent: a record that could be reviewed afterward and attributed to a named person. At the same time, an ordinary customer holding a phone had to be able to finish it. The six steps were also required by regulation, so none of them could be removed. The work went into making each one easier to get through. #### What we did **Six randomized steps.** The spoken digits and the gestures changed in every session, so a recording could not be prepared ahead of time or replayed. The steps were face capture, document capture, a video of the document turned through prescribed rotations, a finger placed on the document's edge, five random digits spoken aloud and a selfie video with random head movements. **The document had to pass a liveness check too.** Most systems stop at checking that a live person is in front of the camera, but here the document also had to prove it was a physical object held in a hand. Turning it shows depth and how light falls on it, and a finger on the edge shows a hand holding it. Together these steps catch attacks that a check of a single photograph would miss. **Feedback while recording.** Computer vision ran on the user's device, with the same layer on web and mobile, so recording started only once a face was in frame and each gesture was checked as it happened. With six steps that could each fail, that immediate feedback is what kept the process tolerable. One vision layer on both platforms also meant one behavior, and in identity verification that is a question of fairness: the same person should not pass on one device and fail on another. **Reading the passport chip.** Later we added reading data directly from the NFC chip in German passports and ID cards. Until then everything was inferred from an image: the model looked at a document and judged it. Chip data is cryptographically signed by the issuer, which made this the largest single gain in reliability in the whole system. **Biometric data storage.** The data stayed unlocked only while it was being processed, then moved to separate storage under a key held outside the development team. Every request and response was encrypted, and every token could be used only once. **A case file for the operator.** The operator had to record a reason, assign the case and, when an action went beyond their permissions, hand it to a colleague who had them. If they judged a selfie insufficient but were not allowed to request another, the case moved on with a note explaining why. Permissions were set per action, not per role. The client commissioned independent penetration and load testing. #### Result - The model produced a confident recommendation in about **98%** of cases, and an operator confirmed **every** case - Support for three German document types, with chip reading on passports and ID cards - Independent security testing, commissioned by the client - **Product sold at MVP stage** An operator confirmed every case because in regulated banking both wrongly accepting and wrongly rejecting a customer have consequences, and each decision has to be attributable to a named person. We built the system as decision support for that person. #### What we would do differently We never established what the model's accuracy actually was, only how often it was confident. Confidence and correctness are different measurements, and we shipped without the second one. ### Case study 11: Invoices frozen at issue and coupons that pay out only once - URL: https://www.microtech.consulting/work/immutable-issued-documents - Domain: Identity and documents - Engagement: Three engagements · customs invoicing, 2020 · remittance terminals, 2022 · meeting platform, 2023 - Published: 2026-09-11 - Stack: Node.js, PostgreSQL, Kotlin, Fabric.js - What could not change: An issued invoice must not change when its template does. - Headline number: 3 domains Three products had to store when a record was created apart from when it became valid. On the customs system, none of 50,000 invoices changed after issue. #### Summary A customs authority needed invoices that could never change after issue. Remittance terminals had to print coupons while offline without risking a double payout, and a meeting platform needed a whiteboard that people could still work with after the meeting ended. The three products were unrelated and built in different years, but each needed the same answer: the stored data had to distinguish a record that exists from a record that is binding. #### The constraint Every system that issues documents eventually has to decide what an old document shows after its template changes, and most decide too late. Templates change: a layout is corrected, a legal notice updated or a logo replaced. Then someone opens a document issued two years ago and sees this year's template, with this year's legal text, on a record that was signed under different terms. No error is raised when a template change alters an old document, and from that point the archive no longer shows what was actually issued. Creation and validity can drift apart in other systems too: a coupon printed with no network, or a whiteboard that only exists as a screenshot. #### What I did **Customs invoicing (2020).** The customs authority required that an issued invoice never change. So at the moment of issue, the document was rendered and stored as immutable HTML, and later template edits touched nothing already issued. The system kept the *definition* of a document separate from the *issued* document, so the template could keep evolving while the history stayed intact. The frozen output also no longer depended on the rendering code staying correct in the future. Had documents been rendered on demand, any change to that code would have retroactively altered every old document. **Remittance terminals (2022).** A recipient collected cash at a filling station using a coupon code. The terminal had to keep working when the network was down, but a coupon that paid out twice was the one failure that cost real money. The terminal printed each coupon as not yet valid, because a coupon that could not be used yet was an acceptable price for never paying one out twice. A coupon became valid when the system said so: automatically when the connection came back, or manually through an operator, who was alerted that an unactivated coupon existed. The system knew which coupons had been printed and were not yet valid, so none of them could be lost without anyone noticing. **Meeting platform (2023).** The whiteboard was saved as structured objects instead of a flat image, so every stroke, shape and piece of text kept its own properties. After the meeting, people could reload the board and keep editing it. #### Result In all three products the record stayed intact through the event that usually breaks it: a template change, a lost connection or the end of a session. - **Customs invoicing: validated on 50,000 invoices**, none of which changed after issue #### What I'd do differently On the customs system, freezing the issued document was correct but incomplete, because the template itself was never versioned. No issued invoice could change, but there was no record of *which* template version produced it, or of who changed the template and when. The snapshot answered the urgent question and left the audit question open. I would version the templates from the start and point each issued document at the version that produced it. ### Case study 12: React Native modules for passport chips and POS terminals - URL: https://www.microtech.consulting/work/react-native-hardware-native-modules - Domain: Identity and documents - Engagement: Two engagements · German financial institution, 2020 · cross-border remittance, 2022 · both via agency - Published: 2026-09-11 - Stack: Java, Kotlin, Swift, Turbo Modules, React Native, Android, NFC / ICAO 9303 - What could not change: Neither the passport chip nor the payment terminal had a library worth using. - Headline number: 100+ terminals On two projects I wrote a hardware protocol natively and gave React Native a single API for it: a German passport's NFC chip, and over 100 payment terminals. #### Summary Twice I had to make React Native talk to hardware that had no library worth using: the NFC chip in a German passport and a Chinese payment terminal running Android. In both cases I implemented the protocol in the platform's own language and gave JavaScript a narrow interface, so platform details stayed out of the JavaScript code. What differed was what each piece of hardware demanded. #### The constraint React Native works well until an app needs something the platform can do and JavaScript cannot reach. Reading an e-passport means implementing a protocol, ICAO 9303, which requires an authentication handshake before the chip returns any data. In 2020 there was no usable library for it. The Chinese payment terminal was harder still, because its SDK documentation was sparse and written in Spanish. I translated it in order to work with the device at all. In both cases the bridge between the native code and JavaScript was the whole job. A mistake in that interface would have cost something in every feature built on it later. #### What I did **The passport reader (2020).** I implemented the chip protocol in Java for Android, ported the same logic to Swift for iOS and exposed it to React Native through a Turbo Module. Turbo Modules were then still an experimental part of the new architecture, had to be registered by hand and had thin documentation. Porting the same logic, instead of writing a second implementation from scratch, was the important decision. Two independent implementations of a protocol like this drift: they start treating edge cases differently, and then the same passport passes on one phone and fails on another. In identity verification, that means the person holding the document is treated differently depending on their phone. An external service decoded the retrieved data, and my part was reading it off the chip. **The payment terminal (2022).** I exposed the terminal's card, printer and hardware functions to React Native through a Turbo Module in Java. Then I wrote a launcher in Kotlin that replaced the Android home screen and locked the device to a single app. On a device that dispenses cash, locking it down was a matter of control: the person behind the counter must not be able to open a browser, install anything or change a setting. The lock paid off a second time, because a device locked to one app you control can be updated over the network. More than a hundred terminals were updated without anyone visiting a site. The app checked object storage for a new version, and if an update failed, nothing happened at all: the app kept running and retried every five minutes until it succeeded. Every terminal was registered in an admin dashboard that showed its activity, from the moment it connected through to who issued which coupon. **Thermal printing.** A receipt printer does not know about images, fonts or layout, only dots. A logo has to be turned into a bitmap and positioned by hand, in paper units, with no preview. That sounds trivial, but the only way to do it is to print and measure. #### Result - Cryptographically signed passport data read from the chip on both platforms, from one protocol implementation - Over 100 payment terminals locked to a single app and updated over the network - Failed updates that cost nothing: the terminal kept working and retried #### What I'd do differently On the passport module I ported the Java implementation to Swift by hand and verified it by testing. I should have built a shared set of protocol test vectors, known inputs with their expected outputs, and run it against both implementations. Testing that two implementations behave the same is different from testing that they are correct, and I did the first while believing I had done the second. ### Case study 13: Speeding up a report without changing its queries or schema - URL: https://www.microtech.consulting/work/query-optimization-under-fixed-schema - Domain: Data and infrastructure - Engagement: Data warehouse architect · 2025 – present · direct client · the choice of warehouse was mine - Published: 2026-09-08 - Stack: Amazon Redshift, S3, MySQL, materialized views - What could not change: The BI tool generates the queries and customers' saved reports depend on the schema, so neither could change. - Headline number: 15 min → 0.2 s For a supplier to large US retail chains, the largest customer's sales report went from over fifteen minutes to 0.2 seconds. No saved report had to be rebuilt. #### Summary The client supplies fashion accessories to large American retail chains, and those chains read their own sales data through a BI tool. Two things could not be touched: the queries, because the tool generates them, and the schema, because customers have saved reports that depend on it. The largest customer's report went from over fifteen minutes to two tenths of a second, and a second report went from four minutes to a tenth. Nielsen Norman Group puts the limit for an uninterrupted flow of thought at 1 second and the limit of attention at 10 seconds, after which users go and do something else. Fifteen minutes is ninety times that 10-second limit, and the report now opens in under 1 second. #### The constraint The report is part of what the client sells: their customers open it to see how their own products are moving. The queries belong to the BI tool, which generates them, so there was nothing to rewrite. The schema in practice belongs to the customers, because their saved reports are built on it, and changing it would mean asking every customer to rebuild their work. That ruled out both of the usual fixes for a slow report: rewriting the query and remodeling the schema. What was left was to keep the queries and the schema exactly as they were and change the system they run against. #### What I did I chose Redshift because the client was moving every service to AWS. A warehouse in the same cloud as the rest of the system means simpler transfer, one account, one access model and one team maintaining it. Snowflake or BigQuery would have been just as capable, but they did not fit where the client's infrastructure was heading. There was no migration in the usual sense, because existing jobs already exported data on over 200 million products from the MySQL source system to S3. My layer picks up those exports and loads them into Redshift. I chose the distribution and sort keys from the queries the BI tool actually runs. Those keys decide which node each row lives on and the order rows sit in on disk, which no query names, so they could change while the schema stayed exactly as it was. Keys chosen from the shape of the schema alone would have made the warehouse expensive without making it fast. I moved the heaviest reports onto materialized views with dependent views built on them, refreshed incrementally once a day. Precomputed numbers that drift from their source would be worse than slow ones, so a validation script checks that the views and the source still agree. #### Result - Largest customer's report: **over 15 minutes → 0.2 seconds** - A second report: **4 minutes → 0.1 seconds** - **No customer had to rebuild a single saved report** - Daily refresh, validated against the source Below one second, customers explore the report instead of requesting it and waiting, and in practice that makes it a different product: they change a filter, compare a period and ask the next question in the same sitting. #### What I would do differently Daily refresh was right for this data, which arrives daily anyway. If someone asks for fresher numbers, though, the only way to provide them is to rebuild the refresh path. I would have built the rollup so the refresh interval could change without reworking it. ### Case study 14: Cutting an AWS bill from $24,000 to $2,000 a month - URL: https://www.microtech.consulting/work/aws-cost-reduction-eight-times - Domain: Data and infrastructure - Engagement: Full-stack engineer · national identity authority, West Africa · 2024 · 6 months · direct client - Published: 2026-09-11 - Stack: AWS, S3, Node.js - What could not change: The product kept doing the same work for the same users, and nothing was decommissioned. - Headline number: $24k → $2k A national identity authority's AWS bill was inflated by three different kinds of problem, and none of them raised an error. Nothing was decommissioned. #### Summary The first thing I did on the project was read the AWS bill, which came to $24,000 a month. Six months later the same system ran for $2,000 a month. Nothing was decommissioned, and the product served the same users doing the same work. The saving came from three separate problems: everything was over-provisioned, infinite loops were running, and uploads went through the backend. Each is a different kind of problem and is found a different way, so knowing which kind you have is more useful than the total. Flexera's 2026 survey of 753 organizations estimates that 29% of cloud spend is wasted, and 85% of those organizations name managing cloud spend as a top challenge. The waste on this project was far larger than 29%: the bill was about eight times what the workload needed. #### The constraint Nothing in the system was broken in a way anyone would notice. Cloud waste is hard to catch, and it persists, because it breaks nothing. A slow endpoint draws complaints and a failing job raises an alert, but an oversized instance, a runaway loop or a badly placed upload path keeps working normally, month after month, while you pay for it. Until someone sets up a budget alarm, the only way to find this kind of waste is to go and look at the bill on purpose. #### What I did **Over-provisioning.** I found the sizing problem by comparing provisioned capacity with observed use. Everything was over-provisioned, including the instances and the database. This is rarely negligence: someone sizes an environment at launch when nobody knows the load, picks generously, and correctly so. Then the load becomes known and nobody goes back to it, because nothing is wrong and something else is always more urgent. **Infinite loops.** I found the fault by looking for cost that didn't track traffic. Loops in the system were consuming compute continuously, and somebody had been paying for them month after month without knowing they existed. These were actual infinite loops, not a hot path or an inefficient query. Over-provisioning shows up as low utilization, while a runaway process shows up as high utilization that nobody can attribute to anything a user is doing. **Uploads routed through the backend.** I found the architectural cause by reading the code. Uploads went through the backend on their way to S3, when the client could have sent them there directly. Every photograph, whether of a face or of a document, arrived at the server, occupied its memory for the duration of the request and was then pushed onward. In this system every application is an upload, so the upload path was the main path through the product. Routing uploads through the backend tied instance memory to the number of concurrent uploads, sent every byte across the network twice, and capped throughput at what the application server could handle, although S3 is designed to absorb far more. No dashboard shows a cause like this one, which is why it tends to be found last, and it is usually the largest of the three. #### Result - **Monthly spend: $24,000 → $2,000** - Against what the workload actually needed, the bill was about eight times too large, and the final bill came in lower still, so the cut from $24,000 to $2,000 is twelvefold - Each of the three causes was found by a different method, and none of them raised an error #### What I'd do differently The bill should not have been the developer's discovery. Nobody was watching it and nothing alerted when it grew. A budget alarm costs nothing and would have caught the infinite loops in their first week rather than their fiftieth. ### Case study 15: Meeting records and file permissions, modeled as a graph - URL: https://www.microtech.consulting/work/permissions-as-a-graph - Domain: Business systems and integrations - Engagement: Full-stack engineer · 2023 · 8 months · via agency · team of 5 · the data model was my decision - Published: 2026-09-08 - Stack: Neo4j, WebRTC, AWS Transcribe, React, DocuSign - What could not change: Whether a person may open a document had to be answered instantly, however long the chain behind it. - Headline number: Sold In a white-label meeting platform for healthcare and finance, access to a file depends on a chain of links. The product was sold to an American bank. #### Summary The platform runs remote meetings and is built around what each meeting leaves behind: who attended, what was said, which documents were in play, who was allowed to see them and who signed. In a team of five, I chose the database, modeled the domain, and built file management, transcription, recording and post-processing. The product was sold to an American bank. #### The constraint In healthcare and finance, the video call is a commodity and customers pay for the record of the meeting, so the record is what the system has to guarantee. The hard question is whether a person may open a particular file, and the answer depends on a chain: they attended a meeting, the meeting is linked to a document, the document has versions, a version carries a signature, and permission can come either directly or through the meeting. A document can also belong to several meetings at once, so it cannot simply be filed under one of them. In a relational schema, every such permission check is a recursive join, which slows down with every new type of relationship and gets harder to maintain with every new rule. #### What we did **A graph data model in Neo4j.** I modeled people, meetings, files and signatures as nodes, and attendance, attachment and permissions as edges. There are four permissions: read, write, download and delete. A permission check becomes a traversal of the graph, which is the operation a graph database is built for. Google models access control as a graph too, for the same reason, so this is a recognized pattern. **Files added during the meeting.** A document can be uploaded in advance or attached while the meeting is running, and the moment it is attached it has to appear for everyone present, with the right permissions for each of them. The graph therefore changes live during the meeting, while people are watching. **Transcripts that feed the next meeting.** Transcription runs in real time with speakers separated, and the finished transcript goes into the agenda of the next meeting. **Whiteboard saved as objects.** Strokes, shapes and text are stored as separate elements with their own properties, not as a flat image, so the board can be reopened and edited after the meeting. **Guest access, because of HIPAA.** A patient should not have to create an account to attend a consultation, so meeting HIPAA meant building a feature: patients can join as guests. **A browser extension with one permission.** The extension is optional, is used for starting and reviewing meetings, and has no access to media at all. Extensions for meeting platforms tend to ask for broad permissions, such as tab capture, the microphone and access to every page. In a product sold into healthcare, broad permissions cause three problems: a harder review in the extension store, a warning at install, and a question in the customer's security review that has no good answer. #### Result - Permission checks answered by traversing the graph, however long the chain - Documents that belong to several meetings, with version history and signing - Real-time transcription with speakers separated, feeding the next meeting's agenda - Guest access that satisfies HIPAA - **Product sold to an American bank** #### What we would do differently Five of us built broadly for eight months, and no shared component layer ever emerged. The data model was the product's strength, but the front end ended up with three UI frameworks and four dropdown libraries in the same codebase. We would build the shared component library first, which is what I did on the next project. ### Case study 16: An ERP that plans crews by trade across several countries - URL: https://www.microtech.consulting/work/construction-erp-workforce-planning - Domain: Business systems and integrations - Engagement: Lead developer · 2025 · 6 months · direct client · team of 4, development ran through me - Published: 2026-09-08 - Stack: NestJS, Next.js, PostgreSQL, Turborepo, SAP - What could not change: SAP had to remain the system everything starts from, with the new ERP running alongside it. - Headline number: 150,000 We built it for a construction company in six months as a team of four. It tracks 150,000 items across 15 warehouses and runs alongside SAP. #### Summary A construction company with its own machinery and sites in several countries needed one system to replace its scattered records. As a team of four, we built ten modules from scratch in six months, and the system is in production and running without trouble. The inventory is what people see first, but the crew planning is the part no off-the-shelf product could provide. #### The constraint Standard ERP software knows how many workers you have and what they cost. It does not know that a site entering its next phase no longer needs excavator operators, or that the rebar workers it frees up are exactly what another site, in a different country, needs in ten days. The most expensive question in this business is which workers go to which site, and when. Get it wrong and you either pay people to stand idle or hold up a site because there is no carpenter. No off-the-shelf system answers that question, which is why the client had this one built. The client was also keeping SAP, so the new system had to run alongside it. #### What we did **Inventory down to the shelf.** The system tracks more than 150,000 items across 15 warehouses in several countries. For every item it records the warehouse, the rack and the shelf, so a stock check gives an answer like "we have 400, in the Sweden warehouse, rack 12, shelf 3", and someone can go straight there. **Three ways to enter stock.** Stock can be entered by barcode in the warehouse, from the purchase order at goods-in, or by hand for everything else, which matches how people work in each of those places. A system with only one way in gets worked around, and that is how inventory systems fail: the stock in the system stops matching the stock on the shelf. **Crew planning across sites.** Each site is a project in the system, which tracks who is on which site, who needs to move and which trades the site will need. A spreadsheet cannot plan people across time and across borders like this, and that planning is the main reason the client has the system. **Integration with SAP.** The integration carried customers, items, orders, invoices, stock and finance between the two systems, effectively the whole operational picture, not a monthly export. This is the hardest kind of integration, because both systems describe the same reality, and whenever they disagree, the person looking at one of them makes a wrong decision straight away. We also built invoicing, payments, a supplier ledger with accounting export, dashboards, notes and tasks. #### Result - **150,000+ items, 15 warehouses, located to the shelf** - Crew planning by trade, across sites and countries - SAP integration carrying the full operational picture - Ten modules in six months, built by a team of four - **In production and running without trouble**: a bad ERP is obvious straight away, because people start working around it #### What I'd do differently With ten modules to deliver in six months, the planning module got the same share of the schedule as invoicing. Invoicing is something any system does, and the planning module was the part nobody else could have supplied. Given that time again, I would spend less of it on the standard modules and more on the one that made the system worth building. ### Case study 17: HubSpot forms built to match the rest of the site - URL: https://www.microtech.consulting/work/hubspot-cms-custom-forms - Domain: Business systems and integrations - Engagement: Web engineer · 2023 · 6 months · Swedish SaaS in code analysis - Published: 2026-09-08 - Stack: HubSpot CMS, HubL, JavaScript, CSS - What could not change: The forms had to match the site's design without losing the tracking cookie that ties each submission to a visit. - Headline number: Zero deploys We moved a Swedish SaaS company's marketing site onto HubSpot CMS and built the custom forms it had been told were not possible, with tracking intact. #### Summary The client sells behavioral code analysis to engineering teams, so its website is its primary sales channel. We moved the existing site onto HubSpot CMS and rebuilt it from reusable modules. For the client, the main result is that the marketing team now changes headlines and copy, and adds fields, without a developer or a deploy. I was brought in specifically for the forms, after the client had been told they could not be built the way it wanted them. #### The constraint Adding a HubSpot form is easy until someone wants it to look like the rest of the site. HubSpot's embedded form comes with its own markup and styling, and deeper customization is limited and brittle. The alternative is to build the form yourself against the API. That gives you the design, but everything else becomes your job: validation, error states, hidden fields, conditional logic, bot protection, and the detail most people miss, passing the tracking cookie with every submission. Without the tracking cookie the form still works, but it is worthless to marketing, because no submission can be attributed to the visit that produced it. #### What I did I built the pages as HubL templates and modules, with a library of reusable blocks that every page is assembled from. Building each page from scratch would have turned a migration of dozens of pages into dozens of one-off templates that nobody could maintain afterward. I set up the fields so the marketing team edits content directly: headlines, descriptions and new fields. On a B2B site where messaging is tested constantly and campaigns launch on their own schedule, whether a change takes two minutes or needs a ticket and a wait sets the pace for the whole marketing team. I built the purchase and contact forms fully custom against the HubSpot API, with the tracking cookie passed on every submission, so attribution still works. #### Result - Existing site migrated to HubSpot CMS, **in production since 2023** - The marketing team edits content without a developer or a deploy - Custom-designed purchase and contact forms, with tracking preserved #### What I would do differently The custom forms solved the design problem and created a maintenance one: every future change in how the CRM expects submissions is now our problem rather than the platform's. If I did it again, I would write that trade-off down for the client and hand it over with the forms. ### Case study 18: Payment integrations where Stripe was not always an option - URL: https://www.microtech.consulting/work/payment-gateways-four-markets - Domain: Business systems and integrations - Engagement: Five engagements · 2020–2025 · Europe, the Balkans, West Africa, global - Published: 2026-09-11 - Stack: Stripe, PayPal, Apple Pay, Google Pay, national gateways, Node.js - What could not change: The law or a license decided which payment partner a product had to use. - Headline number: 4 markets I built payment integrations for five products in Europe, the Balkans, West Africa and worldwide. For two of them, regulation chose the payment partner. #### Summary Across five products I integrated Stripe, PayPal, Apple Pay and Google Pay, a national government payment gateway in West Africa and a domestic gateway in Bosnia and Herzegovina. The technical work varies less from one product to the next than you would expect. The bigger difference is that the choice of provider usually isn't yours, and that can decide whether a product launches at all. #### The constraint In a Western SaaS product, choosing a payment provider means comparing fees, developer experience and features. In other markets there is often nothing to choose. A government fee in Nigeria is collected through the system the state recognizes, because the law says where that money must arrive. A cross-border remittance product runs on a licensed partner, because without the license there is no product. In neither case does a better developer experience come into the decision. A practical consequence that people underestimate is that the integration you end up building is often the one with the least documentation, the smallest community and no answers on Stack Overflow. #### What I did **Government fee collection through a national gateway.** PayPal ran alongside it for applicants outside the country, since a passport system also serves people abroad. Both payment options feed into the same flow. **Cross-border remittances through a licensed partner.** The partner verified the payer's identity through card and bank checks, and our system verified the payment instruments: SWIFT, IBAN and card networks. This split is the usual one and the correct one, because a payer's identity is proven by the instrument they pay with, and the bank that issued it has already done that check. **Marketplace subscriptions and consumer payments.** I built these on Stripe, PayPal, Apple Pay and Google Pay, including recurring charges with separate handling for a successful charge, a failed one and an upcoming one. #### Result - Payment integrations in production in four markets - Two of them use partners chosen by regulation #### What I'd do differently I built each integration where it was needed, around the shape of that one product. By the third one it was clear that the same concerns kept coming back: idempotency, retries, reconciliation and webhook verification. I never turned them into anything reusable. It would have helped, but each project ended before the pattern was clear enough for me to act on. ## Services in full ### Web development #### Full-stack web development - URL: https://www.microtech.consulting/services/full-stack-web-development - Stack: TypeScript, React, Next.js, Node.js, NestJS, PostgreSQL, Redis, AWS Full-stack developers for a product that is already live. We join your team, and one developer builds each feature from the database to the page. Our longest engagement on a live product lasted four years. **Who it is for.** A company that knows what it is building and needs senior developers who work on both the frontend and the backend. Usually the product is already live with its own team, and it has to keep running while we change it. **What we have built:** - A marketplace codebase shared by five kinds of user, with permissions set by type and role. The API repeats every check the interface makes. (case study 08: https://www.microtech.consulting/work/multi-persona-single-codebase) - An ERP that runs alongside SAP for a construction company: 150,000 items in 15 warehouses, and crews planned by trade across several countries. (case study 16: https://www.microtech.consulting/work/construction-erp-workforce-planning) - An analytics layer that takes two million writes a day, updates the customer’s dashboard live and returns a year of history in under a second. (case study 05: https://www.microtech.consulting/work/analytics-two-million-writes-per-day) - A live marketplace moved from PHP to Node.js with no outage. Lighthouse rose from 60 to above 90 once its public site moved to Next.js. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) **Questions and answers:** - Q: Can you join an existing codebase and team? A: Yes, and that is the usual case. Most of the time we are taking a feature from the database to the screen in code someone else wrote. Our longest engagement began by taking over a product that was already running, and it lasted four years. - Q: Can you bring more people? A: Yes. Additional developers join your team full-time, as described on the dedicated developer page. - Q: Who decides the architecture? A: You do. We set out three options, each with its price and what would have to be true in two years for it to pay off, and explain which one we recommend and why. #### Multi-tenant and white-label SaaS - URL: https://www.microtech.consulting/services/multi-tenant-saas - Stack: PostgreSQL (row-level security), Prisma, NestJS, Next.js, design tokens per brand Multi-tenant SaaS that keeps each customer’s data apart. For SaaS sold to many businesses or under many brands, the database or data layer keeps customers apart. A design system we built serves more than 30 brands. **Who it is for.** SaaS companies that sell one product to many businesses, or sell it under many brands, from a single codebase. **What we have built:** - A white-label meeting platform for healthcare and finance. Whether someone may open a file depends on a chain of relationships: the meetings they attended, the documents linked to those meetings, and the versions and signatures of each document. (case study 15: https://www.microtech.consulting/work/permissions-as-a-graph) - A design system of about a hundred components serving more than thirty white-label brands, each brand a set of token values. Three years later the same client came back to have their Android app rescued. (case study 02: https://www.microtech.consulting/work/design-tokens-thirty-white-labels) - On a truck-services marketplace, one codebase served five kinds of user: service vendors, fleet carriers, owner operators, company drivers and call center staff. A permission combines type and role, so a vendor’s operator and a fleet carrier’s operator have different rights. (case study 08: https://www.microtech.consulting/work/multi-persona-single-codebase) Two multi-tenant products of our own are in development. In one, the database enforces isolation, and the build fails if a table is added without an access policy. In the other, a query that runs without a tenant context returns nothing. **Questions and answers:** - Q: Should isolation be enforced in the database or in the code? A: It depends on who writes the queries. When many people and tools write them, row-level security in the database is worth its cost, because none of them can forget it. With one small team and a single access path, enforcing it in code can be enough. We explain the reason for whichever we choose. - Q: Do you take the tenant from the domain or from the token? A: From both, for different jobs. The domain decides whose content is shown, and everything behind the login goes through the token, because a domain doesn’t prove who someone is. - Q: How is a new brand added? A: With a set of token values and a domain. There is no new code path and no fork of the component library. - Q: Can one customer’s data ever reach another? A: Preventing that is the point of the design. Isolation doesn’t depend on every query carrying the right filter, and a query with no tenant context gets no rows back. #### Marketplace and logistics platforms - URL: https://www.microtech.consulting/services/marketplace-platforms - Stack: React, Redux, Next.js, Node.js, Express, MySQL, InfluxDB, AWS Lambda, SQS Every kind of user in one marketplace codebase. If each new type of user has meant another app, we give each its own screens and permissions. On a US truck-services marketplace, five types share one codebase. **Who it is for.** A marketplace or directory where people on different sides do different jobs: some sell, some buy, and some act on behalf of others. Often it is already running, and each new type of user has so far meant another app or another pile of conditions in the code. **What we have built:** - A US marketplace for truck services, where each user type has its own routes and what a user may do depends on both their type and their role. The 506 API routes are split into two separate sets, public and admin. (case study 08: https://www.microtech.consulting/work/multi-persona-single-codebase) - Six daily jobs handle renewal, downgrades, dunning and re-engagement for the marketplace’s annual advertising, and apply the same rules to every account. (case study 07: https://www.microtech.consulting/work/scheduled-jobs-as-revenue-logic) - Around 180 event types that track what an advertiser pays for, from the position where a listing appeared to the phone call it brought in. (case study 06: https://www.microtech.consulting/work/product-analytics-event-taxonomy) - Through four years and four phases of work, the same marketplace never went offline. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) Subscriptions and consumer payments on that marketplace went through Stripe, PayPal, Apple Pay and Google Pay. A successful, a failed and an upcoming charge each sent the customer a different message. **Questions and answers:** - Q: Should each user type get its own app? A: We keep one codebase and give each user type its own set of routes. Separate apps look tidier for about six months. After that, every shared change has to be made five times, and sooner or later one copy gets missed. - Q: Is hiding a screen enough to protect it? A: No. Hiding a route in the client only organizes the interface, and anyone who calls the API directly goes around it. That is why the API checks every request on its own. - Q: Can a call center act for other users? A: Yes. On the truck-services marketplace the call center was a user type of its own, with its own roles, and its operators worked on behalf of other users. #### SEO and programmatic pages - URL: https://www.microtech.consulting/services/seo-programmatic-pages - Stack: Next.js, React, server rendering, static prerendering, Node.js, OpenSearch Turning your data into pages search engines read in full. Server-rendered Next.js pages built from your records, for directories and catalogs that depend on search. One marketplace’s SEO score rose from 30 to above 90. **Who it is for.** Products that depend on search, such as directories, marketplaces and catalogs. Their pages are built from data, and a crawler has to receive each page as complete as a browser does. **What we have built:** - A US marketplace that depends on organic search moved its public site to Next.js with no downtime, and its SEO score rose from 30 to above 90. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) - When a listing is downgraded for non-payment, it is re-indexed straight away, so search results match what the advertiser pays for. (case study 07: https://www.microtech.consulting/work/scheduled-jobs-as-revenue-logic) - On our own site the language is part of the route, so each language is prerendered as static HTML of about 152 KB. In the original version, a crawler only ever saw English. (article: https://www.microtech.consulting/blog/a-real-page-is-a-better-test-than-a-component) **Questions and answers:** - Q: Server-rendered or client-rendered? A: Server-rendered, or prerendered as static HTML where the data allows it. A crawler should get the whole page in its first response. - Q: Will you promise rankings? A: No. We control what a crawler receives: complete HTML, one URL per language and a clean heading hierarchy. Rankings depend on far more than the code. - Q: Can you do this on a site that’s already live? A: Yes. A US marketplace we worked on raised its SEO score on its old PHP code, before anything was rewritten. #### Web performance - URL: https://www.microtech.consulting/services/web-performance - Format: a fixed-price written assessment Does your slow site really need a rewrite? If a slow website’s only proposed fix is a rewrite, we measure its speed and list the fixes that work without one. On one marketplace, the twenty slowest queries got 90% faster before any rewrite. **Sound familiar?** - Lighthouse performance sits around 60, and no one can say what is holding it down - The only proposal on the table is to rewrite everything - Images and mail are handled by the same server that renders the pages - A few pages are slow because of database queries that have never been looked at - Your customers find you through search, and the site is the product **What you get.** The document sets out: - What makes the pages slow, split by cause: the server, the database, the assets or the frontend. Each one is found and fixed in a different way. - The slowest queries, one by one, with what an index or another change would gain. - Everything that can be fixed without a rewrite, ordered by what it gains against what it costs. - What a rewrite would give you that these fixes would not, which is usually less than it seems. **Where we have done this before:** - A US marketplace on shared hosting that could not scale. In the first two months, without rewriting its PHP, we made its twenty slowest queries 90% faster. Lighthouse performance went from 60 to above 90, and SEO from 30 to above 90, after its public site moved to Next.js. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) - A sales report in a BI tool went from over fifteen minutes to 0.2 seconds, without changing a single query or column. (case study 13: https://www.microtech.consulting/work/query-optimization-under-fixed-schema) - Sending uploads straight to storage instead of through the backend allowed smaller instances and made uploads faster. It was one of three changes that took a monthly bill from $24,000 to $2,000. (article: https://www.microtech.consulting/blog/direct-s3-upload-instead-of-through-your-backend) **Questions and answers:** - Q: How long does the assessment take? A: We set the date after seeing how much there is to read, and it is written into the offer before we start. - Q: Do we have to rewrite the site? A: Not always. On the marketplace in our case study, the twenty slowest queries got 90% faster on the code it already had. Lighthouse went from 60 to above 90 later, with the move to Next.js. We measure first, then tell you which fixes need a rewrite and which don’t. - Q: Can you make the fixes as well? A: Yes, as separate work. Once the document shows what is needed, we make the fixes and bill them by the hour. - Q: What access do you need? A: Access to the repository, and read access to hosting and monitoring. We don’t need production data. #### Admin dashboards and internal tools - URL: https://www.microtech.consulting/services/admin-dashboards-internal-tools - Stack: React, Next.js, NestJS, Node.js, PostgreSQL, MySQL, Turborepo, SAP integration Admin panels built around how your staff work all day. Back-office tools in React and Next.js for staff who spend the day in one system. On a construction ERP, staff find any of 150,000+ items down to the shelf. **Who it is for.** A company whose staff spend the day in one system: stock, crews, listings, invoices. Often it has to run alongside an existing system that isn’t going away, and the data in both has to match. **What we have built:** - A construction company’s ERP, where warehouse staff find any of more than 150,000 items spread over 15 warehouses down to the shelf, and planners assign crews by trade to sites in several countries. We built its ten modules in six months. (case study 16: https://www.microtech.consulting/work/construction-erp-workforce-planning) - A live dashboard for advertisers on a US platform for truck services. For accounts with more than 900 listings, a full year of history loads in under a second. (case study 05: https://www.microtech.consulting/work/analytics-two-million-writes-per-day) - On the same platform, a separate CRM for the company’s own staff. It talks only to the admin set of API routes, which is kept apart from the routes customers use. (case study 08: https://www.microtech.consulting/work/multi-persona-single-codebase) - Six jobs that run on their own every day to handle renewals, downgrades, recurring charges and re-engagement. Their emails come from 55 templates and go out through one sending service. (case study 07: https://www.microtech.consulting/work/scheduled-jobs-as-revenue-logic) On the ERP, stock can be entered in three ways: by barcode in the warehouse, from the purchase order at goods-in, and by hand for everything else. With only one way in, people would start working around the system, and the stock on screen would stop matching the stock on the shelf. **Questions and answers:** - Q: Should we build the tool or buy one? A: Usually some of both. We would buy what every system of its kind already does and build only the part no vendor sells. On the construction ERP, that part was planning crews by trade across sites and countries. - Q: We already run SAP. Does it stay? A: It can. The ERP we built runs alongside SAP and keeps customers, items, orders, invoices, stock and finance in sync between the two. - Q: Can a dashboard be live and still fast? A: Yes, as long as one database isn’t asked to do every job. On the advertiser dashboard, raw events go to one store and a daily summary per listing to another, and the yearly report reads only the summaries. #### HubSpot CMS development - URL: https://www.microtech.consulting/services/hubspot-cms-development - Stack: HubSpot CMS, HubL, HubSpot API, JavaScript, CSS HubSpot pages marketing can change without a developer. B2B companies on HubSpot get modules and custom forms, and marketing edits pages without a deploy. A Swedish SaaS company’s site has run on them since 2023. **Who it is for.** A B2B company that sells through its website and runs it on HubSpot, or is moving it there. Marketing wants to publish on its own schedule without waiting for a developer to deploy. **What we have built:** - The marketing site of a Swedish SaaS company, moved onto HubSpot CMS and rebuilt as a library of reusable modules. It has been in production since 2023. (case study 17: https://www.microtech.consulting/work/hubspot-cms-custom-forms) **Questions and answers:** - Q: Can a HubSpot form look like the rest of the site? A: Yes, if we build it on the HubSpot API instead of embedding HubSpot’s form. The embedded form brings its own markup and styling. When we build the form ourselves, we also write the validation, error states, hidden fields, conditional logic and bot protection that the embedded form would otherwise handle. - Q: Will marketing still get attribution? A: Yes. The tracking cookie goes with every submission. If it were left out, the form would still work, but none of the submissions could be matched to the visit behind it. - Q: Can marketing change pages without us? A: Yes. Changing a headline, a paragraph or a form field is a content edit in HubSpot, so it needs neither a ticket nor a deploy. - Q: Is a custom form always the right call? A: No. It gives you the design you want and adds code that someone has to maintain. When the embedded form is close enough to what you want, we recommend keeping it. #### React SPA architecture - URL: https://www.microtech.consulting/services/react-spa-architecture - Stack: React, TypeScript, Vite, Redux, styled-components, pnpm workspaces, ESLint rules of our own One way to fetch data and refresh sessions in your React SPA. If each feature in your SPA fetches data and handles sessions its own way, we give each concern its own layer, and build checks keep features on those layers. **Who it is for.** A team whose React single-page app grew one feature at a time, until each feature fetched data, cached it and dealt with an expired session in its own way. **What we have built:** - Our own design system has three targets: a Vite SPA, Next.js and React Native. The call that renders the login screen is the same, byte for byte, in all of them. (case study 01: https://www.microtech.consulting/work/cross-platform-design-system) - React and Redux dashboards for five kinds of user on a US marketplace. Each user type got its own branch of the router, /dashboard/{user_type}/{page}, so role checks didn’t spread through the components. (case study 08: https://www.microtech.consulting/work/multi-persona-single-codebase) - On the same marketplace, build rules made every API call declare its request and response types and kept each component at 200 lines or fewer. (case study 03: https://www.microtech.consulting/work/ai-assisted-engineering-standards) No client paid for the design system; we built it as our own product. It shows where we put the boundaries between layers in an SPA. **Questions and answers:** - Q: Do you rewrite our SPA? A: No. We start with a list of where each feature fetches data, caches it and handles an expired session today. Then we move those pieces into one layer, one at a time. - Q: What does a rule in the build look like? A: It is a team convention written as code. The same rule is a warning in the editor and an error in the pre-commit hook and in CI, so it is present at every stage but blocks you only where stopping is cheap. - Q: SPA or server rendering? A: It depends on the product. Our own design system runs both ways, as a Vite SPA and server-rendered in Next.js, with the same component calls. #### SaaS MVP - URL: https://www.microtech.consulting/services/saas-mvp - Stack: TypeScript, Next.js, React, NestJS, PostgreSQL, Stripe From a specification to a first version you keep building on. For founders with a specification and no product yet: a small first version in React and Node.js. We built a ten-module ERP from scratch in six months. **Who it is for.** A founder or company with a specification and no product yet, who wants a small first version they can keep building on. **What we have built:** - A complete ERP built from scratch in six months. All ten modules are in production and running without trouble. (case study 16: https://www.microtech.consulting/work/construction-erp-workforce-planning) - Our design system, with 74 components and 678 tests. This site runs on it, and so does a financial platform of our own. (case study 01: https://www.microtech.consulting/work/cross-platform-design-system) - We built recurring billing on Stripe, PayPal, Apple Pay and Google Pay, with separate handling for a charge that succeeds, one that fails and one still to come. (case study 18: https://www.microtech.consulting/work/payment-gateways-four-markets) Our own products are still in development and have no external users. **Questions and answers:** - Q: Can you build it for a fixed price? A: No. The scope of an MVP moves by design, so a fixed price would rest on a guess that one side ends up paying for. We bill development by the hour; only a written assessment has a fixed price. - Q: Can the first version cover web and mobile? A: Yes, from one design system. Our own marketing page runs on a phone as well, and 91% of what appears there is web code used without changes. - Q: What happens after the first version? A: Development continues in the same codebase. Nothing in it was written to be thrown away. #### Accessibility - URL: https://www.microtech.consulting/services/accessibility - Stack: React, React Native, TypeScript, ARIA, custom verification rules, ESLint Accessibility fixes, kept in place by checks in the build. We fix names, focus and semantics in React and React Native, then add build checks. Our own review found 9 of 75 components with labels screen readers skipped. **Who it is for.** A team with a component library or product where someone worked on accessibility once, and nobody knows whether that work still holds. **What we have built:** - We reviewed all 75 components our design system had at the time. Nine had a label no screen reader would announce, because the label sat on a node with no role. The build now rejects any label without a role. (article: https://www.microtech.consulting/blog/three-bug-classes-your-tools-cannot-see) - We rebuilt our marketing page in the same system and checked it in a headless browser: 29 links with correct accessible names and a clean heading hierarchy. (article: https://www.microtech.consulting/blog/a-real-page-is-a-better-test-than-a-component) All three examples come from our own design system rather than a client audit, and its aria-label and tabindex coverage is still incomplete. **Questions and answers:** - Q: Do you certify compliance? A: No. We fix names, roles, focus and semantics in your code and add the checks that keep them fixed. We don’t issue compliance certificates. - Q: Why don’t our tools catch this? A: Because the code is valid. An aria-label on a bare div is spelled correctly and has the right type, so TypeScript and ESLint accept it, yet the ARIA specification says it is ignored. - Q: Can this be added to an existing library? A: Yes. We look for a component in your library that already gets it right, then search for the places that break the same pattern. In our design system, Icon always paired its label with a role, so a search of the code found all nine broken components. ### Mobile #### Hardware integration in React Native - URL: https://www.microtech.consulting/services/react-native-hardware-integration - Stack: React Native, Kotlin, Java, Turbo Modules, NFC, thermal printing Passport chips and POS terminals in your React Native app. When a chip reader or terminal has no React Native library, we write the native module ourselves. Our React Native app runs on more than 100 POS terminals. **Who it is for.** An app that has to read a chip or work with a terminal or another device for which no ready-made React Native package exists. **What we have built:** - Reading the NFC chip in German passports and ID cards during remote identity verification for a German financial institution, 2020. (case study 10: https://www.microtech.consulting/work/liveness-detection-person-and-document) - POS terminals running Android for cross-border remittances, 2022. The card, printer and other hardware functions reach React Native through a Turbo Module, and a Kotlin launcher locks each device to a single app. (case study 12: https://www.microtech.consulting/work/react-native-hardware-native-modules) - A coupon printed on a POS terminal’s thermal printer at a filling station. It cannot be cashed until the system recognizes it. (case study 11: https://www.microtech.consulting/work/immutable-issued-documents) **Questions and answers:** - Q: What if the manufacturer has no React Native SDK? A: Most don’t. In 2020 there was no usable library for reading a passport chip, and the payment terminal in 2022 had none worth using either, so both times we wrote the native module ourselves. - Q: Do you support both iOS and Android? A: Yes. For the passport reader we implemented the chip protocol in Java for Android and ported the same logic to Swift for iOS, so both apps read the chip the same way. - Q: Can you work with a device we already have? A: Yes, most projects start that way. Send us the model and whatever documentation you have, or tell us there is none. - Q: What if the documentation is poor, or in another language? A: Then working through it is part of the job. The POS terminal in the remittance project, a Chinese device, came with sparse SDK documentation in Spanish, which we translated so that we could work with the device at all. - Q: Do we have to leave Expo? A: No. A native module needs a development build, which Expo supports, so you keep the Expo workflow. What you give up is Expo Go for that app. #### React Native development - URL: https://www.microtech.consulting/services/react-native-development - Stack: React Native, Expo, TypeScript, Native modules, Tokens and logic shared with web One React Native codebase for your iOS and Android apps. For companies with a web app that now need a mobile one, we share tokens, components and logic with the web. Our own port reused 91% of what the phone draws. **Who it is for.** A company that has a web app and now needs a mobile one, or whose mobile app has to work without a network or talk to hardware. **What we have built:** - The web app, the mobile app and the API for remote identity verification at a German financial institution, with one computer-vision layer running on both web and mobile. (case study 10: https://www.microtech.consulting/work/liveness-detection-person-and-document) - An app for passport applications, built with Expo and published on Google Play, used by agents who work in villages with no signal. (case study 09: https://www.microtech.consulting/work/offline-first-sensitive-data-capture) - Our own design system runs on three platforms. When our marketing page was ported to a phone, 91% of the code the phone runs came from the web unchanged. (case study 01: https://www.microtech.consulting/work/cross-platform-design-system) - An Android app that could no longer be installed on current phones. We got it running on both current and older devices for a client who came back three years after the first engagement. (case study 02: https://www.microtech.consulting/work/design-tokens-thirty-white-labels) **Questions and answers:** - Q: How much code can we share with the web? A: That depends on your code, so we measure it on one real screen before we quote. In our own port, the measurement also showed that everything specific to the browser was in one file, and we found and listed it before the port began. - Q: What if the app has to work with hardware? A: That is a separate service, hardware integration in React Native. It covers passport chips, payment terminals and other devices. - Q: Can you take over mobile apps that people already use? A: Yes. The US marketplace we took over already had mobile apps in use, and during the rebuild we moved them to Expo. A mobile user updates whenever they like, so the old backend kept running until analytics showed that its last user had left. That engagement lasted four years, our longest. #### Offline-first apps - URL: https://www.microtech.consulting/services/offline-first-apps - Stack: React Native, Expo, secure on-device storage, remote wipe, Kotlin, PostgreSQL, AWS Mobile apps for field work where there is no signal. Field staff capture sensitive data with no signal, and the app sends it once a connection returns. A passport app built this way runs in West Africa. **Who it is for.** An organization whose people work in the field, at counters or in villages, without a reliable connection. The data is usually sensitive, and the devices don’t always stay in the office. **What we have built:** - Passport and ID card applications, with photographs and biometrics, captured on company phones where there is no signal and uploaded once there is. Built for a national identity authority in West Africa and in production. (case study 09: https://www.microtech.consulting/work/offline-first-sensitive-data-capture) - Remittance terminals that keep printing coupons without a network. A coupon becomes valid only when the system confirms it, either automatically once the connection returns or through an operator. (case study 11: https://www.microtech.consulting/work/immutable-issued-documents) - More than a hundred terminals updated over the network. When an update failed, nothing changed: the terminal kept working and tried again every five minutes. (case study 12: https://www.microtech.consulting/work/react-native-hardware-native-modules) **Questions and answers:** - Q: What if a phone is lost with data on it? A: The phones belong to the organization and can be wiped remotely, which is what makes it acceptable to keep the data on them. With personal phones the same design would not have passed, and stronger encryption would not have changed that. - Q: How do you avoid sync conflicts? A: We keep the offline period short. On the identity project, agents returned their phones to the office at the end of each day, so the app never had to reconcile more than one day of work and there were no merge conflicts to resolve. - Q: What if a phone doesn’t come back for a week? A: Then the app needs a defined behavior for that case. We did not test it on the identity project, and looking back we would have added a hard expiry on unsynced data from the start. It would have cost an afternoon. - Q: Can an offline device take payments? A: It can record them, but they count only once the system confirms them. On the remittance terminals, a coupon printed offline could not be cashed until then, because a coupon paid out twice was the one failure that cost real money. #### Web to mobile port - URL: https://www.microtech.consulting/services/web-to-mobile-port - Stack: React Native, Expo, Next.js, Vite, TypeScript, shared design tokens Your web app on iOS and Android, reusing the code you have. We port one real screen first, count how much of your web code runs on a phone, then quote. In our own port, 102 of 1,077 lines were written for mobile. **Who it is for.** A company with a working web app and a mobile app on its roadmap, which does not yet know how much of the web code will actually run on a phone. **What we have built:** - Our own marketing page, ported to a phone and run in Expo Go. Of the 1,077 lines that run on the device, 102 were written for mobile, and no section of the page was rewritten. (article: https://www.microtech.consulting/blog/a-real-page-is-a-better-test-than-a-component) - Our design system’s login screen calls its components with byte-identical code in all three of its apps: Next.js, a Vite SPA and React Native. Only the wrapper around it differs per platform. (case study 01: https://www.microtech.consulting/work/cross-platform-design-system) - On a US marketplace, the dashboards and the mobile app draw on more than 200 shared components in one monorepo. Only side effects differ between the platforms. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) **Questions and answers:** - Q: How much of our code will carry over? A: You get a figure once the first screen is ported. On our own marketing page, 91% of what the phone draws was reused unchanged. An earlier estimate said 62%, because it classified the code of the entire site before anything ran on a device. Both figures are correct, since they divide by different totals. - Q: Do screens have to be rewritten for mobile? A: In our own port, none were. All the web-only code came down to four elements in one layout file, which a 55-line native counterpart replaced. The first screen we port for you shows whether your web-only code sits in one place like that or is spread across the app. - Q: What doesn’t carry over? A: The app shell: routing, sticky bars, skip links, page landmarks, and links for mail and phone. In our port that came to 102 lines. - Q: Will our tests catch what breaks on the phone? A: Not all of it. In our port, a native test passed for a screen that could not open, and a phone showed within seconds a crash that the compiler, the tests and the production export had all let through. That is why we also check on a real device. ### Backend, data and integrations #### API and backend development - URL: https://www.microtech.consulting/services/api-backend-development - Stack: Node.js, NestJS, Express, TypeScript, PostgreSQL, MySQL, Redis, SQS, AWS APIs your apps can rely on while the backend changes. Every call has a typed request and response, and permissions are checked on the server. One US marketplace API we built has 506 routes in public and admin sets. **Who it is for.** Your frontend, mobile app or partners depend on an API that has to stay predictable, and that API often has to grow, or be replaced, while it is live. **What we have built:** - 506 API routes for a US marketplace with five kinds of user, kept in two separate sets for public and admin use. The API checks permissions itself and leaves none of that to the interface. (case study 08: https://www.microtech.consulting/work/multi-persona-single-codebase) - A backend with 100 data models and 194 migrations, moved from PHP to Node.js and later to a typed framework while the product stayed live, with zero outages. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) - A permission model stored as a graph, so a question like “may this person open this file?” is answered by traversing it, however long the chain of links behind the answer. (case study 15: https://www.microtech.consulting/work/permissions-as-a-graph) - Calls from our backend to a national registry in West Africa, protected by keys, digest authentication, single-use tokens and an IP allow-list. A stolen key on its own opens nothing. (case study 09: https://www.microtech.consulting/work/offline-first-sensitive-data-capture) We also built a NestJS ERP that runs next to SAP and exchanges customer, item, order, invoice, stock and finance data with it. **Questions and answers:** - Q: Can the API change without breaking the mobile apps already installed? A: Yes, and that is usually the hardest part. When we replaced the marketplace backend, the old one kept running beside the new one, synced in both directions, until measurements showed that the last old app had stopped calling it. - Q: How is the API documented? A: Mainly in the code. The build enforces the request and response types, so the documented contract and what the service actually does can’t drift apart unnoticed. - Q: One service or many? A: As few as the work allows, with the code they share kept in a shared package. That package should exist by the fifth service, and the marketplace still had none after the fifteenth. It grew to nineteen repositories, and the same queue helper ended up copied into seven of them. - Q: Can a new backend run alongside a system we are keeping, such as SAP? A: Yes. The ERP mentioned above runs next to SAP. Most of the effort goes into making both systems show the same customers, orders and stock, because people act on whichever screen they have open. #### Payment integrations - URL: https://www.microtech.consulting/services/payment-integrations - Stack: Stripe, PayPal, Apple Pay, Google Pay, national gateways, webhooks, Node.js Taking payments in markets where Stripe isn’t available. Where Stripe works we use it, and elsewhere we integrate the gateway your market or regulator requires. We have done this for five products in four markets. **Who it is for.** Companies that have to take payments in a market the usual tutorials don’t cover, or where a regulator or a license decides which payment partner they can use. **What we have built:** - Passport and ID card fees paid through a national government gateway in West Africa, with PayPal for applicants who live abroad. Both ways of paying lead into the same application flow. (case study 18: https://www.microtech.consulting/work/payment-gateways-four-markets) - Recurring charges for a marketplace’s advertisers through Stripe, PayPal, Apple Pay and Google Pay. A successful charge, a failed one and an upcoming one each send the customer a different message. (case study 07: https://www.microtech.consulting/work/scheduled-jobs-as-revenue-logic) - Coupons for collecting a remittance, printed at a terminal even when it has no network. A coupon becomes valid only when the system confirms it, so none can be paid out twice. (case study 11: https://www.microtech.consulting/work/immutable-issued-documents) We have also integrated a domestic payment gateway in Bosnia and Herzegovina. **Questions and answers:** - Q: Stripe isn’t available in our market. What now? A: Then we integrate the partner your market recognizes. We have done this with a national government gateway in West Africa and with a domestic gateway in the Balkans. - Q: The local gateway has almost no documentation. A: That is common. The gateway a market requires is often the one with the least documentation and the smallest community around it, and we integrate it all the same. - Q: What happens when a recurring charge fails? A: The customer gets a message written for that case, because someone whose payment failed probably still wants the service. - Q: Who checks the identity of the payer? A: On the remittance product the licensed partner did, through card and bank checks, while our system verified the payment instruments. That split is the usual one, and it is correct: the bank that issued the card or holds the account has already confirmed who owns it. #### Scheduled jobs and billing logic - URL: https://www.microtech.consulting/services/scheduled-jobs-billing-logic - Stack: Node.js, AWS Lambda, SQS, MySQL, Handlebars, object storage for templates Renewals and reminders that run without anyone remembering. Subscription and listings businesses get scheduled jobs that treat every account by the same rules. A US marketplace ran six of them every day. **Who it is for.** A subscription or listings business where revenue comes in on a renewal date that is different for each customer, and where thousands of expiry dates are too many for anyone to watch by hand. **What we have built:** - Six daily jobs on a US marketplace for truck services. They sent reminders before expiry, downgraded listings after non-payment, processed recurring charges, followed up on unverified listings, ran a re-engagement campaign and warned fleet operators about upcoming vehicle inspections. (case study 07: https://www.microtech.consulting/work/scheduled-jobs-as-revenue-logic) - Over-the-network updates for payment terminals that retried every five minutes until they succeeded, while the terminal kept working normally. (case study 12: https://www.microtech.consulting/work/react-native-hardware-native-modules) **Questions and answers:** - Q: Why not handle renewals by hand? A: By hand, the policy reaches some accounts and misses others, which is worse than not having it at all. In code every account is treated the same way, and nobody has to decide to apply it. - Q: How do you stop staging from emailing real customers? A: Outside production, the single sending service redirects all mail to a test address, so staging has no route to a real customer’s inbox. - Q: Email or in-app? A: We choose per job. Someone who stopped halfway through creating a listing gets the reminder in the app, at the point where they left off. - Q: When should re-engagement run? A: When the data shows that an owner has stopped paying attention. For the marketplace’s annual listings that meant a three-step campaign at roughly 179, 182 and 186 days after a listing’s last update, about half a year before renewal. #### Product analytics and event tracking - URL: https://www.microtech.consulting/services/product-analytics-event-tracking - Stack: Node.js, InfluxDB, MySQL, WebSockets, AWS Event tracking built around what your customers pay for. Products sold on leads, calls or visibility get events that show customers what they paid for. One US marketplace tracks about 180 event types. **Who it is for.** Products sold on results, visibility, leads or calls, whose customers ask at renewal what they got for the money. Pageviews and bounce rates can’t answer that question. **What we have built:** - Around 180 event types on an advertising marketplace in the US, covering each step from the position an advertiser paid for to the phone call it produced. (case study 06: https://www.microtech.consulting/work/product-analytics-event-taxonomy) - Total and unique views stored separately, and bot traffic filtered at three layers: the firewall, known addresses and the user agent. An inflated count costs you the customer’s trust. (case study 05: https://www.microtech.consulting/work/analytics-two-million-writes-per-day) **Questions and answers:** - Q: Isn’t 180 event types too many? A: No. Together they map how the business makes money: position, impression, interest, intent and contact, with the sales funnel alongside. - Q: Why not use general web analytics? A: General web analytics measures traffic to the site as a whole. It can’t tell one of your customers what they received, and it can’t show that figure in their account next to their renewal. - Q: Totals or uniques? A: Both, kept apart. Totals are the bigger number, and uniques tell a customer how many different people saw them. A unique view is counted per session and page, so a person who searched in two cities is counted twice, since they were looking for two different things. - Q: What gets recorded at the moment it happens? A: Anything you sell. A premium listing is sold as better placement, so its position is recorded the moment the listing appears instead of being worked out afterwards. #### High-write data systems - URL: https://www.microtech.consulting/services/high-write-data-systems - Stack: InfluxDB, MySQL, S3, Node.js, WebSockets, AWS Live dashboards and a year of history in under a second. Your customers see their numbers live and for a whole year. A time-series analytics layer we built takes 2M writes a day and returns a year in under a second. **Who it is for.** A product that records a lot of events, readings, clicks or views, and whose customers want to see their own numbers live and over a whole year. **What we have built:** - Over two million writes a day go into a time-series store with a deliberately small index, and each advertiser reads the results live in their dashboard. (case study 05: https://www.microtech.consulting/work/analytics-two-million-writes-per-day) - Self-hosting the time-series database saved about $27,000 a year by our estimate. A later retention change cut the data from two terabytes to under one gigabyte, and self-hosting was still cheaper. By then the deciding cost was query count, where before it had been storage. (article: https://www.microtech.consulting/blog/we-never-had-a-storage-problem) **Questions and answers:** - Q: Do we need a faster database? A: Usually not. What worked on the marketplace was dividing the work: raw events went to a time-series store, and a daily rollup per listing went to the relational database. - Q: How long do you keep the raw data? A: As long as someone may need to reprocess it. The marketplace kept raw events for seven days, with a daily export to object storage as the archive. We never checked what thirty days would have cost, and today we would. - Q: Managed service or our own instance? A: That depends on which line of the bill is largest. Per-query charges grow with the number of people looking at the data, so they weigh most on a product whose customers check their own dashboards. When only a few engineers read the data, the managed service is often cheaper. - Q: Why does the index matter so much? A: In a time-series store, tags are indexed and fields are not. Put an identifier such as a listing ID in a tag and every new listing creates a new series, until the index grows too large to work. It is the most common way these installations fail. #### SQL and data warehouse optimization - URL: https://www.microtech.consulting/services/sql-data-warehouse-optimization - Format: a fixed-price written assessment Faster warehouse reports without touching queries or schema. A written review for reports that take minutes when the queries and schema can’t change. One retail supplier’s report went from over 15 minutes to 0.2 seconds. **Sound familiar?** - A report your customers open takes minutes to load - Your BI tool generates the queries, so there is nothing for you to rewrite - Customers have saved reports built on the schema, so the schema can’t change either - Someone has suggested moving to another warehouse, but it isn’t clear whether that would help - You have precomputed tables, and nobody is sure they still match the source data **What you get.** What the document covers: - Where the time goes, measured on the queries your system runs and the reports people wait for. - What can change underneath the queries and the schema: keys, indexes, materialized views and how often they refresh. - How to keep precomputed data correct: a check against the source, and a refresh interval that matches how often new data arrives. - Which changes would not pay off yet, with the reason for each. **Where we have done this before:** - A US retail supplier whose customers read their own sales through a BI tool, with the queries and the schema both off limits. The largest customer’s report went from over 15 minutes to 0.2 seconds, another from 4 minutes to 0.1 seconds, and no customer rebuilt a saved report. (case study 13: https://www.microtech.consulting/work/query-optimization-under-fixed-schema) - When we took over a marketplace whose hosting couldn’t keep up, we indexed its twenty slowest queries in the first two months and made them 90% faster. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) - For advertisers on a US marketplace, the yearly report opens in under a second even with over 900 listings, because it reads only the daily rollups. (case study 05: https://www.microtech.consulting/work/analytics-two-million-writes-per-day) **Questions and answers:** - Q: When do we get the document? A: We set the date once we have seen the query history and the list of slow reports, and write it into the offer. - Q: What should we prepare? A: Read access to the warehouse or database, its query history, and a list of the reports people wait for. - Q: Do we have to move to another warehouse? A: Usually not. The retail supplier’s warehouse was picked because the rest of its system was moving to AWS rather than for its features. The speedup came from the keys and materialized views built in it. - Q: Will our saved reports break? A: No. The schema stays as it is, so saved reports keep working. None of the retail supplier’s customers had to rebuild one. - Q: Do you do the work too? A: Yes. The keys, views and checks the document recommends are development work, which we bill by the hour. #### Permissions and RBAC - URL: https://www.microtech.consulting/services/permissions-rbac - Stack: TypeScript, Node.js, NestJS, Express, PostgreSQL, MySQL, Neo4j, React Who can do what in a product with several kinds of user. When “admin” means something different for each user type, we check access on the server and keep the model in one table, as on a marketplace with five types. **Who it is for.** A product where “admin” means something different for each kind of user, or where access follows a relationship such as a meeting, a document or a team. **What we have built:** - On a US marketplace, five kinds of user share one codebase and each has at least two roles. A permission is resolved from type and role together, so an operator at a vendor and an operator at a fleet carrier get different permissions. The API’s 506 routes are divided between a public set and an admin set. (case study 08: https://www.microtech.consulting/work/multi-persona-single-codebase) - A meeting platform for healthcare and finance, where someone may open a file because they were given access or because they attended a meeting it is attached to, and one document can belong to several meetings. Every person, meeting, file and signature is a node in a graph, and a permission check follows the links between them, however many there are. (case study 15: https://www.microtech.consulting/work/permissions-as-a-graph) - In a regulated identity check for a German financial institution, operator permissions were set per action rather than per role. When an action was beyond one operator, the case went to a colleague who held that permission, with a note. (case study 10: https://www.microtech.consulting/work/liveness-detection-person-and-document) **Questions and answers:** - Q: Roles or relationships? A: Use roles when access depends on who someone is, and relationships when it depends on what they are connected to, such as a meeting, a document or a version. Most products need both. - Q: Do we need a graph database? A: Not always. On the meeting platform it paid off, because permission depended on a chain of links that kept growing. In a relational schema that check becomes a recursive join, and it gets slower with every new kind of relationship. - Q: Can this be added to a product that already exists? A: Yes. First we read what the routes and the API allow today and write it down as one table. Changes come after that. #### Email infrastructure - URL: https://www.microtech.consulting/services/email-infrastructure - Stack: Node.js, AWS Lambda, SQS, S3, Handlebars, MySQL One sending service for every email your product sends. Each email goes from a template through a queue to one sending service, which records it. A US marketplace sent renewal and payment emails from 55 templates. **Who it is for.** A product that sends renewal notices, reminders and payment emails, and a team that needs to know what went out, to whom and why. **What we have built:** - Renewals, payment notices and re-engagement on a US marketplace went out from 55 email templates through a single sending service. (case study 07: https://www.microtech.consulting/work/scheduled-jobs-as-revenue-logic) - We moved a live marketplace’s mail onto a queue in the first two months of stabilizing it, before any code was rewritten. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) - For recurring payments, the customer gets one email when a charge succeeds, another when it fails and a third ahead of the next charge. (case study 18: https://www.microtech.consulting/work/payment-gateways-four-markets) **Questions and answers:** - Q: Why one sending service? A: Because some rules have to cover every message, such as redirecting mail outside production, recording what was sent or changing how mail goes out. With one service, each rule is written once. When every job sends on its own, every job has to remember every rule. - Q: Where are the templates kept? A: In object storage. Each job reads the template it needs, so a template is changed in one place. - Q: Can we see what went out? A: Yes. Every job writes a record of what it sent. On the marketplace the jobs logged nothing but failures, and for email tied to revenue that wasn’t enough: you also need a report of what was sent. #### ERP, CRM and third-party integrations - URL: https://www.microtech.consulting/services/erp-crm-integrations - Stack: TypeScript, Node.js, NestJS, Next.js, PostgreSQL, SAP, HubSpot CMS, HubL Your ERP or CRM stays, and new software works alongside it. We connect new software to the system you keep, and shared data such as invoices matches in both. A construction ERP we built syncs six kinds of data with SAP. **Who it is for.** A company that needs new software to work alongside a system it won’t replace: an ERP, a CRM or a national registry. **What we have built:** - A construction ERP connected to SAP, which the company kept. Instead of a monthly export, the integration carried customers, items, orders, invoices, stock and finance. (case study 16: https://www.microtech.consulting/work/construction-erp-workforce-planning) - Custom purchase and contact forms for a Swedish SaaS company, built against the HubSpot API. Each submission passes on the tracking cookie, so marketing can attribute it to the visit that produced it. (case study 17: https://www.microtech.consulting/work/hubspot-cms-custom-forms) - A passport system for a West African national identity authority checks applications against the national registry. The connection requires keys, digest authentication, single-use tokens and a request from an allowed IP address, so someone holding a stolen key still cannot get in. (case study 09: https://www.microtech.consulting/work/offline-first-sensitive-data-capture) **Questions and answers:** - Q: Will you replace the system we have? A: In most cases, no. Replacing a system the business runs on is a separate decision with its own reasons. On the construction ERP, SAP stayed. - Q: What is the hardest part? A: Keeping the two systems in agreement. When stock or an invoice differs between them, someone makes a decision on the wrong number. - Q: Embedded CRM forms or custom ones? A: Embedded, when the design allows it. A custom form gives you the design, but hidden fields, validation, error states, bot protection and the tracking cookie become your job, along with every later change in how the CRM expects submissions. #### Real-time and WebSockets - URL: https://www.microtech.consulting/services/real-time-websockets - Stack: WebSockets, API Gateway, AWS Lambda, Redis, Node.js Know the cost of live updates before you pick serverless. For real-time dashboards, notifications or chat, we price the WebSocket layer first. In our model, under 1,000 users most of the bill is a fixed $16.64 a month. **Who it is for.** Teams building live dashboards, notifications or chat who want to know what the socket layer will cost at their current size and at the next one. **What we have built:** - A WebSocket service on a US marketplace carrying live dashboard updates for advertisers, one-to-one notifications, forced logout and a lock that stops two admins editing the same record. The analytics behind those dashboards take in more than two million writes a day. (case study 05: https://www.microtech.consulting/work/analytics-two-million-writes-per-day) - We modeled serverless WebSockets in eighteen scenarios. With fewer than a thousand users, most of the bill is $16.64 a month for Redis and a VPC endpoint, and traffic barely changes it. (article: https://www.microtech.consulting/blog/serverless-websockets-you-pay-for-silence) - A messaging app using Lambda and Redis behind API Gateway, modeled at seven sizes. The real ceiling is 500 new connections per second, per account and region, and only a quota increase from AWS raises it. (article: https://www.microtech.consulting/blog/messaging-app-on-aws-and-where-it-stops) Both models are arithmetic on published AWS rates, not measurements of a running system. We use this arithmetic to decide between serverless and a server. **Questions and answers:** - Q: Serverless or a server? A: It depends on your user count and fanout. In our WebSocket model, a single server is already the cheaper option at a thousand users, and a redundant pair is cheaper by five thousand. For chat in groups of fifty, one server costs less from around three hundred users. - Q: Do connection minutes dominate the bill? A: Rarely. They did in only three of the eighteen modeled scenarios, all of them at light usage with five thousand users or more. A connection minute costs a quarter of a message, so above about fifteen messages an hour per user, messages cost more. - Q: Have you measured these costs on a running system? A: No. The live dashboard is a delivered project, but the cost figures are models built on published AWS rates, and the two blog posts behind them state every assumption. ### Regulated and sensitive systems #### Identity verification and KYC - URL: https://www.microtech.consulting/services/identity-verification-kyc - Format: a build, billed by the hour KYC with liveness checks on the person and the document. Identity verification for regulated web and mobile apps: a model recommends and an operator confirms each case. We built it for a German financial institution. **Sound familiar?** - The regulator wants a liveness check, and a photo of the document isn’t enough - Fraud gets through with a photo of a screen or a printed copy of a document - Verification works on web but not on mobile, or the other way around - You can’t show a regulator why one particular application was approved - A session can be pieced together from two different phones, and nothing catches it **What you get.** A verification flow for web and mobile, built from four parts: - Steps that ask the applicant for something unpredictable, such as a gesture or random digits read aloud, so a video recorded earlier fails. - Checks that the document is a physical object in someone’s hand: the applicant turns it and puts a finger on its edge, which a photo or a screen can’t imitate. - Where the document has a chip, the app reads it directly. The chip data is signed by the issuer, so authenticity is proven cryptographically instead of judged from an image. - An operator console where every case is confirmed by a person whose name goes on the decision, with a trail of when each step happened and on which device. **Where we have done this before:** - Liveness checks on the person and the document for a German financial institution, across a web app, a mobile app and an API. (case study 10: https://www.microtech.consulting/work/liveness-detection-person-and-document) - The NFC chip in German passports, read from a React Native app. (case study 12: https://www.microtech.consulting/work/react-native-hardware-native-modules) - Biometric capture without internet, for a passport and ID system in West Africa. (case study 09: https://www.microtech.consulting/work/offline-first-sensitive-data-capture) **Questions and answers:** - Q: Do you use a ready-made KYC service or build one? A: It depends on your market, your volume and your regulator. We compare both options with numbers before you decide. - Q: Web or mobile? A: Both. The checks run in one shared layer on web and mobile, so the same person gets the same result on either device. - Q: Which documents can you support? A: Passports, national ID cards and driver’s licenses. If the document has a chip, we read it directly using ICAO 9303. - Q: Is the decision automated? A: No. The model recommends and an operator confirms every case. At the German financial institution an operator signed off on all of them, even though the model was confident about 98% of the time, because in regulated banking every decision must be attributable to a named person. - Q: Where is the biometric data kept? A: It is unlocked only while a check runs. After that it sits in separate storage, locked with a key that you assign to someone outside the development team. #### Fintech development - URL: https://www.microtech.consulting/services/fintech-development - Format: a fixed-price written assessment Payment and billing software that reconciles to the cent. Remittance, invoicing or billing software gets a two-week review, then the work it calls for. We have built payments for five products in four markets. **Sound familiar?** - The invoice and the database disagree by a few cents - Stripe doesn’t work in your market - An issued document can still be changed afterward - Billing, renewals and reminders depend on someone remembering - A payment went through with the wrong amount, and the system carried on as if it were right **What you get.** The review checks your system on four points, and the build that follows fixes the ones that fall short: - Amounts stored as integers in the smallest currency unit, from the database to the invoice, so two screens never round the same amount differently. - Issued documents that stay frozen. A correction is recorded separately, and the original stays readable in its issued form. - Billing, renewals and dunning as scheduled jobs that apply one rule to every account. Nothing sent from staging can reach a real customer. - A payment provider chosen for each market, with a local gateway where the global ones don’t work, and failed payments and retries handled as part of the product. **Where we have done this before:** - Payment integrations for five products in four markets, from Stripe and PayPal to a national government gateway in West Africa and a domestic gateway in Bosnia and Herzegovina. (case study 18: https://www.microtech.consulting/work/payment-gateways-four-markets) - Customs invoicing, remittance terminals and a meetings platform, each built to keep the moment a document is created apart from the moment it becomes valid. (case study 11: https://www.microtech.consulting/work/immutable-issued-documents) - Six daily jobs that handle renewals, downgrades, dunning and reminders for a US marketplace. (case study 07: https://www.microtech.consulting/work/scheduled-jobs-as-revenue-logic) **Questions and answers:** - Q: Do you work with local banks and gateways? A: Yes, including in the Balkans and West Africa. - Q: What happens with exchange rates? A: We freeze the rate at the moment of payment. An invoice that has been issued but not yet paid takes the rate of the day it is settled. - Q: Do you handle chargebacks and refunds? A: The system records them. We build the part that has to reconcile, and the bookkeeping stays with your accountant. - Q: Can you work with the payment provider we already have? A: Yes. Most of this work is done around the provider you already use, without a migration to another one. - Q: How does it start? A: With the two-week review of what you have. If building is needed, we agree on it afterward, based on what the review found. #### Healthcare software under HIPAA - URL: https://www.microtech.consulting/services/healthcare-hipaa - Stack: Neo4j, React, WebRTC, AWS Transcribe, DocuSign, AWS Healthcare meetings on record: who attended and who signed. Healthcare products must show who attended each consultation and who signed. We set access per person and document, and patients can join as guests. **Who it is for.** A healthcare or finance product that has to keep track of who attended each consultation, which documents were used and who signed them. **What we have built:** - A white-label meetings platform for healthcare and finance, with people, meetings, files and signatures stored as a graph. Whether someone may open a file is answered by tracing the connections from that person to the file. (case study 15: https://www.microtech.consulting/work/permissions-as-a-graph) **Questions and answers:** - Q: Do you build the video layer? A: No. The meetings platform used an existing video layer. Our work was the record around the call: file management, transcription, recording, permissions and signing. - Q: Can a patient join without an account? A: Yes. Guest access on the meetings platform was built for that, as a HIPAA requirement. - Q: Can one document belong to several meetings? A: Yes, with version history and signing. Someone can get access to a document directly or through a meeting they attended, and the graph handles both. #### Government documents and audit trails - URL: https://www.microtech.consulting/services/government-documents-audit-trails - Stack: Node.js, PostgreSQL, React, Next.js, Expo, AWS Every decision on an official document traced to a person. For public bodies that issue passports or IDs: field staff work offline and issued documents never change. Our passport system in West Africa is in production. **Who it is for.** A public body, or a supplier to one, that issues passports, ID cards, invoices or other documents that will be checked years after issue. **What we have built:** - Passport and ID issuance for a national identity authority in West Africa. Agents capture applications and biometrics with no signal on company phones that can be wiped remotely, and the server catches duplicates. The system is in production and the app is on Google Play. (case study 09: https://www.microtech.consulting/work/offline-first-sensitive-data-capture) - Customs invoices saved as immutable HTML when issued. Editing the template later can’t alter an invoice that has already gone out. (case study 11: https://www.microtech.consulting/work/immutable-issued-documents) - Remote identity verification in which the operator records a reason for every decision and is named on it, so the record holds up in a review years later. (case study 10: https://www.microtech.consulting/work/liveness-detection-person-and-document) **Questions and answers:** - Q: What if there is no internet in the field? A: Applications and biometrics wait in secure storage on the phone and upload once it has a connection again. - Q: Why catch duplicates on the server? A: A phone that has been offline can’t know what other phones submitted in the meantime. Only the server, which every device eventually syncs with, can tell whether an application already exists. - Q: Is a frozen copy enough for an audit? A: It shows what was issued. An audit also asks which version of the template was used and who changed that template, so templates need a version history of their own. The customs invoicing system never had one. - Q: Do you work with national payment gateways? A: Yes. Passport fees went through the national gateway, and applicants abroad paid with PayPal. #### Invoicing and customs systems - URL: https://www.microtech.consulting/services/invoicing-customs-systems - Stack: Node.js, PostgreSQL, immutable HTML snapshots, NestJS, SAP Invoices you can show years later exactly as issued. Each invoice is stored at the moment of issue, so later template edits can’t change it. On a customs system we checked 50,000 invoices, and none had changed. **Who it is for.** Any business or authority that may be asked, years from now, to show an invoice exactly as it was issued. **What we have built:** - Customs invoicing that renders each invoice once, at the moment of issue, and stores it as immutable HTML. We validated it on 50,000 invoices, and none changed after issue. (case study 11: https://www.microtech.consulting/work/immutable-issued-documents) - Invoicing, payments and a supplier ledger with accounting export, as part of a construction ERP that runs alongside SAP. (case study 16: https://www.microtech.consulting/work/construction-erp-workforce-planning) - On a US marketplace, the daily renewal job downgrades a listing more than seven days late, updates its invoice and re-indexes the record, by the same rule for every account. (case study 07: https://www.microtech.consulting/work/scheduled-jobs-as-revenue-logic) **Questions and answers:** - Q: Why not render invoices on demand? A: Because then every change to the rendering code would also change every old invoice, and nothing would raise an error. - Q: How are corrections handled? A: With a new document. The invoice being corrected is never edited. - Q: Can it work alongside our ERP or accounting? A: Yes. The construction ERP exchanged customer, order, invoice, stock and finance data with SAP, which stayed the system everything starts from. #### Security review - URL: https://www.microtech.consulting/services/security-review - Format: a fixed-price written assessment Who can read other users’ data in your app? We read your code to show who can reach what, before a customer’s security review asks. In our own design system, 188 findings came down to three causes. **Sound familiar?** - Nobody has checked who can read someone else’s data - Permissions are enforced in the interface, and you aren’t sure the API checks them again - A customer’s security review is coming, and you don’t know what they will ask - Access rules grew one condition at a time, and nobody can say what a role can do without reading the whole codebase **What you get.** The document covers your access rules in four parts: - A table of every user type and role against every action, so you can see who can reach what without reading code. - Every place where a permission is checked only in the interface and the API accepts the request anyway. - The causes behind the findings, since fixing a cause also prevents the findings it would have produced next. - For each cause, whether an automated check in the build can catch it or someone has to keep looking for it by hand. **Where we have done this before:** - A marketplace that had SQL injection reaching production when we took it over. In the first two months, before anything was rewritten, we added a firewall and closed the inherited security holes. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) - Five kinds of user, from service vendors to a call center, share one codebase. Each type has its own routes. Permissions combine type and role, and the API validates them itself instead of trusting the route a request came from. (case study 08: https://www.microtech.consulting/work/multi-persona-single-codebase) - On a remote-meeting platform sold into healthcare and finance, file access follows a graph of people, meetings and documents, and the browser extension requests a single permission, without media access. (case study 15: https://www.microtech.consulting/work/permissions-as-a-graph) **Questions and answers:** - Q: Is this a penetration test? A: No. We read the code and the access rules. A penetration test attacks the running system, and that is a separate job. - Q: What access does the review need? A: We need read access to the repositories, plus a description of your user types and roles. We work from the code, so we don’t touch production data. - Q: Can you also fix what the review finds? A: Yes, as separate hourly work once the document shows what needs fixing. ### Cloud and DevOps #### Cloud cost review - URL: https://www.microtech.consulting/services/cloud-cost-review - Format: a fixed-price written assessment Why your cloud bill went up, line by line. If the bill grows faster than traffic, a two-week review shows which lines you can cut. One national identity system went from $24,000 to $2,000 a month. **Sound familiar?** - The bill grows faster than traffic, and nobody knows which line is behind it - Someone said you should move to serverless, or off it, and you have no way to check - You pay for a managed service and aren’t sure it’s cheaper than running your own instance - The last time anyone read the bill was when you chose the region - Uploads go through your backend, and the instance grew to carry them **What you get.** Two weeks after we get read access to the account and the code, you get a document with: - The bill broken down by meter. AWS reports what you spent on each service, such as EC2. The breakdown shows what you spent on storage, access, traffic and compute, which are different problems with different fixes. - Every cause we find, sorted into one of three kinds: capacity that was sized wrong, something that is broken, or something that was built wrong. Each kind is found differently and fixed differently. - The fixes worth making, each with the amount it saves, in order of savings against effort. - What isn’t worth fixing, and why. This is usually half the document. **Where we have done this before:** - A national identity system in West Africa had all three kinds of cause, and none of them had produced an error. Within six months its monthly bill went from $24,000 to $2,000, for the same users doing the same work. Against what the workload needed, the bill had been about eight times too large; the final cut was twelvefold. (case study 14: https://www.microtech.consulting/work/aws-cost-reduction-eight-times) - Marketplace analytics at 2M writes a day: storage was 95% of the managed time-series bill, and our own instance came out about $27,000 a year cheaper, by our estimate. A retention change cut storage to $1.31 a month, and the managed service still cost more, this time because it charges for every query a customer’s dashboard runs. (case study 05: https://www.microtech.consulting/work/analytics-two-million-writes-per-day) **Questions and answers:** - Q: What do you need from us? A: Read access to billing and CloudWatch, and to the repositories, because the architectural causes only show up in the code. We don’t need to see production data. - Q: Will you also make the fixes? A: We can. The fixes are billed by the hour as separate work, and we start once the review has shown which ones are worth making. - Q: What if the conclusion is that we should change platforms? A: Then the document recommends it and shows the numbers behind the recommendation. Several times, though, the conclusion was to stay on the current platform. #### Zero-downtime migration - URL: https://www.microtech.consulting/services/zero-downtime-migration - Format: a fixed-price written assessment Moving to a new system while the old one keeps running. For a migration that keeps getting postponed: a two-week written plan that includes the way back. A US marketplace moved from PHP to Node.js with zero outages. **Sound familiar?** - The migration has been postponed three times - It’s planned for Saturday at three in the morning - Nobody knows how you would go back - The new system has been finished and waiting for months - You are paying for both, and have been for longer than planned **What you get.** What the plan sets out: - The order in which parts of the system move, and the one thing that stays unchanged while they do. Usually that is an interface, a schema or an address. - The way back, written as a procedure someone can follow at three in the morning without making a single decision. - Which parts run in both systems at once, for how long, and how the two are kept in sync during that time. - The measurement that says the old system can be switched off, instead of a date somebody picked in a meeting. **Where we have done this before:** - A US marketplace moved from PHP to Node.js with zero outages. Its two databases were synced in both directions for more than a year, and going back was a change of origin at the CDN that took seconds. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) - A national identity system moved off its old registry gradually, pulling from it every month while both stayed live. (case study 09: https://www.microtech.consulting/work/offline-first-sensitive-data-capture) - A reporting warehouse rebuilt underneath a BI tool whose queries and schema had to stay exactly as they were. The report for the largest customer now opens in two tenths of a second, down from more than fifteen minutes, and every customer’s saved reports kept working. (case study 13: https://www.microtech.consulting/work/query-optimization-under-fixed-schema) **Questions and answers:** - Q: What access do you need? A: Read access to the code and the schema of both systems, and someone who knows why the old one behaves the way it does. The two weeks start once we have that access. The plan doesn’t require production data. - Q: Can you carry out the migration as well? A: Yes, as a separate engagement. We agree on it after the plan, because only then do we know how long the two systems will have to run side by side. - Q: How long do the two systems run side by side? A: Until the data shows the old one is no longer used. On the longest migration we have run, that took more than a year. #### AWS architecture - URL: https://www.microtech.consulting/services/aws-architecture - Stack: AWS, EC2, S3, Lambda, API Gateway, SQS, ElastiCache, Redshift, CloudWatch AWS architecture for the load you have and the next step. For products on AWS that outgrew their setup, we size from measured load and design for the bill. One identity system went from $24,000 to $2,000 a month. **Who it is for.** A product that is already on AWS or moving there, and needs someone to decide what runs where and what it will cost. Most often it is a system that grew faster than anyone revisited its setup. **What we have built:** - A West African national identity system whose bill for the same workload came down from $24,000 to $2,000 a month, with nothing switched off. (case study 14: https://www.microtech.consulting/work/aws-cost-reduction-eight-times) - Passport applications captured offline on company phones that can be wiped remotely. The national registry can only be reached with keys, single-use tokens and IP allow-listing. (case study 09: https://www.microtech.consulting/work/offline-first-sensitive-data-capture) - A US marketplace moved from shared hosting onto AWS in two months, and later onto containers with autoscaling, without a single outage. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) - Serverless WebSockets on API Gateway, Lambda and Redis, priced in eighteen scenarios. Below about a thousand users, traffic hardly registers on the bill, which is almost all Redis and the VPC endpoint. (article: https://www.microtech.consulting/blog/serverless-websockets-you-pay-for-silence) **Questions and answers:** - Q: Is serverless cheaper than running servers? A: Only up to a point, and we work out where that point is for your traffic. When we modeled WebSockets, serverless already cost more than one server at a thousand users, and more than a redundant pair by five thousand. - Q: Can you work on an account that is already running? A: Yes. The West African identity system stayed live throughout and kept serving the same users while its bill came down. - Q: Do you move systems onto AWS too? A: Yes. We moved the marketplace’s PHP application onto AWS as it was and stabilized it there. The rewrite came after that. - Q: Can we start with a review of our current AWS account? A: Yes. The cloud cost review is a two-week written assessment at a fixed price. Architecture work after it is billed by the hour. #### CI/CD and code standards - URL: https://www.microtech.consulting/services/ci-cd-code-standards - Stack: Pre-commit hooks, CI, ESLint with custom rules, TypeScript, pnpm workspaces Code standards checked before every commit and again in CI. Your team’s conventions become pre-commit and CI checks, with a separate set for each codebase. A US marketplace ran them across nineteen repositories. **Who it is for.** A team whose conventions hold only while someone has time for careful review. Often the team is about to add AI to how it writes code, and then code arrives faster than anyone can read it closely. **What we have built:** - Rules across the nineteen repositories of a US marketplace, among them a ban on the any type, no component longer than 200 lines, and a typed request and response on every API call. Both the pre-commit hook and CI check them. (case study 03: https://www.microtech.consulting/work/ai-assisted-engineering-standards) - Our cross-platform design system has about 2,450 lines of verification that fail the build. CI also runs a real build with each of Next, Vite and Metro, because one of the rules is only truly checked by next build. (case study 01: https://www.microtech.consulting/work/cross-platform-design-system) - A review of our design system found 188 issues and traced them to three root causes, all of which had passed typecheck, ESLint and the build. Two of the three are now checks of their own: a label without a role, and a prop declared in a contract that can’t be traced to an element. (article: https://www.microtech.consulting/blog/three-bug-classes-your-tools-cannot-see) **Questions and answers:** - Q: Why not one set of rules for everything? A: Because one set for a backend and a design system ends up too permissive to matter in one or strict enough that people bypass it in the other. Deciding which rules belong in which codebase is a judgment call. - Q: Won’t a strict hook slow the team down? A: It will if it is slow. People start bypassing a hook that takes thirty seconds within a week, so the hook only runs the fast checks. - Q: Which rule paid back the most? A: On the marketplace, the 200-line limit on components. It makes you split a component as soon as it starts to sprawl, while splitting is still easy. - Q: Can you add this to a pipeline we already have? A: Yes. We add the rules to the hooks and CI you already run, one codebase at a time. #### Automated and end-to-end testing - URL: https://www.microtech.consulting/services/automated-testing - Stack: TypeScript, unit and component tests, end-to-end suites, headless browser checks, CI Automated tests that stop the build when something breaks. For teams that drop tests first under a deadline: unit, component and end-to-end tests, wired into CI. Our own design system runs 678 of them. **Who it is for.** A team whose tests are the first thing dropped under a deadline, or a product with no tests at all and a release button nobody wants to press. **What we have built:** - 678 tests across 62 suites in our cross-platform design system, covering the web, a SPA and native. (case study 01: https://www.microtech.consulting/work/cross-platform-design-system) - Two tests that check the emitted style directly, added after a layout bug crashed the app on a phone while typecheck, native tests and the production export had all passed. We proved them by putting the bug back and watching them fail on the exact property. (article: https://www.microtech.consulting/blog/a-real-page-is-a-better-test-than-a-component) - On a US marketplace for truck services, once the rules were enforced in CI, the team stopped writing tests by hand and generated them with Claude Code. (case study 03: https://www.microtech.consulting/work/ai-assisted-engineering-standards) Our end-to-end work so far is on two products of our own, still in development and without external users: 331 tests in one, 16 end-to-end suites in the other. **Questions and answers:** - Q: Do you write end-to-end tests? A: Yes, but so far only for our own products, which are still in development. We haven’t run an end-to-end project for a client. - Q: What do tests miss? A: Whatever they don’t check for. On our design system a native test stayed green for a screen that could not open on a phone, because the test renderer never asks whether a component exists on the device. The fix was a check that fails if anything other than View or Text is rendered. - Q: Can AI write the tests? A: Yes, provided the checking is automatic. AI moves the work from writing tests to reviewing them, so generated tests only save time when the hooks and CI do most of that checking. - Q: Can you add tests to a codebase that has none? A: Yes. We start where a failure would cost you the most. #### Docker, self-hosting and backups - URL: https://www.microtech.consulting/services/docker-self-hosting-backups - Stack: Containers, EC2, EBS, snapshots, S3, CloudWatch, InfluxDB Managed service or your own instance: the full price of each. We price a managed service against your own instance, backups, failover and upkeep included. Self-hosting one database saved about $27,000 a year, we estimate. **Who it is for.** A team that pays for a managed database and wonders whether its own instance would be cheaper. Or a team that already self-hosts and isn’t sure what a restore would bring back. **What we have built:** - InfluxDB on our own EC2 instance instead of the managed service, for an analytics layer. By our estimate it saved roughly $27,000 a year while storage made up 95% of the managed bill, and it stayed cheaper after a retention change because the managed service charges per query. (article: https://www.microtech.consulting/blog/we-never-had-a-storage-problem) - Serverless WebSockets priced against a server of your own across eighteen scenarios. The crossover against one server came before a thousand users, and against a redundant pair before five thousand. (article: https://www.microtech.consulting/blog/serverless-websockets-you-pay-for-silence) - A US marketplace began on shared hosting and ended up on containers with autoscaling, and the product stayed up throughout. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) **Questions and answers:** - Q: Is self-hosting always cheaper? A: No. If both options cost under about $200 a month, take the managed version with backups and a support line, because the difference is smaller than the time you would spend on it. Self-hosting pays off when your customers read their own data and per-query pricing grows with every one of them. - Q: What do we give up? A: Usually the last part of availability. The setup in our write-up was an active-passive pair on one shared volume. It survives an instance dying but not the loss of the volume or the zone, and it gave about 80% of the availability for about 3% of the price. - Q: What does the invoice leave out? A: Maintenance, upgrades and on-call. If nobody on your team already patches instances and tests restores, self-hosting doesn’t save money. It gives someone a new job. - Q: Is the $27,000 measured? A: No. It is our estimate, from US East list prices in mid-2026 and our own usage, and it leaves out maintenance and on-call. ### AI #### App audit and rescue - URL: https://www.microtech.consulting/services/app-rescue - Format: a fixed-price written assessment What to fix first in an app that now has real users. An app built fast with Lovable, Bolt or Cursor, or by a team that has left, gets a two-week written assessment: what to fix first and what to keep. **Sound familiar?** - Built in Lovable, Bolt or Cursor, or by a team that has left - It worked until real users arrived - Nobody on the team reads the code that goes to production - Every change breaks something else, and data access has never been checked - Supabase holds the data, and the tool that wrote the app also wrote its RLS policies **What you get.** In two weeks you get a document that covers: - The urgent problems: who can access which data, how users sign in and which secrets ended up in the client. They come first because they are the only ones that can’t wait. - Which problems are expensive and which are only ugly. The two usually get mixed up, and they are fixed in very different ways. - A recommendation to rescue or rewrite each part of the app, so you never have to decide for the whole app at once. - The rules to add before the next feature, so that new code, whether a person or a tool writes it, doesn’t bring the same problems back. **Where we have done this before:** - A US marketplace that went down regularly, running PHP on hosting that couldn’t scale, with SQL injection in production. In the two months we spent stabilizing it, before any code was rewritten, we made its twenty slowest queries 90% faster and closed the security holes. The rebuild took the two years after that. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) - On a team that writes code with Claude Code, the pre-commit hook and CI enforce rules such as these: no component over 200 lines, no TypeScript any, and a request and response type on every API call. (case study 03: https://www.microtech.consulting/work/ai-assisted-engineering-standards) - For a healthcare and finance meetings platform, the server works out who may open each file by following the links between people, meetings, documents and signatures. (case study 15: https://www.microtech.consulting/work/permissions-as-a-graph) **Questions and answers:** - Q: What do you need to start? A: Access to the repository and a description of how people use the app. The two weeks start when we have access to the code, and we work without production data. - Q: Do we have to rewrite everything? A: Not necessarily. The document recommends rescue or rewrite for each part separately, and if the data model is sound, most of the app can stay. - Q: Can you do the fixes as well? A: Yes. We start with whatever the document marks as urgent, and that work is paid by the hour. #### AI in your engineering team - URL: https://www.microtech.consulting/services/ai-in-engineering-teams - Stack: Claude Code, pre-commit hooks, CI, ESLint, TypeScript, Figma AI in your engineering team without a code review bottleneck. We bring Claude Code into your team’s daily work, and automated checks take the routine half of review. On a team of twelve, throughput rose an estimated 50%. **Who it is for.** A team that has started using AI and found that code review became the bottleneck, or one that wants to start without the codebase getting worse. **What we have built:** - A US marketplace with a team of twelve, where throughput rose by roughly 50% once the rules ran before commit and in CI. The figure is estimated from ticket cycle time. (case study 03: https://www.microtech.consulting/work/ai-assisted-engineering-standards) - In our own design system, a generated change that breaks one of its conventions fails the build, because about 2,450 lines of verification code check them. (case study 01: https://www.microtech.consulting/work/cross-platform-design-system) - Six confident errors in one afternoon of AI-assisted research, and the habits that caught them. (article: https://www.microtech.consulting/blog/the-fool-who-believes-what-he-reads) **Questions and answers:** - Q: Will AI make my team faster? A: Not by itself. It moves work from writing code to reviewing it, and if your team already waits on review, more code makes the wait longer. On the marketplace, the speedup came after the checks were in place. - Q: Is the 50% real? A: It is our estimate from ticket cycle time, and we did not run a controlled test. In a controlled study by METR, experienced developers felt faster and were measured 19% slower, so treat self-reported speed with care, including ours. - Q: Where does AI help most? A: In areas your team knows well, where it drafts faster than people write and the team spots its mistakes at once. Outside that knowledge, nobody can tell a good answer from a bad one. - Q: Which tools do you use? A: Claude Code for daily work, with design connected to Figma. The checks around the tool matter more than which tool it is. #### Supabase review - URL: https://www.microtech.consulting/services/supabase-review - Format: a fixed-price written assessment Can one user read another user’s rows in your Supabase? If an AI tool or tutorial wrote your Supabase RLS policies and nobody read them: in one week, a table of what each role can read and write, tested by queries. **Sound familiar?** - The RLS policies were generated or copied from a tutorial and nobody has read them through - You cannot say with confidence whether one user can read another’s row - A key that was meant to stay on the server shows up somewhere in the client - A storage bucket has been public “temporarily” since week one - An edge function runs with the service role because that was the only way to make it work **What you get.** The week ends with a document that lists: - An access table that shows, for every table and every role, what that role can see and what it can change. We build it by running queries, so it reflects what the policies actually allow. - Tables with no policy at all, and tables where RLS is on but the policy in effect lets everything through. - Keys and secrets we found in the client bundle or the repository, marked where they need to be rotated immediately. - Public storage buckets, their path rules and edge functions that bypass the policies because they run with elevated rights. **Where we have done this before:** - In a white-label meeting product for healthcare and finance, the right to open a file depended on a chain through a meeting, a document, its version and a signature. One condition on a row could not express that. (case study 15: https://www.microtech.consulting/work/permissions-as-a-graph) - One codebase for five kinds of user, where a vendor’s operator and a fleet carrier’s operator get different rights because a permission is resolved from user type and role together. The backend validates it again, since separating routes in the client only organizes the interface. (case study 08: https://www.microtech.consulting/work/multi-persona-single-codebase) - A passport system where the server catches duplicate applications before anything is accepted, and the national registry sits behind keys, digest authentication, single-use tokens and an IP allow-list, so one stolen key is not enough to get in. (case study 09: https://www.microtech.consulting/work/offline-first-sensitive-data-capture) - Signed upload links scoped to one object and one method, expiring in minutes, with a lifecycle rule that cleans up the orphaned files they leave behind. (article: https://www.microtech.consulting/blog/direct-s3-upload-instead-of-through-your-backend) **Questions and answers:** - Q: How long does it take? A: One week from the day we get access to the project and the repository. The first two days go on the inventory, and the rest of the week on running the checks role by role. - Q: What access do you need? A: Read-only access to the Supabase project and the repository. Production data isn’t needed, because the policies are tested against test rows. - Q: Is this the same as the app assessment? A: No. This review covers data access only and takes a week. If you also need to know what is urgent, what is expensive and what to rewrite across the whole app, that is the two-week app audit and rescue. - Q: What if you find a serious leak during the week? A: If we find a leaked service role key or a policy that exposes another user’s rows, we tell you that day, before the document is finished. Fixing it is not part of the review, and we charge for that work by the hour. #### AI agents and LLM integration - URL: https://www.microtech.consulting/services/ai-agents-llm-integration - Stack: Claude Code, TensorFlow, Node.js, AWS, per-action permissions, decision records AI agents that prepare each case for a person to decide. Where a wrong action costs money or trust, the model prepares each case and a person decides. At a German financial institution, operators confirmed every case. **Who it is for.** A team that wants a model or an agent inside a real workflow, where a wrong action costs money or trust and someone has to answer for it. **What we have built:** - For a German financial institution’s remote identity checks, the model made a confident recommendation in about 98% of cases, and an operator confirmed every case. The 98% measures only how often the model was sure of itself. (case study 10: https://www.microtech.consulting/work/liveness-detection-person-and-document) - A language model in daily engineering work: Claude Code writes integrations, components and tests for a US marketplace, and nothing it writes is accepted until the team’s automated checks pass. (case study 03: https://www.microtech.consulting/work/ai-assisted-engineering-standards) - An afternoon of research in which an AI was confidently wrong six times, and every error leaned toward a tidier answer. (article: https://www.microtech.consulting/blog/the-fool-who-believes-what-he-reads) The model in the identity work was a computer-vision model, not a language model. The arrangement around it applies to a language model as well: the model suggests, an operator confirms and records a reason, and the decision can later be traced to that operator. **Questions and answers:** - Q: Can the agent act on its own? A: For drafts and suggestions, yes. Anything that moves money, changes a record or reaches a customer waits for a person to approve it, because in regulated work someone has to answer for the decision. - Q: How do you know the model is right? A: Confidence and correctness are separate measurements. On the identity project we tracked how often the model was confident and never established how often it was right. Next time we measure both. - Q: What goes wrong most often? A: Confident answers that rest on assumptions nobody stated. We ask for the assumptions before the answer, and then ask what would have to be true for the result to be wrong. ### Design systems #### Design system and component library - URL: https://www.microtech.consulting/services/design-system-component-library - Stack: TypeScript, React, Next.js, React Native, Vite, styled-components, pnpm workspaces, custom ESLint rules One component library for web and React Native. If your web and mobile apps have started to look different, we write each component once for both. Our own system has 74 components and 678 tests. **Who it is for.** A team whose web app and mobile app have started to look and behave differently, or a team about to build its third set of buttons from scratch. **What we have built:** - Our own cross-platform design system: 74 components, 678 tests and an 81-page catalog generated from the source code. Its login form is a single file that a Next.js app, a Vite app and a React Native app all use unchanged. (case study 01: https://www.microtech.consulting/work/cross-platform-design-system) - More than 200 components in a monorepo for a US truck-services marketplace, built while the product stayed live and used by both its dashboards and its mobile app. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) - A library of about a hundred components, built in two months for a white-label construction product with more than thirty brands. It works with any framework and is organized by size, type and kind, so developers can find what they need. (case study 02: https://www.microtech.consulting/work/design-tokens-thirty-white-labels) - We measured one page written three ways. The design system version was 44% smaller than the version hand-written with styled-components, and it had 13 hardcoded design values where the hand-written one had 197. (article: https://www.microtech.consulting/blog/the-hand-written-version-was-the-biggest) **Questions and answers:** - Q: Will one component really work on web and mobile? A: Yes. About half of the components in our own system are a single file for both platforms. In the rest, the difference comes down to one primitive, such as a div that becomes a View, and nothing built on top of it has to know. - Q: How much does a mobile port reuse? A: In the port of our marketing page, the phone reused 91% of what it draws without a change. The web-only part was confined to one layout file, which followed from keeping the platform split in the primitives. - Q: Do we have to stop and start over? A: No. We built the marketplace library inside a product that kept running. - Q: Is a half-built system worth it? A: Not on the page we measured. The version with a hand-written partial system was the largest of the three, bigger even than plain HTML, because it first had to rebuild the containers, headings, buttons and cards that a design system already provides. #### Design tokens and multi-brand theming - URL: https://www.microtech.consulting/services/design-tokens-multi-brand - Stack: Design tokens, Figma, JSON, SCSS, CSS variables, TypeScript, npm packages A new brand or a dark theme is a new set of token values. Components take every color and size from tokens, so their code stays the same for each brand. One library of about 100 components serves 30+ brands. **Who it is for.** You sell your product under other companies’ brands, or you need a light and a dark theme without maintaining two of everything. **What we have built:** - A white-label product for construction companies, sold under more than thirty brands, each with its own colors, logos and imagery. About a hundred components take all of that from tokens that were exported from Figma to JSON and generated into SCSS. One developer built the library in two months. (case study 02: https://www.microtech.consulting/work/design-tokens-thirty-white-labels) - In our cross-platform design system, a theme token becomes a CSS variable on the web and a value the native resolver fills in on the phone. Each color is defined once for every platform. (case study 01: https://www.microtech.consulting/work/cross-platform-design-system) - On one page built three ways for comparison, a brand color change meant editing 58 places in plain HTML and one token in the design system version, which applied it on all three platforms. (article: https://www.microtech.consulting/blog/the-hand-written-version-was-the-biggest) **Questions and answers:** - Q: What does a new brand cost? A: A new brand is a new set of token values for its colors, type and imagery, and the component code doesn’t change. That is how one library stayed maintainable across more than thirty brands. - Q: Does it tie us to one framework? A: Not necessarily. We built the thirty-brand library to work without any particular framework because two different products used it. Tying it to one framework would have meant implementing the same design a second time for the other product. - Q: Can we add a dark theme later? A: Yes, if no color is written directly into the components. Our own marketing page, rebuilt on semantic tokens, worked in light and dark without extra work, while the original version had its colors hard-coded and existed only in dark. - Q: Do the tokens come from Figma? A: They can. In 2022 the thirty-brand library’s tokens were exported from Figma into JSON. Our current system gets them through an MCP server automatically, as the Figma to code page describes. #### Figma to code - URL: https://www.microtech.consulting/services/figma-to-code - Stack: Figma, Figma MCP, design tokens, JSON, SCSS, TypeScript, pnpm workspaces Getting Figma changes into code without copying hex values. Design tokens go from Figma into one place in your code, automated where possible, so nobody copies hex values by hand. Our own system imports them over MCP. **Who it is for.** The design file says one thing and the code another, and the only connection between them is a person copying hex values. **What we have built:** - Our current design system takes palettes, scales and theme values from Figma automatically, over an MCP server. (case study 01: https://www.microtech.consulting/work/cross-platform-design-system) - A thirty-brand library in 2022, where a plugin exported the tokens from Figma to JSON and the JSON was generated into SCSS. It was automated, but it worked in one direction only and easily fell behind the design file. (case study 02: https://www.microtech.consulting/work/design-tokens-thirty-white-labels) - A team of twelve at a US marketplace for truck services, where by 2026 design was connected to Figma and the team used Claude Code every day. (case study 03: https://www.microtech.consulting/work/ai-assisted-engineering-standards) **Questions and answers:** - Q: Do you generate components from Figma? A: No. We take palettes, scales and theme values from Figma, and the components are written in code on top of them. - Q: What does it fix? A: Design and code change on different schedules. Without something linking them, the Figma file and the code match only by accident, and it is hard to tell which of the two is correct. - Q: Does it work with our design file? A: That depends on how the file is structured, which is the first thing we look at. - Q: And for several brands? A: Then each brand gets its own set of token values. The design tokens and multi-brand theming page explains how that works. ### How we can work #### A developer in your team - URL: https://www.microtech.consulting/services/dedicated-developer A senior developer who joins your team for the long term. A senior React and React Native engineer joins your team full-time and remotely, with six years across web, mobile and backend, four of them leading a team of twelve. **Who it is for.** Usually a larger company that needs an experienced developer and wants that person working in its own team, tools and process. **What we have built:** - Four years on one client’s US marketplace, through four phases of work, none of which caused an outage. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) - A design system for a white-label product, and three years later the same client asked us back to fix their Android app. (case study 02: https://www.microtech.consulting/work/design-tokens-thirty-white-labels) - Lead developer in a team of four, building an ERP that had to work alongside the client’s existing SAP. (case study 16: https://www.microtech.consulting/work/construction-erp-workforce-planning) - Coding standards turned into automated checks, and three developers trained from one specialism into full-stack work. (case study 03: https://www.microtech.consulting/work/ai-assisted-engineering-standards) **Questions and answers:** - Q: Through Upwork or directly? A: Both. You can hire through Upwork or sign a contract with us directly. - Q: How do we start? A: With a conversation. After that we agree on the scope and a start date. - Q: Employment or contract? A: Whichever suits you: a project, a long-term contract or employment. - Q: Can you lead as well as build? A: Yes. The same developer led a team of twelve as its Technical Lead for four years. By default, though, this engagement is a senior developer working inside your team. If you need someone to run the team, that is our technical leadership service. #### App takeover and launch - URL: https://www.microtech.consulting/services/app-takeover - Format: a fixed-price written assessment We take over your unfinished app and launch it. For an app another developer left “90% done”: a one-week review of what is left before launch, then we finish it. We don’t rewrite the parts that already work. **Sound familiar?** - The app has been “90% done” for months - The developer or agency that built it has left, and you have the code - What remains is edge cases, store submission and the work that wasn’t in the plan - You don’t know which parts of the existing code are worth keeping - The previous developer’s accounts and keys are gone, or nobody knows who has them **What you get.** Before any code is changed, the review tells you: - What works today. We find that out by running the app, because the repository alone doesn’t show it. - What is still missing before launch, item by item, with an estimate for each. - For each part of the existing code, whether it is cheaper to keep or to replace, and why. - What the App Store and Google Play reviews will check: permissions, privacy declarations, accounts and anything else that commonly gets a submission rejected. **Where we have done this before:** - We inherited a live US marketplace that kept crashing on its hosting. Two months went into stabilizing it, and in four years it never had an outage. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) - A client came back after three years because their Android app could no longer be installed on current devices. It now runs on new and older phones alike. (case study 02: https://www.microtech.consulting/work/design-tokens-thirty-white-labels) - We moved a Swedish SaaS company’s marketing site onto HubSpot CMS, a platform someone else had already chosen, and built the custom forms the client had been told were not possible. (case study 17: https://www.microtech.consulting/work/hubspot-cms-custom-forms) **Questions and answers:** - Q: Will you rewrite everything? A: No. We rewrite only what blocks the launch or isn’t safe, and the review lists those parts. - Q: Web and mobile? A: Yes: React, Next.js, Node.js and React Native. - Q: App Store and Google Play submission? A: Yes. Submitting to both stores is part of the launch. - Q: How much does it cost? A: The one-week review has a fixed price. Finishing is billed by the hour, because how much is left only becomes clear in the review. - Q: What if the previous developer is still around? A: That helps. A handover conversation saves days of reading the code. It isn’t required, and most takeovers happen without one. #### Technical leadership - URL: https://www.microtech.consulting/services/technical-leadership - Stack: Architecture, roadmap, hiring, code standards in CI, written decisions, Node.js, React, AWS Hands-on technical leadership for your product and team. A Technical Lead who owns your architecture, roadmap and hiring once the product outgrows the person who started it. We led a team of twelve for four years. **Who it is for.** A company whose product has outgrown the person who started it, or a client that needs a single technical owner for the architecture, the roadmap and the team. **What we have built:** - Technical Lead on a US marketplace for four years, leading a team of twelve and owning the architecture, roadmap, hiring and client relationship. Four phases, zero outages. (case study 04: https://www.microtech.consulting/work/zero-downtime-php-to-node-migration) - Engineering standards set for each codebase and enforced in CI, and only then AI brought into the team’s daily work. The team’s throughput went up about 50%, which we estimated by comparing ticket cycle times. (case study 03: https://www.microtech.consulting/work/ai-assisted-engineering-standards) - Development lead on a construction company’s ERP with a team of four: ten modules in six months, now in production. (case study 16: https://www.microtech.consulting/work/construction-erp-workforce-planning) - Redshift chosen for a fashion supplier’s data warehouse because the client was moving every service to AWS. That kept the warehouse in the same cloud and account as everything else, maintained by the same team. (case study 13: https://www.microtech.consulting/work/query-optimization-under-fixed-schema) **Questions and answers:** - Q: Do you still write code? A: Yes. On the marketplace, the same four years as Technical Lead included designing and building an analytics layer that takes two million writes a day. - Q: Do you hire for us? A: It can be part of the role. On the marketplace, hiring sat alongside the architecture, the roadmap and the client relationship. - Q: What do you change first? A: Whatever is losing money or data. On the marketplace that meant two months of stabilization before any rewrite: adding a firewall, closing the security holes we inherited and indexing the twenty slowest queries. - Q: What would you do differently? A: We would share code sooner. There were nineteen repositories and no shared package, so one queue helper was copied into seven of them. A shared internal package should exist by the fifth service. #### Technical due diligence - URL: https://www.microtech.consulting/services/technical-due-diligence - Format: a fixed-price written assessment What’s in the codebase you’re about to buy or fund. Before you buy or fund a product, an independent written assessment tells you what its system costs to run, what it would cost to fix and which parts are sound. **Sound familiar?** - The product looks good in the demo, and nobody on your side has read the code - The cloud bill is one number that nobody can break down - The team says a rewrite is needed, or that none is, and you can’t check either claim - Only one or two people know what the system does, and they may not stay **What you get.** What the document contains: - What the system costs to run, broken down by billing meter, and how much of that comes from sizing, from faults and from the architecture. - Where the risks are: data access, secrets, authentication and anything else that would fail a security review. - A part-by-part view of what can stay and what would have to be rewritten, with the reasoning written out. - What we did not check, written down, so the document isn’t read as more than it is. **Where we have done this before:** - A national identity system in West Africa with three causes of excess cost: sizing, a fault and the architecture. None of them showed up as an error, and monthly spend fell from $24,000 to $2,000. (case study 14: https://www.microtech.consulting/work/aws-cost-reduction-eight-times) - A retail data warehouse where neither the queries nor the schema could be changed. The largest customer’s report dropped from more than 15 minutes to 0.2 seconds, and every saved customer report kept working unchanged. (case study 13: https://www.microtech.consulting/work/query-optimization-under-fixed-schema) **Questions and answers:** - Q: Have you done this for an acquisition before? A: Not under that name. The method comes from systems we joined and had to understand quickly, starting with the bill and the slowest paths. - Q: What do you need? A: Only the ability to read the code repositories and the billing data. We don’t need production data. - Q: Will the team know? A: That is your decision. It goes faster if some of their time is available to confirm what the code can’t tell us. - Q: Do you sign an NDA? A: Yes.