The RESTful API backend for api.nebalus.dev, built with PHP 8.3+ and the Slim 4 framework.
- Features
- Tech Stack
- Architecture
- Requirements
- Getting Started
- Configuration
- API Endpoints
- Development Commands
- Project Structure
- Testing
- Code Quality
- Contributing
- License
- RESTful API — Clean, modular architecture following REST principles
- JWT Authentication — Secure token-based authentication system
- Role-Based Access Control (RBAC) — Granular permission management with roles
- Dependency Injection — Full DI support via PHP-DI container
- CORS Support — Cross-Origin Resource Sharing middleware
- Error Handling — Centralized error handling with detailed logging
- Blog Module — Create, edit, delete, and retrieve blog posts
- Linktree Module — Customizable link aggregation for user profiles with click tracking
- Referral Module — Referral link management with click analytics and history
- User Management — Manage users and their role assignments
- Role Management — Create, edit, and delete roles
- Permission Management — Fine-grained permission control per role
- Health Checks — Built-in
/healthendpoint for monitoring - Prometheus Metrics —
/metricsendpoint for observability - Structured Logging — Monolog-based logging with configurable levels
- Email Notifications — Templated emails via Twig and Resend
| Category | Technology |
|---|---|
| Language | PHP 8.3+ |
| Framework | Slim 4 |
| DI Container | PHP-DI |
| Database | MySQL with Latitude query builder |
| Cache | Redis |
| Search | Elasticsearch |
| Logging | Monolog |
| Metrics | Prometheus PHP Client |
| Authentication | ReallySimpleJWT |
| 2FA/OTP | OTPHP |
| Resend + Twig templates | |
| HTTP Client | Guzzle |
| Validation | Sanitizr |
| Testing | PHPUnit 12 |
| Linting | PHPMD + PHP_CodeSniffer |
| Containers | Docker + Docker Compose |
| Task Runner | Just |
The application follows a clean, layered architecture pattern:
┌──────────────────────────────────────────────────────────────┐
│ Middleware │
│ (CORS → Metrics → Auth → Permission → Body Parsing → Routing)│
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ Actions │
│ (Handle HTTP requests, validate input) │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ Services │
│ (Business logic and orchestration) │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ Repositories │
│ (Data access and persistence) │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ MySQL / Redis / Elasticsearch │
└──────────────────────────────────────────────────────────────┘
- Action-Domain-Responder (ADR) — Clean separation of HTTP handling from business logic
- Value Objects — Immutable domain objects for type safety
- Repository Pattern — Abstracted data access layer
- Factory Pattern — For creating complex objects (DI container, loggers, etc.)
| Middleware | Description |
|---|---|
CorsMiddleware |
Handles CORS headers and preflight requests |
MetricsMiddleware |
Collects Prometheus metrics for each request |
AuthMiddleware |
Validates JWT tokens and authenticates users |
PermissionMiddleware |
Enforces role-based permission checks |
- PHP 8.3+ with extensions:
pdo,redis - Docker & Docker Compose
- Just — Command runner (recommended)
- MySQL — Running on an external Docker network
- Composer — PHP dependency manager
git clone https://github.com/nebalus/WebBackend.git
cd WebBackendcomposer installCopy the example environment file and configure your secrets:
cp .env.example .envEdit .env with your configuration:
RESEND_API_KEY=YOUR_RESEND_API_KEY
JWT_SECRET=your_secure_random_jwt_secretThe application expects a MySQL database on an external Docker network:
docker network create nebalus-web-storage-development-netNote: Ensure your MySQL container is connected to this network.
just startOr using Docker Compose directly:
docker compose -f docker-compose.development.yml upThe API will be available at http://localhost.
Test the health endpoint:
curl http://localhost/health| Variable | Description | Default |
|---|---|---|
APP_ENV |
Environment mode (development/production) |
development |
ERROR_LOGLEVEL |
Monolog log level | Warning |
JWT_SECRET |
Secret key for JWT signing | Required |
JWT_EXPIRATION_TIME |
JWT token expiration in seconds | 86400 (24 hours) |
ACCESS_CONTROL_ALLOW_ORIGIN |
CORS allowed origins | * |
MYSQL_HOST |
MySQL hostname | nebalus-web-storage-mysql |
MYSQL_PORT |
MySQL port | 3306 |
MYSQL_DATABASE |
MySQL database name | main |
MYSQL_USER |
MySQL username | admin |
MYSQL_PASSWORD |
MySQL password | Required |
REDIS_HOST |
Redis hostname | redis |
REDIS_PORT |
Redis port | 6379 |
RESEND_API_KEY |
Resend API key for email delivery | Required |
| File | Purpose |
|---|---|
phpunit.xml |
PHPUnit test configuration |
phpcs.xml |
PHP_CodeSniffer code style rules |
phpmd.xml |
PHPMD mess detector rules |
| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Health check |
GET |
/metrics |
Prometheus metrics |
GET |
/services/referral/{code} |
Track referral link click |
GET |
/services/linktree/{username} |
Get user's linktree |
| Method | Endpoint | Description |
|---|---|---|
POST |
/ui/auth |
Authenticate and receive JWT token |
POST |
/ui/register |
Register a new user |
Base path: /ui/users/{user_id}/services
| Method | Endpoint | Description |
|---|---|---|
POST |
/blogs |
Create a new blog post |
GET |
/blogs/all |
Get all user's blogs |
GET |
/blogs/{blog_id} |
Get a specific blog |
PUT |
/blogs/{blog_id} |
Update a blog |
DELETE |
/blogs/{blog_id} |
Delete a blog |
| Method | Endpoint | Description |
|---|---|---|
GET |
/linktree |
Get user's linktree config |
PUT |
/linktree |
Update linktree |
DELETE |
/linktree |
Delete linktree |
| Method | Endpoint | Description |
|---|---|---|
POST |
/referrals |
Create a new referral |
GET |
/referrals/all |
Get all user's referrals |
GET |
/referrals/{code} |
Get a specific referral |
PUT |
/referrals/{code} |
Update a referral |
DELETE |
/referrals/{code} |
Delete a referral |
GET |
/referrals/{code}/click_history |
Get referral click history |
Base path: /ui/admin
| Method | Endpoint | Description |
|---|---|---|
GET |
/permissions/all |
List all permissions |
GET |
/permissions/{permission_id} |
Get a specific permission |
| Method | Endpoint | Description |
|---|---|---|
POST |
/roles |
Create a new role |
GET |
/roles/all |
List all roles |
GET |
/roles/{role_id} |
Get a specific role |
PUT |
/roles/{role_id} |
Update a role |
DELETE |
/roles/{role_id} |
Delete a role |
GET |
/roles/{role_id}/permissions/all |
Get role's permissions |
PUT |
/roles/{role_id}/permissions |
Upsert role permissions |
DELETE |
/roles/{role_id}/permissions |
Delete role permissions |
| Method | Endpoint | Description |
|---|---|---|
GET |
/users/{user_id}/roles/all |
Get user's roles |
POST |
/users/{user_id}/roles/{role_id} |
Assign role to user |
DELETE |
/users/{user_id}/roles/{role_id} |
Remove role from user |
The project uses Just as a command runner:
| Command | Description |
|---|---|
just start |
Start development containers |
just stop |
Stop development containers |
just restart |
Restart development containers |
just build |
Build development containers |
just test |
Run PHPUnit tests |
just lint |
Run PHPMD and PHP_CodeSniffer |
| Command | Description |
|---|---|
just start-prod |
Start production containers |
just stop-prod |
Stop production containers |
just restart-prod |
Restart production containers |
just build-prod |
Build production containers |
.
├── docker/ # Docker configuration
│ ├── nginx/ # Nginx Dockerfile and config
│ ├── php-fpm/ # PHP-FPM Dockerfile and config
│ └── redis/ # Redis Dockerfile
├── endpoints/ # Bruno API collection for testing
│ ├── Services/ # Service endpoint definitions
│ ├── Ui/ # UI endpoint definitions
│ └── environments/ # Environment configs
├── public/ # Web root
│ └── index.php # Application entry point
├── src/ # Application source code
│ ├── Api/ # API layer
│ │ ├── AbstractAction.php # Base action class
│ │ ├── AbstractService.php # Base service class
│ │ ├── AbstractValidator.php # Base validator class
│ │ ├── Admin/ # Admin endpoints
│ │ │ ├── Permission/ # Permission management
│ │ │ ├── Role/ # Role management
│ │ │ └── User/ # User management
│ │ ├── Health/ # Health check endpoint
│ │ ├── Metrics/ # Prometheus metrics endpoint
│ │ ├── Module/ # Feature modules
│ │ │ ├── Blog/ # Blog CRUD operations
│ │ │ ├── Linktree/ # Linktree management
│ │ │ └── Referral/ # Referral tracking
│ │ └── User/ # User authentication
│ │ ├── Auth/ # Login/token generation
│ │ ├── GetUserPermissions/ # Permission retrieval
│ │ └── Register/ # User registration
│ ├── Config/ # Configuration classes
│ │ ├── GeneralConfig.php # General app settings
│ │ ├── MySqlConfig.php # MySQL connection config
│ │ ├── RedisConfig.php # Redis connection config
│ │ └── ResendConfig.php # Email service config
│ ├── Exception/ # Custom exceptions
│ ├── Factory/ # Factory classes
│ ├── Repository/ # Data access layer
│ │ ├── AccountRepository/ # Account data access
│ │ ├── BlogRepository/ # Blog data access
│ │ ├── LinktreeRepository/ # Linktree data access
│ │ ├── PermissionsRepository/ # Permission data access
│ │ ├── ReferralRepository/ # Referral data access
│ │ ├── RoleRepository/ # Role data access
│ │ └── UserRepository/ # User data access
│ ├── Slim/ # Slim framework extensions
│ │ ├── Handler/ # Error handlers
│ │ ├── Middleware/ # Custom middleware
│ │ │ ├── AuthMiddleware.php # JWT authentication
│ │ │ ├── CorsMiddleware.php # CORS handling
│ │ │ ├── MetricsMiddleware.php # Prometheus metrics
│ │ │ └── PermissionMiddleware.php # RBAC enforcement
│ │ └── RouteCollector.php # Route definitions
│ ├── Utils/ # Utility classes
│ └── Value/ # Value objects
├── templates/ # Twig templates
│ └── email/ # Email templates
├── tests/ # PHPUnit tests
│ └── Api/ # API tests (mirrors src/Api)
├── .env.example # Environment template
├── composer.json # PHP dependencies
├── docker-compose.development.yml # Dev Docker Compose
├── justfile # Just command definitions
├── phpcs.xml # Code style config
├── phpmd.xml # PHPMD config
└── phpunit.xml # PHPUnit config
Run the full test suite:
just testOr directly via Docker:
docker compose -f docker-compose.development.yml run php-fpm \
/var/www/vendor/bin/phpunit -c /var/www/phpunit.xmlTests are organized to mirror the src/ directory structure:
tests/
└── Api/
├── Admin/
│ ├── Permission/
│ ├── Role/
│ └── User/
├── Module/
│ ├── Blog/
│ ├── Linktree/
│ └── Referral/
└── User/
Each endpoint typically has tests for:
*ActionTest.php— HTTP action tests*ServiceTest.php— Business logic tests*ValidatorTest.php— Input validation tests*ResponderTest.php— Response formatting tests
Run all linting checks:
just lintThis executes:
-
PHPMD (PHP Mess Detector):
phpmd src text phpmd.xml
-
PHP_CodeSniffer:
phpcs --standard=phpcs.xml src
The project enforces consistent code style through:
- PHPMD — Detects potential problems, unused code, and complexity issues
- PHP_CodeSniffer — Enforces PSR-12 coding standards
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes
- Run tests:
just test - Run linting:
just lint - Commit your changes:
git commit -m 'Add my feature' - Push to the branch:
git push origin feature/my-feature - Open a Pull Request
- Follow PSR-12 coding standards
- Write tests for new features
- Ensure all tests pass before submitting
- Document public APIs
This project is licensed under the MIT License — see the LICENSE file for details.
Nebalus
📧 [email protected]
🌐 nebalus.dev