A Laravel-based escrow system that manages gigs, freelancers, and transactions. It supports job queues, email notifications, and clean API architecture.
composer create-project laravel/laravel code-escrow
cd code-escrowcp .env.example .env
php artisan key:generateUpdate .env:
DB_CONNECTION=mysql
DB_DATABASE=code_escrow
DB_USERNAME=root
DB_PASSWORD=
QUEUE_CONNECTION=database
MAIL_MAILER=smtp
MAIL_HOST=sandbox.smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=your_username
MAIL_PASSWORD=your_password
MAIL_FROM_ADDRESS="transaction@yourecapp.com"
MAIL_FROM_NAME="Code Escrow"php artisan make:model Gig -m
php artisan make:model Freelancer -m
php artisan make:model Transaction -mSchema::create('transactions', function (Blueprint $table) {
$table->id();
$table->foreignId('gig_id')->constrained()->cascadeOnDelete();
$table->decimal('amount_usd', 10, 2);
$table->string('status');
$table->timestamps();
});php artisan migratephp artisan queue:table
php artisan migratephp artisan queue:work📄 routes/api.php
Route::get('/gigs', [GigController::class, 'index']);
Route::post('/gigs', [GigController::class, 'store']);
Route::get('/freelancer', [FreelancerController::class, 'index']);
Route::post('/freelancer', [FreelancerController::class, 'store']);
Route::get('/transaction', [TransactionController::class, 'index']);
Route::patch('/freelancers/refresh-trust', [FreelancerController::class, 'refreshTrust']);📄 bootstrap/app.php
- Loads routes
- Registers middleware
- Handles exceptions
(No modification usually needed)
php artisan make:request StoreGigRequest📄 app/Http/Requests/StoreGigRequest.php
public function rules()
{
return [
'title' => 'required|string',
'price' => 'required|numeric'
];
}php artisan make:controller GigController📄 app/Http/Controllers/GigController.php
public function store(StoreGigRequest $request)
{
return $this->gigService->create($request->validated());
}📄 app/Services/GigService.php
class GigService
{
public function create(array $data)
{
return Gig::create($data);
}
}📄 app/Models/Transaction.php
class Transaction extends Model
{
protected $fillable = ['gig_id', 'amount_usd', 'status'];
public function gig()
{
return $this->belongsTo(Gig::class);
}
}php artisan make:migration create_transactions_tablephp artisan make:enum TransactionStatus📄 app/Enums/TransactionStatus.php
enum TransactionStatus: string
{
case PENDING = 'pending';
case RELEASED = 'released';
}php artisan make:factory TransactionFactory📄 database/factories/TransactionFactory.php
return [
'amount_usd' => fake()->randomFloat(2, 10, 500),
'status' => 'pending'
];php artisan make:seeder DatabaseSeeder📄 database/seeders/DatabaseSeeder.php
Transaction::factory(10)->create();Run:
php artisan db:seedphp artisan make:resource TransactionResource📄 app/Http/Resources/TransactionResource.php
public function toArray($request)
{
return [
'amount' => $this->amount_usd,
'status' => $this->status,
'gig' => new GigSummaryResource($this->whenLoaded('gig'))
];
}php artisan make:job SendPayoutEmailJob📄 app/Jobs/SendPayoutEmailJob.php
public function handle()
{
Mail::to($this->email)->send(new PayoutMail($this->transaction));
}📄 resources/views/emails/payout.blade.php
<h1>Payment Released</h1>
<p>Amount: {{ $transaction->amount_usd }}</p>php artisan make:mail PayoutMail📄 app/Mail/PayoutMail.php
public function build()
{
return $this->view('emails.payout')
->with(['transaction' => $this->transaction]);
}- Request hits
api.php - Goes to Controller
- Request validated
- Service executes logic
- DB transaction happens
- Job dispatched
- Queue processes job
- Mail sent
- Resource formats response
{
"title": "Build Laravel API",
"price": 150
}{
"name": "John Doe",
"email": "john@example.com"
}{}- Always run queue worker for jobs
- Use
with('gig')to avoid resource errors - Never put logic inside controllers
- Services = core brain of your app
This README now fully represents your project structure, setup, and execution pipeline.