Architecture at a Glance

Summary

A single-page map of how Dotkernel API is put together: the Core/App split introduced in 6.0, the Headless Platform and modular-monolith layout, the path a request takes through the middleware pipeline into a handler, the roles of handlers, services, repositories, input filters and entities, how configuration and dependency injection are organized, the PSRs behind it all, and the four security layers.

Details

Dotkernel API follows a modular, middleware-based architecture designed for scalability and maintainability. Understanding the core structure is essential before diving into development.

The Core vs App Split (Since v6.0)

Since version 6.0, Dotkernel API is organized into two distinct layers: Core and App.

Layer Purpose Items Location
Core The backbone of your application, the system-level infrastructure that handles fundamental concerns Authentication & Authorization, Database, Common Services, Shared Entities src/Core/src/
App The project-specific features, "business logic" of your application Routes, Handlers, Custom Services, Input Filters, Custom Middleware, Error Reporting src/App/src/

Architecture

Dotkernel API is built toward a Headless Platform architecture. Out of the box, it is a modular monolith that can be split into modules and microservices.

┌──────────────────────────────────────────────────────────┐
│                    Multiple Frontends                    │
│        (Web, Mobile, Desktop, Voice, etc.)               │
└────────────┬────────────────────────────┬────────────────┘
             │                            │
             └────────────┬───────────────┘
                          │ (REST/JSON APIs)
┌─────────────────────────▼──────────────────────────────┐
│           Dotkernel API (Headless Backend)             │
│  ┌──────────────────────────────────────────────────┐  │
│  │ Core Layer (Infrastructure)                      │  │
│  │ • Authentication (OAuth2)                        │  │
│  │ • Authorization (RBAC)                           │  │
│  │ • Database (Doctrine ORM)                        │  │
│  │ • Middleware Pipeline                            │  │
│  └──────────────────────────────────────────────────┘  │
│  ┌──────────────────────────────────────────────────┐  │
│  │ App Layer (Business Logic)                       │  │
│  │ • Endpoints & Routes                             │  │
│  │ • Handlers & Services                            │  │
│  │ • Custom Logic                                   │  │
│  └──────────────────────────────────────────────────┘  │
└─────────────────────────────────────┬──────────────────┘
                                      │
                    ┌─────────────────▼─────────────────┐
                    │   Database                        │
                    │ (MariaDB / PostgreSQL)            │
                    └───────────────────────────────────┘

Modular Monolith Architecture

Applications are organized into modules, each handling a specific domain.

Built-in Modules:

  • Admin: Admin account management (superuser/admin roles)
  • User: Regular user management (user/guest roles)
  • Security: OAuth2 token generation and refresh
  • App: Error reporting and general endpoints
  • Core: Shared infrastructure and base classes

Custom Modules: You can create your own modules (e.g., Book, Product, Article) following the same pattern.

Request Flow

Here's how a typical request flows through Dotkernel API:

1. HTTP Request
   ↓
2. Middleware Pipeline (config/pipeline.php)
   ├─ CorsMiddleware (handle CORS)
   ├─ AuthenticationMiddleware (identify user)
   ├─ AuthorizationMiddleware (check permissions)
   ├─ ContentNegotiationMiddleware (validate Accept/Content-Type)
   └─ RouteMiddleware (match route)
   ↓
3. Handler (PSR-15 RequestHandler)
   ├─ Receive ServerRequestInterface
   ├─ Execute business logic
   └─ Return ResponseInterface
   ↓
4. Response Middleware (if any)
   ├─ ProblemDetailsMiddleware (handle exceptions)
   ├─ DeprecationMiddleware (add deprecation headers)
   └─ Response Header Middleware (set custom headers)
   ↓
5. HTTP Response

Key Components

Component Purpose Example Notes
Handlers (PSR-15) Process incoming HTTP requests, coordinate application logic/services, and return the HTTP response GetUserResourceHandler.php, PostUserResourceHandler.php Some of the benefits are: separation of concerns, easier testing, clearer intent
Services Contains the business logic layer that sits between the handlers and repositories Business rules validation, Data transformation, Cross-cutting concerns Execution flow: Handler → Service → Repository → Database
Repositories Data access layer using Doctrine ORM Query building, Entity persistence, Database abstraction The only component that interacts with the database
Input Filters Filter and validate requests using Laminas InputFilter Login form, contact us form, $_GET and $_POST values, CLI arguments Execution flow: Request → InputFilter → Validation → Handler
Entities Represent database tables using Doctrine ORM class User { ... } Ensure consistency between database and application data

Configuration Organization

config/
├─ config.php                     (Main entry point)
├─ pipeline.php                   (Middleware stack)
├─ container.php                  (Dependency injection)
└─ autoload/
    ├─ dependencies.global.php        (Service definitions)
    ├─ authorization.global.php       (RBAC rules)
    ├─ content-negotiation.global.php (Accept/Content-Type)
    ├─ doctrine.global.php            (ORM configuration)
    └─ local.php                      (Environment-specific, ignored by VCS, private config)

Dependency Injection

Dotkernel API uses constructor injection with attributes:

use Dot\DependencyInjection\Attribute\Inject;

class UserHandler
{
    #[Inject(
        UserService::class,
        "config"
    )]
    public function __construct(
        protected UserService $userService,
        protected array $config
    ) {}
}

Services are automatically resolved and injected by AttributedServiceFactory.

Data Flow Architecture

┌─────────────────────────────────────────┐
│    Incoming HTTP Request (PSR-7)        │
└────────────┬────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────┐
│    Middleware Pipeline                  │
│  (Auth, Validation, Negotiation)        │
└────────────┬────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────┐
│    Handler (Business Logic)             │
│  • Extract request data                 │
│  • Validate with InputFilter            │
│  • Call Service layer                   │
└────────────┬────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────┐
│    Service Layer (Domain Logic)         │
│  • Business rules                       │
│  • Data transformation                  │
│  • Call Repository layer                │
└────────────┬────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────┐
│    Repository Layer (Data Access)       │
│  • Doctrine queries                     │
│  • Entity persistence                   │
└────────────┬────────────────────────────┘
             │
             ▼
┌─────────────────────────────────────────┐
│    Database (MariaDB / PostgreSQL)      │
└─────────────────────────────────────────┘

Standards & PSRs

Dotkernel API adheres to PHP standards for interoperability. They ensure that your code can integrate with other PSR-compliant libraries.

PSR and Specifications Git Implementation Level Description
PSR-7 http-message Core HTTP Message Interfaces (Requests/Responses)
PSR-11 container Core Container Interface (Dependency Injection)
PSR-15 http-server-handler, http-server-middleware Core HTTP Handlers and Middleware (Request processing)
PSR-3 log Supporting Logger Interface (Requests/Responses)
PSR-4 Supporting Autoloading (File organization)
PSR-6 cache Supporting Caching Interface
PSR-13 Git link Supporting Link Definition Interfaces
PSR-14 event-dispatcher Supporting Event Dispatcher
PSR-17 http-factory Supporting HTTP Factories
PSR-18 http-client Supporting HTTP Client
PSR-20 clock Supporting Clock

Supporting PSRs are installed by dependencies.

Security Layers

┌─────────────────────────────┐
│  1. Authentication          │
│  (OAuth2 tokens)            │
├─────────────────────────────┤
│  2. Authorization           │
│  (RBAC permissions)         │
├─────────────────────────────┤
│  3. Input Validation        │
│  (InputFilter)              │
├─────────────────────────────┤
│  4. Content Negotiation     │
│  (Accept/Content-Type)      │
└─────────────────────────────┘

When to Use Each Layer

Layer Purpose Example
Core System infrastructure Authentication, database setup
App Project features User CRUD operations, custom logic
Handler Request/response mapping Extract user ID, call service
Service Business rules Validate user data, calculate totals
Repository Data queries Find users, save entity

FAQ

Q: Where should I put a new feature?

A: In the App layer, under src/App/src/ or your own module. Core (src/Core/src/) is reserved for infrastructure such as authentication, database access and shared entities. See Core and App.

Q: What is the execution order from request to database?

A: Handler → Service → Repository → Database. The handler maps the request, the service holds business rules, and the repository is the only layer that touches the database.

Q: Which middlewares run before my handler?

A: CORS, authentication, authorization, content negotiation and routing, in that order, as defined in config/pipeline.php. See Middleware flow.

Q: What runs after the handler returns?

A: The response-side middlewares: problem details for exceptions, the deprecation headers, and any custom response headers.

Q: What are the built-in modules?

A: Admin, User, Security, App and Core. Your own modules — Book, Product, Article and so on — follow the same pattern.

Q: Is this a monolith or microservices?

A: Out of the box it is a modular monolith, structured so that individual modules can later be split into separate services.

Q: Where is business logic supposed to live?

A: In services, not handlers or repositories. Handlers extract and validate request data and delegate; repositories only query and persist.

Q: How do dependencies reach my classes?

A: Through constructor injection declared with the #[Inject] attribute and resolved by AttributedServiceFactory. See Dependency injection.

Q: Which configuration file does what?

A: config.php is the entry point, pipeline.php the middleware stack, container.php the DI container, and config/autoload/ holds per-concern files — with local.php for environment-specific values that stay out of version control.

Q: What are the four security layers?

A: Authentication with OAuth2 tokens, authorization with RBAC permissions, input validation with input filters, and content negotiation on Accept and Content-Type. See Basic security.

Q: Which databases are supported?

A: MariaDB and PostgreSQL. See Server requirements.

Q: Which PSRs are core rather than supporting?

A: PSR-7, PSR-11 and PSR-15 are core to the architecture; the rest arrive through dependencies. See PSRs.