Application Structure

Who this is for

You finished DeskFlow tutorial Step 1 and want to understand every folder in your DeskFlow repo before adding database tables and auth.

What you will learn

  • Which paths are safe to edit (services/, switches/, environment/)
  • Where logs, cache, and generated bootstrap files land under storage/
  • How v3 layout differs from v2 (AppRealm, public/static/)

Before you start

Before you start

How it works

Every HTTP and CLI request loads the same bootstrap/application.php, which returns a singleton AppRealm. Your code lives under Application\ — mapped to services/, switches/, and sibling folders without per-directory Composer entries.

v3 app layout (from composer create-project pionia/pionia-app):

bootstrap/
  application.php    return AppRealm::create(__DIR__)
environment/
  .env               APP_NAME, PORT, DEBUG
  settings.ini       logging, db, cors, [app_switches], jobs, realtime
public/
  index.php          HTTP entry → bootHttp()
  .htaccess
  static/            optional user assets (favicon, SPA build output)
services/            *Action business logic (TaskService, MemberService)
switches/            registerServices() → service aliases
middlewares/         request/response middleware
authentications/     auth backends (JWT for alex@northwind.studio)
commands/            custom CLI commands
storage/
  cache/
  logs/
  bootstrap/         generated by `php pionia optimize` (route cache, providers, preload — gitignored)
  metrics/           request metrics + optional opcache-snapshot.json
worker.php           RoadRunner worker (HTTP + jobs)
.rr.yaml             RoadRunner config
pionia               CLI entry → bootConsole()
composer.json

Directory roles

PathRole
bootstrap/AppRealm::create() — single realm instance for HTTP, CLI, and workers
environment/.env + settings.ini ([app_switches], database, cache, logging, maintenance)
public/Web root only — never expose project root
services/Classes extending Service; methods named {action}Action
switches/Map service alias → class (taskTaskService)
middlewares/Global or route middleware chains
authentications/Pluggable auth strategies
commands/Custom pionia commands
storage/Cache, logs, metrics, and generated bootstrap caches
worker.phpPersistent workers via RoadRunner

DeskFlow services map

Folder / fileDeskFlow usage
services/TaskService.phptask.list, task.create
services/MemberService.phpmember.login for alex@northwind.studio
services/ProjectService.phpproject.list (often generic CRUD)
switches/MainSwitch.phpRegisters task, member, project on /api/v1/
environment/settings.ini[app_switches], [db], [cache]
storage/logs/Errors when DEBUG=true

v2 → v3 changes

v2v3
PioniaApplication + wireTo()AppRealm + [app_switches] in settings.ini
static/ at repo rootpublic/static/ or framework welcome assets
handleRequest() on appbootHttp() from public/index.php
PHP 8.1, core ^2.0PHP 8.5+, core ^3.0

Autoload namespace: Application\ mapped to the project root (composer.json).

Common mistakes

  • Committing environment/.env — keep secrets gitignored; share .env.example instead.
  • Serving from repo root — point nginx/Apache document root at public/ only.
  • Deleting storage/ entirely — wipe storage/cache/ or run cache:clear; logs and metrics need the folder.
  • Looking for routes in bootstrap/routes.php — v3 registers switches from settings.ini, not a routes file.

What’s next

API tutorial

Continue DeskFlow tutorial.

Database getting started

SQLite tasks table for DeskFlow.

Building your API

Services, actions, validation.