Skip to content
HomeAt Splunk, that means pairing React product work with Python services, operational data, permissions, evaluation, and release controls. Earlier at Deloitte, I built extraction, storage, API, and visualization systems; two removed more than 36,000 hours of annual manual work and cut investment-processing time by 66%.WritingArticles and notes on software engineering, AI engineering, system design, and the trade-offs behind production systems.ProjectsSelected systems, the constraints that shaped them, and the trade-offs I would revisit.Abdul AhadI’m an AI full-stack engineer with more than five years of experience building data-intensive enterprise software and production AI systems. At Splunk, I drove AI Service and KPI Discovery from an early prototype through technical design, validation, and production delivery. The capability analyzes operational data and recommends service models and health signals within Splunk IT Service Intelligence.ContactIf you’re hiring for a role, comparing architecture options, or building something with a difficult failure mode, send enough context to make the conversation useful.ColophonHow this portfolio handles static publishing, search, contact delivery, analytics, and releases.Capacity Planning Before Architecture DiagramsA practical method for turning workload assumptions into request, storage, bandwidth, concurrency, and failure-capacity budgets before choosing an architecture.Design Modules Around Change, Not LayersA practical guide to information hiding, volatile decisions, coupling, cohesion, dependency direction, and avoiding abstractions that preserve the wrong boundaries.From Model Call to Reliable AI WorkflowHow one model request grows into retrieval, tools, deterministic workflows, agents, evaluation, observability, and human escalation.Queues, Backpressure, and Idempotency: Designing for FailureHow bounded queues, admission control, idempotency keys, retry budgets, and dead-letter handling turn asynchronous delivery into a controlled reliability system.Refactoring a Legacy Backend Without a Big-Bang RewriteA staged method for understanding, testing, isolating, replacing, observing, and finally deleting legacy backend behavior without one irreversible cutover.MCP in Production: Trust Boundaries, Permissions, and Tool DesignA production-focused guide to MCP hosts, clients, servers, capability discovery, authorization, consent, token audiences, and safely designed tools.A portfolio built as a publishing systemA static-first technical publication paired with a rate-limited, AI-assisted contact workflow that is queued, retried, idempotent, and recoverable.ThreadsA discussion application with threaded posts, comments, profiles, and community spaces.Prompt NexusAn open-source application for creating, finding, and sharing prompts for AI tools.SeedA statically generated blogging application backed by a headless content system.CactaA short-video social application with publishing, discovery, profiles, and audience interactions.System DesignCapacity, queues, failure handling, and distributed-system trade-offs.AI EngineeringLLM workflows, tools, evaluation, permissions, and operations.Software EngineeringModules, testing, refactoring, interfaces, and maintainability.System Design from First PrinciplesCapacity planning, queues, backpressure, retries, and failure handling.Production AI EngineeringModel calls, workflows, tools, evaluation, permissions, and operations.

← Back to Projects

2026 · current

A portfolio built as a publishing system

A static-first technical publication paired with a rate-limited, AI-assisted contact workflow that is queued, retried, idempotent, and recoverable.

nextjsreacttypescriptkeystaticzodupstash-redisqstashgeminivercel

This site has two jobs: make my engineering work legible and give me a low-friction place to publish. The interesting work is not the page styling. It is keeping authoring convenient without turning the public site into a runtime CMS application, and making a contact request durable without making the visitor wait for every downstream service.

The constraints#

  • Public pages must be statically generated and useful without client JavaScript.
  • A draft must not leak through a route, feed, search index, sitemap, metadata, or social image.
  • Articles and one-paragraph Notes must use the same publishing system.
  • Public copy, taxonomies, navigation, and projects must be editable without changing TypeScript.
  • Contact delivery must acknowledge quickly, survive downstream failures, and avoid duplicate records.

Those constraints lead to two deliberately different paths.

View diagram source
flowchart LR
    A[Keystatic] --> B[MDX and JSON]
    B --> C[Zod validation]
    C --> D[Static pages]
    C --> E[RSS, search, sitemap, metadata]

    F[Contact form] --> G[Validate and sanitize]
    G --> R[Redis rate limit]
    R --> H[QStash]
    H --> I[Gemini analysis or safe fallback]
    I --> J[Idempotent Sheets write]
    J --> K[Best-effort Telegram alert]
    H --> L[Retries and managed DLQ]

The read path pays its complexity at build time. Keystatic writes ordinary repository files; shared loaders validate relationships and publication state; Next.js generates the routes and discovery artifacts. The browser receives complete content, then small client leaves add search, filtering, reading progress, theme selection, code-copy feedback, and the mobile dialog.

The contact path pays its complexity at runtime because delivery matters more than rendering. Same-origin, body-size, honeypot, signed form-age, and Redis-backed rate-limit checks reject bad requests before they become background work. The API sanitizes accepted fields, assigns a submission ID, and returns success only after QStash accepts the message. A QStash-signed worker asks Gemini for structured analysis or uses a safe fallback, writes the durable Sheets record under the idempotency key, and sends Telegram only as a best-effort notification. Persistence failures remain retryable; exhausted deliveries reach a managed dead-letter queue.

The contact form is a small distributed workflow#

The form does not call an email API and hope for the best. It separates fast visitor feedback from work that can fail, retry, or arrive more than once.

1. Reject bad work early#

The request crosses same-origin, body-size, honeypot, and signed form-age checks before reaching the public route. Upstash Redis applies the primary per-IP rate limit. The token adds form-age friction; it is deliberately not described as replay prevention.

2. Hand delivery to QStash#

The public route validates raw fields with Zod, sanitizes them, creates a cryptographically random submissionId, and publishes the clean payload to QStash. The visitor sees success only after QStash accepts it. Gemini, Sheets, and Telegram are not on the user-facing latency path.

3. Keep AI bounded#

The process route accepts only QStash-signed deliveries. Gemini receives sanitized data inside explicit XML boundaries and must return a structured result. Its analysis helps classify and summarize the message; it does not decide whether the message is persisted. A timeout, provider error, or invalid model response produces a safe fallback instead of dropping the submission.

4. Persist before notifying#

The worker sends an HMAC-signed payload to the bound Sheets endpoint. The Apps Script holds a lock, checks submissionId, and appends only when that ID is new. A duplicate queue delivery therefore becomes an idempotent success rather than a duplicate row. Telegram runs afterward as a best-effort alert, not as the durable record.

5. Make failure recoverable#

A persistence failure returns a retryable error so QStash can apply exponential backoff. Exhausted deliveries remain in its managed dead-letter queue and trigger a signed callback. The callback attempts a redacted Telegram warning and always returns 200 because retrying that webhook cannot replay the original job.

BoundaryResponsibility
Proxy + RedisReject malformed, cross-origin, automated, or excessive work
Public APIValidate, sanitize, identify, and enqueue
QStashAuthenticate delivery, retry, and retain exhausted messages
GeminiOptional structured enrichment with a safe fallback
SheetsHMAC-verified, locked, idempotent durable record
TelegramBest-effort operational notification

Decisions that matter#

Files are the public source of truth#

Keystatic is a write interface, not a production read dependency. This keeps local changes reviewable, makes a broken relationship fail during validation, and avoids adding a CMS network request to every page.

One schema owns runtime truth#

Zod schemas define content and API boundaries, and TypeScript types are inferred from them. Keystatic mirrors those constraints for authoring, with parity tests guarding the seam that cannot be shared directly. Errors include the file, field, invalid value, and valid alternatives.

Publication is enforced at every projection#

Filtering a draft only on its page is insufficient. The same published rule applies when generating static parameters, metadata, Open Graph images, RSS, search, sitemaps, topic counts, and series navigation. A known draft slug behaves like an unknown route.

Small client leaves earn their place#

Static generation does not mean removing all state. Navigation, theme selection, URL-backed writing filters, active table-of-contents state, and copy feedback are isolated client components. Page and layout components remain server-rendered.

What I got wrong in v1#

I over-optimized client JavaScript out of the header and replaced a reliable navigation component with persistent native disclosure state. Because the root layout survives client navigation, the mobile menu stayed open after following a link. The correction is a small native-dialog leaf with explicit close, focus, scroll, route-change, breakpoint, and unmount behavior.

Taxonomies, navigation, and public copy were also split across content files and TypeScript registries. That made ordinary editorial changes depend on a code editor and allowed the authoring schema to drift from build-time validation.

Finally, the validator treated every post as long-form. It required a fixed outline, citations, and a Mermaid diagram even when a short Note was the better form.

Failure modes and controls#

FailureControl
A renamed taxonomy breaks contentCross-reference validation fails the build with valid alternatives
A draft appears in discoveryPublication filtering is tested across every generated projection
A duplicate queue delivery appends twicesubmissionId is checked under the Sheets lock
A downstream provider is unavailableQStash retries; safe analysis fallback; managed DLQ
A menu exit leaves the page lockedEvery close path and unmount restores body scroll
JavaScript is unavailablePublic content, links, and the unfiltered writing library still render

Result and remaining trade-offs#

One content graph now produces pages, taxonomy directories, RSS, search, sitemaps, metadata, and social cards. The public read path remains static, while the only custom runtime workflow is isolated and recoverable.

The trade-off is stricter authoring discipline: a slug rename must update its relationships in the same change, and a failed validation blocks release. I prefer that visible build failure to a quiet broken link in production. I also keep Keystatic intentionally bounded; it can reorder and hide known sections, but it is not an arbitrary page builder.