Skip to content

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

  1. Copy app/starterapp/myapp
  2. Update namespace in all PHP files: AppStarterAppMyapp
  3. Update .env and .env.sample
  4. Add namespace to composer.json:
    "AppMyapp\\": "app/myapp/src/"
    
  5. Run composer dump-autoload
  6. Add virtual host to docker/service/nginx/conf.d/default.conf
  7. Copy tests/AppStartertests/AppMyapp
  8. Add Behat suites to behat.yml
  9. 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