Picture a hiring manager opening your GitHub link for a quick look. They are unlikely to read your code line by line. They are looking for one answer: can this person build something that survives real conditions?

Many backend portfolios do not answer that question. A to-do API, a blog CMS and a clone of a tutorial project all prove the same thing: you can follow instructions. They say nothing about money, concurrency, failure or security, which is where backend work gets hard.

This article gives you five project specs that do prove it. Each one has a scope, must-haves, stretch goals, what it proves, and what a reviewer should find when they open it. It ends with a README template and a reviewer checklist you can run on your own repository before you share it.

Why most portfolio projects don't help#

A project helps in an interview when it gives the interviewer something to ask about. Good questions need a hard problem inside the project. Compare two hypothetical answers to "tell me about this project":

  • "It's a REST API with users, posts and comments."
  • "It's a payments API. Retried requests with the same key must not charge twice, so I store the key with a request hash and return the saved response. I tested it with 50 parallel requests."

The second answer is an invented example of what you could say after building and testing the project yourself. It would open many follow-up questions, and you would already know the answers. That is the goal.

A strong portfolio project has four properties:

  1. A real failure mode. Double charge, oversell, lost webhook, leaked token.
  2. A test that reproduces the failure. Ideally a concurrency or retry test, not only a happy path.
  3. A written decision. Why this isolation level, why this table design, what you rejected.
  4. A small surface. One problem done well beats five half-done.

The five projects at a glance#

The five portfolio projects and the failure each one proves you can handle
Five projects, five failure modes
# Project Failure it proves you can handle Companion article (some still unpublished)
1 Idempotent payments API Duplicate requests and client retries Idempotency keys
2 Ledger wallet Money that does not add up Double-entry ledger (companion article, coming soon)
3 Flash-sale inventory Overselling under concurrency Prevent overselling (companion article, coming soon)
4 Webhook processor Duplicate, late and forged events Payment webhook latency (companion article, coming soon)
5 Secure MCP server Tools exposed to an AI agent without limits MCP auth and permissions (companion article, coming soon)

You do not need all five. Build two or three, finish them properly, and pick the ones closest to the jobs you want. Applying to fintech roles? Take 1, 2 and 4. Applying to e-commerce? Take 3 and 1.

Which project fits which role#

Target role Build first Then add Why
Fintech or payments backend 1 Idempotent payments 2 Ledger, 4 Webhooks Money and retries are daily work
E-commerce or marketplace 3 Flash-sale inventory 1 Payments Stock and checkout under load
Platform or integrations 4 Webhook processor 1 Payments Unreliable inbound events
AI-adjacent backend 5 Secure MCP server 1 or 4 Agent tools need permissions and audit
General backend, junior Any one, finished well A second later Depth beats breadth

Project 1: Idempotent payments API#

Scope. A small API with POST /payments that accepts an Idempotency-Key header. A fake gateway class stands in for the real provider, so nobody needs live keys.

Must-haves

  • Same key and same body returns the saved response, with no second charge.
  • Same key and a different body returns a clear error (HTTP 422 or 409, your choice, documented).
  • A unique database constraint on the key, so two simultaneous requests cannot both pass.
  • A test that fires parallel requests with one key and asserts exactly one payment row.

Stretch

  • Key expiry and a cleanup job.
  • A record of in-flight requests so a second caller waits or gets a "still processing" response.

What it proves. You understand that networks retry, and that "check, then insert" is not safe without a constraint. Stripe's idempotent requests documentation is a good reference design to compare against: it saves the first response per key, and errors when a reused key comes with different parameters.

Full walkthrough: Idempotency Keys in Laravel.

Project 2: Ledger wallet#

Scope. Users hold balances. Money moves between wallets. Every movement is recorded as balanced debit and credit entries, and the balance is derived from entries.

Must-haves

  • Entries are append-only. Corrections are new entries, never edits.
  • Every transfer is one database transaction, and its debits equal its credits.
  • A check that sums all entries and returns zero.
  • Transfer with insufficient funds fails cleanly and leaves nothing behind.
  • A concurrency test: many simultaneous withdrawals from one wallet never take it below zero.

Stretch

  • Holds and releases (authorize, then capture).
  • A balance snapshot table, rebuilt and verified against entries.
  • Integer minor units for amounts, never floats.

What it proves. You can model money without "balance = balance - x" bugs, and you know why accounting uses two sides. Details: Double-Entry Ledger Wallet (companion article, coming soon).

Project 3: Flash-sale inventory#

Scope. A product with limited stock and an endpoint to reserve or buy it. Hundreds of requests arrive at once.

Must-haves

  • Stock never goes below zero, proven by a parallel test.
  • You can explain your locking choice: pessimistic lock (SELECT ... FOR UPDATE), an atomic conditional UPDATE, or optimistic versioning. MySQL documents row locking in Locking Reads.
  • Reservations expire if payment never arrives.
  • A small README table comparing the approaches you tried, with your own measured timings and your hardware stated.

Stretch

  • A waiting-room or queue for the sale start.
  • Per-user purchase limits.

What it proves. You know that a race condition does not show up in a single manual test. Test with real parallel requests through PHP-FPM and nginx, not php artisan serve, which can hide races. Details: Prevent Overselling (companion article, coming soon).

Project 4: Webhook processor#

Scope. An endpoint that receives payment events from a provider (a simulator you write is fine), verifies them, and updates orders.

Must-haves

  • Signature verification on the raw request body, with a timestamp tolerance.
  • Fast acknowledgement: store the event, queue the work, return 2xx. Stripe's webhook guide says the endpoint must return a 2xx quickly, before any complex logic that could cause a timeout.
  • A dedup table keyed by provider event id, with a unique constraint.
  • Safe handling of out-of-order events: an old "pending" event must not overwrite a "paid" order.
  • Failed jobs retry with backoff and land in a failed-jobs list you can inspect. See Laravel's queue documentation.

Stretch

  • A replay command for stored events.
  • A small dashboard of received, processed and failed events.

What it proves. You treat inbound events as unreliable: they can repeat, arrive late, or be forged. Related: How we cut payment webhook latency (companion article, coming soon).

Project 5: Secure MCP server#

Scope. A Model Context Protocol server that exposes a few tools (for example "look up an order", "issue a refund") to an AI client, with authentication and per-tool permissions.

Must-haves

  • Authentication on every request to your server, following the MCP authorization specification, which is the current revision (2026-07-28) at the time of writing.
  • Least privilege: each token can call only the tools it needs.
  • Destructive tools (refund, delete) require a separate permission and an audit log row.
  • Input validation on every tool argument. Treat model output as untrusted input.
  • Tests that show a read-only token cannot call a write tool.

Stretch

What it proves. You can expose backend capability to AI agents without handing them the keys to everything. Details: Laravel MCP server auth and permissions (companion article, coming soon).

Real open-source Laravel projects to study#

Reading production code teaches you what a portfolio README cannot. These are public repositories. The Laravel version column comes from each repository's composer.json on its default branch, checked on 9 November 2026. It will drift, so check before you rely on it.

Project What it is License (GitHub) laravel/framework Good to study for
Firefly III Personal finance manager AGPL-3.0 ^13 Project 2: money, transactions, rules
Bagisto E-commerce and marketplace platform MIT ^13.0 Project 3: catalog, orders, inventory
Koel Music streaming server MIT ^13.0 Clean API plus a separate frontend
Pixelfed Federated photo sharing AGPL-3.0 ^13.0 Project 4: handling inbound federated activity
Snipe-IT IT asset management AGPL-3.0 ^12.0 Permissions, audit trail, large schema

How to read one in 30 minutes: start at routes/, pick one write endpoint, follow it through the controller, service or action, model and migration, then find its tests. Write down how it handles failure. That note is a good interview answer.

Useful Laravel packages for these projects#

Versions and requirements below come from each package's Packagist metadata on 9 November 2026. Check Packagist before installing.

Package Use it for Latest seen Requires
laravel/sanctum API tokens (Projects 1, 5) v4.3.3 PHP ^8.2, Laravel 11 to 13
spatie/laravel-permission Roles and permissions (Projects 2, 5) 8.5.0 PHP ^8.3, Laravel 12 to 13
spatie/laravel-activitylog Audit log of who did what (Projects 2, 5) 5.1.4 PHP ^8.4, Laravel 12 to 13
laravel/horizon Redis queue dashboard and retries (Project 4) v5.50.1 PHP ^8.0, Laravel 9 to 13
laravel/telescope Local debugging of requests, jobs, queries v5.27.0 PHP ^8.0, Laravel 8 to 13
laravel/octane Long-running app server for speed tests v2.23.0 PHP ^8.2, Laravel 11 to 13
larastan/larastan Static analysis v3.14.0 PHP ^8.2, Laravel 11 to 13
laravel/pint Code style fixer v1.32.1 PHP ^8.3
spatie/laravel-backup Database and file backups 10.4.0 PHP ^8.4, Laravel 12 to 13

Use packages for solved problems, then spend your effort on the hard part of the project. Do not install a permissions package and call it a security project. Packagist metadata tells you what a package supports, not whether it fits your design: read its docs and tests first. Telescope and Horizon dashboards need to be protected or disabled in production. I did not run any of these packages for this article.

A README template that works#

The README is the part reviewers actually read. The block below is a Markdown template, not executable code; the commands inside it are placeholders for your own project. Copy this and fill every section. Delete nothing; if a section is empty, the project is not done.

README.mdMarkdown
# Project name

One sentence: what problem this solves and what can go wrong without it.

## The hard part
Which failure does this project handle? (double charge, oversell, replayed event...)

## How it works
A diagram or 5-10 lines. Link to the key file.

## Run it
Exact commands. Should work from a clean clone in under 5 minutes.

    cp .env.example .env
    composer install
    php artisan migrate --seed
    php artisan test

## Tests
What is covered, and how to run the concurrency test.
Paste real output. Say what hardware you ran it on.

## Decisions and trade-offs
Table: option, why chosen or rejected.

## Limits
What this does not handle. Be honest.

## What I would do next
2-4 bullets.

What reviewers look at#

Use this as a self-review. These are practical signals, not figures from any survey.

  • The README explains the problem in the first screen.
  • Setup works from a clean clone with the commands shown.
  • Tests exist, pass, and include at least one failure case (retry, race, bad signature).
  • No secrets in the repository or git history. .env.example only.
  • Commits are small and have meaningful messages.
  • Money is stored as integers in minor units.
  • Database constraints back up application checks (unique, foreign key, check).
  • Errors return clear status codes and messages, not stack traces.
  • A "Limits" section says what the project does not do.
  • Claims in the README match what the code does. Do not write "scales to millions" unless you measured it.

Common mistakes#

Mistake Why it hurts Fix
Ten shallow projects No depth to discuss Two or three deep ones
Tutorial clone with renamed files Reviewers recognise it Change the problem, add a failure test
No tests Nothing proves it works Test the failure mode first
Floats for money Rounding bugs, an instant red flag Integer minor units
Claims without measurement Cannot defend them in an interview Run it, paste real output, state hardware
Committed .env or API keys Security red flag Rotate the key, use .env.example
Only happy-path tests Misses the real problem Add retries, parallel requests, bad input
Huge scope, unfinished Looks abandoned Cut scope, ship the must-haves

How to use these in an interview#

Prepare a one-minute story for each project: the problem, what broke in your first version, how you found it, what you changed. "What broke in my first version" is the strongest part, and it only exists if you actually ran the tests and wrote down what happened. Do not invent a story. If it did not happen, say what you would watch for.

Key takeaways#

  • A portfolio project is a source of interview questions. Pick problems with real failure modes.
  • Five strong specs: idempotent payments, ledger wallet, flash-sale inventory, webhook processor, secure MCP server.
  • Two or three finished projects beat ten shallow ones.
  • Every project needs a test that reproduces its failure, a written decision log, and an honest limits section.
  • Run your README from a clean clone before you share it.

References#

Want help choosing or reviewing a project?#

If you want a second pair of eyes on a portfolio repository, see mentorship or services.