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

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 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.phpdisks.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.phpredis
  • 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.phpdisks.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.phpmailers.ses
  • Env vars: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION

If using AWS SQS for queue:

  • Config: config/queue.phpconnections.sqs
  • Env vars: AWS credentials + SQS_PREFIX, SQS_QUEUE, SQS_SUFFIX

Integration audit: 2026-02-13