Code Review is the highest-ROI practice for keeping a codebase healthy — but poorly managed, it’s the biggest bottleneck. In 2026, my review flow changed radically: AI for mechanics, human for strategy. Result: feedback cycle from days to hours, less fatigue, more robust code.
The Complete Flow: 3 Phases, Zero Friction
flowchart TD
A[Dev opens PR] --> B[Claude Code: Auto Filter]
B --> C{Critical issues?}
C -->|Yes| D[Dev fixes + re-push]
C -->|No| E[Human Reviewer: 3 Pillars]
E --> F[Approved + Merge]
F --> G[Post-merge: Docs sync via MCP]
Phase 1: Automated Filter — Claude Code (Pre-Review)
Before I even open the PR, the author runs (or CI runs):
# In author's terminal (or GitHub Action)
claude-code review \
--base main \
--head feature/new-feature \
--prompt-file .claude/prompts/code-review.md \
--output github-comments
Standard Prompt (.claude/prompts/code-review.md)
# Automated Code Review — Project: [Name]
## Repository Context
- Stack: Laravel 11 + Vue 3 + Inertia + TypeScript + Pest
- Architecture: Modular Monolith (app/Modules/)
- Patterns: Action pattern, DTOs, Domain Events, Form Requests
- Testing: Pest (feature > unit), Vitest (components), Playwright (critical E2E)
- Conventions: PSR-12, Laravel Pint, TypeScript strict, Conventional Commits
## What to Look For (Priority Order)
### 🔴 CRITICAL — Blocks Merge
1. **Security**: SQL injection, XSS, auth bypass, secrets in code, mass assignment without guards
2. **Data Integrity**: Irreversible migrations, missing FKs, missing transactions
3. **Broken Tests**: Failing in CI, flaky tests without quarantine
4. **Regressions**: Changes breaking existing tests without updating them
### 🟠 HIGH — Requires Fix Before Approve
5. **N+1 Queries**: `foreach` with DB query, missing `loadMissing()`, incomplete eager loading
6. **Validation**: Missing Form Request, validation in controller, mass assignment without `$fillable`/`$guarded`
7. **Authorization**: Missing Policy/Gate, `authorize()` in controller, data leakage
8. **Typing**: TypeScript `any`, PHPStan Level 6+ violations, stale PhpDoc
### 🟡 MEDIUM — Comment, Don't Block (Ideally Fixed in PR)
9. **Conventions**: PSR-12, Laravel Pint, inconsistent naming, unused imports
10. **Tests**: < 80% coverage on new code, missing feature test for happy path, untested edge cases
11. **Documentation**: Missing ADR for architectural decision, stale README, missing public PHPDoc
12. **Performance**: Missing cache on expensive query, missing DB index, sync job that should be async
### 🟢 LOW — Suggestion (Optional)
13. **Simplicity**: Over-engineered, premature abstraction, forced DRY
14. **DX**: Missing helper, macro, or trait that would reduce boilerplate
15. **Observability**: Missing structured logging, Pulse metric, Sentry breadcrumb
## What NOT to Look For (Human Does This)
- Business intentionality vs Linear/Jira ticket
- 6-month architectural trade-offs
- Simplicity vs AI "cleverness"
- UX/product decisions
-Product/UX decisions
- Domain naming (ubiquitous language)
Phase 2: Human Review — The 3 Pillars (Where I Spend My Time)
Once the auto-filter passes (or author fixes criticals), I step in. My review focuses exclusively on what AI doesn’t master:
Pillar 1: Business Intentionality
Key Question: “Does this code solve the actual ticket problem, or just the technical problem the dev assumed?”
## Real Example
Ticket: "User can cancel monthly subscription"
❌ PR implements: Immediate cancellation + automatic refund
✅ Business required: Cancellation at end of billing period + proration + confirmation email
PR Comment:
> "Ticket LINEAR-1234 specifies 'cancellation at end of current billing period with proration'.
> Here it cancels immediately and refunds full amount.
> Confirm with PO if immediate behavior is intentional (scope change) or a bug.
> If intentional, update ticket and add test for proration."
Pillar 2: Architecture & Scalability (6-Month View)
Key Question: “Does this change introduce coupling that will hurt in 6 months?”
// ❌ PR proposes: Billing logic directly in Controller
class InvoiceController extends Controller {
public function store(StoreInvoiceRequest $request) {
$invoice = Invoice::create($request->validated());
// Business logic: 50 lines of calculations, Stripe, ERP sync, emails
$this->syncToERP($invoice);
$this->sendConfirmationEmail($invoice);
return $invoice;
}
}
// ✅ Reviewer Comment:
// "This logic belongs in `CreateInvoiceAction` (Action pattern).
// Controller should only: authorize + validate + dispatch Action + respond.
// Why? 1) Testable without HTTP 2) Reusable from CLI/Job/API 3) Separates concerns
// See app/Modules/Billing/Actions/CreateInvoiceAction.php for existing pattern."
Pillar 3: Maintainability & Simplicity
Key Question: “Will the next dev (or me in 6 months) understand this without debugging?”
// ❌ PR proposes: "Smart" helper with 15 optional params
function formatCurrency(
amount: number,
currency: string,
locale?: string,
showSymbol?: boolean,
compact?: boolean,
roundingMode?: 'ceil' | 'floor' | 'round',
fallback?: string,
// ... 8 more
): string { /* 80 lines */ }
// ✅ Reviewer Comment:
// "This is 'clever' but fragile. We prefer 2 simple functions:
// 1) formatCurrency(amount, currency, locale?) → string (95% case)
// 2) formatCurrencyCompact(amount, currency) → string (5% case)
// Fewer params = fewer bugs, better autocomplete, testable.
// Forced DRY here increases cognitive complexity, doesn't reduce it."
Mandatory PR Template (.github/pull_request_template.md)
## 📋 Context
- **Ticket**: [LINEAR-XXXX](link) / [JIRA-XXXX](link)
- **Problem**: What this PR solves in one sentence
- **Key Decisions**: ADR referenced if applicable (e.g. `docs/adr/014-stripe-webhook-idempotency.md`)
## 🧪 Testing
- [ ] Pest feature tests: happy path + edge cases (validation, auth, limits)
- [ ] Vitest component tests: props, events, states
- [ ] Playwright E2E: critical flow (if touches checkout, auth, payments)
- [ ] Mutation testing (Infection): ≥ 80% on new code
- [ ] Tests pass in CI: `php artisan test --parallel` + `npm test`
## 🤖 AI Review (Pre-check)
- [ ] `claude-code review --base main` run locally
- [ ] 🔴/🟠 issues resolved before requesting human review
- [ ] Atomic commits, conventional messages (`feat:`, `fix:`, `refactor:`)
## 👀 For Human Reviewer
- **Intentionality**: Does it solve the real ticket?
- **Architecture**: Does it fit `app/Modules/*/Actions|DTOs|Events`?
- **Simplicity**: Can it be read without debugging?
- **Naming**: Ubiquitous domain language?
## 🚀 Deploy
- [ ] Feature flag if risky change (`config/feature-flags.php`)
- [ ] Reversible migrations (`down()` tested)
- [ ] Runbook updated if new alert/metric
Cycle Metrics (What We Measure)
| Metric | Before (Human Only) | After (Human + AI) | Target |
|---|---|---|---|
| Time to First Review | 18-48h | 2-4h | < 4h |
| Review Cycles/PR | 3-5 | 1-2 | ≤ 2 |
| PR Cycle Time | 3-5 days | 4-12h | < 24h |
| ”Nitpick” Comments/PR | 8-15 | 1-3 | ≤ 3 |
| Prod Bugs/Release | 2-3 | 0-1 | 0 |
| Reviewer Fatigue (survey) | 3.2/5 | 4.6/5 | ≥ 4.5 |
Culture: “AI for Mechanics, Human for Strategy”
Team Rules (In CONTRIBUTING.md)
- Author runs AI filter BEFORE requesting review — “Don’t waste my time on semicolons”
- Human reviewer ONLY comments on Pillars 1-3 — If you see a style comment, it’s a process failure
- Small PRs (<300 lines, 1 purpose) — If it doesn’t fit, split it. AI reviews small PRs better.
- Review SLA: 4 business hours — If you can’t, reassign. “Approve/Request Changes” buttons in GitHub.
- Post-merge: MCP syncs docs — ADRs, OpenAPI, CHANGELOG updated automatically via MCP server.
Example of a “Well-Done” Human Comment
> **Architecture** (Pillar 2)
>
> In `app/Modules/Billing/Actions/CreateSubscriptionAction.php:45`
>
> `SyncToERPJob` is dispatched synchronously inside the DB transaction.
> If ERP fails → subscription rollback → user has no subscription but Stripe charged.
>
> **Proposal**: Move `SyncToERPJob` outside transaction (after_commit) + compensation:
> ```php
> DB::transaction(function () {
> $subscription = $this->createSubscription($data);
> // Only local DB here
> });
>
> // After commit - if fails, compensate via Stripe webhook + retry
> SyncToERPJob::dispatch($subscription)->afterCommit();
> ```
>
> See `docs/adr/012-erp-sync-reliability.md` for full pattern.
>
> Thoughts? If agreed, implement in this PR or follow-up ticket.
What I NEVER Delegate to AI (Red List)
| Area | Why |
|---|---|
| Architectural decisions | AI optimizes locally, misses system-wide + business trade-offs |
| Critical security (auth, payments, crypto) | I review line-by-line; AI assists, doesn’t decide |
| Business intentionality | Only human validates against ticket/PO/client |
| Final merge | I approve full diff in GitHub before merge |
| Domain naming | Ubiquitous language = team agreement, not AI suggestion |
Tool Stack (2026)
| Tool | Role |
|---|---|
| Claude Code | Auto pre-review filter, refactoring, test scaffolding |
| GitHub Actions | CI gate: tests, PHPStan, Pint, Lighthouse CI, Mutation testing |
| Sentry + Pulse | Post-merge observability (error rate, perf, cron) |
| MCP Servers | Post-merge doc sync (ADR, OpenAPI, CHANGELOG) |
| Linear/GitHub Projects | Ticket ↔ PR ↔ Deploy tracking |
Want to Implement This in Your Team?
Available for technical consulting (2-4 weeks) or hiring as Senior who brings this workflow ready.
Modalities:
- EOR (Deel, Remote, Oyster) — core indefinite roles
- Freelance B2B (Autónomo, intra-community invoice 0% VAT) — 3-12 month projects
- Direct Permanent — if you have Spanish entity
Stack: Laravel 11, PHP 8.3+, Vue 3 + TS, Inertia.js, Livewire 3, Astro, Docker, GitHub Actions, Laravel Pulse, Sentry, Claude Code / Cursor / MCP servers.
View My Profile, Full Stack & Terms →
Related Articles on This Blog
- How I Use Claude Code in Production with Laravel and Vue — Morning flow, writing, refactoring, MCP
- Metrics a Senior Full-Stack Should Defend — Cycle Time, MTTR, Core Web Vitals, infra cost, Bus Factor
- Laravel + Vue for Distributed Teams — Inertia architecture, async workflow, onboarding
- Async-First: How I Work Remote from Barcelona — Communication, tooling, rituals
- CTO Guide to Hiring Laravel Developers in Spain — Market, profiles, interview process
