Directory structure

Concept Core does not impose any directory structure. The location of all folders — including src, config, storage, database — can be customized in bootstrap/paths.php and PSR-4 autoloading in composer.json.

Concept Skeleton ships a ready scaffold with src/App/ layout (component-ready). Below is the recommended project root structure and three common approaches to organizing code inside src. These are guidelines, not a mandatory standard.

Root directories (public, bootstrap, config, etc.) — recommended convention for getting started. They can be renamed or moved if you update paths.php and web server settings.

Recommended root structure

Matches Concept Skeleton and keys in bootstrap/paths.php:

project/
├── public/                      # document root: index.php, assets, vendor/
│   ├── index.php
│   ├── assets/
│   └── vendor/
├── bootstrap/
│   ├── app.php
│   ├── paths.php
│   └── providers/               # app.php, console.php
├── bin/console.php
├── config/                      # PHP config + config/{dev,production}/
├── routes/                      # routes (loaded from config)
├── resources/
│   ├── lang/validator/          # PathName::VALIDATOR_TRANSLATIONS
│   └── views/
│       ├── errors/fallback/     # PathName::ERRORS_FALLBACK_VIEWS
│       └── frontend/
├── database/
│   ├── migrations/              # PathName::MIGRATIONS
│   └── seeders/                 # PathName::SEEDERS
├── storage/
│   ├── logs/                    # PathName::LOGS
│   └── cache/                   # PathName::CACHE
├── src/                         # PathName::SRC — application code
├── tests/
├── .env.example
└── composer.json

The path to each directory is set in paths.php via PathName constants (PathName::CONFIG, PathName::SRC, PathName::LOGS, etc.). Core accesses them through PathManager::get(PathName::…), not hard-coded strings. For example, code can live in app/ instead of src/ — just change the value for PathName::SRC and Composer namespaces.

Concept Skeleton default

The starter template uses a component-ready layout: shared code in src/App/, global routes in routes/web.php, landing templates in resources/views/frontend/. Components (src/Components/) are added as needed.

src/App/
├── Controllers/              # Concept\App\Controllers\* (IndexController)
└── Extensions/Twig/          # Concept\App\Extensions\Twig\*

routes/web.php                # global routes + middleware stack
resources/views/frontend/     # @frontend/… — landing, shared pages

Composer (skeleton):

"autoload": {
    "psr-4": {
        "Concept\\": "src/",
        "Database\\Seeders\\": "database/seeders/"
    }
}

paths.php: full set of PathName keys (details). Providers are already wired in bootstrap/providers/ — see Setup.

Organizing code in src

Besides the skeleton layout (src/App/), you can choose layered MVC or modular components. All three variants are compatible with Concept Core.

1. Layered MVC (package by layer)

Classic layered architecture: code is grouped by type (controllers, models, requests), not by module. In the PHP community this is often called package by layer — the opposite of “package by feature”.

Layers sit directly in the code directory (e.g. src/), without intermediate folders like App or Components:

src/
├── Controllers/       # Concept\Controllers\*
├── Models/            # Concept\Models\*
├── Requests/          # FormRequest, DTO requests
├── Validation/
│   └── Rules/
├── Extensions/
│   └── Twig/
├── Services/          # optional: business logic
└── Middlewares/       # optional: HTTP middleware

Namespace follows PSR-4: with "Concept\\": "src/", class src/Controllers/HomeController.php has namespace Concept\Controllers, not Concept\App\Controllers.

When to choose: small applications, single domain, few modules; team used to classic MVC (Symfony 2–4, early Laravel).

Drawbacks: as the project grows, it is hard to find “everything about orders” — files are scattered across layers.

Composer (example):

"autoload": {
    "psr-4": {
        "Concept\\": "src/"
    }
}

paths.php: PathName::SRC => 'src' (details).

2. Components (modular monolith)

Modular monolith with pluggable components: shared application core + isolated functional modules. This combines package by feature (inside each component) with MVC layers. Supported by the Concept Core component system.

src/
├── App/                          # shared application code
│   ├── Controllers/              # global controllers
│   ├── Models/                   # BaseModel, shared traits
│   ├── Requests/
│   ├── Validation/Rules/
│   ├── Extensions/Twig/
│   └── Services/
└── Components/                   # functional modules
    ├── AuthAdmin/
    │   ├── AuthAdminComponent.php
    │   ├── routes.php
    │   ├── Controllers/
    │   ├── Models/
    │   ├── Requests/
    │   ├── Dto/
    │   ├── Middlewares/
    │   ├── Commands/
    │   ├── Services/
    │   ├── Enums/
    │   ├── Extensions/
    │   ├── Views/                # module Twig (@auth-admin/…)
    │   ├── Assets/               # JS/CSS → public via CLI
    │   └── Database/
    │       ├── Migrations/
    │       └── Seeders/
    ├── UserCabinet/
    └── ProjectManager/

Each component implements ComponentInterface directly in its {Name}Component.php class. Active modules are listed in config/components.php or config/{env}/components.php. Routes, views, migrations, seeders, CLI commands, assets, and service providers are declared via interface methods (routes(), viewPaths(), migrationPaths(), etc.). The App directory is for shared pieces (base models, Twig extensions, validation rules). Step-by-step example — AuthAdmin.

When to choose: several subsystems (admin, cabinet, public site), need to enable or disable modules via config, different teams work on separate components.

Comparison

Layered MVC Components Concept Skeleton
Academic term Layered / package by layer Modular monolith, package by feature Component-ready App/
Project size Small — medium Medium — large Start — any
src organization Controllers/ at top level App/ + Components/ App/ (+ optional Components/)
Namespace (example) Concept\Controllers\* Concept\App\*, Concept\Components\* Concept\App\*
Routes routes/web.php + routes.php in each component routes/web.php
Concept Core Full support + component subsystem Ready scaffold + providers
Composer PSR-4 Concept\\src/ Concept\\src/ + Database\\Seeders\\

Views, lang, storage

Paths are configured in paths.php via Concept\Core\Foundation\PathName constants. Core accesses them through PathManager::get(PathName::…).

What PathName Path in skeleton
Shared Twig templates PathName::VIEWS resources/views/ (@frontend/, layouts)
Fallback error templates PathName::ERRORS_FALLBACK_VIEWS resources/views/errors/fallback/
Language files PathName::LANG resources/lang/
Validator translations PathName::VALIDATOR_TRANSLATIONS resources/lang/validator/
Module templates ComponentInterface::viewPaths() src/Components/{Name}/Views/@auth-admin/…
Application migrations PathName::MIGRATIONS database/migrations/ + paths in config/migrations.php
Application seeders PathName::SEEDERS database/seeders/ (namespace Database\Seeders\)
Logs PathName::LOGS storage/logs/
Cache PathName::CACHE storage/cache/ (Twig, Valinor, etc.)
Component assets ComponentInterface::assets() component:publish-assetspublic/components/… (php bin/console.php component:publish-assets)

Full list of keys — in the PathName table. Component migrations and seeders are registered via migrationPaths() and seeders() on the component class, not via global PathName::MIGRATIONS / PathName::SEEDERS.

What to choose

  • Concept Skeleton — quick start: HTTP + Twig, src/App/, ready providers; add components as needed.
  • Layered MVC — simple start without App/, single domain, few modules.
  • Components — several subsystems, need module isolation and Concept core support.

Structure can be changed at any time: update paths.php, composer.json, and config.

Next: request lifecycle and setup of entry points.