<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Archivo:wght@400;500;600;700&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500&display=swap"> Skip to content
  • INITIALIZING SYSTEMOK
  • LOADING PROJECTSOK
  • LOADING ARCHITECTUREOK
  • VERIFYING EXPERIENCEOK
  • SYSTEM ONLINE

BUILT TO SHIP.BUILT TO SCALE. BUILT TO PROVE IT.

AI-powered SaaS and full-stack product engineering — from architecture to production.

AI-Powered SaaS & Full-Stack Product Engineer · Remote · India · UTC+05:30

This page, measuredPENDING
Time to first byte
measuring…
DOM interactive
measuring…
JavaScript transferred
measuring…
Render strategy
prerendered

Zoneless change detection — zone.js is not in the bundle

Statically prerendered, hydrated incrementally on viewport

No animation library: CSS keyframes and one rAF loop

Motion, contrast and keyboard paths all honoured

Scroll — evidence follows
01Proof

Numbers, not adjectives.

Anyone can claim they are experienced. These are the countable parts of the record — maintained in one configuration file, and each one is something I can walk you through in detail on a call.
01
15+
Projects shipped
Concept → production
02
06
AI systems
RAG, semantic search, agents
03
08
Production systems
Live, monitored, maintained
04
20+
Technologies
Used in anger, not in tutorials
05
24+
Experiments
Prototypes in the lab

Counters animate on first view only. Values render server-side, so they are correct before any JavaScript runs.

02Builds

Case files, not screenshots.

Each build is documented the way an engineer would want it documented: the problem, the architecture, the decisions worth defending, what went wrong, and what was traded away to make it work.

Problem

Recruiters were reading every resume by hand. Keyword filters were the only automation available, and keyword filters fail exactly where it matters: a "React engineer" never matches a CV that says "built SPAs in Next.js". Screening a single role meant hours of linear reading, and good candidates were being rejected by string matching.

Solution

A recruitment platform that reads job descriptions and resumes as meaning rather than text. Documents are parsed, chunked and embedded into a vector store; candidate matching is a retrieval problem, not a filter problem. On top of retrieval, an LLM produces a structured analysis per candidate — strengths, gaps, and evidence quoted from the resume — so a recruiter reviews reasoning instead of raw documents.

Key engineering decisions

  1. 01Retrieval before generation, alwaysThe LLM never sees a full resume corpus. Vector search narrows to a small candidate set first, and only that set is expanded into a prompt. This caps token cost per request at a predictable ceiling and keeps the model grounded in retrieved text instead of improvising.
  2. 02A separate Python service instead of Node bindingsThe AI work belongs where its ecosystem lives. Isolating it behind an HTTP boundary means the model layer can be redeployed, rate-limited and scaled independently of the CRUD services — and a slow embedding job cannot starve the Node event loop.
  3. 03Embedding as an idempotent background jobUploads return immediately with a document ID. Parsing and embedding run through a queue, keyed by content hash, so a retry never produces duplicate vectors and a failed batch resumes rather than restarts.
  4. 04Structured output, not free textCandidate analysis is requested as a strict schema and validated on arrival. Anything that fails validation is retried once and then degraded to retrieval-only results — the UI shows matches without commentary rather than showing something malformed.

Challenges

  • Resumes are hostile documentsTwo-column PDFs, tables, images of text, and inconsistent section headers. Naive extraction interleaves columns and produces nonsense chunks. Layout-aware extraction with a per-format fallback chain fixed the majority; anything below a confidence threshold is flagged for manual review rather than silently indexed badly.
  • Semantic match is not the same as a good matchPure cosine similarity happily ranks a senior architect and a junior with the same vocabulary as near-identical. Retrieval had to be combined with hard structural filters — years of experience, location, work authorisation — applied before ranking, not after.

Trade-offs

  • A managed LLM API over A self-hosted open-weights modelQuality per unit of engineering time was decisive at this stage. The generation layer sits behind an interface, so moving it in-house later is a swap, not a rewrite.
  • Qdrant as a dedicated vector store over pgvector inside the existing PostgreSQLPayload filtering combined with ANN search at this corpus size is where pgvector starts to strain. The cost is one more system to operate.

Outcome

  • Screening moved from linear reading to reviewing a ranked, explained shortlist.
  • Matching survives vocabulary mismatch — the failure mode keyword filters could never fix.
  • The AI layer is replaceable: retrieval, ranking and generation are three separate seams.

Problem

Operations teams were finding out about incidents from users. Data existed, but it lived in per-service logs with no shared timeline, no shared vocabulary, and no way to ask "what changed in the last ten minutes" across the whole estate.

Solution

An ingest-and-observe platform: agents push metrics and events over a single authenticated channel, the backend normalises them into a shared schema, and dashboards subscribe to live streams rather than polling. Alert rules evaluate on the ingest path so detection happens before a human opens a tab.

Key engineering decisions

  1. 01Redis pub/sub between ingest and the socket layerIngest nodes and socket nodes scale on different curves. Decoupling them through pub/sub means a dashboard connection is never pinned to the node that received the data, and either side can be redeployed without dropping the other.
  2. 02Rollups written on ingest, not computed on readDashboards ask for minute, hour and day granularity constantly. Pre-aggregating on the write path turns an expensive scan into a point read, and bounds the cost of a dashboard that someone leaves open on a wall display.
  3. 03Tenant isolation enforced at the query layerEvery read goes through a repository that requires a tenant context — there is no code path that can construct a cross-tenant query, because the unscoped query function does not exist.
  4. 04Backpressure over bufferingWhen ingest saturates, agents are told to slow down and batch harder. An unbounded in-memory buffer converts a traffic spike into an out-of-memory crash; explicit backpressure converts it into slightly stale graphs.

Challenges

  • Reconnect stormsA deploy disconnects every dashboard at once, and every client retries at once. Jittered exponential backoff plus resumable subscriptions turned a synchronised thundering herd into a spread-out reconnection curve.
  • Charts that fight the browserA live chart naively re-rendering on every message will pin a CPU core. Rendering is decoupled from data arrival — messages update a buffer, and a single animation-frame loop draws whatever the buffer holds.

Trade-offs

  • WebSockets over Server-sent events or pollingThe channel is genuinely bidirectional — clients subscribe, unsubscribe and acknowledge. SSE would have needed a second channel back.
  • Rollups at write time over Query-time aggregationRead volume dominates by a wide margin. The cost is that changing a rollup definition means a backfill.

Outcome

  • Detection moved ahead of user reports — alerts fire on the ingest path.
  • One timeline across services replaced per-service log spelunking.
  • Ingest and realtime scale independently; neither blocks the other.

Problem

A growing SaaS had four kinds of user — super admin, admin, analyst, viewer — and permission logic scattered across every service. Adding a role meant touching every service, quota rules lived in application code, and nobody could answer "who changed this and when" without reading logs.

Solution

A control plane that owns identity, roles, quotas and audit as a first-class concern. The gateway resolves a caller to a role and an allow-list of routes before a request reaches any service; quota accounting runs on the same hop, so limits are enforced once instead of re-implemented per service.

Key engineering decisions

  1. 01Route allow-lists per role, declared as dataEach role owns a manifest of the routes it may reach. Authorisation becomes a lookup against a declaration rather than a chain of conditionals spread across services — and a permissions review means reading one file per role.
  2. 02Quota counters in Redis, reconciled to PostgreSQLIncrement-and-check has to be fast and atomic on every request; durable accounting has to be exact. Redis handles the hot path, and a periodic reconciliation writes authoritative usage to PostgreSQL.
  3. 03Deny by defaultA route that is not in a role manifest is refused. New endpoints are invisible until explicitly granted, which makes the dangerous failure mode — accidental exposure — impossible by construction.
  4. 04Audit as an append-only streamEvery mutation writes an immutable record with actor, tenant, before and after. Writes are fire-and-forget onto a queue so audit can never add latency to, or fail, the operation it describes.

Challenges

  • Quota limits that must not double-count on retryA client retry after a timeout would otherwise burn quota twice. Requests carry an idempotency key and the counter increments once per key, so a retried request is accounted exactly once.
  • Role changes taking effect immediatelyCached claims make authorisation fast but make revocation slow. A short-lived token plus a revocation channel means a downgraded user loses access in seconds, not at token expiry.

Trade-offs

  • Centralised authorisation at the gateway over Per-service authorisation middlewareOne place to reason about, one place to audit. The cost is that the gateway becomes a component that must not fail — so it is stateless and horizontally replicated.

Outcome

  • Adding a role is a manifest change, not a cross-service refactor.
  • Quota enforcement happens once, at the edge, with idempotent accounting.
  • Every privileged mutation is attributable to an actor and a tenant.

Problem

Institutional knowledge was spread across contracts, specifications and reports that nobody could search meaningfully. Full-text search returned documents; people needed answers, and they needed to see where the answer came from before they would trust it.

Solution

A workspace where a corpus is ingested once and queried conversationally. Every generated sentence carries a citation back to the source chunk, and the UI puts the retrieved passage next to the answer. When retrieval confidence is low, the system says it does not know rather than filling the gap.

Key engineering decisions

  1. 01Hybrid retrieval instead of pure vector searchDense vectors miss exact identifiers — clause numbers, part codes, names. Lexical search misses paraphrase. Running both and fusing the ranked lists covers each method's blind spot.
  2. 02Citations are structural, not requested politelyChunks enter the prompt with stable IDs and the response schema requires them. A sentence without a resolvable citation is dropped before it reaches the UI.
  3. 03An explicit abstain pathBelow a retrieval score threshold the system returns "no supported answer found" with the closest passages. A confident wrong answer costs more trust than an honest gap.
  4. 04Streamed responsesTime to first token matters more than total time for perceived speed. Tokens stream as they arrive, and citations resolve progressively behind them.

Challenges

  • Chunk boundaries destroy meaningA fixed-size split routinely cuts a definition away from the term it defines. Splitting on structure first — headings, clauses, paragraphs — and only then enforcing a size ceiling preserved far more retrievable units.
  • Re-ingesting a changed documentNaive re-ingest leaves stale vectors behind and duplicates the rest. Chunks are keyed by content hash, so re-ingest is a set difference: add what is new, delete what is gone, keep what is unchanged.

Trade-offs

  • Reranking every query over Trusting first-pass ANN orderAnswer quality is the product. The extra hop costs latency, so it runs only over a small top-k window.
  • Abstaining when unsure over Always producing an answerA tool people stop trusting is worse than a tool that occasionally says no.

Outcome

  • Answers arrive with the passage they came from, side by side.
  • Re-ingest is incremental — changed documents cost proportional work.
  • The system declines to answer rather than inventing one.

Client work under NDA is shown in a live walkthrough rather than published here.

03Systems

Architecture, explained.

Drawing boxes is easy. Defending them is the job. Every component below carries the reasoning behind it — why it exists, what it was chosen over, how it behaves under load, and what happens when it goes down.

The shape most product work converges on: one edge, independently deployable services, a durable core and an async spine.

  1. CLIENT
  2. EDGE
  3. SERVICES
  4. CORE
  5. ASYNC

Select any component to see the reasoning behind it.

Componentauthn · routing · limits

API Gateway

Why it exists
One front door. Terminates auth, resolves the caller to a role, applies rate limits and quota, then dispatches to the right service.
Why this choice
A thin Node service rather than a heavyweight gateway product — the routing rules are declarative data, and keeping it in-process makes auth changes a single deploy.
Problem it solves
Stops authorisation logic being reimplemented — and subtly diverging — inside every downstream service.
Under scale
Stateless by design, so it scales horizontally behind a load balancer. Session state lives in Redis, never in the process.
When it fails
It is on the critical path, so it must be replicated: at least two instances, health-checked, with the balancer removing unhealthy nodes automatically.
Engineering breakdown Redis Queues vs Direct API Processing 5 min read Read article
04Scale Lab

What happens when it grows?

The same product at five different loads. Every step adds a component, and every component is there because something specific broke without it. Architecture built for a million users on day one is a way of running out of money before user one hundred.
Load2 / 5
Operational cost5 components
1,000 usersReference topology
  1. CDNNEWstatic + assets
  2. Load BalancerNEWhealth checks
  3. APIinstance 1
    APINEWinstance 2
  4. RedisNEWsessions · hot reads
  5. Databasemanaged · PITR

Add a cache and a second instance. Stop being a single point of failure.

What changes at this tier

  • Second API instance behind a load balancer — deploys stop being outages.
  • Sessions moved out of process memory into Redis, which is what makes instance two possible.
  • Hot reads cached with explicit TTLs.
  • Static assets served from a CDN instead of the origin.

The bottleneck

A single process was both a capacity ceiling and a restart-shaped outage. Statelessness, not raw capacity, is what this tier buys.

What it costs you

Cache invalidation now exists as a category of bug. Every cached value needs an owner and a TTL.

Design targets

API instances
2
Cache hit target
> 70% on hot reads
Deploy
rolling, zero downtime
Ops surface
5 components

A reference progression, not a report from one specific system. Real sizing comes from measuring your traffic, not from a chart.

Engineering breakdown How to Scale a Node.js API from 100 to 1M Requests 6 min read Read article
05Reliability

The happy path is the easy part.

Anyone can build software that works when everything works. Pick a failure below and watch how the architecture is supposed to respond — detection, degradation, recovery, and what the user sees while it happens.
System health ALL SYSTEMS NOMINAL
  • APIgateway · 3 instancesOperational
  • Databaseprimary + replicaOperational
  • Authenticationtokens · claims cacheOperational
  • AI Pipelineretrieval + generationOperational
  • Queuedurable · DLQOperational
  • Deploymentrolling · health-gatedOperational

Incident timeline

  1. FAILURE
  2. DETECTION
  3. FALLBACK
  4. RECOVERY
  5. STABLE

No active incident. Every service is reporting healthy — inject a failure to see the system respond.

Inject a failure

ops.log0 lines

Waiting for an incident. Select a failure to begin.

Simulation of a reference architecture — not a feed from a production system. The behaviour shown is the designed response, and it is the same response I write runbooks for.

Engineering breakdown What Happens When Your Database Goes Down? 4 min read Read article
06Failure Lab

What happens when it breaks?

Every one of these will happen to a production system eventually. The difference between an incident and an outage is whether the answer was written down before it did.

Response chain

  1. FAILURE

    Primary stops accepting connections.

  2. DETECTION

    Pool health check fails ×2. Circuit opens.

  3. FALLBACK

    Read-only mode. Writes buffered to queue.

  4. RECOVERY

    Replica promoted. Connections re-established.

  5. STABLE

    Buffered writes replayed idempotently.

How it is detected
Connection pool health check fails twice in a row — under two seconds, well before a user-visible timeout.
What absorbs it
The API flips to read-only mode: cached reads are served with an explicit staleness marker, and writes are accepted into the queue rather than rejected.
How it recovers
Failover promotes the replica. The queue replays buffered writes in order, and idempotency keys make replay safe.
Blast radius
Writes stop. Cached reads continue. Authentication survives on already-issued tokens.
What the user sees
The product becomes read-only and says so. Work in progress is held client-side, not discarded.

Degrade on purpose, or collapse by accident.

Engineering breakdown How to Handle Third-Party API Failures 5 min read Read article
07Delivery

Fast is not rushed. Fast is less friction.

Speed does not come from typing quickly. It comes from deciding the expensive things early, deploying from week one, and refusing to build what nobody asked for.

01 — Day 0

Idea

We establish what the thing actually is, in one sentence, and who it is for. Most of this conversation is subtraction — deciding what the first version does not do.

What you get

A one-page problem statement and a named first user.

What you see

A written summary of your idea, reflected back precisely enough that you can tell whether I understood it.

08AI Lab

AI as a subsystem, not a wrapper.

Three working demonstrations. The retrieval below is real — TF-IDF vectors and cosine similarity, computed on your device over a small corpus, with no network call and no artificial delay.
  1. Document

    corpus

  2. Chunking

    structural

  3. Vectors

    weighted

  4. Index

    searchable

  5. Retrieval

    cosine k

  6. Grounding

    cited

  7. Answer

    sourced

Try one

Corpus
16 documents
Similarity
cosine, TF-IDF weighted
Network calls
0

Ask a question and the pipeline runs end to end: the query is tokenised and weighted, compared against every document vector, and the closest passages are returned with their scores.

Engineering breakdown How Production RAG Systems Actually Work 5 min read Read article
09Process

No surprises. Ever.

The technical risk in a project is usually smaller than the communication risk. Here is exactly what happens, what you receive at each step, and how you can tell whether things are on track without having to ask.
  1. 01

    Discover

    • Problem statement
    • Scoped flow list
    • Explicit out-of-scope list
    • Fixed-price or time-boxed estimate
    You see
    A written scope you can push back on before any money moves.
    Communication
    One call, then everything in writing. If it is not written down, it is not agreed.
    Tracking
    Scope document, version-controlled, with a changelog.
  2. 02

    Architect

    • Architecture diagram
    • Database schema
    • API contract
    • Decision record with alternatives
    You see
    The system on one page, before it exists.
    Communication
    A walkthrough call. You do not need to be technical — you need to be able to ask "what happens if this breaks" and get a real answer.
    Tracking
    Diagrams and decision records in the repository, next to the code they describe.
  3. 03

    Build

    • Vertical slices, each shippable
    • Reviewed pull requests
    • Always-current staging environment
    You see
    A staging URL that updates as work lands, plus a weekly written update.
    Communication
    Async by default: written updates, a shared channel for questions, and a scheduled call only when a decision needs one.
    Tracking
    Milestones on a board. Every task links to the commit and the pull request that closed it.
  4. 04

    Test

    • Automated tests in CI
    • Manual pass on critical flows
    • Load check on the hot paths
    • Failure-path verification
    You see
    Green CI on every pull request, and a test plan for your critical flows.
    Communication
    Bugs triaged into blocking, scheduled, or acknowledged-and-parked, in the open.
    Tracking
    A single bug list. Nothing is fixed quietly and nothing is hidden.
  5. 05

    Deploy

    • CI/CD pipeline
    • Health checks and alerts
    • Rollback path
    • Runbook
    You see
    A production URL, a deploy history, and a written answer to "what do we do at 2am".
    Communication
    A launch checklist agreed in advance. No surprise launches.
    Tracking
    Tagged releases with notes. Every deploy is traceable to a commit.
  6. 06

    Improve

    • Usage and error dashboards
    • Prioritised backlog
    • Handover documentation
    • Support window
    You see
    What users actually do, what is failing, and what to build next.
    Communication
    A monthly review while support is active. Handover includes a live session, not just documents.
    Tracking
    Everything stays in your repository and your accounts. You own it from day one.
09.1Working agreement
Git workflow
Trunk-based with short-lived feature branches. Conventional commits, squash merges, protected main, and a pull request for every change — including mine.
Milestones
Payment tied to shipped milestones rather than hours. Each milestone has a written definition of done agreed before work starts.
Testing
Automated coverage concentrated on money, permissions, data integrity and failure paths. CI blocks the merge, not the conversation.
Deployment
Pipeline configured in week one. Staging mirrors production. Rolling, health-gated releases with a rehearsed rollback.
Documentation
README that gets a new developer running in under ten minutes, architecture decision records, an API reference, and a runbook for the failure cases.
Handover
Your repositories, your cloud accounts, your domains — from day one, not at the end. Handover is a live walkthrough plus written documentation.
Post-launch
A defined support window after launch for defects, at no extra cost. Beyond that, a retainer or ad-hoc, your choice — stated up front.
Communication
Async-first, in writing, in a shared channel. Weekly written update every week without being asked. Bad news travels fastest.
10Technology

Tools, with reasons.

Not a logo wall. Every item below is something I have used in production and can defend in a technical conversation — including where it is the wrong choice.

Frontend

Interfaces that stay fast as they grow complicated.

Angular
Primary framework — signals, standalone components, zoneless change detection
React
Where a project or team already lives there
TypeScript
Strict mode, everywhere, no exceptions
Tailwind CSS
Design systems that survive more than one contributor
RxJS
Streams, realtime channels, and coordinated async

Backend

Services with clear boundaries and honest failure behaviour.

Node.js
Primary runtime for I/O-bound services
Express
HTTP layer, gateways, middleware pipelines
FastAPI
Python services, especially anything model-adjacent
REST + WebSockets
Request/response where it fits, streaming where it does not
JWT / RBAC
Authentication and role-based authorisation at the edge

Data

Storage chosen for the access pattern, not for familiarity.

PostgreSQL
System of record — relational data with real constraints
MongoDB
Document-shaped data with genuinely variable schemas
Redis
Cache, sessions, atomic counters, pub/sub
Qdrant
Vector search with payload filtering
Schema design
Indexing, partitioning, migrations that run without downtime

AI

AI as an engineered subsystem, not a wrapper around a prompt.

RAG pipelines
Extraction, chunking, embedding, retrieval, reranking
Embeddings
Batched, content-hash cached, versioned per model
Semantic search
Hybrid dense + lexical retrieval with fused ranking
LLM integration
Structured output, streaming, grounding, circuit breakers
Evaluation
Retrieval and answer quality measured, not assumed

Infrastructure

Deployment that is reversible and observable from week one.

Docker
Identical environments from laptop to production
AWS
Compute, storage, managed databases, networking
CloudFront / CDN
Edge caching for static assets and API reads
Nginx
Reverse proxy, TLS termination, routing
CI/CD
Automated pipelines with health-gated, reversible releases
Observability
Structured logs, metrics, alerts that reach a person
11Verified work

Don't take my word. Check.

Everything on this page is meant to be verifiable. Below are the channels for doing that — and, where a claim cannot be published, an honest note saying so rather than a vague one implying otherwise.
LINK PENDING

Source repositories

Public repositories, commit history and code review discussions.

Open GitHub
ON REQUEST

Live deployments

Running systems, reachable and inspectable. Client work is shown under NDA on a call.

Request walkthrough
ON REQUEST

Technical documentation

Architecture decision records, API references and runbooks written for the systems above.

Request samples
ON REQUEST

Client references

Direct conversation with people I have delivered for, arranged on request.

Request references
11.1Client feedbackAwaiting sign-off

There are no testimonials here yet, because there are no approved ones yet.

Inventing three would take ten minutes and would be the single most dishonest thing on this page. This slot is built and waiting: the moment a client signs off on a quote, it appears here with their name and role attached. Until then, references are available by direct conversation — which is stronger evidence anyway.

What goes here

  • Attributed client quote with name and role
  • Named outcome the client agreed to publish
  • Link to the live product where permitted
  • Deployment and repository evidence
12About

I build software that moves from idea to production.

I work across the whole stack — Angular and TypeScript on the front, Node and Python services behind it, PostgreSQL, Redis and vector stores underneath. Most of my recent work has been AI-shaped: retrieval pipelines, semantic search, and the unglamorous engineering that keeps a model-dependent product working when the model does not.

What I care about is the part after the demo: the schema that will still make sense in a year, the failure path nobody wanted to think about, the deploy that can be rolled back at 2am. If you are looking for someone to own a product end to end and tell you the truth about it while doing so, we will get on well.

Discipline
AI-Powered SaaS & Full-Stack Product Engineer
Based
Remote · India · UTC+05:30
Status
Open for Q3 project work
13Start

Have a product to build?

Tell me what you are building and what is in the way. You will get a written reply with an honest read on scope, approach and risk — including whether I think I am the right person for it.

Response
Within one business day
First call
30 minutes, technical, no pitch deck
Availability
Taking on 2 concurrent engagements
Direct
Project intake0 / 7 complete
Current stage
Desired timeline
Budget range
Technologies involved — optional, pick any

Opens a pre-filled draft in your mail client. Nothing is transmitted from this page, and nothing is stored in your browser.