Skip to content

Hi, my name is

Anas Rezk.

Senior Full-Stack Engineer. React, React Native, and Angular — systems that ship across mobile, admin, and the pipeline between them.

Berlin, Germany

zsh

$ whoami

anas rezk — senior full-stack engineer · berlin

$ cat ./stack

react native · angular · typescript · react

01 About

I'm a Senior Full-Stack Engineer with 8+ years of experience across startups and international teams, building production systems rather than just interfaces — mobile apps talking to hardware, admin panels driving real operations, and the release pipelines that get both into people's hands.

I spent four years at Tourlane, where I owned a company-wide design system and led the migration from Create React App to Vite. Before and alongside that, I've built products at WeatherPromise and Basharsoft — and since 2021 I've been architecting and building Dinex, a restaurant POS with a React Native floor app and an Angular admin panel, from hardware integration down to the TestFlight pipeline that ships it.

Core stack:

  • TypeScript
  • React
  • React Native
  • Redux Toolkit
  • Angular
  • Next.js
  • Vite
  • Tailwind CSS
  • Storybook
  • Cypress

02 Selected Work

Tourlane · 2023

Migrating Tourlane from CRA to Vite

Senior Frontend Engineer

Cut build times roughly in half and tightened dev feedback loops by moving a large production React app off Create React App onto Vite.

Problem

Tourlane’s main customer-facing app had outgrown Create React App. Cold builds and CI pipelines were slow, local dev startup lagged, and Webpack’s HMR had grown unpredictable on a codebase of this size — every change cost the team seconds of waiting that added up across dozens of engineers, many times a day.

Options weighed

I evaluated three realistic paths: stay on CRA and tune Webpack (lowest risk, lowest ceiling); migrate to Next.js (powerful, but a heavier architectural shift than the app needed and a larger blast radius); or adopt Vite (esbuild-powered dev server, Rollup production builds, minimal config). I prototyped the Vite path against the real app to validate the build output and dev experience before committing.

Tradeoff

Vite meant trading CRA’s batteries-included familiarity for an explicit, configure-it-yourself setup — plugins, env handling, and a handful of CRA-specific assumptions to unwind. The bet was that a one-time migration cost would pay back continuously in faster builds and a sharper feedback loop, without forcing the broader framework change a Next.js move would have required.

Outcome

Build times dropped by roughly 50% and local dev startup became near-instant, visibly tightening the feedback loop for the whole frontend team. The migration shipped incrementally with no disruption to feature delivery, and the leaner config lowered the day-to-day cost of working in the codebase.

  • Vite
  • React
  • TypeScript
  • esbuild

Dinex · 2021 — present

Dinex — one POS, two frameworks, one system

Architect & Lead Engineer

Dinex is a restaurant POS built as two coordinated apps — a React Native/Redux Toolkit floor app that drives ESC/POS thermal printers, and an Angular admin panel — independently monitored with Sentry and shipped through a dual-environment TestFlight pipeline.

Problem

Restaurant staff need a floor app that takes orders, routes them to the kitchen, and prints receipts and tickets without getting in the way during a full service. The business side needs a separate admin surface for menu, staff, branches, and reporting. Both have to work against the same backend without drifting into inconsistent behavior, duplicated logic, or two different definitions of what an order is.

System

Architecture diagram: React Native app with Redux Toolkit and RTK Query connects to a shared Dinex API and to an ESC/POS thermal printer; Angular admin panel with NgRx migrating to Signals and reactive forms also connects to the shared API; Sentry monitors both the mobile app and the admin panel independently

Options weighed

For the floor app, native performance and direct access to the Epson ESC/POS SDK mattered more than sharing code with the admin side, so it’s React Native and Expo rather than one framework stretched across a POS terminal and a back-office panel. For state, ad hoc Context/hooks stopped scaling once auth, the active order, printer status, and menu data were all interacting; Redux Toolkit plus roughly a dozen RTK Query endpoints replaced that with one predictable state shape.

The admin panel predates current Angular best practice. Rather than a big-bang rewrite, it’s migrating incrementally: some slices are still classic NgRx (reducers, effects, entity adapters), most forms are still ReactiveFormsModule, and newer state — like the menu-items store — is built with @ngrx/signals and computed() selectors. Each generation gets touched and modernized as its screens get real work, not on a schedule.

Tradeoff

Two frameworks means two dependency trees and two release pipelines with nothing shared out of the box — error reporting, environment config, and printing conventions have to be deliberately kept consistent rather than inherited from a shared package. The incremental Angular migration has its own cost: onboarding means reading both the NgRx-and-reactive-forms era and the Signals era in the same codebase. The payoff on both counts is that neither app was ever blocked waiting on a rewrite to ship features.

Outcome

Both apps are independently instrumented with Sentry rather than sharing one monitoring setup — environment-gated tracing and session replay on the mobile side (full sampling only in production, to keep noise and cost down in dev), and tracing, replay, and a custom error handler on the Angular side that recovers from stale-deployment chunk-load errors before reporting anything.

Releases go through a dual-environment pipeline — a testing build with its own bundle identifier and its own API host, validated by internal testers before a separately configured production build ever gets promoted:

State diagram: source branch builds with a testing profile, ships to TestFlight internal testers for QA validation; on pass, a separate production profile is built and promoted through TestFlight and the App Store to release; on fail, control loops back to source for a fix and rebuild

Two production bugs are representative of the hardware-adjacent work on the floor app. A hung native print call had no timeout, so a stuck job could freeze the print screen indefinitely. The native bridge call to the printer SDK doesn’t reliably reject on its own, so the fix is a bounded timeout per batch and per invoice, plus a generation guard so a late callback from an already-timed-out batch can’t corrupt the next one (representative shape, not the literal source):

// InvoicePrinter.tsx — simplified
let batchGeneration = 0;

async function printBatch(invoices: Invoice[]) {
  const generation = ++batchGeneration;
  const timeoutMs = Math.max(
    MIN_PRINT_BATCH_TIMEOUT_MS,
    invoices.length * PRINT_TIMEOUT_MS_PER_INVOICE,
  );

  return Promise.race([
    printAllInvoices(invoices),
    new Promise((_, reject) =>
      setTimeout(() => reject(new PrintTimeoutError()), timeoutMs),
    ),
  ]).finally(() => {
    // A callback from a superseded batch must not touch current state.
    if (generation !== batchGeneration) return;
  });
}

Separately, receipts printed at the wrong size on printer models that didn’t match the original hardware, because the image width handed to the printer’s addImage() call was hardcoded — fixed by making paper width a configurable setting instead of a constant.

  • React Native
  • Expo
  • Redux Toolkit
  • Angular
  • Sentry

Dinex · 2022 — present

Printing Arabic receipts around an SDK encoding gap

Architect & Lead Engineer

The Epson ESC/POS SDK has no Unicode support — sending Arabic text produces garbled output. I worked around it by rendering each receipt as a hidden React Native view, capturing it as a PNG, and sending the image to the printer instead of text bytes.

Problem

Dinex serves Arabic-speaking markets, so every receipt needs correct Arabic text — right-to-left layout, proper character shaping, diacritics. The thermal printer SDK (react-native-esc-pos-printer) communicates in raw ESC/POS byte sequences, which have no Unicode or Arabic encoding support. Piping Arabic strings through it produced garbled characters on every test print. A missing feature in the SDK was blocking a shipping requirement.

Flow

Sequence diagram: app creates order, server returns object, parallel fetch of templates and printer config, ViewShot captures hidden receipt views as PNG, Epson printer receives image bytes, cleanup

Options weighed

The first option was to find an alternative SDK with Arabic support. Nothing existed at the time that matched the Epson hardware and React Native — and swapping SDKs would have been a large, risky migration with no guarantee of success.

The second option was to manually rasterise Arabic glyphs into bitmap tiles and compose them into an ESC/POS image command. Technically possible, but it required maintaining a custom font renderer, handling every font size and weight independently, and was brittle against future template changes.

The third option was to invert the approach entirely: render the receipt as a real React Native component (which uses the OS’s native text engine, so Arabic shaping and RTL work correctly), capture it as a PNG with react-native-view-shot, and send the image bytes via addImage() rather than text commands. The printer receives a raster image — it never has to interpret a character.

Tradeoff

The image path adds a render-and-capture step before each print job, and the captured PNGs have to be explicitly released after printing to avoid accumulating file handles. It also means the receipt is a fixed raster — the printer can’t reflow or query the text. The upside is complete fidelity: any React Native component renders correctly, Arabic or otherwise, with no separate encoding path and no per-glyph maintenance. Multiple receipts capture in parallel (one ViewShot per printer job), so the latency cost stays flat as job count grows.

Outcome

Receipts print with correct Arabic text, proper RTL margins, and consistent branding on every supported Epson model. English and Arabic share one rendering pipeline with no separate code paths — switching languages changes the direction prop on the template component and nothing else. A useImageCleanup hook registers each captured URI and calls releaseCapture() after every job, whether it succeeds or fails, so memory stays clean across high-volume shifts.

  • React Native
  • Expo
  • react-native-view-shot
  • ESC/POS

Tourlane · 2021 — 2023

Owning a company-wide design system

Senior Frontend Engineer

Built and owned the shared component library that brought UI consistency to 5+ applications across Tourlane's frontend organization.

Problem

Tourlane’s frontend had grown into multiple applications, each reinventing buttons, inputs, and layout primitives in slightly different ways. The drift showed up as inconsistent UI for customers and duplicated effort for engineers, with no shared source of truth for components or design decisions.

Options weighed

The choices were to keep copying patterns between apps (cheap now, expensive forever), adopt a third-party UI kit (fast, but a poor fit for Tourlane’s brand and bespoke flows), or build an in-house design system tailored to the product. I went with an owned system: React components in TypeScript, styled with CSS-in-JS for co-located theming, and documented in Storybook as living, testable documentation.

Tradeoff

An in-house system is a real ongoing investment — it needs versioning, an adoption path, and an owner who fields requests and guards consistency. The payoff is a single source of truth that fits the product exactly and removes the per-app reinvention tax, which justified the maintenance commitment.

Outcome

The design system became the shared UI foundation across 5+ applications, giving customers a consistent experience and giving engineers a documented, reusable toolkit instead of one-off components. Owning it end to end — API design, accessibility, docs, and rollout — made it a backbone of the frontend org rather than just another package.

  • React
  • TypeScript
  • CSS-in-JS
  • Storybook

03 Get in touch

I'm currently open to senior full-stack opportunities in Berlin. If you think we might be a good fit — or you just want to talk shop — my inbox is open.