Files
usher-manage-stack/.planning/codebase/INTEGRATIONS.md
2026-02-13 10:34:18 +08:00

282 lines
10 KiB
Markdown

# 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 invalidation
- `SiteRevalidatService::revalidatePage(?slug)` - Trigger page cache invalidation
- `SiteRevalidationService::revalidateDocument(?slug)` - Trigger document cache invalidation
- Triggered by: `app/Observers/DocumentObserver.php` on 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: `mysql` or `sqlite`
- `DB_HOST` - Database server (e.g., `127.0.0.1`)
- `DB_PORT` - Port (default 3306 for MySQL)
- `DB_DATABASE` - Database name
- `DB_USERNAME` - Username
- `DB_PASSWORD` - Password
- ORM/Client: Laravel Eloquent (built-in)
- Encryption: AES-256-CBC via `config/app.php` cipher
- Notable tables:
- `users` - System users (staff, admin)
- `members` - Member profiles (encrypted national IDs)
- `finance_documents` - Finance approvals with multi-tier workflows
- `payments` - Member fee payments
- `articles`, `pages`, `categories`, `tags` - CMS content
- `documents` - Document library entries
- `roles`, `permissions`, `model_has_roles` - Spatie permission tables
- `settings` - 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_ID`
- `AWS_SECRET_ACCESS_KEY`
- `AWS_DEFAULT_REGION`
- `AWS_BUCKET`
- `AWS_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 via `CACHE_PREFIX` env)
- Settings cache: Automatically cleared on `SystemSetting` model mutation
**Session Storage:**
- Providers: File (default), Database, Redis
- Config: `config/session.php`
- Default driver: `file`
- Lifetime: 120 minutes (configurable via `SESSION_LIFETIME` env)
- CSRF tokens: Protected via Laravel middleware
## Authentication & Identity
**Auth Provider:**
- Type: Custom (Session-based)
- Implementation: Built-in Laravel authentication with `User` model
- 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 (via `SANCTUM_STATEFUL_DOMAINS` env)
- Token prefix: Customizable via `SANCTUM_TOKEN_PREFIX` env
- 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 roles
- `permissions` - Available permissions
- `model_has_roles` - User-to-role assignments
- `model_has_permissions` - User-to-permission direct assignments
- `role_has_permissions` - Role-to-permission assignments
- Core roles (seeded in `database/seeders/`):
- `admin` - Full system access
- `finance_requester` - Submit finance documents
- `finance_cashier` - Tier 1 approvals (small amounts)
- `finance_accountant` - Tier 2 approvals (medium amounts) and ledger recording
- `finance_chair` - Tier 2 approvals (medium amounts)
- `finance_board_member` - Tier 3 approvals (large amounts)
- `secretary_general` - CMS management, member management
- `membership_manager` - Member lifecycle management
**Identity/National ID Encryption:**
- Encryption: AES-256 via Laravel's encryption
- Fields in `members` table:
- `national_id_encrypted` - Stores encrypted national ID
- `national_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_TOKEN` env var
- Method: `POST`
- Payload: `{ type: 'article'|'page'|'document', slug?: string }`
**Outgoing Webhooks:**
- Next.js site revalidation: `POST {NEXTJS_REVALIDATE_URL}`
- URL: `NEXTJS_REVALIDATE_TOKEN` env 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
## 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.log`
- `daily` - Rotate daily, keep 14 days
- `slack` - Send logs to Slack webhook (env: `LOG_SLACK_WEBHOOK_URL`)
- `papertrail` - Syslog UDP to Papertrail (env: `PAPERTRAIL_URL`, `PAPERTRAIL_PORT`)
- `stderr` - Output to stderr
- `syslog` - System syslog
- `errorlog` - PHP error_log
- `log` - File channel with custom naming
- `array` - In-memory (testing only)
- Log level: `debug` (default, configurable via `LOG_LEVEL` env)
- Deprecations channel: Null by default (can redirect via `LOG_DEPRECATIONS_CHANNEL` env)
**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` (or `composer install --no-dev` for 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
- Static analysis: PHPStan
- Run: `./vendor/bin/phpstan analyse`
- Config: `phpstan.neon` (if present)
**Testing:**
- Unit & Feature Tests: PHPUnit
- Run: `php artisan test`
- Run specific: `php artisan test --filter=ClassName`
- Config: `phpunit.xml`
- Browser/E2E Tests: Laravel Dusk
- Run: `php artisan dusk`
- Uses Chrome/Chromium driver
## Environment Configuration
**Required Environment Variables:**
Core:
- `APP_NAME` - Application name
- `APP_ENV` - Environment: `local`, `production`
- `APP_DEBUG` - Boolean: enable/disable debug mode
- `APP_KEY` - Base64 encryption key (auto-generated)
- `APP_URL` - Full URL: `https://member.usher.org.tw` (production)
Database:
- `DB_CONNECTION` - `mysql` (default) or `sqlite`
- `DB_HOST` - Database server
- `DB_PORT` - Port (3306 for MySQL)
- `DB_DATABASE` - Database name
- `DB_USERNAME` - Username
- `DB_PASSWORD` - Password
Mail:
- `MAIL_MAILER` - `smtp` (default), `mailgun`, `postmark`, `ses`, `log`
- `MAIL_HOST` - SMTP host
- `MAIL_PORT` - SMTP port (587 typical)
- `MAIL_USERNAME` - SMTP username
- `MAIL_PASSWORD` - SMTP password
- `MAIL_ENCRYPTION` - `tls`, `ssl`, or null
- `MAIL_FROM_ADDRESS` - From email address
- `MAIL_FROM_NAME` - From name
Caching & Queuing:
- `CACHE_DRIVER` - `file` (default), `redis`, `memcached`, `dynamodb`
- `QUEUE_CONNECTION` - `sync` (default), `database`, `redis`, `sqs`
- `SESSION_DRIVER` - `file` (default), `database`, `redis`
Feature Toggles:
- `REGISTRATION_ENABLED` - Boolean: allow public registration (`false` by default)
Frontend Integration:
- `NEXTJS_REVALIDATE_URL` - Full URL to Next.js revalidation endpoint
- `NEXTJS_REVALIDATE_TOKEN` - Bearer token for revalidation requests
- `NEXTJS_PUBLIC_PATH` - Optional: path to Next.js `public/` directory (for local asset sync)
**Secrets Location:**
- Method: Environment variables (`.env` file, 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*