## Getting Started
### Minimal Setup
1. **Install the Bundle**
```bash
composer require dbp/relay-checkin-bundle
php artisan vendor:publish --provider="Dbp\RelayCheckinBundle\RelayCheckinBundle" --tag="config"
config/relay_checkin.php.Configure Required Services
config/relay_checkin.php with:
campus_qr_api_url (your CampusQR instance endpoint).database_connection (if using local storage for check-ins).encryption_key (for secure QR code generation).CAMPUS_QR_API_KEY environment variable is set.Run Migrations
php artisan migrate
checkins, locations, and users (if using local storage).First Use Case: Register a Location
use Dbp\RelayCheckinBundle\Service\LocationService;
$locationService = app(LocationService::class);
$location = $locationService->create([
'name' => 'Main Campus Building',
'code' => 'BUILDING_01',
]);
storage/app/qr_codes/).Frontend Integration:
/api/checkin) using Laravel’s Route::post:
Route::post('/api/checkin', [CheckinController::class, 'store']);
user_id, location_id, timestamp):
use Dbp\RelayCheckinBundle\DTO\CheckinDTO;
public function store(Request $request) {
$dto = new CheckinDTO(
$request->user_id,
$request->location_id,
$request->timestamp ?? now()
);
$checkinService = app(CheckinService::class);
$checkin = $checkinService->create($dto);
return response()->json($checkin);
}
Sync with CampusQR:
CampusQRApiService to relay check-ins to CampusQR:
$apiService = app(CampusQRApiService::class);
$apiService->relayCheckin($checkin->user_id, $checkin->location_id, $checkin->timestamp);
$locationService = app(LocationService::class);
$locations = [
['name' => 'Lab A', 'code' => 'LAB_A'],
['name' => 'Lab B', 'code' => 'LAB_B'],
];
foreach ($locations as $data) {
$locationService->create($data);
}
storage/app/qr_codes/{location_code}.png.$locationService->setQrContentGenerator(function ($location) {
return "LOCATION:{$location->code}:SALT_" . config('app.key');
});
$checkinService = app(CheckinService::class);
$history = $checkinService->getUserHistory($userId, now()->subDays(7));
use Illuminate\Support\Facades\Storage;
$csv = $checkinService->exportUserHistory($userId);
Storage::put('exports/checkin_history_{$userId}.csv', $csv);
Route::post('/api/campusqr/webhook', [CampusQRWebhookController::class, 'handle']);
$alertService = app(AlertService::class);
$alertService->notifyExposedUsers($exposedUserId, now()->subHours(2));
CheckinCreated events for real-time processing:
Event::listen(CheckinCreated::class, function ($event) {
// Send Slack notification or log to a third-party system
});
RelayCheckinToCampusQR::dispatch($checkin);
CampusQRApiService in unit tests:
$this->partialMock(CampusQRApiService::class, function ($mock) {
$mock->shouldReceive('relayCheckin')->once();
});
/api/v1/checkin) to avoid breaking changes.Route::middleware(['throttle:60,1'])->post('/api/checkin', ...);
CampusQR API Dependencies:
docker-compose up -d dbp/check-in/campus-qr
ClientException if the API URL or key is misconfigured. Verify with:
curl -X GET {campus_qr_api_url}/health -H "Authorization: Bearer $CAMPUS_QR_API_KEY"
QR Code Security:
$locationService->setQrContentGenerator(function ($location) {
return "LOCATION:{$location->code}:{$location->updated_at->timestamp}";
});
Str::random(32) for dynamic salts.Database Schema Mismatches:
php artisan vendor:publish --tag="migrations"
to publish the bundle’s migrations before running php artisan migrate.Timezone Handling:
config/relay_checkin.php:
'timezone' => 'Europe/Vienna', // Default in CampusQR
setTimezone() when processing timestamps:
$checkin->timestamp->setTimezone(config('relay_checkin.timezone'));
Webhook Delays:
use Illuminate\Support\Facades\Http;
$response = Http::withOptions(['timeout' => 10])
->post($campusQrUrl, $payload)
->throw();
Logging:
config/relay_checkin.php:
'debug' => env('APP_ENV') === 'local',
$apiService->setDebugMode(true);
Common Errors:
InvalidLocationException: Thrown if a location code doesn’t exist. Validate with:
if (!$locationService->exists($locationCode)) {
throw new InvalidLocationException("Location {$locationCode} not found.");
}
DuplicateCheckinException: Prevent duplicates by checking:
if ($checkinService->existsForUserAndLocation($userId, $locationId, $timestamp)) {
throw new DuplicateCheckinException("Already checked in.");
}
Performance:
checkins table for large datasets:
Schema::table('checkins', function (Blueprint $table) {
$table->index(['user_id', 'location_id', 'timestamp']);
});
CheckinService to add validation:
$checkinService = app(CheckinService::class);
$checkinService->setValidator(function ($dto) {
How can I help you explore Laravel packages today?