10 KiB
10 KiB
External Integrations
Analysis Date: 2026-02-13
APIs & External Services
Next.js Frontend Site Revalidation:
- Service: Custom webhook to Next.js
/api/revalidate - What it's used for: Trigger static site regeneration when articles, pages, or documents change
- SDK/Client: Guzzle HTTP client (
guzzlehttp/guzzle) - Implementation:
app/Services/SiteRevalidationService.php - Methods:
SiteRevalidationService::revalidateArticle(?slug)- Trigger article cache invalidationSiteRevalidatService::revalidatePage(?slug)- Trigger page cache invalidationSiteRevalidationService::revalidateDocument(?slug)- Trigger document cache invalidation
- Triggered by:
app/Observers/DocumentObserver.phpon article/page create/update/delete - Timeout: 5 seconds
- Error handling: Logged as warning, does not fail request
Email Service Provider (Configurable):
- Services supported: SMTP, Mailgun, Postmark, AWS SES
- SDK/Client: Laravel Mail facades
- Implementation: Controllers use
Mail::to($email)->queue(MailClass::class) - Auth:
MAIL_HOST,MAIL_PORT,MAIL_USERNAME,MAIL_PASSWORD, or API keys - Dev/Test: Mailpit on
localhost:1025(configured in.env.example) - Queue integration: All mail uses async queue for better performance
Data Storage
Primary Database:
- Type/Provider: MySQL (production) or SQLite (development)
- Connection config:
config/database.php - Connection env vars:
DB_CONNECTION- Type:mysqlorsqliteDB_HOST- Database server (e.g.,127.0.0.1)DB_PORT- Port (default 3306 for MySQL)DB_DATABASE- Database nameDB_USERNAME- UsernameDB_PASSWORD- Password
- ORM/Client: Laravel Eloquent (built-in)
- Encryption: AES-256-CBC via
config/app.phpcipher - Notable tables:
users- System users (staff, admin)members- Member profiles (encrypted national IDs)finance_documents- Finance approvals with multi-tier workflowspayments- Member fee paymentsarticles,pages,categories,tags- CMS contentdocuments- Document library entriesroles,permissions,model_has_roles- Spatie permission tablessettings- System-wide configuration (cached)
File Storage:
- Databases: Local disk and S3 configurable
- Private files:
storage/app/(served via controller) - Public files:
storage/app/public/(served via/storage/...URL) - S3 Config:
config/filesystems.php→disks.s3 - S3 env vars:
AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_DEFAULT_REGIONAWS_BUCKETAWS_URL(optional CDN)AWS_ENDPOINT(optional for S3-compatible services)
Caching:
- Providers: File (default), Redis, Memcached, DynamoDB
- Config:
config/cache.php - Default driver:
file(suitable for single-server, can switch to Redis) - Used for:
settings()helper caching, query result caching - Cache prefix:
laravel_cache_(configurable viaCACHE_PREFIXenv) - Settings cache: Automatically cleared on
SystemSettingmodel mutation
Session Storage:
- Providers: File (default), Database, Redis
- Config:
config/session.php - Default driver:
file - Lifetime: 120 minutes (configurable via
SESSION_LIFETIMEenv) - CSRF tokens: Protected via Laravel middleware
Authentication & Identity
Auth Provider:
- Type: Custom (Session-based)
- Implementation: Built-in Laravel authentication with
Usermodel - Guard:
web(session-based) - Config:
config/auth.php - Provider: Eloquent user provider (
App\Models\User)
API Token Authentication:
- Service: Laravel Sanctum
- Implementation:
config/sanctum.php - For: Public API endpoints (
/api/v1/*) - Stateful domains:
localhost,127.0.0.1, custom domain (viaSANCTUM_STATEFUL_DOMAINSenv) - Token prefix: Customizable via
SANCTUM_TOKEN_PREFIXenv - Expiration: No default expiration (tokens live indefinitely unless custom set)
Role-Based Access Control (RBAC):
- Service: Spatie Laravel Permission
- Package:
spatie/laravel-permission@^6.23 - Config:
config/permission.php - Models:
Spatie\Permission\Models\Role,Spatie\Permission\Models\Permission - Tables:
roles- Available rolespermissions- Available permissionsmodel_has_roles- User-to-role assignmentsmodel_has_permissions- User-to-permission direct assignmentsrole_has_permissions- Role-to-permission assignments
- Core roles (seeded in
database/seeders/):admin- Full system accessfinance_requester- Submit finance documentsfinance_cashier- Tier 1 approvals (small amounts)finance_accountant- Tier 2 approvals (medium amounts) and ledger recordingfinance_chair- Tier 2 approvals (medium amounts)finance_board_member- Tier 3 approvals (large amounts)secretary_general- CMS management, member managementmembership_manager- Member lifecycle management
Identity/National ID Encryption:
- Encryption: AES-256 via Laravel's encryption
- Fields in
memberstable:national_id_encrypted- Stores encrypted national IDnational_id_hash- SHA256 hash for searching (indexed)national_id- Virtual accessor (decrypts on read)
- Location:
app/Models/Member.php
Webhooks & Callbacks
Incoming Webhooks:
- Site revalidation endpoint:
/api/revalidate(public, requires valid token)- Token:
NEXTJS_REVALIDATE_TOKENenv var - Method:
POST - Payload:
{ type: 'article'|'page'|'document', slug?: string }
- Token:
Outgoing Webhooks:
- Next.js site revalidation:
POST {NEXTJS_REVALIDATE_URL}- URL:
NEXTJS_REVALIDATE_TOKENenv var - Token header:
x-revalidate-token - Payload:
{ type: 'article'|'page'|'document', slug?: string } - Triggered on: Article/Page/Document create/update/delete
- Implementation:
app/Services/SiteRevalidationService.php - Timeout: 5 seconds, failures logged but do not block request
- URL:
Monitoring & Observability
Error Tracking:
- Service: Spatie Ignition (error page companion)
- Package:
spatie/laravel-ignition@^2.0 - Used in: Development and error page debugging
- Config:
config/app.php→ providers
Logging:
- Framework: Monolog (via Laravel)
- Config:
config/logging.php - Default channel:
stack(multi-handler) - Channels available:
single- Single log file:storage/logs/laravel.logdaily- Rotate daily, keep 14 daysslack- Send logs to Slack webhook (env:LOG_SLACK_WEBHOOK_URL)papertrail- Syslog UDP to Papertrail (env:PAPERTRAIL_URL,PAPERTRAIL_PORT)stderr- Output to stderrsyslog- System syslogerrorlog- PHP error_loglog- File channel with custom namingarray- In-memory (testing only)
- Log level:
debug(default, configurable viaLOG_LEVELenv) - Deprecations channel: Null by default (can redirect via
LOG_DEPRECATIONS_CHANNELenv)
Audit Logging:
- Service: Custom audit logger
- Implementation:
app/Support/AuditLogger.php - Usage:
AuditLogger::log($action, $auditable, $metadata) - Tracked: Model mutations (create/update/delete) for compliance
- Storage: Appended to audit log entries
CI/CD & Deployment
Hosting:
- Platform: Dedicated servers, Docker (Laravel Sail), or cloud (AWS, etc.)
- Port: API typically runs on port 8001 (not 8000 - that's often occupied)
Build Process:
- Frontend assets:
npm run build(Vite compilation) - Backend:
composer install(orcomposer install --no-devfor production) - Migrations:
php artisan migrate --force - Cache:
php artisan config:cache,php artisan view:cache
Code Quality (Pre-commit):
- Linter: Laravel Pint (PSR-12)
- Run:
./vendor/bin/pint - Fixes style issues automatically
- Run:
- Static analysis: PHPStan
- Run:
./vendor/bin/phpstan analyse - Config:
phpstan.neon(if present)
- Run:
Testing:
- Unit & Feature Tests: PHPUnit
- Run:
php artisan test - Run specific:
php artisan test --filter=ClassName - Config:
phpunit.xml
- Run:
- Browser/E2E Tests: Laravel Dusk
- Run:
php artisan dusk - Uses Chrome/Chromium driver
- Run:
Environment Configuration
Required Environment Variables:
Core:
APP_NAME- Application nameAPP_ENV- Environment:local,productionAPP_DEBUG- Boolean: enable/disable debug modeAPP_KEY- Base64 encryption key (auto-generated)APP_URL- Full URL:https://member.usher.org.tw(production)
Database:
DB_CONNECTION-mysql(default) orsqliteDB_HOST- Database serverDB_PORT- Port (3306 for MySQL)DB_DATABASE- Database nameDB_USERNAME- UsernameDB_PASSWORD- Password
Mail:
MAIL_MAILER-smtp(default),mailgun,postmark,ses,logMAIL_HOST- SMTP hostMAIL_PORT- SMTP port (587 typical)MAIL_USERNAME- SMTP usernameMAIL_PASSWORD- SMTP passwordMAIL_ENCRYPTION-tls,ssl, or nullMAIL_FROM_ADDRESS- From email addressMAIL_FROM_NAME- From name
Caching & Queuing:
CACHE_DRIVER-file(default),redis,memcached,dynamodbQUEUE_CONNECTION-sync(default),database,redis,sqsSESSION_DRIVER-file(default),database,redis
Feature Toggles:
REGISTRATION_ENABLED- Boolean: allow public registration (falseby default)
Frontend Integration:
NEXTJS_REVALIDATE_URL- Full URL to Next.js revalidation endpointNEXTJS_REVALIDATE_TOKEN- Bearer token for revalidation requestsNEXTJS_PUBLIC_PATH- Optional: path to Next.jspublic/directory (for local asset sync)
Secrets Location:
- Method: Environment variables (
.envfile, never committed) - Production: Use hosted secrets manager or CI/CD environment variables
- Never commit: Passwords, API keys, encryption keys, tokens
Optional: Redis
If using Redis for caching/sessions/queue:
- Config:
config/database.php→redis - Env vars:
REDIS_HOST-127.0.0.1(default)REDIS_PORT-6379(default)REDIS_PASSWORD- Password (null by default)REDIS_CLIENT-phpredis(default)REDIS_CLUSTER-redis(default)
- Databases:
- Default: 0 (primary connection)
- Cache: 1 (separate database for cache keys)
Optional: AWS Integration
If using AWS S3 for file storage:
- Config:
config/filesystems.php→disks.s3 - Env vars:
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_DEFAULT_REGION,AWS_BUCKET
If using AWS SES for email:
- Config:
config/mail.php→mailers.ses - Env vars:
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_DEFAULT_REGION
If using AWS SQS for queue:
- Config:
config/queue.php→connections.sqs - Env vars: AWS credentials +
SQS_PREFIX,SQS_QUEUE,SQS_SUFFIX
Integration audit: 2026-02-13