UK based, no sponsorship needed
Amin Mallol
Full-stack engineer, Rails and Next.js
I built and ran four production SaaS products for a London fund manager, mostly on my own, for five years.
Open to London on-site, hybrid, or fully remote.
- in production
- 5 yrsin production
- SaaS products
- 4SaaS products
- commits
- ~4,500commits
- fully remote
- 3 yrsfully remote
Selected work
Four products, five years
All four are real, all four carry real users, and the commit split on every one of them is on its page. Pick the lens that matches the role you are hiring for: the order and the summaries change.
Side projects
An ebook storefront, a spec gate enforced by a database trigger, and a £60 commercial failure with a written kill rule.
How I work
Four decisions, not four adjectives
Every one of these comes with the incident that taught it. If you want to probe one in an interview, the code is still there and I can walk you through it.
- 01
Fail closed, unless closing fails worse
A default is a security decision. Picking one means knowing which way the failure hurts, and writing that down next to the code so the next person does not quietly reverse it.
CynadEvidence
The investor portal returns 404 for any host not in its tenant map, after a fallback let a misconfigured alias impersonate a real fund and receive its cookies. The admin app in the same product deliberately does not, because its default host is the public marketing site.
- 02
Put the invariant where it cannot be bypassed
If a rule matters, it does not belong in the layer that is easiest to write it in. It belongs in the lowest layer that can still enforce it, because that is the only version of the rule that survives a refactor, a second client, or a script someone runs at midnight.
devSpec · CynadEvidence
devSpec's specification gate is a Postgres trigger, so no API route can route around it. Cynad's publish-once prices are enforced in the model and re-checked cross-row in the bulk import path, because the valuation code depends on the invariant rather than re-deriving it.
- 03
Know the bug class, not just the bug
Fixing the reported case is half the work. The question worth asking is what category it belongs to, because that is what tells you where else the same mistake is already sitting.
CynadEvidence
Rate limiting keyed on the request path meant two spellings of the same route disabled every throttle in the file, not just one. The fix resolves through the router and matches on the action. The related shape, found by asking what else leaks through an alternate path, was a password oracle in two-factor sign-in.
- 04
Let the machine type; keep the deciding
Generated code is cheap and confidently wrong output is cheaper still, so the leverage is not in producing more of it. It is in specifying precisely what is wanted beforehand, and in putting the rules somewhere nothing can route around afterwards.
devSpecEvidence
Work is specified in versioned work orders that name the API contract and what is out of scope before anything is written. devSpec enforces the same idea as a product: its gate is a Postgres trigger, so no client, no stray API call and no agent can get past an unanswered question.
- 05
Constraints are a design input
A 512MB budget or a 30-second request cap is not an obstacle to route around; it is information about which designs are available. Taking it seriously early is cheaper than discovering it in production.
FlexiFormEvidence
FlexiForm's job system runs as threads in one process rather than four forked ones, Selenium is lazily loaded because it costs 11MB resident, and spreadsheet exports are streamed to disk instead of buffered, where the buffer would cost three times the file size inside a web thread.
AI-augmented engineering
Where the speed comes from
I started writing software before the AI wave and I would still be doing this without it. What changed is where my hours go. I no longer spend them hunting a missing bracket, wiring up the fourth near-identical form, or reading a file top to bottom to find one thing. I spend them on the decisions that are actually expensive to get wrong: the architecture, the database schema, where an invariant has to live, what the user is really trying to do, and what we are not going to build.
The risk in working this way is obvious, and it is not speed. It is confidently wrong output arriving faster than you can check it. So the parts of my practice I have actually invested in are the ones that catch it: writing the specification before anything is generated, planting controls to detect when a model is making things up, and measuring code health with real static analysis rather than an impression. When something is genuinely subtle, I read the code and fix it myself.
2,391
lines of versioned work orders
Specification before code
Work is specified before any of it is written. Versioned, dated work orders that supersede each other when a constraint changes, each naming the repository, the stack, the exact API contract and what is explicitly out of scope. One of them hands work across two repositories with a role-by-action permission matrix, so the implementer never has to infer who is allowed to do what. This is the same discipline I productised in devSpec, where the gate sits in a Postgres trigger precisely so that no client, no stray call and no agent can route around it.
4 of 27
claims killed before publication
Controls against confabulation
Research that will be published gets a control. Every extraction request carries one fabricated statistic alongside the real ones, so a model that is willing to invent a number has to reveal it. On the last set, every planted control was correctly rejected, 23 claims were confirmed verbatim against their primary source, and 4 were corrected or killed outright. Without the controls, those 4 would have shipped.
86 files
judged per run, framework v2.6
Measurement, not impressions
I built a versioned code-health framework that scores a codebase on evidence rather than on how it feels to read. It fuses an LLM judge, at a pinned model and effort level, with real static analysis: cyclomatic and cognitive complexity, duplication detection, coverage, dependency audit and secret scanning. Scores are weighted (security 0.30, quality 0.25, coverage 0.20, robustness 0.15, efficiency 0.10), windowed over 90 days of churn, carried forward between runs and pinned to a commit, so two runs are comparable. It also runs in a due-diligence mode I have used to assess software before an acquisition.
None of this is a substitute for knowing the stack. It is how I avoid spending a senior engineer's day on work that does not need one.
Tech stack
What I have actually used, and where
No logo wall and no skill bars. Each entry says how long and on which product, because that is the only version of this list you can interview against.
Frontend
Next.js
4 yrsCynad · Weazly · FlexiForm · Sesame
Five production App Router apps, Next 13 through 16. Host-based multi-tenant routing, locale-segmented routing, proxy-level auth gating and HTTPS upgrade.
React
5 yrsevery product
React 18 and 19. 334 components on Cynad alone; the two largest regulated forms are ~5,000 lines each and I would not write them that way again.
TypeScript
1 yrIgnitopedia · devSpec · this site
Honest version: the production work at Tiger Hill is JavaScript, and that was a founding decision I inherited. New personal code is TypeScript with strict mode, including this site, which also has the CI none of those frontends have.
Redux Toolkit
4 yrsCynad · Weazly · FlexiForm · Sesame
Hand-rolled thunks across 47 slices. Includes an idempotent session teardown that collapses nine simultaneous 401s into one logout, acting on 401 and never 403.
Tailwind CSS
3 yrsCynad · this site
v3 alongside Sass in production; v4 with CSS custom properties here.
Sass
5 yrsCynad · Weazly · FlexiForm · Sesame
Around 53,000 lines of it across the Tiger Hill frontends.
MUI
4 yrsall four products
v5 through v7, with Emotion SSR caching, mostly for data-dense admin surfaces.
Motion / Framer Motion
3 yrsall four products
v10 through v12, with reduced-motion respected.
Backend
Ruby on Rails
5 yrsCynad · Weazly · FlexiForm · Sesame
Four API-only apps, Rails 7 through 8.1, on Ruby 4. 103 models, 123 controllers, 264 migrations between them, all JSON:API.
PostgreSQL
5 yrsevery product
DISTINCT ON for append-only answer history, plpgsql triggers enforcing product rules, atomic UPDATE ... RETURNING as a job guard, and Solid Queue running on Postgres rather than Redis.
Authentication
5 yrsall four products
Devise with JWT denylist revocation, TOTP two-factor with encrypted secrets, account lockout, and a two-step sign-in designed not to leak a password oracle.
Authorization
4 yrsCynad · Weazly · FlexiForm
76 Pundit policies, fail-closed: every action must declare one or the request fails. Includes a four-level tenancy graph walk and tenant-aware policy context.
Background jobs
2 yrsWeazly · FlexiForm
Sidekiq with Redis on one, Solid Queue on Postgres on the other, including concurrency limits, recurring schedules and a stale-run reconciler.
Node / Next route handlers
3 yrsFlexiForm · Weazly · Ignitopedia
Stripe checkout sessions and signature-verified webhooks, PayPal create-and-capture, SEC proxying with retry and backoff.
Infrastructure & tooling
Heroku
5 yrsall four products
Nine apps, Postgres, S3 via add-on, custom buildpacks for headless Chrome, and real work done inside a 512MB dyno.
Vercel
1 yrIgnitopedia · devSpec · this site
Edge-region pinning, cron jobs, Neon Postgres, preview deployments.
AWS S3
4 yrsCynad · FlexiForm · Sesame
Active Storage, with object keys built to mirror the tenancy tree so a file's path says who owns it.
GitHub Actions
1 yrCynad API · this site
Brakeman with exit-on-warn, bundler-audit, RuboCop and RSpec against a Postgres service container. I added it to a repository that had gone 2,655 commits with nothing mechanical checking it.
Resend
2 yrsall four products
Transactional and outreach mail, domain verification, and HMAC-signed webhooks for delivery, bounce, complaint and click events.
Stripe
3 yrsWeazly · FlexiForm · Sesame
Embedded checkout, subscriptions, server-owned price catalogues so a client can never post an amount, signature-verified webhooks.
Testing & quality
RSpec
5 yrsall four Rails APIs
Around 1,100 examples on Cynad. On FlexiForm the spec suite is larger than the application code. PDF endpoints are tested against real headless Chrome rather than stubs, by policy.
Playwright
2 yrsCynad investor portal · this site
68 specs in five tiers: auth setup, smoke, read-only journeys that ask the API for the value they assert, a seed fingerprint check that fails fast on drift, and mutating tests on a single worker.
Jest / Vitest + RTL
3 yrsCynad investor portal · this site
40 unit suites on the portal; Vitest here, including a test that validates all site content against its schema.
Accessibility
2 yrsCynad investor portal · this site
axe-core run inside the Playwright suite rather than as a one-off audit.
Security tooling
1 yrCynad API
Brakeman and bundler-audit as a merge gate. Brakeman is what caught a file read taking an unvalidated parameter in the CSV import path.
AI-augmented engineering
Claude Code
since 2025every repository above
Daily driver since late 2025, with per-project permission allowlists, hooks and a written operating protocol that separates a hypothesis from a decision and stops after two failed attempts at the same fix.
Agent specification
since 2025Cynad
Versioned, superseding work orders naming the repository, stack, API contract and out-of-scope list, including a cross-repository handoff carrying a role-by-action permission matrix.
LLM-as-judge evaluation
since 2026Cynad · due diligence
A code-health framework fusing a pinned judge model with eslint, sonarjs, jscpd, coverage and npm audit into a weighted score, windowed over 90 days of churn and pinned to a commit so runs are comparable.
Verification technique
since 2026research and content work
Planted control statistics in extraction requests to detect confabulation, with every claim traced back to a primary source before it is published.
About
First engineer, and for most of it the only one
I joined Tiger Hill Advisors in December 2021 as its first and, for most of that time, only engineer. What started as one investor portal became four products: a multi-tenant fund administration platform now serving four fund managers on their own domains, an SEC filings intelligence tool with an AI research layer, a form and survey platform with a usage-metered billing engine, and a regulated bullion brokerage with KYC and vault custody.
Three years of that has been fully remote, as the only engineer, with four live tenant deployments and no customer-facing incident. When a company asks whether someone can be trusted with this much ownership unsupervised, that is the answer I have, and it is the part of the job I am proudest of.
I work in Rails and Next.js because that is what the problems needed: an API that has to be correct about other people's money, and front ends that real users sit in front of every day. I care most about where an invariant lives, because the right answer is usually further down the stack than it is comfortable to put it.
Contact
Hiring, or just curious
I am open to London on-site, hybrid and fully remote roles. If you have a specific question about any of the work above, ask it directly: the code is still in front of me and I would rather answer precisely than send a brochure.
- Elsewhere
- GitHub ↗LinkedIn ↗