High concurrency, Swoole based, Symfony 8 API
Features
- Swoole HTTP Server, Task Worker (Queue), Cron Worker SwooleBundle
- Auto-generated API documentation ApiBundle
- API TypeScript client generator
- GitHub Actions auto deployment
- Horizontally scalable
- Firebase push notifications
- Email/SMS OTP verification
- Media upload & processing MediaBundle
- Storage: Cloudflare R2, Backblaze B2, Local StorageBundle
- JWT authentication with refresh tokens
- Role-based access control (RBAC)
- Enum-based permission system
- Multi-language support (i18n)
- Organization/tenant management
- User switch & impersonation
- PHPUnit tests with fixtures
Requirements
- PostgreSQL 14+
- Composer 2+
- PHP 8.4+
- Swoole 4.11+ (
pecl install swoole) - GD extension (
--with-gd) - Required extensions: intl, bcmath, curl, ctype, iconv
- php.ini configuration:
- max_file_uploads=50
- post_max_size=20M
- upload_max_filesize=20M
- memory_limit=512M
- realpath_cache_size=16M
- realpath_cache_ttl=600
- opcache.enable=1
- opcache.enable_cli=1
- opcache.memory_consumption=256
- opcache.interned_strings_buffer=64
- opcache.max_accelerated_files=50000
- opcache.validate_timestamps=0 (ONLY PROD)
- opcache.preload=../api/config/preload.php (ONLY PROD)
- opcache.preload_user=root (ONLY PROD)
- opcache.jit=tracing
- opcache.jit_buffer_size=256M
- Swoole 4.11+ (
Development (macOS)
# macOS utilities (for hot-reload)
brew install fswatch util-linux
# PHP extensions
pecl install swoole # enable: openssl, http2, curl, postgresql
# Setup
cp .env .env.local
composer install
# Database
bin/console doctrine:database:create
bin/console doctrine:schema:update --force
# Run dev server (with hot-reload)
bin/console swoole:server:startProduction (Docker)
# Build
git clone --depth 1 <repo>
composer install --no-dev
composer dump-autoload --no-dev --classmap-authoritative
# Configure (optional)
cp .env .env.local
# Docker
docker build -t raiden-api .
docker run -d -p 80:80 --restart always --name raiden-api raiden-api
# Migrations
docker exec raiden-api bin/console doctrine:database:create
docker exec raiden-api bin/console doctrine:schema:update --forceGitHub Actions Deployment
Deploy to multiple servers via GitHub Container Registry.
- Generate SSH key:
ssh-keygen -t ed25519 - Add to Repository Secrets:
SERVER_PRIVATEKEY - Set Variables:
APP_HOSTS: ["11.111.222.222"] APP_ENVS: [ "APP_ENV=prod", "DATABASE_URL=postgresql://user:pass@host:5432/db?serverVersion=14", "LOCK_DSN=semaphore" ]
- Create
productionbranch → Run Deployer action
GitHub Actions Staging
Deploy to single server with auto PostgreSQL container.
- Generate SSH key
- Add Secret:
SERVER_PRIVATEKEY - Set Variables:
STAG_HOSTS: "11.111.222.222" STAG_ENVS: [ "POSTGRES_PASSWORD=pass123", "APP_ENV=prod", "APP_SECRET=secret", "APP_JWT_SECRET=jwtsecret", "DATABASE_URL=postgresql://postgres:pass123@postgres:5432/postgres?serverVersion=14", "FIREBASE_DSN=firebase://KEY@default" ]
- Create
stagingbranch → Run Staging action
# Setup
cp phpunit.xml.dist phpunit.xml
# Commands
composer qa:phpstan # Static analysis
composer qa:lint # Check code style
composer qa:fix # Fix code style
composer test # Run tests
composer test:stop # Stop on first failure
composer fix # Run all QA + tests- SwooleBundle - HTTP server, task queue, cron
- ApiBundle - Auto docs, TS client generator
- StorageBundle - Multi-driver file storage
- MediaBundle - Image/video processing
Login: POST /api/login → Returns access_token + refresh_token
Refresh: POST /api/token/refresh with refresh_token
Register: POST /api/register → Sends OTP
Verify OTP: POST /api/verify-otp → Activates account
Setup:
- Firebase Console → Create project
- Project Settings → Cloud Messaging → Enable Legacy API
- Set
.env:FIREBASE_DSN=firebase://SERVER_KEY@default
Send:
$pusher->send((new Notification())
->setTitle('Title')
->setMessage('Message')
->setOwner($user));Email:
$mailPusher->send((new Email())
->to('user@mail.com')
->subject('Subject')
->html('Body'));SMS:
$smsPusher->send(phoneNumber: 5111111111, countryCode: 90, message: 'OTP: 1234');OTP codes expire in 15 minutes. Email/SMS sent via queue (async).
// Generate OTP
$otpKey = (new OtpKey())
->setType(OtpType::EMAIL)
->setAddress('user@mail.com')
->setOtpKey(rand(100000, 999999))
->setExpiredAt(new \DateTimeImmutable('+15 minutes'));
// Verify
$valid = !$otpKey->isExpired() && !$otpKey->isUsed();Enum-based permissions via PermissionManager:
// Check permission
if ($permissionManager->has(CorePermission::USER_EDIT)) {
// Allow action
}
// User types: SUPER_ADMIN, ADMIN, USER