Integrations & Third-Party Services
External integrations and services used by Profile PS3.
AWS S3 File Storage
Profile PS3 uses AWS S3 for scalable, reliable project attachment storage.
Configuration
Package: league/flysystem-aws-s3-v3: 3.25.1
Environment Variables:
FILESYSTEM_DISK=s3
AWS_ACCESS_KEY_ID=your-access-key-id
AWS_SECRET_ACCESS_KEY=your-secret-access-key
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=profileps3-attachments
AWS_URL=https://profileps3-attachments.s3.us-east-1.amazonaws.com
AWS_USE_PATH_STYLE_ENDPOINT=false
File Storage Structure
s3://profileps3-attachments/
├── attachments/
│ ├── projects/
│ │ ├── 2026/
│ │ │ ├── 01/
│ │ │ │ ├── project-123-spec.pdf
│ │ │ │ └── project-124-photo.jpg
│ │ │ └── 02/
│ │ └── 2025/
│ ├── reports/
│ └── exports/
└── temp/
Usage Examples
Upload File:
use Illuminate\Support\Facades\Storage;
$path = Storage::disk('s3')->putFileAs(
'attachments/projects/' . date('Y/m'),
$request->file('attachment'),
$filename
);
Generate Signed URL (time-limited download):
$url = Storage::disk('s3')->temporaryUrl(
$attachment->path,
now()->addMinutes(30)
);
Delete File:
Storage::disk('s3')->delete($attachment->path);
Project Attachments Model
Model: App\Models\Attachment
Eloquent Observer: AttachmentObserver
- Automatically deletes S3 files when attachment record deleted
- Handles cleanup on project deletion
File Validation:
// In Filament FileUpload component
Forms\Components\FileUpload::make('file')
->disk('s3')
->directory('attachments/projects')
->maxSize(50 * 1024) // 50MB
->acceptedFileTypes([
'application/pdf',
'image/jpeg',
'image/png',
'image/webp',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
])
->preserveFilenames()
->downloadable()
->openable();
Local Development Fallback
For development without AWS credentials:
FILESYSTEM_DISK=local
Files stored in storage/app/attachments/
S3 Bucket Configuration
Bucket Policy (read-only for authenticated users):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT_ID:user/profileps3-app"
},
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::profileps3-attachments/*"
}
]
}
CORS Configuration:
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "PUT", "POST", "DELETE"],
"AllowedOrigins": ["https://profileps3.com"],
"ExposeHeaders": ["ETag"]
}
]
Mailgun Email Service
Transactional and notification emails via Mailgun.
Configuration
Package: symfony/mailgun-mailer: ^7.3
Environment Variables:
MAIL_MAILER=mailgun
[email protected]
MAIL_FROM_NAME="Profile PS3"
MAILGUN_DOMAIN=mg.profileps3.com
MAILGUN_SECRET=key-xxxxxxxxxxxxxxxxxxxxxxxx
MAILGUN_ENDPOINT=api.mailgun.net
Email Types
Account Management:
- User registration confirmation
- Account approval notification
- Account denial notification
- Password reset
- Email verification
Project Notifications:
- New project created (to regional manager)
- Project milestone achieved
- Project archived
MFA:
- MFA setup instructions
- Recovery code generation
Marketing (opt-in):
- Product updates
- Feature announcements
- Monthly newsletter
Sending Emails
Using Mailables:
use App\Mail\AccountApproved;
use Illuminate\Support\Facades\Mail;
Mail::to($user->email)->send(new AccountApproved($user));
Using Notifications:
use App\Notifications\ProjectCreatedNotification;
$regionalManager->notify(new ProjectCreatedNotification($project));
Queue for Background Sending:
Mail::to($user)->queue(new AccountApproved($user));
Email Preferences
Users can manage email subscriptions via profile:
Model: User has get_product_updates boolean field
Check Before Sending:
if ($user->get_product_updates) {
Mail::to($user)->send(new ProductUpdateEmail());
}
Mailgun Features
Tracking:
- Open tracking
- Click tracking
- Delivery tracking
Analytics Dashboard:
- Delivery rate
- Bounce rate
- Complaint rate
- Open rate
- Click rate
Suppression Lists:
- Automatic bounce management
- Unsubscribe handling
- Complaint tracking
Email Templates
Located in resources/views/emails/
Example (welcome.blade.php):
<x-mail::message>
# Welcome to Profile PS3
Your account has been approved! You can now log in and start managing your erosion control projects.
<x-mail::button :url="route('filament.app.auth.login')">
Log In
</x-mail::button>
Thanks,<br>
{{ config('app.name') }}
</x-mail::message>
Testing Emails
Development (log emails to file):
MAIL_MAILER=log
View logs: storage/logs/laravel.log
Testing (use Mailtrap or similar):
MAIL_MAILER=smtp
MAIL_HOST=sandbox.smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=your-username
MAIL_PASSWORD=your-password
BDO Export Integration
Profile PS3 exports data to BDO (external system) for synchronization.
Export Configuration
Model: App\Models\BdoExport
Supported Entities:
- Users
- Projects
- Slopes
- Channels
- ECBs (Erosion Control Blankets)
- HECPs (Hydraulically Applied Products)
- TRMs (Turf Reinforcement Mats)
Incremental Export System
Model: App\Models\BdoExportCheckpoint
Tracks last export timestamp and data checksum for each record.
Logic:
// Only export changed records
$recordsToExport = Project::where(function($query) {
$query->whereDoesntHave('bdoCheckpoint')
->orWhereHas('bdoCheckpoint', function($q) {
$q->where('updated_at', '>', DB::raw('last_exported_at'));
});
})->get();
Export Process
Artisan Command:
php artisan bdo:export {entity}
# Examples
php artisan bdo:export users
php artisan bdo:export projects
php artisan bdo:export ecbs
Scheduled Export (in app/Console/Kernel.php):
$schedule->command('bdo:export users')->daily()->at('02:00');
$schedule->command('bdo:export projects')->daily()->at('02:30');
$schedule->command('bdo:export ecbs')->weekly()->sundays()->at('03:00');
Export Format
JSON Export Structure:
{
"export_id": "export-2026-04-21-projects",
"entity_type": "projects",
"timestamp": "2026-04-21T02:30:00Z",
"record_count": 145,
"records": [
{
"id": 123,
"projectNum": "PRJ-20260415-001",
"userId": 45,
"projectAddress": "123 Main St",
"city": "Denver",
"state": "CO",
"projectType": "Slope Protection",
"active": "active",
"created_at": "2026-04-15T10:30:00Z",
"updated_at": "2026-04-20T14:22:00Z"
}
]
}
Export History
View export history in admin panel:
Resource: BdoExportResource
Fields Displayed:
- Export date/time
- Entity type
- Record count
- Status (pending/success/failed)
- Error message (if failed)
Manual Export Trigger
Admins can manually trigger exports via admin panel:
Action: "Run Export" button in BdoExportResource
Error Handling
Retry Logic:
- Failed exports automatically retry 3 times
- Exponential backoff between retries
- Errors logged to
storage/logs/bdo-export.log
Notifications:
- Admin notified of failed exports
- Weekly summary of export status
Future Integration Opportunities
Planned Integrations:
- Payment processing (Stripe/PayPal) for subscription billing
- CRM integration (Salesforce, HubSpot) for lead management
- GIS mapping services (ArcGIS, Mapbox) for project visualization
- Weather API (OpenWeather) for site condition monitoring
- Mobile app API for field data collection
- Webhook notifications for real-time updates
- SSO integration (Google, Microsoft Azure AD) for enterprise customers