Skip to main content
Version: v1

Architecture

This page explains how the Vortex template fits together, for developers and leads who want the big picture before they start a project or while they evaluate the template. It covers the design principles, the lifecycle your code follows from your machine to production and the parts that handle each stage. Each section links to the page that covers its part in depth.

Design principles​

Vortex follows these principles:

  • Simple is better than complex: The template encourages clarity, even in customizations.
  • Use standard tools: Wherever possible, Vortex follows upstream conventions and avoids reinvention.
  • Avoid silent errors: A script that detects a misconfiguration stops with an error. A script missing a required value names the variable.
  • Readability counts: Code and configuration are meant to be understood.
  • Explicit logging helps: Scripts log every major step, so you can follow what's going on.

Code lifecycle​

Vortex runs your code through the same lifecycle locally, in CI and in hosting, with the same scripts at every stage. That reduces the chance of an error that appears in 1 environment and nowhere else.

The following diagram covers the whole system. The sections after it cover each stage:

Local Development
═════════════════════════════════════════════════════════════════════════════════════════
Developer writes code ──► Build and test locally ──► Commit changes
│
▼
Git Repository
═════════════════════════════════════════════════════════════════════════════════════════
Push to remote branch ──► Open/Update Pull Request
│
▼
┌─ CI Pipeline ────────────────────────────────────────────────────────────────────────────┐
│ │
│ ┌─ Database Job (Nightly) ───────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Scheduled ──► Download production ──► Import and export ──► Store database cache │ │
│ │ trigger database to validate the dump │ │
│ │ │ │
│ └─────────────────────────────────────┬──────────────────────────────────────────────┘ │
│ │ Provides cached database │
│ ▼ │
│ ┌─ Lint Job ────────────┐ ┌─ Database Job ────────────────┐ ┌─ Audit Job ──────────┐ │
│ │ │ │ ◆ Nightly cache exists? │ │ Composer audit │ │
│ │ Composer validate │ │ Yes ──► job succeeds │ │ (advisories) │ │
│ │ ▼ │ │ No ──► download, validate, │ │ ▼ │ │
│ │ Hadolint │ │ store cache │ │ npm audit │ │
│ │ ▼ │ └───────────────┬───────────────┘ │ (advisories) │ │
│ │ DCLint │ ▼ │ ▼ │ │
│ │ ▼ │ ┌─ Build Job ───────────────────┐ │ Gitleaks │ │
│ │ Build CLI container │ │ Code assembly │ │ (committed secrets) │ │
│ │ ▼ │ │ Docker, Composer deps, │ │ │ │
│ │ Composer normalize │ │ NPM deps, assets │ │ │ │
│ │ ▼ │ │ ▼ │ │ │ │
│ │ PHPCS │ │ Website setup │ │ │ │
│ │ ▼ │ │ Import cached DB, drush │ │ │ │
│ │ PHPStan │ │ deploy, custom scripts │ │ │ │
│ │ ▼ │ │ ▼ │ │ │ │
│ │ Rector │ │ Testing │ │ │ │
│ │ ▼ │ │ Jest ──► PHPUnit ──► Behat │ │ │ │
│ │ Twig CS Fixer │ └───────────────┬───────────────┘ │ │ │
│ │ ▼ │ │ │ │ │
│ │ Gherkin Lint │ │ │ │ │
│ │ ▼ │ │ │ │ │
│ │ ESLint / Stylelint │ │ │ │ │
│ │ │ │ │ │ │
│ └──────────┬────────────┘ │ │ │ │
│ │ │ │ │ │
│ ▼ ▼ │ │ │
│ ┌─ Deployment Job ─────────────────────────────────────────┐ │ │ │
│ │ │ │ │ │
│ │ Webhook Artifact Lagoon │ │ Does not gate │ │
│ │ Call URL Package artifact Run Lagoon CLI deploy │ │ deployment │ │
│ │ │ │ │ │
│ └──────────────────────────────────────────────────────────┘ └──────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────────────────┘
│
▼
Hosting Platform
═════════════════════════════════════════════════════════════════════════════════════════
◆ Environment ──No──► Sync DB from production ───┐
exists? │
│ Yes ▼
└──────────────────────────────────► drush deploy ──► Custom scripts ──► Notifications


Available Environments
═════════════════════════════════════════════════════════════════════════════════════════
┊ PR Environment ┊ Dev Staging Production
┊ (auto-removed) ┊ develop branch main branch production branch or tag

Local development environment​

Your project runs locally in containers. Docker Compose starts a stack built from the Lagoon container images, which Lagoon runs in production and CI runs too, so your local environment matches CI and Lagoon hosting.

Ahoy wraps multi-step tasks like provisioning, testing and database imports in short commands such as ahoy provision and ahoy test.

Vortex supports Docker Compose as its only local environment. The roadmap lists DDEV and Lando support as a goal.

➡️ See Development > Environment

Automation scripts​

Vortex automates its common tasks with Bash scripts from the drevops/vortex-tooling Composer package, installed to vendor/drevops/vortex-tooling/src/.

The scripts share these traits:

  • They run identically across local, CI and hosting environments.
  • They read environment variables to adapt their behavior.
  • They're modular and extensible.

The scripts are a Composer dependency of your project. Your project's composer.json requires drevops/vortex-tooling with a tilde constraint, ~1.5.0 in the shipped template. The constraint accepts patch releases and holds the minor version, so a new minor release reaches your deployments only after the constraint is raised. A Vortex release that changes the scripts raises it, and ahoy update-vortex brings that change into your composer.json (see Updating Vortex).

The entry-point scripts install as Composer binaries at vendor/bin/vortex-<script>, for example vendor/bin/vortex-provision or vendor/bin/vortex-deploy. The Ahoy commands wrap those binaries. The scripts that the binaries hand work to, such as the script for each deployment type, stay inside the package. Ahoy and CI install the package through scripts/vortex-tooling.sh before the full composer install runs, so the binaries are there from the first command.

The package's GitHub repository is a read-only mirror of the .vortex/tooling/ directory in the Vortex repository. Report bugs and propose changes in the Vortex issue queue.

Never edit the files under vendor/drevops/vortex-tooling/src/, because the next composer update discards your change. Adapt behavior through environment variables, and put project logic in your own scripts under scripts/. vortex-provision discovers and runs every scripts/provision-*.sh file in alphabetical order. Use a cweagans/composer-patches patch only when a shipped script itself has to change.

➡️ See Development > Composer > Vortex tooling package for updating the package and Development > Provision > Running custom scripts for extending provisioning.

Customize scripts​

All scripts read their configuration from environment variables, so you can adapt them to a project or an environment.

During setup, the installer writes your project's values into .env, such as the project machine name and the notification email addresses. Secrets, tokens and per-environment values go into your CI or hosting environment. Local overrides go into .env.local, which Git ignores.

➡️ See Development > Variables

Router scripts​

Vortex has 6 router scripts: entry points that read your configuration and hand the work to the script for your setup. Ahoy and CI call the same router on every setup. Each router picks its script as follows:

  • vortex-fetch-db fetches a database from the source in VORTEX_FETCH_DB_SOURCE: url (the default), ftp, s3, container_registry, acquia or lagoon.
  • vortex-export-db exports the database to a dump file, or to a container image when VORTEX_DB_IMAGE is set.
  • vortex-import-db imports a dump file, and runs the import inside the cli container when you call it from the host.
  • vortex-deploy runs each deployment type listed in VORTEX_DEPLOY_TYPES (artifact, lagoon or webhook), so the same call deploys to Acquia, Lagoon or any host with a deployment webhook.
  • vortex-notify sends a notification to each channel listed in VORTEX_NOTIFY_CHANNELS: email, Slack, New Relic, GitHub, Jira, a webhook or Diffy.
  • vortex-task runs a hosting operation (copy-db, copy-files, purge-cache or custom) with the script for the platform in VORTEX_TASK_PLATFORM: acquia or lagoon. That variable falls back to VORTEX_PLATFORM.
Script architecture diagram
Diagram of scriptsDiagram of scripts

Drupal management​

Provisioning​

Provisioning is central to how Vortex works. A single script, vortex-provision (ahoy provision locally), replaces a series of manual Drush commands and handles the following:

  • Importing a database dump, or installing Drupal from a profile
  • Running updates, config imports, cache rebuilds and deploy hooks
  • Sanitizing a freshly imported database
  • Running your custom scripts/provision-*.sh scripts

Because provisioning is centralized, it runs the same way locally, in CI and in hosting.

You can also add automation around provisioning, such as running migrations conditionally or creating demo content.

➡️ See Development > Provision

Settings management​

Vortex organizes Drupal settings per environment:

  • The provider settings files in web/sites/default/includes/providers/ detect the environment type: local, ci, dev, stage or prod. The ENVIRONMENT_TYPE variable overrides the detected type. Locally, set it in .env.local and run ahoy up. In hosting, set it in the environment's variables.
  • Each module's settings live in their own file in web/sites/default/includes/modules/, with the per-environment logic inside that file.

Keeping each module's settings in its own file avoids config sprawl and lets you remove a module's settings cleanly when you no longer need them.

PHPUnit tests in tests/phpunit/Drupal/ check that these settings load correctly in each environment.

➡️ See Development > Settings

Module and theme scaffolds​

Vortex includes an example custom module and theme, each with tests. Together, they show the following practices:

  • Structuring custom features
  • Writing functional, kernel and unit tests
  • Connecting theme assets to a build pipeline

Use these scaffolds as starting points for your own work.

➡️ See Development > Modules > Module scaffold and Development > Themes

Code quality and testing​

Vortex ships with pre-configured tools for maintaining code quality:

  • PHP CodeSniffer (PHPCS)
  • PHPStan
  • Rector
  • Twig CS Fixer
  • ESLint
  • Stylelint
  • Gherkin Lint
  • Hadolint
  • DCLint
  • SDC Devel

Vortex also ships scaffolds for these test frameworks:

  • PHPUnit: Unit, kernel and functional testing
  • Behat: Behavior-driven testing with screenshot capture and extra steps
  • Jest: JavaScript unit testing

➡️ See Development > Code quality and Development > Testing

Automated dependency updates​

Vortex includes configuration for Renovate to automate dependency upgrades:

  • Drupal core minor and patch updates are checked daily with no waiting period, so core security releases arrive on the next run
  • Container images, GitHub Actions and the CI tools are checked daily
  • The other PHP and JavaScript packages are checked weekly, as is the Renovate image that CircleCI runs
  • Most new releases wait 14 days before they're proposed, so a registry can pull a compromised release first
  • Major versions of PHP and JavaScript packages are left for you to upgrade by hand
  • The PHP, Node.js and npm versions are left unchanged
  • The packages in any package.json below the project root, such as the theme's, are left unchanged
  • PRs include changelogs, run through your continuous integration pipeline and can merge automatically after it passes

Renovate runs as the hosted GitHub app or self-hosted in your CI, and the installer asks which. The schedules live in renovate.json, so you can tweak them.

➡️ See Development > Dependency updates

Environment variables​

Vortex relies on environment variables to configure its behavior across local, CI and hosting environments. Define them in the .env file, or set them in your CI and hosting environments, which is where secrets belong.

➡️ See Variables

Continuous integration workflows​

Vortex supports GitHub Actions and CircleCI, and the installer asks which one your project uses. Both pipelines include the following:

  • Database fetching and caching, for faster builds
  • Full site provisioning
  • Code quality checks
  • Unit, functional and behavior tests
  • Deployment after the tests pass
  • Security audits of Composer and npm packages and a Gitleaks secret scan, in a workflow of their own

Each continuous integration configuration runs the same steps as local development and hosting.

➡️ See Continuous integration

Hosting integrations​

Vortex has built-in support for Acquia and Lagoon hosting. These integrations do the following:

  • Trigger provisioning with the same steps used locally and in CI
  • Provide deployment pipelines suited to each platform

Other platforms work through the artifact and webhook deployment types.

➡️ See Hosting

Documentation & onboarding​

Besides this documentation site, Vortex adds a docs/ scaffold to your repository for project-specific decisions, unless you answer No at the installer's Preserve project documentation? prompt. The scaffold has a page for each of these topics:

  • Testing conventions
  • CI, when the project has a CI provider
  • Deployment, when the project has a deployment type
  • Releasing
  • FAQs

The README.md that Vortex writes for your project includes local setup steps for new team members.

Template tests​

We test the template and its automation scripts at 3 levels:

  • Unit tests: Bats tests run each shell script in isolation, with external commands mocked
  • End-to-end tests: PHPUnit tests run full build pipelines in real Docker containers
  • Real-world validation: The DrevOps website is a production reference site that receives regular upstream updates

➡️ See Contributing > Maintenance > Template