Mahmoud Alshraky

I build systems people use, then keep them running. Full-stack software engineer. I build and run production systems with React, Node.js and PostgreSQL: an exam platform, an HR system for 25+ branches, a shared email gateway, and an in-browser face and hand tracking prototype. Watch each one get built, layer by layer.

How I build a system

It starts on paper

Before any code: who uses it, what must never go wrong, and what the data looks like. The plan is drawn first, then built on.

Then the data

One database holds everything that has to be remembered, designed so a brand-new copy and the live one always match.

Rules in one place

Every request passes through one core that applies the rules once, so the website, the app and the bot cannot disagree. A request that breaks a rule is refused.

Everyone gets the right door

Signing in says who you are; your role says how far you get. A branch manager sees one branch, an administrator sees them all.

Then what people see

The interface goes on last, on top of everything underneath: the same data and rules on a laptop and on a phone, right-to-left where the users read Arabic.

Then I keep it running

Launch is the middle, not the end. Scheduled jobs run on time, tests guard the parts that must not break, and dashboards show whether people find it.

Numbers (19 September 2026)

Systems in production

SQB: Exam-prep platform for the Saudi SMLE, SNLE and SDLE licensing exams

13,000+ practice questions for the Saudi licensing exams in medicine, nursing and dentistry. I built the web app, API, Android app and Telegram bot, and I run it.

  • 13,036 questions on 9 Oct 2026: 7,871 medical, 2,105 nursing, 3,060 dental. Many have written explanations; the recall sets do not yet.
  • Three exam tracks, with content and analytics kept separate per track. The dental track went live on 7 Oct 2026.
  • Prerendered public pages took Google-indexed pages from 5 to 468.

It starts with a search

Students find SQB on Google. Its public pages are prerendered, so search engines read real content. Every lit tile is a page Google knows.

  • Indexed pages went from 5 to 468 between 30 Aug and 16 Sep 2026
  • 734 clicks from Google search in 90 days

Then they practise

Practice questions, explanations and a plan for each student, in a right-to-left interface built for Arabic readers.

  • 1,001 visitors and 4,262 page views in the 30 days to 19 Sep 2026
  • Live at smle-question-bank.com

Then they subscribe

When a student pays, Moyasar confirms it, the subscription switches on and a VAT invoice is generated as a PDF. The receipt email goes out through the gateway I built for my projects.

  • Five plans: monthly, four-month, annual, and group plans for 3 and 5 seats
  • Webhook-driven activation, VAT invoice as a PDF

And they come back

The website, a mobile app and a Telegram bot all run on one backend. A daily question and reminders bring students back.

  • Web, the Expo Android app and the Telegram bot share one API
  • Telegram gets a daily question and a weekly summary
  • Data: DB PostgreSQL, 31 tables; TABLE user_question_progress; TABLE payment_events; TABLE funnel_events, page_engagement, login_history; TABLE subscription_groups, group_seats, trial_grants; SCHEMA Created idempotently at cold start, safe to re-run
  • Search: BUILD Public pages prerendered so crawlers read real content; GSC 468 indexed pages on 16 Sep 2026, from 5 on 30 Aug; GSC 734 clicks and 13.1K impressions in 90 days
  • Interface: UI React 19 and Vite, right-to-left Arabic; URL smle-question-bank.com
  • Payments: PAY Moyasar: Apple Pay, webhooks; POST /webhook confirms and activates the subscription; GET /invoice/:gatewayRef.pdf (VAT invoice); MAIL Shared email gateway, Gmail SMTP fallback
  • Engine: API One Express app, 150 route handlers; GET /api/questions; GET /api/questions/:id/explanation; GET /api/user-subscription/:userId; GET /admin/analytics; APP Expo SDK 57 Android app, same backend (rebuilt Oct 2026, 90 unit tests); BOT Telegram: daily question, weekly summary; CRON 9 scheduled endpoints (Telegram, lifecycle and daily emails)

React 19, Vite, Express, PostgreSQL, Moyasar, Expo SDK 57, Telegram Bot API

https://www.smle-question-bank.com

Multi-branch HR platform: Employee records, payroll, absence and documents for a healthcare company

A healthcare company with 25+ branches and 600+ employees ran its staff on paper. I built its system from scratch: people, payroll, documents, buses and reports.

  • Document expiry alerts fire 30, 60 and 90 days ahead.
  • JWT sessions, role-based access across branches, one-time codes for branch accounts.
  • In-memory caching with short expiry and composite indexes on the hot queries.

25+ branches, one system

Every branch reports to one system: one set of employee records, one set of rules, and the buses that carry the students.

  • 25+ branches and 600+ employees at a healthcare company
  • Student bus transport tracked alongside staff

Nothing expires unnoticed

Every employee file carries identity, residency and contract dates, in Gregorian and Hijri. The expiry page counts what is expired, due in 30 days and due in 90, and lets head office remind a branch. Alerts fire 90, 60 and 30 days ahead.

  • Alerts at 90, 60 and 30 days
  • Screen shows demo data: every name and number is invented

Every branch, every year

Each new school year every branch has to review its staff, documents and buses. One page shows which branches finished, which started and which have not, and what exactly is still missing in each.

  • Per-branch progress, missing documents and missing employee data
  • Reminders and tasks sent to a branch from the same screen

How many staff does a branch need?

From the number of beneficiaries and the therapies each one gets, the system works out how many therapists, nurses and support staff a branch needs, and shows the gap against who is actually employed.

  • Required, present and missing, per role and per branch

Payroll and absence, month by month

Attendance and absences add up to each month's payroll, per employee and per branch, with Hijri dates where people expect them.

  • Payroll, absence and year transitions in one place

Reports people can print

Branch statistics rank every branch by how complete and active its data is, and export to Excel. Payroll, absence and branch reports come out as PDF and Excel files, ready to print, sign or send on.

  • PDF and Excel, with Hijri dates
  • Caching and composite indexes keep them fast
  • Access: AUTH JWT sessions; ROLES Role-based access across 25+ branches; OTP One-time codes for branch and user accounts; AUDIT Review confirmations and year transitions
  • Branches: MODULE branches, branch-documents, branch-statistics; MODULE bus-transportation; PAGE Dashboard and branch statistics; API 18 route modules, one per area
  • Expiry: MODULE employees, employee-file, employee-expiry; MODULE documents, archive, notifications; ALERT 30, 60 and 90 days before expiry
  • Follow-up: PAGE Year-cycle follow-up; MODULE year-cycle, tasks, terms, academic-years; TASK Head office assigns a task to a branch, with a deadline
  • Staffing: PAGE Beneficiaries and hiring requirements; RULE Staff required per role from the enrolled beneficiaries; MODULE beneficiaries, branch-statistics
  • Payroll: MODULE payroll-absences, academic-years; PAGE Payroll and absences
  • Reports: DB PostgreSQL with migrations; CACHE In-memory cache with per-route expiry; INDEX Composite indexes on hot queries; REPORT PDF and Excel, Hijri dates

React 19, Node.js, Express, PostgreSQL, JWT, ExcelJS, PDFKit

Internal system with employee data, so there is no public link. The screens on this page are the same code running on invented demo data. I walk through the real one in an interview or call.

NeuroLink: A camera that reads faces and hands, and does not diagnose

A child plays a 3-minute game while the webcam measures behaviour, all in the browser. The doctor sees only what is new, and decides.

Built for Let's Pitch It 2026 (GDG Qassim). It is a prototype, not a medical device, and it has not been clinically validated.

  • Face and hand tracking run in the browser; the video never leaves the device.
  • Build checks fail if anything but one file touches the camera, or if the code names a condition.

It starts with a webcam

A child plays a short game while the webcam watches. The video never leaves the device: face and hand tracking run in the browser.

  • Runs on the device with MediaPipe
  • A build check fails if anything except one file touches the camera

Hands: 21 points each

Every frame the browser finds 21 landmarks on the hand, enough to tell an open hand from a point, a wave or a fist.

  • Pointing and waving are checked against what the game asked for

Faces: 478 points

478 landmarks, including both irises, give the head turn, where the child is looking, blinks and expression, all condensed into one small record per frame.

  • Head pose, gaze region, blinks, smile and brow raise

A game built as an instrument

Six timed blocks, 3 minutes 5 seconds in total. Every measure is tied to a timestamped moment, so sessions stay comparable with each other.

  • The social-attention block approximates a published paradigm with a webcam and does not claim the original's validation

The doctor decides

The physician sees only what today's session showed that the record does not already contain, as one notification with three choices: add to the record, request a referral, or dismiss. It never diagnoses.

  • Every number shows where it came from
  • A build check fails if the code contains condition-naming vocabulary
  • Camera: CAM One getUserMedia call site; RUN MediaPipe WASM, on the device; FALLBACK GPU first, then CPU; PIN Model files pinned to MediaPipe 0.10.18
  • Hands: HAND 21 landmarks per hand; HANDS extended[5], isPoint, bearing; STATE pointing, onTask, distanceCm
  • Face: FACE 478 landmarks with irises; HEAD headYaw, headPitch, headRoll; GAZE gazeRegion, gazeConf; EYES blinkLeft, blinkRight, eyesOpen; FACE jawOpen, smile, browRaise
  • The game: B0 calib, 20 s; B1 social, 40 s; B2 name, 30 s; B3 point, 40 s; B4 wave, 25 s; B5 bubbles, 30 s
  • The doctor: API FastAPI and SQLite engine; NORMS norms_v1.json, age norms; RULE Each field records its provenance; ACT Add to record, Request referral, Dismiss; NEVER Diagnose or name a condition

TypeScript, MediaPipe, Python, FastAPI, SQLite

The repository is private. I run it live in an interview or a call.

Shared email gateway: One email service for my projects

SQB, the HR system and this portfolio are wired to one email service on a free plan of 100 a day. The gateway splits the quota, adds a second sending account as backup, and falls back to Gmail.

  • Bounces and complaints are suppressed through a webhook signed by Svix.
  • Idempotency keys prevent duplicate sends; error alerts have a cooldown.
  • 35 automated tests in four files.

Three projects, one door

Every project sends through the same gateway instead of carrying its own mail setup. It checks where each request comes from, and turns away mail from a source it does not know.

  • The portfolio sends through it today; SQB and the HR system are connected and being moved over
  • Requests from unregistered origins are dropped

A fair share of 100 a day

Resend's free plan allows 100 emails a day. The gateway splits them between the projects. When that is spent, a second Resend account takes over, and after that mail goes out through Gmail instead of failing.

  • A second sending lane was tested in October: its first domain was too young and landed in spam, an older domain reached the inbox
  • Gmail SMTP takes over when both quotas run out

A bounce is remembered

When an address bounces or complains, a signed report comes back and the gateway stops mailing that address. The same message sent twice goes out once.

  • Webhook reports are verified with Svix signatures
  • Idempotency keys stop duplicate sends

35 tests hold it together

The client, the origin check, the quota and the email templates are covered by 35 automated tests, so one change cannot quietly break mail for every project at once.

  • 35 tests in four files
  • One door: POST /api/v1/send; POST /api/v1/send/bulk; POST /api/v1/notify; GET /api/v1/quota; GET /api/v1/messages/:id
  • Quota: QUOTA Splits Resend's 100 a day across projects; LANE 2 A second Resend account takes over near the first one's limit (since 9 Oct 2026); FALLBACK Gmail SMTP when both are spent
  • Bounces: HOOK POST /api/webhooks/resend; SIG Signed by Svix; RULE Bounces and complaints suppress the address; SAFE Idempotency keys stop duplicate sends; UNSUB GET /u/:token
  • Tests: TEST client.test.ts, 8; TEST origin.test.ts, 6; TEST quota.test.ts, 11; TEST render.test.ts, 10

Next.js, TypeScript, PostgreSQL, Resend, Nodemailer, Svix

Internal infrastructure. Its admin panel shows real users' data, so there is no public link.

Client sites

Al-Haysoni Law Firm: Website for a law firm

A bilingual Arabic and English site for a law firm: right-to-left by default, one-tap WhatsApp enquiries for each practice area, the office on a map, and structured data for search.

  • React and Vite, with all Arabic and English copy in one translations file.
  • Schema.org structured data, sitemap and robots.txt; I fixed the canonical domain and added visitor analytics in October 2026.

React, Vite, Schema.org, Vercel Analytics

https://www.alhisony.com

Erth Environmental Services: Website for an environmental consultancy

An Arabic site for an environmental consultancy, opening on an interactive 3D globe, with dark and light themes and a consultation form.

  • Interactive Three.js globe with Saudi Arabia marked out.
  • A fingerprint drawn from a mathematical field, not by hand.

Three.js, Vite, JavaScript, Google Maps

https://erthfc.com

Experience

Full-stack software engineer, Ultimate Care Rehabilitation Co.

Oct 2025 to now

  • Designed and built an HR system from scratch for a company with 25+ branches and 600+ employees: lifecycle, payroll, absence, documents and student transport.
  • Automated document-expiry alerts and PDF and Excel reports with Hijri dates.

Full-stack developer, SQB

Feb 2025 to now

  • Built the platform, API, database, mobile app and Telegram bot, and run them in production.
  • Prerendered public content for crawlers: Google-indexed pages rose from 5 to 468.

Web developer (freelance), Al-Haysoni Law Firm

Jul to Aug 2025

  • Delivered a bilingual Arabic and English site with Schema.org structured data and WhatsApp enquiries.

Web developer (freelance), Erth Environmental Services

2025, redesigned Sep 2026

  • Built the site, then redesigned it around an interactive Three.js globe.

About

I build the whole system, from the database to the screen, and I stay on after launch.

Contact

alshraky3@gmail.com, GitHub, LinkedIn