Expert guidance for Azonation's Laravel 11 API platform with multi-tenant architecture, payment gateways, and domain-driven design patterns.
Expert development assistant for the Azonation Laravel 11 API platform—a multi-tenant system serving individual users and organizations with membership management, events, projects, committees, e-commerce, and multi-gateway payment processing.
Provides architecture-aware guidance for Azonation's domain-driven Laravel backend, including:
When working on Azonation backend code:
1. **Respect Domain Boundaries**
- Controllers are organized by domain in `app/Http/Controllers/`: Auth, Common, Individual, Org (with subdomains), Ecommerce, PaymentGateway, SuperAdmin
- Keep domain logic within its directory (e.g., membership features in `Org/Membership/`)
- Use Common for shared cross-domain features (Address, PhoneNumber, Notification, Referral, UserCountry)
2. **Follow User Context Patterns**
- User model has `type` field (individual|organisation)
- Check `User::type` early in org-specific features
- Most features require `Auth::id()` or `Auth::user()`
- Track geographic context via UserCountry relationship
3. **Apply File/Image Management Pattern**
- Every major entity has paired models (e.g., EventImage/EventFile, ProjectImage/ProjectFile)
- Use timestamp-prefixed filenames: `YmdHis_originalname.ext`
- Store via `Storage::disk('public')->storeAs('feature/subfolder', $newFileName, 'public')`
- Validate: `'image' => 'image|mimes:jpeg,png,jpg,gif,svg|max:20048'`
- Models hide timestamps by default: `$hidden = ['created_at', 'updated_at']`
4. **Maintain Consistent API Responses**
- Use success helper pattern:
```php
return response()->json([
'status' => 'success',
'message' => $message,
'data' => $data
], $status);
```
5. **Handle Subscriptions and Billing**
- Organizations require ManagementSubscription (auto-created at registration)
- StorageSubscription tracks per-org storage limits with daily billing
- Billing models: ManagementAndStorageBilling, EverydayStorageBilling, EverydayMemberCountAndBilling
- Tie billing to RegionCurrency for multi-currency support
6. **Implement Payment Gateway Integration**
- Use multi-gateway abstraction pattern (PaymentGatewayController)
- Store encrypted credentials in GatewayCredential per region
- Log all transactions to Payment model + gateway-specific models
- Implement idempotency checks in webhook handlers
- Support gateways: Stripe, PayPal, Razorpay, SSL Commerz, Alipay, WeChat Pay, 2Checkout, AuthorizeNet, Square, Paytm, BKash, Tap, manual
7. **Follow Membership Lifecycle**
- Track member status via MembershipStatus (Approved, Pending, Terminated)
- Maintain audit trail in OrgMembershipStatusHistory and OrgMembershipStatusLog
- Handle renewals via OrgMembershipRenewal with configurable pricing
- Track terminations with reasons in MembershipTermination
8. **Use Event/Project/Meeting Pattern**
- Parallel structure for activities: Event, Project, Meeting
- Each has Attendance, GuestAttendance, Dignitary, Summary, Images, Files
- Attendance types configurable via SuperAdmin AttendanceType model
9. **Write Tests Properly**
- Run: `php artisan test` (all), `php artisan test --filter=TestName` (specific)
- Test environment uses in-memory session, array cache, sync queue
- Use factories in `database/factories/` for test data
10. **Follow Authentication Patterns**
- Sanctum for API tokens (User has HasApiTokens trait)
- OAuth2 via Socialite for Google login (stores google_id, oauth_provider, oauth_refresh_token)
- Session auth for web routes
- No explicit role system—check User::type field
11. **Handle Registration Flow**
- Validate input (email uniqueness, password strength)
- Hash password, create User with registration_completed = true
- Create UserCountry association
- Auto-create ManagementSubscription and StorageSubscription for orgs
- Send type-specific welcome emails (IndividualUserRegisteredMail, OrgUserRegisteredMail)
- Handle optional referral codes for ReferralReward tracking
12. **Migration and Database Best Practices**
- 160+ migrations with clear naming: `create_*_table.php`
- Run: `php artisan migrate`
- Use Eloquent relationships—avoid manual joins
- Models define relations; use `$model->relation()->get()`
13. **Common Commands Reference**
```bash
php artisan test # Run PHPUnit tests
php artisan migrate # Run pending migrations
php artisan tinker # Interactive REPL
php artisan cache:clear # Clear cache
php artisan route:list # Show all routes
composer install # Install dependencies
npm install && npm run build # Build Vite assets
```
```php
// In EventImageController
public function store(Request $request) {
$request->validate([
'event_id' => 'required|exists:events,id',
'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:20048'
]);
$image = $request->file('image');
$timestamp = Carbon::now()->format('YmdHis');
$originalName = pathinfo($image->getClientOriginalName(), PATHINFO_FILENAME);
$extension = $image->getClientOriginalExtension();
$newFileName = $timestamp . '_' . $originalName . '.' . $extension;
$path = $image->storeAs('events/images', $newFileName, 'public');
$eventImage = EventImage::create([
'event_id' => $request->event_id,
'image_path' => $path
]);
return response()->json([
'status' => 'success',
'message' => 'Event image uploaded successfully',
'data' => [
'id' => $eventImage->id,
'url' => Storage::url($path)
]
], 201);
}
```
```php
// In AuthController@register (org type)
$user = User::create([
'email' => $request->email,
'password' => Hash::make($request->password),
'type' => 'organisation',
'registration_completed' => true
]);
UserCountry::create([
'user_id' => $user->id,
'country_id' => $request->country_id
]);
ManagementSubscription::create([
'user_id' => $user->id,
'package_id' => $request->management_package_id,
'status' => 'active',
'start_date' => now()
]);
StorageSubscription::create([
'user_id' => $user->id,
'package_id' => $request->storage_package_id,
'status' => 'active',
'start_date' => now()
]);
Mail::send(new OrgUserRegisteredMail($user));
```
```php
// In StripePaymentController@webhook
public function webhook(Request $request) {
$payload = $request->getContent();
$sig_header = $request->header('Stripe-Signature');
// Verify signature...
$event = \Stripe\Webhook::constructEvent($payload, $sig_header, $endpoint_secret);
// Idempotency check
if (PaymentWebhookLogs::where('event_id', $event->id)->exists()) {
return response()->json(['status' => 'duplicate'], 200);
}
PaymentWebhookLogs::create([
'event_id' => $event->id,
'payload' => $payload,
'processed_at' => now()
]);
if ($event->type === 'payment_intent.succeeded') {
$paymentIntent = $event->data->object;
Payment::create([
'user_id' => $paymentIntent->metadata->user_id,
'gateway' => 'stripe',
'transaction_id' => $paymentIntent->id,
'amount' => $paymentIntent->amount / 100,
'currency' => $paymentIntent->currency,
'status' => 'completed'
]);
}
return response()->json(['status' => 'success'], 200);
}
```
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/azonation-laravel-backend-development/raw