slot-booking/bootstrap/app.php
Dmitriy 16f3f851b1 feat: slot booking API with hot cache and oversell protection
GET /slots/availability, POST /slots/{id}/hold, POST /holds/{id}/confirm
and DELETE /holds/{id} on Laravel 12 and MySQL 8.

- availability cached for 10s behind a single-flight lock with a stale
  copy, invalidated after commit on confirm and cancel
- oversell prevented by a conditional decrement, verified by the number
  of affected rows rather than a preceding select
- idempotency enforced by a unique index on holds.idempotency_key
- active holds counted with an expires_at filter, so no background
  cleanup is required for correctness
- 27 feature tests against MySQL, service documentation, Postman collection

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-31 14:47:18 +03:00

39 lines
1.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
use App\Exceptions\SlotBookingException;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
// Пути в задании заданы без префикса. Маршруты при этом остаются
// в routes/api.php со stateless-мидлварами группы api.
api: __DIR__.'/../routes/api.php',
apiPrefix: '',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware): void {
//
})
->withExceptions(function (Exceptions $exceptions): void {
// Доменные отказы несут свой статус и код причины.
$exceptions->render(fn (SlotBookingException $e) => response()->json([
'message' => $e->getMessage(),
'reason' => $e->reason,
], $e->status));
// 404 без имени класса модели в ответе. ModelNotFoundException ловить
// бесполезно: Laravel подменяет её на NotFoundHttpException до колбэков.
$exceptions->render(fn (NotFoundHttpException $e) => response()->json([
'message' => 'Resource not found.',
'reason' => 'not_found',
], 404));
// Только API: JSON даже клиенту без Accept: application/json.
$exceptions->shouldRenderJsonWhen(fn (Request $request, Throwable $e) => true);
})->create();