AI-Assisted Fullstack Engineering Program
One intensive month to become a developer capable of building real systems quickly, with an AI-first mindset and progressive complexity.
The business problem
A payment provider sends HTTP notifications — webhooks — every time a payment changes state: initiated, completed, failed, refunded. These arrive out of order, may be retried multiple times with the same event_id, and must never be lost. Your system must receive them reliably, deduplicate them, reflect the current payment state, and give operators full visibility into every event that touched a payment.
What you will build
- A Webhook Processing System — a single project that grows across all 4 weeks
- A layered backend: HTTP → Service → Repository Interface → Eloquent, with event logging and idempotent payment upserts
- A full-featured dashboard with auth, filters, pagination, and auto-refresh (Vue + Nuxt or Blade + Turbo)
- A decoupled queue system with workers, retry logic, and rate limiting
- Deep specialization in your chosen track: Fullstack, DevOps, or QA
One system — evolving every week
php artisan serve and reading the Laravel Getting Started docs before writing any project code.What you will build and who you will become
The entire program revolves around one system: the Webhook Processing System. It starts as a bare Laravel project and grows into a complete, scalable, tested application.
What you will build
- A real-time webhook receiver with proper validation and idempotency
- A clean layered architecture: HTTP → Service → Repository Interface → Eloquent
- A full-featured dashboard with authentication, filters, pagination, and auto-refresh
- A decoupled queue system with workers, retry logic, and rate limiting
- Deep expertise in your chosen track: Fullstack, DevOps, or QA
Who you become by the end
- You build real systems fast, using AI effectively and with judgment
- You understand and can defend architecture decisions and their trade-offs
- You know how to scale an application that starts simple
How each week is structured
- Before starting: write a short estimate — how long each deliverable will take and why. Compare to reality at the end of the week. Clients judge by how accurately you scope work, not just how well you code.
- During the week: work on a feature branch. Commit regularly with meaningful messages — one commit per logical unit of work, not one giant commit for everything.
- End of week: open a PR targeting
main. Write a description explaining the key architectural decision you made that week and what trade-off it involves. This replaces a client status report. - Weekly review (30 min): walk the mentor through your PR. Explain one decision — not what you built but why you built it that way. Answer questions without opening the code.
- Client communication task: each week includes one short written task — a status update, a clarifying question, or an explanation for a non-technical reader. This is not optional; writing for non-engineers is a job requirement.
Golden rule: no new codebases. Each week you extend what you built the week before. Day 1 code lives in the day 28 system.
Backend Foundations
Build the backend from scratch using Laravel. The architecture is enforced from day one: every request flows through a defined layered stack — there is no shortcut through Eloquent directly from a controller.
Before starting: estimate how long the architecture deliverables and feature deliverables will each take. Write it down — compare to reality at the end of the week. Estimation under constraints is one of the first things clients evaluate.
Required architecture — HTTP → Service → Repository Interfaces
Architecture deliverables
- Define
EventLogRepositoryInterfacewithstore()andfindByPaymentId() - Create
EloquentEventLogRepositoryimplementing the interface - Define
PaymentRepositoryInterfacewithupsert(),findByPaymentId(), andlist() - Create
EloquentPaymentRepositoryimplementing the interface - Bind both interfaces to their implementations in
AppServiceProvider WebhookServicereceives both interfaces via constructor injection — no direct Eloquent usage
Feature deliverables
POST /webhooks/payment— Form Request validatesevent_id,payment_id,eventtype,amount ≥ 0integer (cents —25000= $250.00),currency(3-letter ISO)- Migration for
event_logstable:event_id,payment_id,event,amount,currency,user_id,timestamp,received_at - Migration for
paymentstable:payment_id,event(status),amount,currency,user_id,last_event_id,updated_at - Service flow: always store
EventLog, then idempotently upsertPaymentonly ifevent_idis new GET /paymentsreturns current state perpayment_id, newest firstGET /payments/{id}/eventsreturns allevent_logrows for that payment, ordered bytimestamp- Correct HTTP error responses (400, 422) with consistent JSON structure
- Structured logging of each incoming webhook with context (
event_id,payment_id,user_id) - Frontend: payments list page with auto-refresh; clicking a payment shows its event log
- Unit test: given the same
event_idsent twice, assert the second POST creates a newEventLogrow but does not update thePayment - Open a PR targeting
main— write a description explaining your data model and idempotency strategy as if the reader has never heard the word "idempotency" - Client communication: write a 3-sentence message to a non-technical client explaining what idempotency means and why their payment data won't be corrupted by duplicate webhook deliveries
Apply now — SOLID SRP: before writing WebhookService, re-read SOLID → Single Responsibility. The service has one reason to change: orchestrating the webhook flow. Validation belongs in the Form Request. Logging belongs in a listener or the repository. Persistence belongs behind the interface.
Apply now — REST API Design: before defining routes for POST /webhooks/payment, GET /payments, and GET /payments/{id}/events, re-read REST API → Resource Naming and HTTP Verbs. Every URL should be a noun. Every status code should tell the caller exactly what happened.
Apply now — Clean Code: as you write your first service methods, re-read Clean Code → Naming and Functions. A reviewer will reject handleIt() and $data. Name things so the code reads like prose.
Week 1 deliverable: a working end-to-end webhook processing system with two DB-backed entities. Every POST creates an EventLog row (including retries). The Payment row is upserted only when a new event_id arrives. The detail view surfaces the full event history per payment.
Full Application Build
Extend the backend into a complete application. Both paths implement exactly the same features — the difference is only in the frontend stack. Choose one and commit to it.
Before starting: estimate how long authentication, your chosen frontend path, and the filter/pagination work will each take. Flag your biggest scope risk — what would you cut first if the week ran short?
Path A
Vue + Nuxt. Component-based, SSR optional. Requires Pinia stores for all fetched data and a dedicated API module — no direct axios/fetch calls from components.
SPA / SSR HybridPath B
Blade + Turbo. Server-driven UI, HTML over JSON, minimal JS.
SSR + Turbo StreamsBackend deliverables (both paths)
- Authentication: login / logout and protected routes
- Pagination:
limitandpageparams onGET /payments - Filters on
GET /payments: by status (event), date range,user_id, andcurrency - Admin: manual refund trigger — POST a
payment.refundedwebhook internally - Security audit: review your auth implementation against OWASP A01 (Broken Access Control) and A07 (Authentication Failures) — document any gaps found and how you addressed them
- Open a PR for Week 2 — description must explain which frontend path you chose and why, and one concrete trade-off of that choice
- Client communication: write a status update to a non-technical stakeholder explaining what users can now do in the system that they couldn't do last week
Frontend deliverables (both paths); w2-f4–w2-f5 Path A only
- Dashboard with paginated payments table, status badges, and dynamic filters
- Payment detail view: shows all
event_logrows for apayment_id, ordered bytimestamp, including duplicate deliveries - Smart auto-refresh: updates payments list without breaking active pagination or filters
- Pinia stores hold all fetched data (payments list, payment detail, event logs) — no component-local API calls (Path A only)
- API module (e.g.
api/payments.ts) abstracts all HTTP calls — components never call axios/fetch directly (Path A only)
Apply now — OWASP: every protected route is a potential A01 failure. Re-read OWASP A01 and A07 before finalizing auth middleware. Can an unauthenticated user reach GET /payments? Can a logged-in user trigger a refund they shouldn't own?
Week 2 deliverable: a working application a real user could operate to monitor, filter, and manage the current state of all payments. Path A candidates must additionally demonstrate clean state management via Pinia and a dedicated API module.
Architecture & Scaling
The system works. Now make it resilient and decoupled: the webhook endpoint must not process anything inline — it enqueues and returns immediately. A worker handles everything else.
Before starting: queues add operational complexity — estimate not just build time but verification time. How will you prove the endpoint does not touch the DB during a request? Write your verification strategy before writing code.
Core concepts
- Queues and workers in Laravel: how they decouple ingestion from processing
- Retry logic: what happens when a job fails and how to recover
- Rate limiting: protecting the endpoint from traffic spikes
- Structured logging: logs that can be queried and monitored
Required deliverables
- Webhook only enqueues the job — no inline processing
- Job/Worker processes the event from the queue and persists it via repository
- Deduplication handled in the worker — not in the endpoint
- Automatic retry with exponential backoff for failed jobs
- Rate limiting configured on the webhook endpoint
- Structured logging in the worker with queue context and retry count
- Unit test: assert the webhook endpoint returns 200 immediately and dispatches exactly one job — with no DB write occurring during the HTTP request lifecycle
- Open a PR for Week 3 — description must explain why inline processing was removed and what the system gains and gives up as a result (e.g. eventual consistency, operational complexity)
- Client communication: write a short explanation for a client asking "why does the dashboard sometimes show a payment a few seconds after I sent the webhook?"
Week 3 deliverable: a decoupled system that can receive thousands of webhooks without processing any of them inline — built to handle real production load.
Specialization
On top of the same system, you choose your track and add real technical depth. Each track maps to a distinct engineering role.
Fullstack
Metrics and analytics, real-time notifications (WebSockets), CSV export with active filters, query optimization and database indexing. Then: build a separate plain-PHP hexagonal project — the payment provider itself — with Domain / Application / Infrastructure layers, card tokenization, charge simulation, and automatic webhook dispatch back to the Laravel app.
DevOps
Full Dockerization (backend, DB, worker), CI/CD pipeline, separated environments (dev / staging / prod), Datadog integration (APM, logs, dashboards), health checks.
QA
PHPUnit unit and integration tests, Playwright E2E (CRUD, filters, login), edge cases (duplicates, concurrency, DB failures), quality report.
Deliverables common to all tracks
- Track features working on top of the existing system without regressions
- You can defend every technical decision made during the week and explain its trade-offs
- Minimal documentation of the work completed this week
- Open a PR for Week 4 — description must identify the key design decision in your specialization track and name the trade-off it introduces
- Client communication: write a summary for a client explaining what your specialization track delivered and what production concern it addresses
Week 4 deliverable: a system with genuine depth in your specialization area, stable end-to-end, and explainable under any technical question.
- Define
EventLogRepositoryInterfacewithstore()andfindByPaymentId() - Create
EloquentEventLogRepositoryimplementing the interface - Define
PaymentRepositoryInterfacewithupsert(),findByPaymentId(), andlist() - Create
EloquentPaymentRepositoryimplementing the interface - Bind both interfaces to their implementations in
AppServiceProvider WebhookServicedepends on both interfaces via constructor injection — no direct Eloquent usagePOST /webhooks/payment— Form Request validatesevent_id,payment_id,eventtype,amount ≥ 0integer (cents),currency- Migration for
event_logs:event_id,payment_id,event,amount,currency,user_id,timestamp,received_at - Migration for
payments:payment_id,event,amount,currency,user_id,last_event_id,updated_at - Service flow: always store
EventLog, then upsertPaymentonly ifevent_idnot already applied GET /payments— one object perpayment_id, current state, newest firstGET /payments/{id}/events— all event log rows for that payment, ordered bytimestamp- Correct HTTP error responses (400, 422) with consistent JSON structure
- Structured logging of each incoming webhook with context (
event_id,payment_id,user_id) - Frontend: payments list with auto-refresh; clicking a payment opens its event history
- Unit test: same
event_idsent twice — second POST creates a newEventLogrow but does NOT update thePayment - PR opened for Week 1 with description explaining data model and idempotency strategy in plain language
- Client communication: 3-sentence message explaining idempotency to a non-technical client
- Authentication: login / logout with session or token
- Route protection via auth middleware
- Pagination on
GET /payments:limitandpageparams - Filters on
GET /payments: byevent(status), date range,user_id,currency - Admin: manual refund trigger — POST a
payment.refundedwebhook internally - Frontend: paginated payments table with status badges and dynamic filters
- Frontend: payment detail view showing all
event_logrows ordered bytimestamp, including duplicate deliveries - Frontend: smart auto-refresh that does not break active pagination or filters
- Pinia stores hold all fetched data (payments list, payment detail, event logs) — no component-local API calls (Path A only)
- API module (e.g.
api/payments.ts) abstracts all HTTP calls — components never call axios/fetch directly (Path A only) - Security audit: auth reviewed against OWASP A01 (Broken Access Control) and A07 (Authentication Failures) — gaps documented and addressed
- PR opened for Week 2 with description explaining frontend path choice and its trade-off
- Client communication: status update explaining what users can now do in the system
- Webhook endpoint only enqueues — no inline processing
- Job/Worker processes event from queue and persists via repository
- Deduplication handled in the worker, not in the endpoint
- Automatic retry with exponential backoff for failed jobs
- Rate limiting on the webhook endpoint
- Structured logging in the worker with queue context and retry count
- Unit test: webhook endpoint returns 200 immediately and dispatches exactly one job — no DB write in the request lifecycle
- PR opened for Week 3 with description explaining why inline processing was removed and the system trade-off
- Client communication: explanation for "why does the dashboard show a payment a few seconds after I sent the webhook?"
- Track features working on top of the existing system without regressions
- You can defend every technical decision made during the week and explain its trade-offs
- Minimal documentation of the work completed this week
- PR opened for Week 4 with description identifying the key design decision and the trade-off it introduces
- Client communication: summary explaining what your specialization track delivered and what production concern it addresses
GET /metrics: total payments, payments by status, payments by day and currency- Dashboard displays metrics with basic visualization (counters or simple chart)
- Real-time notifications: WebSockets or optimized polling (< 2 s latency) when payment status changes
- Dashboard updates automatically when new payments arrive or existing ones change
- CSV export of payments list respecting active filters
- DB indexes on critical columns:
payment_id,event(status),user_id,updated_at - Queries optimized: no N+1, eager loading where applicable
- Dashboard response latency measured and documented under load
- Create project structure:
Domain/,Application/,Infrastructure/Resources/(controllers + routes),Infrastructure/Domain/(repositories),Infrastructure/Application/(HandlerBus); addhandlers.phpwiring file - Define Value Object
Money: amount (int, cents) + currency (3-letter ISO), immutable - Define Value Object
PaymentMethodId: opaque string withpm_prefix, generated on creation - Define Value Object
CardFingerprint: SHA-256 of the raw PAN, used for duplicate detection - Define Entity
PaymentMethod: holdsPaymentMethodId,userId,last4,brand,expMonth,expYear,encryptedCard,CardFingerprint - Define Entity/Aggregate
Payment: holdspaymentId,PaymentMethodId,Money,status,createdAt - Define
PaymentMethodRepositoryInterface:store(),findById(),findByFingerprint()— domain layer, no infrastructure imports - Define
PaymentRepositoryInterface:store(),findById()— domain layer, no infrastructure imports - Define
WebhookDispatcherInterface:dispatch(Payment $payment)— domain layer, no HTTP imports - Implement
TokenizeCardCommand+TokenizeCardHandler: encrypt PAN viaopenssl_encrypt, generatepm_id, check fingerprint for duplicates, store via repository interface - Implement
ChargePaymentCommand+ChargePaymentHandler: load payment method, run gateway simulation, createPayment, dispatch webhook viaWebhookDispatcherInterface - Implement PDO-backed
PaymentMethodRepositoryandPaymentRepositorywith SQL schema - Implement
GatewaySimulator:last4 = 4242→payment.completed;last4 = 0002→payment.failed; otherwisepayment.completed - Implement
WebhookHttpDispatcher: sendsPOSTto the Laravel app's/webhooks/paymentendpoint with correct payload shape after every charge - Expose routes:
POST /payment-methods(tokenize),GET /payment-methods/{id}(safe metadata only),POST /payments/charge - Wire
HandlerBusinhandlers.php: map commands to handlers with injected infrastructure dependencies - Laravel checkout page (Path A or B) calls
POST /payment-methodsthenPOST /payments/chargeon the hex provider, then navigates to payment detail in the Laravel app - Security rule:
encryptedCardand raw PAN never appear in API responses or logs — onlypayment_method_idand safe metadata cross the boundary
- Dockerfile for backend (Laravel + PHP-FPM + Nginx)
- Dockerfile for worker (standalone queue consumer)
docker-compose.ymlorchestrating backend, DB, worker, and Redis/queue- CI pipeline: automated build and lint on every push
- CI pipeline: automated tests on every PR
- CD pipeline: automated deploy to staging environment
- Separated
dev,staging, andproductionenvironments with per-env.env - Datadog Agent configured as a sidecar container in
docker-compose.yml - APM enabled: Laravel traces visible in Datadog with service, resource, and duration breakdown
- Log forwarding to Datadog: structured JSON logs from backend and worker ingested and queryable
- Custom Datadog dashboard: webhook ingestion rate, payment processing latency, queue depth, worker error rate
- Alert configured: notify when worker error rate exceeds threshold for 5 minutes
- Health checks on containers for orchestration and basic alerting
- Horizontal worker scaling strategy documented and verified
- Unit test: validation logic in
WebhookService— all required fields, allowedeventvalues,amount ≥ 0 - Unit test: idempotency logic —
EventLogis always stored;Paymentupsert skipped ifevent_idalready applied - Unit test:
upsert()andlist()inEloquentPaymentRepository - Unit test:
store()andfindByPaymentId()inEloquentEventLogRepository - Integration test:
POST /webhooks/paymenthappy path — oneEventLogrow created andPaymentupserted - Integration test: duplicate
event_idcreates a secondEventLogrow but does NOT change thePaymentrow - Integration test: multiple webhooks for same
payment_idproduce multipleevent_logrows but onepaymentsrow - Integration test:
GET /payments/{id}/eventsreturns logs intimestamporder - Integration test:
GET /paymentswith filters and pagination returns correct results - E2E Playwright: payments list auto-refreshes when a new webhook arrives
- E2E Playwright: clicking a payment opens its event log showing all received entries including retries
- E2E Playwright: filter payments by status and navigate pagination without losing state
- Edge case: simulated high concurrency (bulk webhook submission with repeated
event_ids) - Edge case: partial DB failure — assert atomicity (both
EventLogandPaymentwrites succeed or both roll back) - Quality report: coverage, bugs found with severity, recommendations
Hexagonal Payment Provider — Project Structure
A standalone plain-PHP project that acts as the payment provider. The Laravel app is its client: it calls the provider to tokenize cards and charge payments, then receives the result as a webhook through the existing pipeline.
Request flow — POST /payments/charge
Directory structure
payment-provider/
Domain/
Payment/
Payment.php
Money.php <!-- VO -->
PaymentRepositoryInterface.php
WebhookDispatcherInterface.php
PaymentMethod/
PaymentMethod.php
PaymentMethodId.php <!-- VO -->
CardFingerprint.php <!-- VO -->
PaymentMethodRepositoryInterface.php
Application/
TokenizeCard/
TokenizeCardCommand.php
TokenizeCardHandler.php
ChargePayment/
ChargePaymentCommand.php
ChargePaymentHandler.php
Infrastructure/
Domain/
PdoPaymentMethodRepository.php
PdoPaymentRepository.php
GatewaySimulator.php
WebhookHttpDispatcher.php
Resources/
controllers.php
routes.php
Application/
HandlerBus.php
config/
handlers.php <!-- Command → Handler wiring -->
db/
migrations/
Layer responsibilities
Key rule: the Domain layer has no require or use statements pointing outward. Interfaces defined in Domain are implemented in Infrastructure and injected by the HandlerBus configured in handlers.php.
Engineering references — when to apply them
SOLID Principles
Apply during Week 1 when designing WebhookService. S = one reason to change. D = depend on interfaces, not Eloquent.
buildonline/solid-principles DocsDomain-Driven Design
Apply during Week 1–2 when modeling payments, event logs, and repositories. Entities vs Value Objects. Repository as collection abstraction.
buildonline/ddd DocsTest-Driven Development
Apply every week when writing the required unit tests. AAA pattern, test doubles for repositories, test pyramid for QA track.
buildonline/tdd DocsOWASP Top 10
Apply during Week 2 auth audit. A01 Broken Access Control, A07 Authentication Failures. Every protected route is a potential failure.
buildonline/owasp DocsGit Workflow
Apply from day 1. Conventional commits, trunk-based branching, and PR anatomy — every weekly PR must follow this format.
buildonline/git-workflow DocsREST API Design
Apply during Week 1 when defining routes. Resource naming, HTTP verb semantics, status codes, and consistent response shapes.
buildonline/rest-api DocsClean Code
Apply from Week 1 onwards. Naming, function design, guard clauses, comment policy, and code smells. Reviewers will hold you to this.
buildonline/clean-codeLaravel — Core
Laracasts
The reference for Laravel. Start with Laravel From Scratch — covers controllers, services, Eloquent, queues and testing.
youtube.com/@Laracasts YouTubeLaravel Daily
Practical short videos by Povilas Korop. Strong coverage of Repository Pattern, API best practices, and real-world refactoring.
youtube.com/@LaravelDaily YouTubeLaravel Official
Conference talks, feature announcements, and deep dives straight from the Laravel core team.
youtube.com/@LaravelPHP DocsLaravel Queues
Official documentation for jobs, workers, retry logic, rate limiting, and failed job handling — the core of Week 3.
laravel.com/docs/queues DocsService Container & Binding
How to bind EventRepositoryInterface to its Eloquent implementation via AppServiceProvider.
laravel.com/docs/container DocsLaravel Testing
HTTP tests, database assertions, mocking repositories, and feature test structure with PHPUnit.
laravel.com/docs/testingArchitecture — Repository Pattern
Repository Pattern in Laravel
Search for videos covering HTTP → Service → Repository Interface → Eloquent. Several good walkthroughs exist from Laravel Daily and others.
Search: "repository pattern laravel service layer" DocsEloquent & ORM
Models, relationships, query scopes, and Eloquent internals — all of which your repository implementation will use.
laravel.com/docs/eloquentFrontend — Vue / Nuxt & Blade
Vue School
Composition API, Pinia state management, and Nuxt 3 fundamentals — the stack for Path A.
youtube.com/@vueschool DocsNuxt 3 Docs
Server-side rendering, data fetching with useFetch, and composables — all needed for Path A's dashboard.
nuxt.com/docs DocsTurbo Handbook
Turbo Frames, Turbo Streams, and Turbo Drive — the backbone of Path B's server-driven UI with real-time updates.
turbo.hotwired.devDevOps — Docker, CI/CD & Datadog
TechWorld with Nana
Best free content on Docker, Docker Compose, Kubernetes, and CI/CD pipelines. Start with the Docker full course.
youtube.com/@TechWorldwithNana DocsDatadog PHP APM
Setup guide for the Datadog Agent, ddtrace extension, Laravel auto-instrumentation, and log correlation.
docs.datadoghq.com/tracing/…/php DocsGitHub Actions
Workflow syntax, matrix builds, caching dependencies, and deploy jobs — everything needed for the CI/CD pipeline.
docs.github.com/en/actionsTesting — PHPUnit & Playwright
Laravel PHPUnit Testing
Search for recent tutorials on unit tests, feature tests, database factories, and mocking repositories in Laravel.
Search: "laravel phpunit testing" DocsPlaywright Docs
Getting started, page object model, fixtures, and the test recorder — write E2E tests for CRUD flows and auth.
playwright.dev/docs/intro YouTubeThe Codeholic
Laravel REST API tutorials including validation, authentication, and clean project structure — useful for the QA track.
youtube.com/@TheCodeholic