FAISAL AQDAS · SENIOR FRONTEND ENGINEER · FULL-STACK & AI WHEN IT SHIPS FASTER

I buildfrontendsfor enterprise,at production scale.

8 yearsshipping React & TypeScript to Mercedes-Benz, Sonova, Thalia, and TBO Clothing — multi-tenant architecture, Core Web Vitals under 2s, cache invalidation that works the first time. When the product demands it, I reach into NestJS and LLM orchestration to close the loop.

~/decommerce — missionsApi.ts
TS
LCP
1.6s
CLS
0.02
INP
94ms
Lighthouse
96
Scroll
Trusted by teams at
Mercedes-Benz
Growth Engine · 2023
Sonova
Enterprise community · 2022
Thalia
Internal engagement · 2023
TBO Clothing
Community commerce · 2023
Syngenta
Growth Engine · 2023-2025
Decommerce
Platform employer · 2022 →
0yrs
Production React & TypeScript
0+
Lighthouse across Perf / A11y / Best Practices
0%
Content production time reduction — AI automation
0+
Enterprise projects shipped to production
01 / Selected work

Products that ship. Metrics that move.

01 / 04SPEAR

Community Platform

Senior Frontend Engineer · Architecture + UI System

A production Next.js community platform launched as a white-label tenant on the Decommerce stack. Built the design system, the authenticated feed, shop, and rewards flows, mobile-web-first with sub-2s cold load on 4G. Tenant brand tokens drive every surface — colors, type, spacing, component variants — with zero duplicated code per tenant.

Next.jsTypeScriptDesign TokensRTK QueryStorybook
< 2s
Cold load on 4G enterprise mobile
1 kit
Tokens drive every tenant surface
98
Accessibility Lighthouse score
The hard part — per-tenant design config, without a refetch on every render

Every tenant ships with its own brand tokens, layout config, and feature flags. Fetching that config on each navigation would have burned latency and requests on something that changes maybe once a week. I moved the config into the Next.js server cache — tenant-scoped keys, cached indefinitely, invalidated via a tagged write path that only fires when an admin saves a change in the dashboard. Pages render instantly with the right brand on the first byte, and the cache stays honest because the write path is the only thing that can touch it.

LIVE · PRODUCTIONspear.app / feed
SPEAR community app — production feed
Real · shipped
Shared design tokens
space/4 8 12 16 24 32 48
radius/sm md lg xl full
type/xs sm base lg xl 2xl
Architecture notes
Feed: virtualized list · 60fps scroll
Shop: image-first, LCP < 1.8s
Rewards: RTK Query + tag invalidation
Auth: better-auth session cookies
White-label via CSS variables
✓ powered by Decommercemulti-tenant
02 / 04TBO

Performance Rescue

Frontend Engineer · Performance Audit + Optimization

A focused perf engagement on a fashion storefront: audit, diagnose, ship. Found LCP blown out by unoptimized hero imagery, CLS from late-arriving fonts, and render-blocking scripts killing TTI. Shipped wins in four weeks — preload critical resources, split the client bundle, fix image pipeline, eliminate layout shift. The client has since migrated to a Shopify theme; these numbers reflect the engagement.

Next.jsGatsbyWeb VitalsImage pipelineSSG
50 → 96
Lighthouse performance score
-62%
LCP on product detail pages
< 0.01
Cumulative Layout Shift after fix
The hard part — the boring wins, done carefully

No single change moved the score; a stack of unglamorous ones did. The image pipeline was serving original PNG/JPEGs at desktop dimensions to phones — I moved to responsive sources with modern formats and correct `sizes`. A pile of third-party scripts were blocking first render — audited each, deferred what could be deferred, moved the rest into `useEffect` so they never touch the critical path. Render-time was dying to expensive recomputations on every render — memoised what was hot, lifted what was stable. And because it was a Gatsby project, I pushed as much of the content pipeline as possible to build-time SSG so the browser got HTML, not a loading state. Four weeks, 50 → 96.

PERFORMANCE AUDIT · BEFORE → AFTER4-WEEK ENGAGEMENT · 2023
96
PERF
was 50
98
A11Y
was 74
100
BEST
was 85
100
SEO
was 88
Critical path · first 1.8s
document
fonts (preloaded)
hero.webp (SSG)
critical.css
paint
LCP 1.62s · CLS 0.01✓ passes
03 / 04Growth Engine

AI-powered growth platform

Full Stack Lead · Architecture + Shipping

White-label SaaS for enterprise clients across Europe. Architected the Next.js frontend, the multi-tenant theming layer, a gamified growth engine, and an AI-assisted page builder that lets non-technical editors ship branded campaign pages in minutes.

Next.jsNode.jsPostgreSQLRedisBullMQClaude APIOpenAI
87%
Cut content production time with AI-assisted authoring
9 → 0
Production incidents / quarter
27+
Enterprise tenants live on the platform
The hard part — cache granularity at tenant × campaign

A tenant can run dozens of campaigns, and each campaign owns its own design config, missions, rewards, and targeting rules. One cache key per tenant was too coarse — changing one campaign would blow the cache for every other campaign on that tenant. I keyed the Next.js server cache at `tenant:campaign` and invalidated only that exact tuple on config writes. Missions and rewards inherit the same pattern. Result: editors see their changes instantly on the campaign they touched, every other campaign keeps rendering from cache.

DASHBOARD · MULTI-TENANTdecommerce.com / growth-engine
Growth Engine admin — Digital Transformation campaign
Admin · enterprise
Mercedes-Benz Digital Transformation — mobile experience
Client · Mercedes-Benz
AI pipeline · BullMQ workers
claude.page.0xA7processing
claude.seo.0x42done
openai.img.0x91queued
Tenants
27+
AI runs/day
12.4k
Saved
87%
04 / 04Klaire

AI Onboarding Agent

Full Stack Engineer · AI Orchestration + Frontend

Enterprise clients were spending a full week setting up every new campaign on our platform — design, copy, SEO, legal docs, missions — done manually, every time. I built Klaire: an AI agent embedded directly in the platform. Client pastes a URL, Puppeteer scrapes their brand headlessly, Langbase orchestrates the pipeline, GPT-4o writes everything, a live mobile preview updates in real time. Ran in production for enterprise clients across retail, automotive, healthcare, and publishing in DE, EU, and the US.

NestJSNext.jsLangbaseGPT-4oPuppeteerTool calling
1 week → 20 min
Enterprise campaign setup time
0
Developer hours per new client onboarding
DE · EU · US
Enterprise clients live in production
The hard part — making AI reliable enough to trust without review

Connecting the tools was easy — Puppeteer, Langbase, GPT-4o, the frontend preview. The real work was making the output reliable enough that a non-technical client could finish onboarding without a developer checking every generated string. That meant strict schemas on every LLM call, tool calling for anything that touches the database, retries on malformed output, and a validation layer between the model and the UI that refuses bad data instead of rendering it. The thing I'm most proud of has nothing to do with the AI stack — it's that someone with zero technical background could open Klaire and finish in 20 minutes. Removing the need for a developer was the whole product.

AI ONBOARDING AGENT · IN PRODUCTIONdev-admin.decommerce.com
Klaire step 01 — Paste URLKlaire step 02 — Scrape + generate brandKlaire step 03 — Campaign briefKlaire step 04 — Missions authoredKlaire step 05 — SEO + launch
STEP 01Paste URL
Client starts the agent — brand detection begins
URL
01
Puppeteer
02
Langbase
03
GPT-4o
04
Live preview
05
Before
1 week
manual setup
After
20 min
client self-serve
Devs needed
0
per onboarding
What people say

Hired once, re-hired often.

Faisal rebuilt the frontend of our white-label platform while we kept shipping to enterprise clients. Zero regressions, zero production incidents in the quarter after launch. The kind of senior engineer you let own the architecture and then stop worrying about it.
Wang Xi
Engineering Lead · Decommerce
Klaire was the single biggest operational shift we've had. Client onboarding went from a week of back-and-forth with our team to twenty minutes the client does themselves. Faisal architected the whole thing — orchestration, frontend, the reliability layer — and it ran in production for enterprise clients across Europe.
Allan Perrottet
Co-founder · Decommerce
Faisal's templates on ThemeForest set the bar for the team. Clean markup, pixel-accurate, genuinely responsive when 'responsive' was still a buzzword — and every one of them sold in the hundreds to low thousands. He makes frontend look easy.
Hassan Javed
Founder & Technical Lead · AcroEx
02 / How I engineer

Senior means decisions, not just code.

01 / 05

Core Web Vitals by design

I engineer for performance from day one — not as an afterthought. SSR/SSG strategy, route-based code splitting, lazy-loading below-the-fold, preloaded critical assets, eliminated render-blocking resources. Sub-2s mobile on enterprise deployments.

LCP ≤ 2.5sCLS ≤ 0.1INP ≤ 200msLighthouse 92+
02 / 05

State with intentionality

Server state via RTK Query — auto-caching, tag-based invalidation, background refetch, optimistic updates. Local UI state close to the component with useState and useReducer. Redux Toolkit where cross-cutting concerns genuinely demand it. Lean bundles, predictable components.

RTK QueryRedux ToolkitZustanduseReducer
03 / 05

Resilient data layers

Typed API clients with Axios interceptors for auth injection and error normalisation. Request deduplication, retry with exponential backoff, response caching that prevents redundant network calls. GraphQL where clients shape data; REST where simplicity wins.

tRPCGraphQLRESTZod
04 / 05

Architecture for teams, not just today

Feature-based folder structure, strict component boundaries, shared design tokens, Storybook-driven development across multiple enterprise teams. Code a new engineer can navigate on day one — and ship to on day two.

MonorepoStorybookDesign tokensA11y WCAG 2.1 AA
05 / 05

Frontend-embedded AI that ships

I ship AI features the way I ship UI — with the same rigor. LLM orchestration (Claude, GPT-4o, Gemini) through tool calling and multi-step agent loops. Streaming into real interfaces, not chat widgets. The hard part isn't connecting the APIs — it's making the output reliable enough that a non-technical user trusts it without reviewing every result. That's where I operate.

ClaudeGPT-4oLangbaseAgent loopsTool calling
03 / Career

8 years of shipping — and rewriting it better.

Senior Frontend Engineer — Full Stack & AI at Decommerce
2022 — Present

Lead the frontend of a white-label B2B SaaS community platform shipped to enterprise clients across Europe — Mercedes-Benz, Sonova, Thalia, TBO Clothing. Built the multi-tenant design system: tokenised brand config per tenant, a Storybook-driven component library, and a theming engine that lets a new brand ship in hours. Architected the Next.js frontend with per-tenant × per-campaign server caching, feed/shop/rewards flows at sub-2s cold load, and the white-labelling layer. Built the operator UI for the AI Page Builder (Claude/GPT-4o), the authoring surface for Visual Micro-Apps, and the dashboards for the outbound AI-call automation. Reached into NestJS, BullMQ, and the cache invalidation layer whenever the frontend needed the backend to move with it. Cut content production time by 87%; drove production incidents from 9/quarter to zero.

Next.jsReactTypeScriptStorybookRTK QueryNestJSRedisBullMQClaudeGPT-4o
Senior React Developer at ComOn Enterprise LLC
2021 — 2022
Frontend Lead — React Native & AR at Smart Reality
2018 — 2020
Frontend Developer at AcroEx
2016 — 2018
04 / Playground

The code, live.

usersApi.tsRTK Query · TS
// server state as a first-class citizen
export const usersApi = createApi({
  reducerPath: 'usersApi',
  baseQuery: authedBaseQuery('/api'),
  tagTypes: ['Users'],
  endpoints: (build) => ({
    listUsers: build.query<User[], void>({
      query: () => '/users',
      providesTags: ['Users'],
      keepUnusedDataFor: 8,
    }),
  }),
});

const { data, isFetching, refetch } = useListUsersQuery();
// auto cache · tag invalidation · typed errors
previewattempt #0 · cache hits 0
Statusidle
Sourcenetwork
Records
What's actually happening↓ try each button, watch the state
  1. 01
    Refetch network

    Forces a round-trip. 700ms of simulated latency, then the cache is refreshed with the new payload and the timestamp resets.

  2. 02
    Use cache instant · 0 ms

    If the cache is fresh (< 8s old), we return the cached payload synchronously — no loading state, no network. This is the whole point.

  3. 03
    Simulate error retry · 800ms backoff

    60% chance of a failed request. The UI enters error state, then a retry fires with backoff — exactly the pattern production APIs need.

  4. 04
    Invalidate tag-based

    Manually blows the cache — the moment the data you trusted is no longer true (a write, a mutation, a session change). In RTK Query this is a tag invalidation; here it's a ref reset.

This is the same pattern I use in Next.js server cache at tenant:campaign granularity — reads are O(1), the write path is the only source of staleness. More on that in Notes.
05 / Notes

How I think about the work.

01 / 022024 · essay

Cache invalidation is a product decision, not a technical one

Notes from three years of multi-tenant platforms

Every multi-tenant platform I've shipped comes back to the same question: how fine-grained does your cache need to be? Get it wrong in either direction and the product tells on you.

Too coarse — `cache per tenant` — and one admin editing a single campaign nukes the cached pages for every other campaign they own. The editor sees an instant update. Every other editor on the tenant sees a cold render they did not cause.

Too granular — `cache per page per tenant per user` — and you haven't really cached anything. You've just paid for Redis.

The answer is almost never technical. It is: what is the smallest unit of content an editor actually edits? For SPEAR, it was the tenant design config. For Growth Engine, it was the `tenant:campaign` tuple. That tuple becomes the cache key, and the only path that invalidates it is the save endpoint in the admin.

Two properties fall out of this: writes are the only source of staleness (reads are pure), and reads stay O(1) on a warm cache. Editors see their own changes instantly. Everyone else sees the cached page until the moment an edit they care about lands.

That's the whole trick. Pick the right key, put the invalidation on the write path, and stop touching it.

Faisal Aqdas
02 / 022025 · essay

The hard part of AI automation isn't connecting the tools

Notes from a B2B outbound pipeline running 6,316 executions a week

A few months ago I built a fully automated B2B outbound pipeline in n8n. Input: a company name in a Google Sheet. Output: a personalised email draft sitting in Gmail, ready for a human to glance at and send. Zero manual work in between.

The pipeline runs six connected workflows. Apollo finds the right contact. Claude scores the matches and picks the target. PhantomBuster scrapes LinkedIn activity. Google Custom Search pulls public signals. Claude builds an intelligence profile, drafts a cold email, and writes the Gmail draft. A second workflow handles follow-ups — day two tries a Vapi AI phone call first and only falls back to email if unanswered, day five sends a concise second touch. A third polls Gmail every minute, classifies replies, updates the sheet. A fourth deduplicates so no lead ever gets emailed twice.

None of that is the hard part. Connecting APIs is plumbing. n8n makes plumbing trivial.

The hard part is making AI decisions reliable enough to trust without checking every single output. A classifier that's 92% accurate sounds great until you realise that 8% failure rate means dozens of bad labels a week on a pipeline doing thousands of runs. An LLM-written email that's good 19 times out of 20 still embarrasses you on the twentieth if nobody reads it.

The answer isn't one trick, it's a layered one. Strict schemas on every LLM output so bad data fails loud instead of silent. Tool calling for anything that touches a database, so the model proposes and the code disposes. Validation gates between stages that refuse to move forward on malformed input. And one human-in-the-loop checkpoint at the point of irreversibility — the Gmail send button — because that's the exact place where a human's skim costs you seconds and catches the 5% the model got wrong.

Self-hosted on GCP, because cloud n8n hits limits fast on a pipeline moving this much volume. 6,316 executions in a week. Instead of a rep reaching five qualified leads a day, the system reaches a hundred.

That's the real engineering problem in AI automation: not whether the model can do the task, but how you build a system that catches the model when it can't.

Faisal Aqdas
more notes on request
05 / Let's talk

Send me the hardest
frontend problem your team is facing.

I'll reply within a day with how I'd approach it — paid engagement or not. If it's a fit for both of us, we go deeper. If it's not, you'll still have a second opinion on a hard problem.

StatusAvailable immediately
My local time · PKT--:--· off hours
Your local time--:--
Typical responseWithin 24 hours
Best fit
  • Senior / Staff Frontend roles
  • React · Next.js · TypeScript at production scale
  • Design system & multi-tenant architecture
  • AI-frontend — LLMs embedded in real UI, not chat widgets
  • Performance rescues — Core Web Vitals under 2s
  • Remote · async · European time overlap
×Not a fit
  • Junior or mid-level roles
  • WordPress / pure templating work
  • Crypto, web3, gambling, adtech
  • Unpaid trials or spec work
  • On-site only · no remote option
  • Agency-style body-shopping contracts
If we move forward · the first weekNo mystery, no ghosting.
Day 0–1
I reply
With a take on your problem and a link to a 30-min intro slot.
Day 2–3
Intro call
Your stack, team, and hardest constraint. Short, sharp, no sales-y anything.
Day 4–7
Trial or scoped engagement
A paid day-rate pilot, architecture review, or straight offer — whatever fits your process.
Prefer a form?
Same 24-hour reply. Use whichever is easier for you.
Still here?
Send the email. Say what you're building, who's on the team, and the one thing that's blocking you this quarter. I'll read it properly, reply within a day, and either help or point you to someone who can.
— faisal