Multi-Application Architecture
Phexium implements a multi-application architecture allowing multiple distinct applications to coexist within the same monorepo project, while sharing the common framework (src/).
Objectives
The multi-application architecture allows:
- Sharing a common framework (
src/) between applications - Complete isolation of each application (code, configuration, database, public entry point)
- Independent deployment via virtual hosts
- Independent testing of each application
Visual Architecture
phexium/
├── src/ # Phexium framework (shared)
├── app/
│ ├── demo/ # Application 1 (AppDemo\)
│ │ ├── src/ # Application modules
│ │ ├── config/ # Configuration
│ │ ├── database/ # SQL schemas and fixtures
│ │ ├── public/ # Web entry point
│ │ └── .env # Environment configuration
│ └── starter/ # Application 2 (AppStarter\)
│ ├── src/
│ ├── config/
│ ├── public/
│ └── .env
├── public/ # Root landing page
└── tests/
├── AppDemo/ # App 1 tests
└── AppStarter/ # App 2 tests
Access via Virtual Hosts
Each application runs on its own virtual host:
| URL | Application |
|---|---|
| http://localhost:8080 | Landing page (links to apps) |
| http://demo.localhost:8080 | Demo application |
| http://starter.localhost:8080 | Starter application |
Nginx configuration in docker/service/nginx/conf.d/default.conf defines these virtual hosts.
Entry Point
Each application has its own entry point (app/{name}/public/index.php):
<?php
declare(strict_types=1);
require_once __DIR__.'/../../../vendor/autoload.php';
$app = require __DIR__.'/../config/bootstrap.php';
$app->run();
The bootstrap loads the .env file from its application directory.
Naming Conventions
| Type | Pattern | Example |
|---|---|---|
| App directory | app/{name} | app/demo |
| App source | app/{name}/src | app/demo/src |
| Config directory | app/{name}/config | app/demo/config |
| Database directory | app/{name}/database | app/demo/database |
| App namespace | App{Name}\ | AppDemo\ |
| Tests directory | tests/App{Name} | tests/AppDemo |
Configuration Files
Each application has 6 configuration files in app/{name}/config/:
| File | Purpose |
|---|---|
bootstrap.php | Application entry point |
container.php | DI container definitions |
routes.php | HTTP routes |
events.php | Event subscriptions |
permissions.php | RBAC permissions |
container_test.php | Test overrides |
Creating a New Application
- Copy
app/starter→app/myapp - Update namespace in all PHP files:
AppStarter→AppMyapp - Update
.envand.env.sample - Add namespace to
composer.json: - Run
composer dump-autoload - Add virtual host to
docker/service/nginx/conf.d/default.conf - Copy
tests/AppStarter→tests/AppMyapp - Add Behat suites to
behat.yml - Update
php-cs-fixer.php,rector.php,sonar-project.properties
Test Isolation
Each application loads its own container in tests:
// GetContainerTrait loads app/{name}/config/container.php
$container = $this->getContainer();
$useCase = $container->get(HomeUseCase::class);
Running Tests
task tests:acceptance:starter # Starter app tests
task tests:acceptance:demoInMemory # Demo app with InMemory
task tests:acceptance # All applications
Benefits
- Complete isolation between applications
- Independent deployment via virtual hosts
- Framework sharing with centralized bug fixes
- Isolated tests with merged coverage reports
Limitations
- Configuration files must be maintained per application
- New applications require manual addition to build tools and Nginx config
- Strict naming conventions must be respected
See Also
- Project Structure - Directory organization
- Acceptance Testing (Behat) - Per-application test suites