### Install with Composer Source: https://github.com/mozex/laravel-compose/blob/main/docs/installation.md Installs the package via Composer. The service provider registers itself through package discovery. ```bash composer require mozex/laravel-compose ``` -------------------------------- ### Run compose:install to Publish Config Source: https://github.com/mozex/laravel-compose/blob/main/docs/installation.md Run this command when you want to change a default. It writes config/compose.php. ```bash php artisan compose:install ``` -------------------------------- ### Install laravel-compose with Composer Source: https://github.com/mozex/laravel-compose/blob/main/README.md Install the package via Composer. Requires PHP 8.2+. ```bash composer require mozex/laravel-compose ``` -------------------------------- ### Install Scout and Meilisearch driver Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/meilisearch.md Commands to install Laravel Scout with the Meilisearch driver and publish its service provider. ```bash composer require laravel/scout meilisearch/meilisearch-php http-interop/http-factory-guzzle php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider" ``` -------------------------------- ### Run compose:install to publish config Source: https://github.com/mozex/laravel-compose/blob/main/README.md Publishes the config file config/compose.php if you want to change defaults. The server needs Docker with the Compose plugin and the user must be in the docker group; compose:doctor reports missing prerequisites. ```bash php artisan compose:install ``` -------------------------------- ### php artisan compose:redeploy usage examples Source: https://github.com/mozex/laravel-compose/blob/main/docs/deploying/redeploy.md Shows how to run the redeploy command for all stacks, a specific stack, or in dry-run mode. The command exits 0 when every stack was redeployed or skipped, and 1 when any stack failed. ```bash php artisan compose:redeploy # every stack php artisan compose:redeploy meilisearch php artisan compose:redeploy --dry-run # print the plan, touch nothing ``` -------------------------------- ### Define a MeilisearchStack class Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/defining-a-stack.md Example of a stack class implementation that defines environment variables, container enablement, and wait time. ```php namespace App\Docker\Meilisearch; use Illuminate\Support\Facades\Config; use Mozex\Compose\Stack; class MeilisearchStack extends Stack { public function environment(): array { return [ 'MEILISEARCH_KEY' => Config::get('scout.meilisearch.key'), 'MEILISEARCH_PORT' => parse_url(Config::get('scout.meilisearch.host'), PHP_URL_PORT) ?: 7700, ]; } public function enabled(): bool { return (bool) Config::get('services.meilisearch.manage_container', false); } public function wait(): ?int { return 60; } } ``` -------------------------------- ### Run compose:doctor to Verify Requirements Source: https://github.com/mozex/laravel-compose/blob/main/docs/installation.md Run after installing to confirm Docker Engine with the Compose plugin (version 2.17 or newer) and that the deploy user is in the docker group. ```bash php artisan compose:doctor ``` -------------------------------- ### Redeploying stacks via the Compose facade Source: https://github.com/mozex/laravel-compose/blob/main/docs/deploying/redeploy.md Use the Compose::redeploy method to trigger a redeployment. The first example shows a basic call returning results, while the second demonstrates passing a specific stack name and a callback function to handle output buffers. ```php use Mozex Compose Facades Compose; use Mozex Compose Enums RedeployResult; $results = Compose::redeploy(); // ['meili' => RedeployResult::Redeployed, ...] $results = Compose::redeploy('meili', fn (string $type, string $buffer) => print $buffer); ``` -------------------------------- ### Composer script deploy:after with compose:redeploy Source: https://github.com/mozex/laravel-compose/blob/main/docs/deploying/redeploy.md Place the redeploy command after the new release is built and before any step that talks to a container. This example shows a Composer-script style deploy sequence. ```json "deploy:after": [ "php artisan compose:redeploy", "php artisan search:sync-settings", "php artisan horizon:terminate" ] ``` -------------------------------- ### Test a stack class environment() with config Source: https://github.com/mozex/laravel-compose/blob/main/docs/operating/testing.md Use to test a stack class's environment() and enabled() methods against config. The example sets a config value and asserts the derived environment variable. Keep stacks consistent with their compose files using the doctor report in an architecture test. ```php it('derives the port from the scout host', function (): void { config()->set('scout.meilisearch.host', 'http://127.0.0.1:7701'); expect((new MeilisearchStack)->environment()['MEILISEARCH_PORT'])->toBe(7701); }); ``` -------------------------------- ### Fake the Compose manager with Compose::fake() Source: https://github.com/mozex/laravel-compose/blob/main/docs/operating/testing.md Use when a test needs to verify that a deploy command redeploys or skips stacks without actually running docker. Compose::fake() records redeploys and skips, and also fakes processes so status(), logs(), and exec() never reach a daemon. Call Process::fake([...]) before Compose::fake() if you need specific process results, because a bare Process::fake() installed first would shadow patterns added later. ```php use Mozex\Compose\Facades\Compose; it('redeploys the search stack after a deploy', function (): void { $fake = Compose::fake(); $this->artisan('deploy:after')->assertSuccessful(); $fake->assertRedeployed('meilisearch') ->assertSkipped('mailpit'); }); ``` -------------------------------- ### php artisan compose:doctor Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Preflight check for the Compose setup, verifying binary, plugin, daemon, docker group, compose files, variable coverage, public publishes, link directory, and gitignore. ```APIDOC ## [GET] /compose:doctor ### Description Preflight check for the Compose setup, verifying binary, plugin, daemon, docker group, compose files, variable coverage, public publishes, link directory, and gitignore. ### Method GET ### Endpoint php artisan compose:doctor ### Parameters None ### Response #### Success Response (200) - **output** (string) - The result of the preflight checks. #### Response Example ``` [output of the preflight checks] ``` ``` -------------------------------- ### Profile for production-only Caddy service Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/compose-files.md Assign the 'tls' profile to the Caddy service so it only starts when the stack's profiles() includes it, enabling one compose file for both laptop and server deployments. ```yaml caddy: image: caddy:2-alpine container_name: rdp-gateway-caddy profiles: - tls ``` -------------------------------- ### Default Laravel Compose configuration Source: https://github.com/mozex/laravel-compose/blob/main/docs/configuration.md Default configuration returned by the published config file. Every key has a default that works for a single server running the app and its containers. Publish the file with `php artisan compose:install`. ```php return [ 'enabled' => (bool) env('COMPOSE_ENABLED', true), 'stacks' => [ // App\Docker\Meilisearch\MeilisearchStack::class, ], 'discover' => [ app_path('Docker'), base_path('Modules/*/Docker'), ], 'link_directory' => env('COMPOSE_LINK_DIRECTORY'), 'docker' => [ 'binary' => env('COMPOSE_DOCKER_BINARY', 'docker'), 'host' => env('COMPOSE_DOCKER_HOST'), 'context' => env('COMPOSE_DOCKER_CONTEXT'), ], 'env_file' => '.env', 'timeouts' => [ 'pull' => 300, 'build' => 600, 'up' => 120, 'down' => 60, 'remove' => 30, ], ]; ``` -------------------------------- ### Create a stack with php artisan compose:make Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Run this command to generate a new stack directory with a Stack class, docker-compose.yml, and .gitignore. The --path option can override the default app/Docker location. Discovery is enabled for app/Docker/* and Modules/*/Docker by default. ```bash php artisan compose:make meilisearch ``` -------------------------------- ### Deploy script: redeploy and sync index settings Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/meilisearch.md Run these two commands in order on the server to deploy the Meilisearch stack. First redeploy the containers, then sync the index settings. Run `php artisan compose:doctor` once on the server before this to verify docker group membership, the compose file, and listening interfaces. ```bash php artisan compose:redeploy php artisan scout:sync-index-settings ``` -------------------------------- ### php artisan compose:logs {stack} --tail --follow Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Shows logs for a specific stack, with options for tailing and following. ```APIDOC ## [GET] /compose:logs/{stack} ### Description Shows logs for a specific stack, with options for tailing and following. ### Method GET ### Endpoint php artisan compose:logs {stack} ### Parameters #### Path Parameters - **stack** (string) - Required - The name of the stack. #### Query Parameters - **--tail** (integer) - Optional - Number of lines to tail (default 200, use 'all' for everything). - **--follow** (boolean) - Optional - Follow the log output. ### Response #### Success Response (200) - **logs** (string) - The log output. #### Response Example ``` [log output] ``` ``` -------------------------------- ### Scaffold a Meilisearch stack with compose:make Source: https://github.com/mozex/laravel-compose/blob/main/README.md Scaffolds a stack. Creates app/Docker/Meilisearch/ with a docker-compose.yml, a MeilisearchStack.php, and a .gitignore for the generated env file. The compose file names the project and container after your app (e.g., shop-meilisearch for an app called Shop), and that name is used by compose:logs and other commands. ```bash php artisan compose:make meilisearch ``` -------------------------------- ### Configure discovery patterns in config/compose.php Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/discovery.md Defines the paths or globs used to locate stack directories. ```php 'discover' => [ app_path('Docker'), base_path('Modules/*/Docker'), ], ``` -------------------------------- ### Add meilisearch manage_container config to services.php Source: https://github.com/mozex/laravel-compose/blob/main/README.md Wire the switch to an env variable in config/services.php. Set MANAGE_MEILISEARCH_CONTAINER=true on hosts that run Docker; every other host skips the stack. ```php 'meilisearch' => [ 'manage_container' => (bool) env('MANAGE_MEILISEARCH_CONTAINER', false), ], ``` -------------------------------- ### View stack logs via CLI Source: https://github.com/mozex/laravel-compose/blob/main/docs/operating/status-logs-down.md Commands to retrieve logs for a stack. Use --tail to specify the number of lines (default 100) or 'all', and --follow to stream logs. ```bash php artisan compose:logs meilisearch php artisan compose:logs meilisearch --service=meilisearch --tail=500 php artisan compose:logs rdp-gateway --follow ``` -------------------------------- ### One-shot init container with alpine image Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/compose-files.md Defines a service that runs once and exits with code 0, which counts as finished rather than dead in compose:status and health checks. Uses the alpine:3 image and sets container_name to rdp-gateway-init. ```yaml init: image: alpine:3 container_name: rdp-gateway-init restart: "no" command: sh -c "chown -R 1000:1000 /drive" ``` -------------------------------- ### Add per-host switch to config/services.php Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/meilisearch.md Configuration snippet to add the manage_container switch for Meilisearch in the services config file. ```php 'meilisearch' => [ 'manage_container' => (bool) env('MANAGE_MEILISEARCH_CONTAINER', false), ], ``` -------------------------------- ### Cap container logs with json-file driver Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/compose-files.md Configure logging to cap log file size at 50 MB and keep 3 files to prevent disk exhaustion from chatty containers. ```yaml logging: driver: json-file options: max-size: 50m max-file: '3' ``` -------------------------------- ### Envoyer Deploy Hook Source: https://github.com/mozex/laravel-compose/blob/main/docs/deploying/hosting-platforms.md Add a Run script hook on the Activate New Release action in Envoyer. ```bash cd {{ release }} && php artisan compose:redeploy ``` -------------------------------- ### Stack directory structure Source: https://github.com/mozex/laravel-compose/blob/main/docs/introduction.md Shows the layout of a stack directory inside the app, including the compose file, the Stack class, and the generated .env file. ```text app/Docker/Meilisearch/ ├── docker-compose.yml the services, images, ports, volumes ├── MeilisearchStack.php environment() and per-host knobs └── .env generated on every redeploy, gitignored ``` -------------------------------- ### Run test suite with composer test commands Source: https://github.com/mozex/laravel-compose/blob/main/CLAUDE.md Use `composer test` to run lint, PHPStan, type coverage, and Pest tests. Use `composer test:unit` to run only Pest tests. ```bash composer test # lint + phpstan + type coverage + pest composer test:unit # pest only ``` -------------------------------- ### Register stacks at runtime Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/discovery.md Register stack classes or instances from a service provider using the Compose facade. ```php use Mozex\Compose\Facades\Compose; Compose::register(MeilisearchStack::class); Compose::register(new GatewayStack); ``` -------------------------------- ### Recreate container to restore published ports Source: https://github.com/mozex/laravel-compose/blob/main/docs/operating/health-check.md Runs compose:down and compose:redeploy for a stack to recreate its container, which can restore ports that failed to bind at startup. ```bash php artisan compose:down meilisearch php artisan compose:redeploy meilisearch ``` -------------------------------- ### View container logs with compose:logs Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Run this command with the stack name to see the container's own reason for failure. ```bash php artisan compose:logs {stack} ``` -------------------------------- ### Configure services.php Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/telegram-bot-api.md Adds the telegram configuration array to config/services.php to manage API credentials and container settings. ```php 'telegram' => [ 'api_id' => env('TELEGRAM_API_ID'), 'api_hash' => env('TELEGRAM_API_HASH'), 'api_url' => env('TELEGRAM_BOT_API_URL', 'http://127.0.0.1:8081'), 'manage_container' => (bool) env('MANAGE_TELEGRAM_CONTAINER', false), ], ``` -------------------------------- ### Fake processes only with Process::fake() Source: https://github.com/mozex/laravel-compose/blob/main/docs/operating/testing.md Use when you want the real recipe to run against a fake daemon. Every docker invocation goes through Laravel's Process facade with an array command, so assertRan sees the exact arguments. Note that Symfony quotes every argument on Linux, so patterns like '*ps --format*' match on Windows but not on CI; use '*ps*--format*' or match on $process->command in a closure. ```php use Illuminate\Process\PendingProcess; use Illuminate\Support\Facades\Process; Process::fake(); Compose::redeploy('meilisearch'); Process::assertRan(fn (PendingProcess $process): bool => in_array('up', $process->command, true) && in_array('--wait', $process->command, true)); ``` -------------------------------- ### Dry run output for compose:redeploy Source: https://github.com/mozex/laravel-compose/blob/main/docs/deploying/redeploy.md Shows the dry-run output for a stack named 'meili'. Env keys are printed but values are never shown. If a compose file can't be read or environment() throws, it shows 'would fail:' with the reason and the rest of the plan still prints. ```text meili ............................ /srv/app/current/app/Docker/Meilisearch env file: /srv/app/current/app/Docker/Meilisearch/.env with MEILISEARCH_KEY, MEILISEARCH_PORT $ docker compose --project-name meili --project-directory ... pull --ignore-buildable --quiet $ docker rm -f meilisearch $ docker compose --project-name meili --project-directory ... up --detach --remove-orphans --wait --wait-timeout 60 ``` -------------------------------- ### Inspect and stop stacks from code with Compose facade Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Use the Compose facade to programmatically inspect and stop a stack. The status() method returns container statuses, logs() accepts a tail parameter, exec() runs a command inside a container, and down() stops the stack. ```php $stack = Compose::stack('meilisearch'); $stack->isRunning(); $stack->isHealthy(); $stack->status()->containers; $stack->logs(tail: 50); $stack->exec('meilisearch', ['ls', '/meili_data']); // maintenance inside a container $stack->down(); ``` -------------------------------- ### Production .env configuration Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/telegram-bot-api.md Sets the environment variables for the Telegram Bot API in the production .env file. ```text TELEGRAM_API_ID= TELEGRAM_API_HASH= TELEGRAM_BOT_API_URL=http://127.0.0.1:8081 MANAGE_TELEGRAM_CONTAINER=true ``` -------------------------------- ### Publish Meilisearch port on loopback Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/compose-files.md Binds the published port to 127.0.0.1 to avoid exposing the service on all interfaces. Publishing without an address bypasses host firewalls like UFW. Use VPN forwarding for remote access instead of publishing on a VPN address. ```yaml ports: - '127.0.0.1:${MEILISEARCH_PORT:-7700}:7700' ``` -------------------------------- ### Production .env variables Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/meilisearch.md Environment variables for production mode, including the Scout driver, Meilisearch host, key, and the manage container flag. ```env SCOUT_DRIVER=meilisearch MEILISEARCH_HOST=http://127.0.0.1:7700 MEILISEARCH_KEY= MANAGE_MEILISEARCH_CONTAINER=true ``` -------------------------------- ### Interact with running containers using Compose::stack Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/defining-a-stack.md Use the stack object to check container status, health, retrieve logs, execute commands, or bring the stack down. ```php use Mozex\Compose\Facades\Compose; $stack = Compose::stack('meilisearch'); $stack->isRunning(); // every container running, or finished as a one-shot $stack->isHealthy(); // running, and every healthcheck reports healthy $stack->status()->containers; // ContainerStatus objects: name, service, state, health, ports $stack->logs(service: 'meilisearch', tail: 50); $stack->exec('meilisearch', ['ls', '/meili_data']); $stack->down(volumes: false); ``` -------------------------------- ### Compose::fake() Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Creates a fake Compose instance that records redeploys and fakes Process. ```APIDOC ## [POST] /compose/fake ### Description Creates a fake Compose instance that records redeploys and fakes Process. ### Method POST ### Endpoint Compose::fake() ### Parameters None ### Response #### Success Response (200) - **fake** (object) - The fake instance. #### Response Example ``` { "fake": {} } ``` ``` -------------------------------- ### Define MeilisearchStack environment and enabled methods Source: https://github.com/mozex/laravel-compose/blob/main/README.md Stack class that provides environment variables for the compose file. The compose file reads those values as ${MEILISEARCH_KEY} and ${MEILISEARCH_PORT:-7700}. The enabled() method controls whether the stack is used, based on the config value services.meilisearch.manage_container. ```php namespace App\Docker\Meilisearch; use Illuminate\Support\Facades\Config; use Mozex\Compose\Stack; class MeilisearchStack extends Stack { public function environment(): array { return [ 'MEILISEARCH_KEY' => Config::get('scout.meilisearch.key'), 'MEILISEARCH_PORT' => parse_url(Config::get('scout.meilisearch.host'), PHP_URL_PORT) ?: 7700, ]; } public function enabled(): bool { return (bool) Config::get('services.meilisearch.manage_container', false); } } ``` -------------------------------- ### Meilisearch docker-compose.yml Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/meilisearch.md The Docker Compose configuration file for Meilisearch. Save this as app/Docker/Meilisearch/docker-compose.yml. ```yaml name: meilisearch services: meilisearch: image: getmeili/meilisearch:v1.53 container_name: ${COMPOSE_PROJECT_NAME} restart: unless-stopped ports: - '127.0.0.1:${MEILISEARCH_PORT:-7700}:7700' environment: MEILI_MASTER_KEY: ${MEILISEARCH_KEY} MEILI_ENV: production MEILI_NO_ANALYTICS: 'true' MEILI_UPGRADE_DB: 'true' healthcheck: test: ["CMD", "wget", "--no-verbose", "--spider", "http://127.0.0.1:7700/health"] interval: 30s timeout: 5s retries: 3 start_period: 10s ulimits: nofile: soft: 65535 hard: 65535 volumes: - 'meilisearch-data:/meili_data' logging: driver: json-file options: max-size: 50m max-file: '3' volumes: meilisearch-data: driver: local ``` -------------------------------- ### Test redeploys with Compose::fake() Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Use Compose::fake() to record redeploys and fake the Process facade. Assert redeploy and skip behavior, and simulate failures with shouldFail(). ```php $fake = Compose::fake(); // records redeploys, also fakes Process Compose::redeploy(); $fake->assertRedeployed('meilisearch')->assertSkipped('mailpit'); $fake->shouldFail('meilisearch'); // next redeploy reports Failed ``` -------------------------------- ### Compose::stack($stack)->isRunning() Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Checks if a stack is running. ```APIDOC ## [GET] /compose/stack/{stack}/isRunning ### Description Checks if a stack is running. ### Method GET ### Endpoint Compose::stack($stack)->isRunning() ### Parameters #### Path Parameters - **stack** (string) - Required - The name of the stack. ### Response #### Success Response (200) - **result** (boolean) - True if running, false otherwise. #### Response Example ``` true ``` ``` -------------------------------- ### Define a stack with conditional profiles Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/defining-a-stack.md Extend the Stack class to define environment variables and profiles, allowing services to be conditionally enabled based on configuration. ```php class GatewayStack extends Stack { public function environment(): array { return [ 'GATEWAY_PORT' => Config::get('gateway.port'), 'GATEWAY_DOMAIN' => Config::get('gateway.domain'), 'JSON_SECRET_KEY' => Config::get('gateway.secret'), ]; } public function profiles(): array { return Config::get('gateway.tls_enabled') ? ['tls'] : []; } } ``` -------------------------------- ### Ploi COMPOSE_LINK_DIRECTORY Configuration Source: https://github.com/mozex/laravel-compose/blob/main/docs/deploying/hosting-platforms.md Set the link directory to the Ploi containers path so the panel can track stacks. ```text COMPOSE_LINK_DIRECTORY=/home/ploi/containers ``` -------------------------------- ### Configure local mode in compose file Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/telegram-bot-api.md Enable local mode by setting the TELEGRAM_LOCAL environment variable and configuring a bind mount for storage. ```yaml environment: TELEGRAM_LOCAL: 1 volumes: - '${TELEGRAM_STORAGE}:/var/lib/telegram-bot-api' ``` -------------------------------- ### Inspect and stop stacks with artisan commands Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Use these artisan commands to preflight, check status, view logs, and stop stacks. The doctor command checks binary, plugin, daemon, docker group, compose files, variable coverage, public publishes, link directory, and gitignore. Status exits with code 1 when an enabled stack is not running. The down command asks for confirmation unless --force is used. ```bash php artisan compose:doctor # preflight: binary, plugin, daemon, docker group, every compose file, ${VAR} coverage, public publishes, link directory, gitignore php artisan compose:status # table per container; exit 1 when an enabled stack is not running php artisan compose:logs meilisearch --tail=200 --follow # --tail=all for everything php artisan compose:down meilisearch --volumes # asks; --force for scripts ``` -------------------------------- ### $fake->assertSkipped($stack) Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Asserts that a stack was skipped during redeploy. ```APIDOC ## [GET] /compose/fake/assertSkipped/{stack} ### Description Asserts that a stack was skipped during redeploy. ### Method GET ### Endpoint $fake->assertSkipped($stack) ### Parameters #### Path Parameters - **stack** (string) - Required - The name of the stack. ### Response #### Success Response (200) - **result** (boolean) - True if assertion passes. #### Response Example ``` true ``` ``` -------------------------------- ### Configure Nutgram for local API Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/telegram-bot-api.md Updates config/nutgram.php to point to the local API URL and disable HTTP/2. ```php 'config' => [ 'api_url' => env('TELEGRAM_BOT_API_URL', 'http://127.0.0.1:8081'), 'enable_http2' => false, ], ``` -------------------------------- ### $fake->shouldFail($stack) Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Makes the next redeploy for a stack report as failed. ```APIDOC ## [POST] /compose/fake/shouldFail/{stack} ### Description Makes the next redeploy for a stack report as failed. ### Method POST ### Endpoint $fake->shouldFail($stack) ### Parameters #### Path Parameters - **stack** (string) - Required - The name of the stack. ### Response #### Success Response (200) - **message** (string) - Confirmation. #### Response Example ``` { "message": "Next redeploy will fail" } ``` ``` -------------------------------- ### Prefixed Compose File for Shared Host Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/compose-files.md Prefixes both the project and container name with the app name to avoid conflicts when multiple apps share a Docker host. The `compose:make` command writes names in this form using the app's `APP_NAME`. ```yaml name: shop-meilisearch services: meilisearch: container_name: shop-meilisearch ``` -------------------------------- ### Explicitly register stack classes in config/compose.php Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/discovery.md Use this to register stacks that live outside discovery paths or to avoid scanning. ```php 'stacks' => [ App\Docker\Meilisearch\MeilisearchStack::class, ], ``` -------------------------------- ### Generate a master key Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/meilisearch.md Command to generate a random 32-byte hex string for the Meilisearch master key. ```bash php -r "echo bin2hex(random_bytes(32)), PHP_EOL;" ``` -------------------------------- ### Read the stack registry Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/discovery.md Methods to retrieve or check for stacks by name. ```php Compose::stacks(); // array, keyed by name Compose::stack('meili'); // throws ComposeException for an unknown name Compose::has('meili'); ``` -------------------------------- ### MeilisearchStack class Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/meilisearch.md Defines the Meilisearch stack class that configures environment variables, enables the container based on config, and sets a wait time of 60 seconds. ```php */ public function environment(): array { return [ 'MEILISEARCH_KEY' => (string) Config::get('scout.meilisearch.key'), 'MEILISEARCH_PORT' => (int) (parse_url((string) Config::get('scout.meilisearch.host'), PHP_URL_PORT) ?: 7700), ]; } public function enabled(): bool { return (bool) Config::get('services.meilisearch.manage_container', false); } public function wait(): ?int { return 60; } } ``` -------------------------------- ### php artisan compose:down {stack} --volumes --force Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Stops a stack, optionally removing volumes, with a confirmation prompt unless forced. ```APIDOC ## [POST] /compose:down/{stack} ### Description Stops a stack, optionally removing volumes, with a confirmation prompt unless forced. ### Method POST ### Endpoint php artisan compose:down {stack} ### Parameters #### Path Parameters - **stack** (string) - Required - The name of the stack. #### Query Parameters - **--volumes** (boolean) - Optional - Remove volumes. - **--force** (boolean) - Optional - Skip confirmation prompt. ### Response #### Success Response (200) - **message** (string) - Confirmation of stack down. #### Response Example ``` [message] ``` ``` -------------------------------- ### Compose::stack($stack)->logs(tail: 50) Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Retrieves logs for a stack with a specified tail count. ```APIDOC ## [GET] /compose/stack/{stack}/logs ### Description Retrieves logs for a stack with a specified tail count. ### Method GET ### Endpoint Compose::stack($stack)->logs(tail: 50) ### Parameters #### Path Parameters - **stack** (string) - Required - The name of the stack. #### Query Parameters - **tail** (integer) - Optional - Number of lines to retrieve (default 50). ### Response #### Success Response (200) - **logs** (string) - The log output. #### Response Example ``` [log output] ``` ``` -------------------------------- ### Compose::redeploy() Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Triggers a redeploy of all stacks. ```APIDOC ## [POST] /compose/redeploy ### Description Triggers a redeploy of all stacks. ### Method POST ### Endpoint Compose::redeploy() ### Parameters None ### Response #### Success Response (200) - **message** (string) - Confirmation of redeploy. #### Response Example ``` { "message": "Redeploy triggered" } ``` ``` -------------------------------- ### Set remote Docker host via COMPOSE_DOCKER_HOST Source: https://github.com/mozex/laravel-compose/blob/main/docs/deploying/remote-daemons.md Set the global Docker host in .env to a remote daemon. Accepts ssh://, tcp://, or unix:// URLs. For SSH, the deploy user needs a key accepted by the remote user and must be in the remote docker group. ```plaintext COMPOSE_DOCKER_HOST=ssh://deploy@docker-box ``` -------------------------------- ### Create TelegramBotApiStack class Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/telegram-bot-api.md Defines the stack class for managing the Telegram Bot API container, saved as app/Docker/TelegramBotApi/TelegramBotApiStack.php. ```php */ public function environment(): array { return [ 'TELEGRAM_API_ID' => (string) Config::get('services.telegram.api_id'), 'TELEGRAM_API_HASH' => (string) Config::get('services.telegram.api_hash'), 'TELEGRAM_API_PORT' => (int) (parse_url((string) Config::get('services.telegram.api_url'), PHP_URL_PORT) ?: 8081), ]; } public function enabled(): bool { return (bool) Config::get('services.telegram.manage_container', false); } public function wait(): ?int { return 60; } } ``` -------------------------------- ### Stop and remove stacks via CLI Source: https://github.com/mozex/laravel-compose/blob/main/docs/operating/status-logs-down.md Commands to stop and remove containers. Use --volumes to remove associated named volumes, and --force to skip confirmation prompts. ```bash php artisan compose:down # stop and remove every enabled stack's containers php artisan compose:down meilisearch php artisan compose:down meilisearch --volumes ``` -------------------------------- ### Basic Compose File with Project and Container Name Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/compose-files.md Sets the stack name via `name:` and the container name via `container_name:`. Without a fixed container name, Compose generates one per project, which can cause port conflicts with stale containers. Both names are global on the Docker host. ```yaml name: meilisearch services: meilisearch: image: getmeili/meilisearch:v1.16 container_name: meilisearch ``` -------------------------------- ### Define storage path in stack class Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/telegram-bot-api.md Set the TELEGRAM_STORAGE path in your stack class to ensure the bot's storage directory persists across releases. ```php 'TELEGRAM_STORAGE' => storage_path('app/telegram-bot-api'), ``` -------------------------------- ### php artisan compose:status Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Displays a table per container and exits with code 1 when an enabled stack is not running. ```APIDOC ## [GET] /compose:status ### Description Displays a table per container and exits with code 1 when an enabled stack is not running. ### Method GET ### Endpoint php artisan compose:status ### Parameters None ### Response #### Success Response (200) - **table** (string) - Table per container. #### Error Response (1) - **message** (string) - Indicates an enabled stack is not running. #### Response Example ``` [table output] ``` ``` -------------------------------- ### Log out bot from cloud API Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/telegram-bot-api.md Execute this command to log the bot out of the cloud API before connecting to a local server. Note that switching back to the cloud API is blocked for ten minutes after logout. ```bash curl -s "https://api.telegram.org/bot/logOut" ``` -------------------------------- ### Compose::stack($stack)->down() Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Stops the stack. ```APIDOC ## [POST] /compose/stack/{stack}/down ### Description Stops the stack. ### Method POST ### Endpoint Compose::stack($stack)->down() ### Parameters #### Path Parameters - **stack** (string) - Required - The name of the stack. ### Response #### Success Response (200) - **message** (string) - Confirmation of stack down. #### Response Example ``` [message] ``` ``` -------------------------------- ### $fake->assertRedeployed($stack) Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Asserts that a stack was redeployed. ```APIDOC ## [GET] /compose/fake/assertRedeployed/{stack} ### Description Asserts that a stack was redeployed. ### Method GET ### Endpoint $fake->assertRedeployed($stack) ### Parameters #### Path Parameters - **stack** (string) - Required - The name of the stack. ### Response #### Success Response (200) - **result** (boolean) - True if assertion passes. #### Response Example ``` true ``` ``` -------------------------------- ### Compose::stack($stack)->exec($container, $command) Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Executes a command inside a container of the stack for maintenance purposes. ```APIDOC ## [POST] /compose/stack/{stack}/exec ### Description Executes a command inside a container of the stack for maintenance purposes. ### Method POST ### Endpoint Compose::stack($stack)->exec($container, $command) ### Parameters #### Path Parameters - **stack** (string) - Required - The name of the stack. #### Request Body - **container** (string) - Required - The container name. - **command** (array) - Required - The command and arguments to execute. ### Request Example ``` { "container": "meilisearch", "command": ["ls", "/meili_data"] } ``` ### Response #### Success Response (200) - **output** (string) - The command output. #### Response Example ``` [command output] ``` ``` -------------------------------- ### Check stack status via CLI Source: https://github.com/mozex/laravel-compose/blob/main/docs/operating/status-logs-down.md Use these commands to view the status of all stacks or a specific stack. The exit code is 0 if all enabled stacks are running, and 1 if any container is stopped or missing. ```bash php artisan compose:status php artisan compose:status meilisearch ``` ```text +-------------+-------------+-------------+---------+---------+---------------------------+ | Stack | Service | Container | State | Health | Ports | +-------------+-------------+-------------+---------+---------+---------------------------+ | meilisearch | meilisearch | meilisearch | running | healthy | 127.0.0.1:7700->7700/tcp | | rdp-gateway | init | ...-init | exited | - | - | | rdp-gateway | guacd | ...-guacd | running | - | - | | mailpit | - | - | disabled| - | - | +-------------+-------------+-------------+---------+---------+---------------------------+ ``` -------------------------------- ### Meilisearch Docker Compose Configuration Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Defines a Meilisearch service with a named volume, healthcheck, and loopback port binding. Requires MEILISEARCH_PORT and MEILISEARCH_KEY environment variables. Use container_name for the stale-container sweep and prefer named volumes over bind mounts. ```yaml name: meilisearch services: meilisearch: image: getmeili/meilisearch:v1.16 container_name: meilisearch # required for the stale-container sweep restart: unless-stopped ports: - '127.0.0.1:${MEILISEARCH_PORT:-7700}:7700' # loopback: Docker bypasses UFW environment: MEILI_MASTER_KEY: ${MEILISEARCH_KEY} healthcheck: test: ["CMD", "wget", "--no-verbose", "--spider", "http://127.0.0.1:7700/health"] interval: 30s volumes: - 'meilisearch-data:/meili_data' # named volume, not a bind mount logging: driver: json-file options: { max-size: 50m, max-file: '3' } volumes: meilisearch-data: ``` -------------------------------- ### Compose::stack($stack)->status() Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Returns the status of a stack, including container information. ```APIDOC ## [GET] /compose/stack/{stack}/status ### Description Returns the status of a stack, including container information. ### Method GET ### Endpoint Compose::stack($stack)->status() ### Parameters #### Path Parameters - **stack** (string) - Required - The name of the stack. ### Response #### Success Response (200) - **containers** (array) - List of containers. #### Response Example ``` { "containers": [] } ``` ``` -------------------------------- ### Run compose:doctor to check remote daemon connection Source: https://github.com/mozex/laravel-compose/blob/main/docs/deploying/remote-daemons.md Checks the remote daemon connection and prints its version and the address reached. Errors like wrong keys or missing docker group membership appear here with the reason Docker gave. ```bash php artisan compose:doctor ``` -------------------------------- ### Check stack status with compose:redeploy --dry-run Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Run this command to see if the stack is listed and skipped during redeploy. A skipped stack indicates that enabled() or COMPOSE_ENABLED is off on this host. ```bash php artisan compose:redeploy --dry-run ``` -------------------------------- ### Check and redeploy stack with compose:doctor and compose:redeploy Source: https://github.com/mozex/laravel-compose/blob/main/README.md Check the result and bring the stack up. Add php artisan compose:redeploy to your deploy script before any step that talks to the container. ```bash php artisan compose:doctor ``` ```bash php artisan compose:redeploy ``` -------------------------------- ### Validate stack consistency in tests Source: https://github.com/mozex/laravel-compose/blob/main/docs/deploying/doctor.md Use the Compose facade in a test suite to validate that stacks remain consistent with their compose files. ```php use Mozex\Compose\Facades\Compose; it('keeps every stack consistent with its compose file', function (): void { $report = Compose::validate(withDaemon: false); expect($report->isClean())->toBeTrue(implode("\n", $report->lines())); }); ``` -------------------------------- ### Docker Compose configuration for Telegram Bot API Source: https://github.com/mozex/laravel-compose/blob/main/docs/recipes/telegram-bot-api.md Save this configuration as app/Docker/TelegramBotApi/docker-compose.yml. It requires TELEGRAM_API_ID and TELEGRAM_API_HASH credentials from my.telegram.org. ```yaml name: telegram-bot-api services: telegram-bot-api: image: aiogram/telegram-bot-api:10.3 container_name: ${COMPOSE_PROJECT_NAME} restart: unless-stopped ports: - '127.0.0.1:${TELEGRAM_API_PORT:-8081}:8081' environment: TELEGRAM_API_ID: ${TELEGRAM_API_ID} TELEGRAM_API_HASH: ${TELEGRAM_API_HASH} TELEGRAM_STAT: 1 healthcheck: test: ["CMD", "wget", "--no-verbose", "--spider", "http://127.0.0.1:8082/"] interval: 30s timeout: 5s retries: 3 start_period: 10s volumes: - 'telegram-bot-api-data:/var/lib/telegram-bot-api' logging: driver: json-file options: max-size: 50m max-file: '3' volumes: telegram-bot-api-data: driver: local ``` -------------------------------- ### Custom Stack class overriding defaults Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Defines a MeilisearchStack extending the Mozex\Compose\Stack class. Override environment() to set MEILISEARCH_KEY and MEILISEARCH_PORT from config, enabled() to control whether the stack is used, and other methods to customize compose behavior. The environment() method must include every ${VAR} the compose file consumes without a default. The env file always wins over the shell, and values may be scalars, null, backed enums, or Stringable, but not arrays or line breaks. ```php namespace App\Docker\Meilisearch; use Illuminate\Support\Facades\Config; use Mozex\Compose\Stack; class MeilisearchStack extends Stack { // Written to the stack's .env before every redeploy. Read config, never env() directly. public function environment(): array { return [ 'MEILISEARCH_KEY' => Config::get('scout.meilisearch.key'), 'MEILISEARCH_PORT' => parse_url(Config::get('scout.meilisearch.host'), PHP_URL_PORT) ?: 7700, ]; } // False on hosts without Docker, CI, and machines using a native service. Redeploy skips the stack. public function enabled(): bool { return (bool) Config::get('services.meilisearch.manage_container', false); } public function profiles(): array { return []; } // compose profiles to activate, e.g. ['tls'] public function wait(): ?int { return 60; } // up --wait --wait-timeout 60; null = don't wait public function build(): bool { return false; } // compose build --pull first, for build: sections public function pull(): bool { return true; } // compose pull before the sweep (keeps floating tags fresh) public function host(): ?string { return null; } // DOCKER_HOST override for a remote daemon public function linkPath(): ?string { return null; } // null = {link_directory}/{name, dashes as underscores}; '' = no link } ``` -------------------------------- ### Run doctor command Source: https://github.com/mozex/laravel-compose/blob/main/docs/deploying/doctor.md Execute the doctor command to perform preflight checks, with an optional flag to skip Docker-dependent checks. ```bash php artisan compose:doctor php artisan compose:doctor --no-daemon # skip everything that needs docker ``` -------------------------------- ### Architecture test for stack validation Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Use this expectation in an architecture test to ensure every project with stacks passes validation without the daemon. ```php expect(Compose::validate(withDaemon: false)->isClean())->toBeTrue(); ``` -------------------------------- ### Add Meilisearch healthcheck Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/compose-files.md Defines a healthcheck using wget to probe the /health endpoint. The probe is read by wait(), compose:status, and the laravel-health check. Use 127.0.0.1 instead of localhost to avoid IPv6 resolution issues. ```yaml healthcheck: test: ["CMD", "wget", "--no-verbose", "--spider", "http://127.0.0.1:7700/health"] interval: 30s timeout: 5s retries: 3 start_period: 10s ``` -------------------------------- ### Compose::validate(withDaemon: false) Source: https://github.com/mozex/laravel-compose/blob/main/resources/boost/skills/laravel-compose/SKILL.md Validates the Compose configuration, optionally without the daemon, and returns a result with isClean(). ```APIDOC ## [GET] /compose/validate ### Description Validates the Compose configuration, optionally without the daemon, and returns a result with isClean(). ### Method GET ### Endpoint Compose::validate(withDaemon: false) ### Parameters #### Query Parameters - **withDaemon** (boolean) - Optional - Whether to include daemon validation (default true). ### Response #### Success Response (200) - **isClean** (boolean) - True if validation passes. #### Response Example ``` true ``` ``` -------------------------------- ### Use named volumes for persistence Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/compose-files.md Define a named volume for Meilisearch data to survive redeploys and avoid coupling to a specific release directory. ```yaml volumes: - 'meilisearch-data:/meili_data' volumes: meilisearch-data: driver: local ``` -------------------------------- ### Set ulimits for file descriptor limits Source: https://github.com/mozex/laravel-compose/blob/main/docs/stacks/compose-files.md Sets nofile soft and hard limits to 65535 for a service. Containers inherit the daemon's file-descriptor limit, which may be low for workloads like a search engine rebuilding an index. This configuration is applied on redeploy. ```yaml ulimits: nofile: soft: 65535 hard: 65535 ```