dx/README.md

12 KiB

🛠️ DX

dx is a framework-agnostic bash CLI that orchestrates the full development lifecycle for PHP projects — Docker, Apache, Traefik, environment config, migrations, and tests — across multiple frameworks (Yii2, Laravel).

The dx script at the project root is the entrypoint. It loads dxkit/bootstrap.sh and dispatches to the command and module system inside dxkit/.

Prerequisites

  • Bash (Linux/macOS native; Windows via Git Bash or WSL)
  • Docker + Docker Compose
  • dx must be executable: chmod +x dx

Quick start

./dx setup              # first time: build image + init environment
./dx up                 # start the stack
./dx shell              # enter the app container
./dx console migrate    # run database migrations

Command reference

Setup & initialization

Command Description
dx build Build the Docker image and generate the compose stack
dx init [env] Bring the project to a runnable state for an environment (default: dev)
dx setup build + init in one step

dx build flags

Flag Description
--dev / --qly / --prd Target environment (default: --dev)
--project=NAME Override the project name
--port=PORT Override the app HTTP port
--db=mysql|mssql Database engine (default: mysql)
--db-port=PORT Override the database port
--sync-hosts Write the project domain to /etc/hosts after build
--no-vhosts Skip Apache virtual host generation
--no-interact Non-interactive mode (no prompts)
--debug Enable shell trace output

dx init flags

Flag Description
--skip-vendors Skip composer install
--skip-framework-init Skip framework init script
--skip-framework-config Skip framework config generation
--skip-proxy Skip starting the reverse proxy
--debug Enable shell trace output

Runtime

Command Description
dx up Start the Docker stack
dx down Stop the Docker stack
dx logs Tail container logs
dx shell / dx bash Open an interactive shell inside the app container
dx exec <cmd> [args] Run a command inside the app container
dx list / dx ls List stack containers
dx test [args] Run PHPUnit tests inside the container

dx up flags

Flag Description
--sync-hosts Sync domain entries to /etc/hosts before starting
--skip-proxy Do not ensure the reverse proxy is running
--recreate Force container recreation
--build Rebuild the image before starting
--foreground Run in foreground (don't detach)
--debug Enable shell trace output

dx down flags

Flag Description
--volumes Also remove Docker volumes
--orphans Remove orphan containers
--debug Enable shell trace output

Framework console

Command Description
dx console <cmd> [args] Run a framework console command
dx yii <cmd> Alias for Yii2 (php yii <cmd>)
dx artisan <cmd> Alias for Laravel (php artisan <cmd>)

Migration shortcuts

These are resolved by the active framework driver.

Yii2

Command Description
dx migrate Run all pending migrations
dx migrate-create <name> Generate a new timestamped migration file in console/migrations/
dx migrate-down [n] Revert n migrations (default: 1)
dx migrate-new Show pending migrations
dx migrate-history Show migration history

Laravel

Command Description
dx migrate Run all pending migrations
dx migrate-create <name> Create a migration via artisan make:migration
dx migrate-rollback [--step=N] Revert migrations
dx migrate-status Show migration status
dx migrate-fresh Drop all tables and re-run all migrations

Apache

Command Description
dx apache validate Validate vhost configuration
dx apache reload Graceful reload (picks up config changes without downtime)
dx apache restart Full restart
dx apache vhosts List all loaded virtual hosts
dx apache modules List all loaded Apache modules
dx apache version Show Apache version
dx apache logs [error|access] Tail error or access logs

Proxy (Traefik)

Command Description
dx proxy start Start the Traefik reverse proxy
dx proxy stop Stop the proxy
dx proxy restart Restart the proxy
dx proxy status Show proxy status
dx proxy logs Tail proxy logs

Network & hosts

Command Description
dx network status Show resolved port assignments
dx network resolve Re-run port resolution and show changes
dx network hosts Alias for the hosts command
dx hosts sync Write project domain entries to /etc/hosts (requires root/sudo)
dx hosts remove Remove project entries from /etc/hosts
dx hosts list Show current /etc/hosts entries for this project
dx hosts preview Preview entries that would be written

Workspace

Command Description
dx workspace / dx ws Drop into a subshell where all dx commands and framework driver commands are available without the dx prefix

Global flags

These flags are accepted by all commands:

Flag Description
--framework=NAME Override auto-detected framework
--debug Enable shell trace output (set -x)

Environments

Three built-in environments:

Name Use
dev Development (default)
qly Quality
prd Production

Environment variables are layered in order:

  1. dxkit/env/globals.env — shared defaults, source-controlled
  2. .project/artifacts/env/${ENVIRONMENT}.env — local overrides, gitignored
  3. .project/artifacts/env/${ENVIRONMENT}.resolved.env — generated resolved values, gitignored

Resolved port assignments are written to .project/artifacts/ports and loaded back on subsequent runs.

Port values in env files may use the auto:PORT syntax — dxkit will find the next available port starting from that number.


Framework support

Framework detection reads composer.json at project root.

Framework Detected by Console binary dx console alias
Yii2 Advanced yiisoft/yii2 + advanced template structure yii dx yii
Yii2 Basic yiisoft/yii2 + basic template structure yii dx yii
Laravel laravel/framework artisan dx artisan

Use --framework=NAME to override detection (e.g. --framework=yii2-advanced).


Architecture

For contributors and maintainers.

dx                          # project-level entrypoint; defines aliases, calls dx::dispatch()
dxkit/
├── bootstrap.sh            # loads core.sh, exports PROJECT_ROOT, defines dx::load_modules()
├── core.sh                 # sources all core subsystems in order
├── core/                   # low-level infrastructure
│   ├── platform.sh         # OS detection, privilege elevation
│   ├── context.sh          # execution context management
│   ├── utils.sh            # general utilities
│   ├── string.sh           # string helpers
│   ├── hook.sh             # pre/post hook system
│   ├── module.sh           # module loader
│   ├── command.sh          # command registration framework
│   ├── loader.sh           # dynamic file loader
│   ├── flag.sh             # flag/argument parsing
│   └── runtime/runtime.sh  # runtime abstraction entry
├── commands/               # one file per command, loaded dynamically by the dispatcher
│   ├── build.command.sh
│   ├── init.command.sh
│   ├── setup.command.sh
│   ├── console.command.sh
│   ├── apache.command.sh
│   ├── hosts.command.sh
│   ├── network.command.sh
│   ├── proxy.command.sh
│   ├── workspace.command.sh
│   ├── docker/             # low-level docker subcommands
│   └── runtime/            # runtime-abstracted subcommands (used by default)
├── modules/                # reusable function libraries sourced at startup
│   ├── app.module.sh       # framework abstraction layer (scaffold, init, config, console)
│   ├── docker.module.sh    # Docker and Docker Compose wrappers
│   ├── env.module.sh       # environment variable loading and derivation
│   ├── log.module.sh       # structured logging with icons and context prefixes
│   ├── fs.module.sh        # cross-platform file write and sed utilities
│   ├── network.module.sh   # port resolution and persistence
│   ├── apache.module.sh    # Apache management functions
│   ├── proxy.module.sh     # proxy abstraction (delegates to docker/proxy.module.sh)
│   ├── artifact.module.sh  # runtime artifact directory management
│   ├── composer.module.sh  # composer operations (install, update, require, auth)
│   ├── template.module.sh  # envsubst-based template rendering
│   ├── yii.module.sh       # Yii2 shared utilities (exec, env name mapping)
│   ├── phpstorm.module.sh  # PhpStorm datasource config generation
│   ├── docker/
│   │   ├── db.module.sh    # database port/path/env helpers (MySQL + MSSQL)
│   │   └── proxy.module.sh # Traefik container lifecycle and label generation
│   └── framework/
│       ├── yii2-advanced.module.sh
│       ├── yii2-basic.module.sh
│       └── laravel.module.sh
├── drivers/                # framework-specific command registration
│   ├── dispatcher.sh       # resolves framework → driver, populates DRIVER_COMMANDS
│   ├── yii2/
│   │   ├── driver.sh       # registers yii, migrate-* commands
│   │   └── migrate.sh      # migration file generation helpers
│   └── laravel/
│       ├── driver.sh       # registers artisan, migrate-* commands
│       └── migrate.sh      # artisan make:migration wrappers
├── runtime/                # runtime abstraction (Docker vs. native execution)
│   ├── runtime.sh          # selects active runtime
│   ├── docker.runtime.sh   # implements runtime::exec via docker compose exec
│   └── native.runtime.sh   # implements runtime::exec directly on host
├── templates/              # envsubst-rendered config templates
│   ├── docker/
│   │   ├── Dockerfile.template
│   │   └── docker-compose.yml.template
│   ├── apache/
│   │   ├── yii2-advanced/vhosts.conf.template
│   │   └── yii2-basic/vhosts.conf.template
│   ├── yii2-advanced/
│   │   ├── main-local.php.template
│   │   └── components/     # db.mysql, db.mssql, log php templates
│   └── yii2-basic/
│       ├── db.mysql.php.template
│       └── db.mssql.php.template
├── env/                    # layered environment variable files
│   ├── globals.env
│   ├── dev.env
│   ├── qly.env
│   └── prd.env
└── docker/
    └── entrypoint.sh       # container entrypoint script

How command dispatch works

  1. dx <command> [args] calls dx::dispatch()
  2. Aliases in dx are resolved first (e.g. shruntime/shell, lsruntime/list)
  3. Built-ins (help, elevate) are handled inline
  4. Driver commands registered in DRIVER_COMMANDS (via dxkit/drivers/dispatcher.sh) are checked next
  5. Remaining commands are matched to files in dxkit/commands/ and loaded dynamically

Adding a new command

  1. Create dxkit/commands/<name>.command.sh with a function command::<name>()
  2. Optionally register an alias in dx under the alias map
  3. For framework-specific commands, register the command name in the driver file (dxkit/drivers/<framework>/driver.sh)