Status: Draft
Updated: 2026-06-05 Owner: Core
Purpose: Draft for script-based setup, initialization, test configuration, and automation-friendly review flows.
- Defines how local, test, and automation environments should be initialized.
- Covers base configuration for
env:test, PHPUnit, review automation, and reusable helper scripts. - Supports reliable contributor and coding-agent workflows.
- Establishes repeatable setup and verification commands that fit this repository's Symfony 8 structure.
- Keeps local and automation flows close enough that failures are reproducible.
Setup and test automation should make the project easy to clone, verify, and review without relying on hidden local state. The repository should prefer Symfony and Composer commands, release-safe bin/ entry points, small .codex/ helper scripts for agent workflows, and documented environment defaults over ad-hoc shell knowledge.
The local development flow should support humans and coding agents. Required commands should be discoverable from AGENTS.md, .codex/README.md, and the relevant draft. Optional helper scripts may wrap repeated commands, but they should not hide important Symfony behavior. Files in .codex/ are repository working aids and must not be required by release packages.
Setup should be split into two callable flows. bin/init should verify dependencies and repair safe missing setup pieces where possible, for example missing Composer packages, importmap assets, or the Tailwind binary. If the system Composer command is unavailable or fails because Composer is missing, bin/init may use the bundled bin/composer fallback. bin/setup should orchestrate first-run configuration and may call bin/init before asking for mandatory installation data such as database settings, admin login, site name, and site URL. The same setup workflow should be usable from CLI and from a dedicated web setup environment.
The test environment should be deterministic. It should use env:test, SQLite by default, explicit fixtures, isolated storage paths, and predictable database setup. Automation should be able to run targeted checks for small changes and broader checks before releases or high-risk merges. PHPUnit bootstrap owns test database setup directly: it clears var/test, applies migrations, and seeds deterministic demo data without requiring bin/setup.
- Keep Composer as the dependency installation entry point.
- Keep Symfony Console commands as the main operational interface.
- Use
.env.testfor PHPUnit defaults and avoid local-only values in committed configuration. - Prefer SQLite for fast isolated tests unless a feature needs database-specific behavior.
- Store release-relevant setup and initialization entry points in
bin/. - Store reusable agent/helper scripts in
.codex/and document them in.codex/README.md. - Exclude
.codex/from release packages unless a later release draft explicitly includes selected files. - Keep helper scripts small, named by purpose, and safe to run repeatedly.
- Provide
bin/initas the dependency and environment verification entry point. - Provide
bin/setupas the first-run configuration entry point. Keep repository initialization inbin/init; setup should assume dependencies are available and focus on application configuration. - Make setup callable from CLI and from a dedicated web setup environment.
- Collect mandatory configuration during setup, including installer language, database settings, admin login, site name, and site URL.
- Preconfigure test environments so code review automation and PHPUnit can run without interactive input.
- Let
bin/inituse the bundledbin/composerfallback when the system Composer command is missing or unusable. - Keep
bin/composeras a compatibility fallback and avoid requiring it when system Composer works. - Let
bin/initbootstrap Composer packages withcomposer install --no-dev --no-scripts --optimize-autoloader, then resolveAPP_ENV, and run a final optimized Composer install with development dependencies only fordevandtest. - Let
bin/initresolveAPP_ENVthrough Symfony'sDotenv::bootEnv()after Composer packages are installed so automation uses the same environment fallback behavior asbin/console. - Let
bin/initrely on Composer auto-scripts forassets:install,importmap:install, andtailwind:buildinstead of running those commands again. - Let
bin/initcompile the AssetMapper only forprod; skip AssetMapper compilation fordevandtest. - Use SQLite for the default
env:testdatabase unless a feature needs database-specific behavior. - Let the PHPUnit bootstrap apply migrations and seed deterministic demo data for
env:testwithout requiringbin/setup. - Keep the first seed strategy explicit and small in
tests/Support, then revisit fixture builders or dedicated fixture tooling once content entities and schemas are stable. - Use
php bin/phpunitfor the full PHPUnit suite and targeted PHPUnit commands during development. - Use
php bin/console lint:containerfor service wiring and configuration changes. - Use
.codex/compare_translations.phpfor translation-key drift. - Use
php bin/console render:route /<route>for Twig and translation review. - Use
php bin/console tailwind:buildwhen frontend CSS changes; keepasset-map:compileproduction-only. - Run
php bin/console assets:rebuildwhen package changes affect templates, CSS, JavaScript, imported assets, or Tailwind class usage. - Keep local frontend watchers optional for development convenience; release/admin workflows should use explicit build commands.
- Provide setup or reset commands only when they are deterministic and environment-aware.
- Avoid scripts that mutate production-like data unless they require explicit confirmation.
- Keep automation output concise and useful for review comments, CI logs, and agent summaries.
- Provide a release-readiness verification path once implementation begins, covering setup, migrations, tests, translations, container linting, asset builds, route rendering smoke checks, and backup/restore smoke checks where practical.
- Test setup helpers with a clean or reset test environment.
- Test
bin/initwith missing dependencies, complete dependencies, missing importmap assets, and missing Tailwind binary scenarios. - Test
bin/initfalls back tobin/composerwhen system Composer is unavailable. - Test
env:testbootstrap applies migrations and imports deterministic demo data. - Test CLI and web setup paths share validation and configuration behavior.
- Run targeted PHPUnit coverage while developing a feature, then broader suites before release or high-risk merges.
- Run
lint:containerafter adding commands, services, subscribers, handlers, voters, validators, or configuration. - Verify helper scripts have clear failure output and non-zero exit codes on failure.
- Test automation should cover the command order for package asset rebuilds once lifecycle commands exist.
- Test or manually verify the release-readiness path before public releases.
- Update
.codex/README.mdwhenever helper scripts are added, renamed, or removed.
- Decision recorded: Keep
.codex/as the repository-owned automation and agent helper area, but do not require it in release packages. - Decision recorded: Provide release-relevant setup through
bin/setup, while keeping dependency and repository initialization inbin/init. - Decision recorded: Provide
bin/initas a dependency and environment check that verifies Composer packages, importmap assets, Tailwind binary availability, and similar setup prerequisites, and may attempt safe auto-repair such as running Composer install when packages are missing. - Decision recorded: Make the setup workflow callable from CLI and from a dedicated web setup environment, sharing validation and configuration behavior.
- Decision recorded: The web setup wizard must remain database-free until the final apply step starts the shared setup runner. Wizard rendering, preflight checks, form-state persistence, step gating, and error routing must not require Doctrine DBAL/ORM connections.
- Decision recorded: Web setup state is preserved across steps so users can move back to completed steps and change language, site metadata, database settings, or admin data before applying setup. Steps unlock only after their required values pass local validation; final execution still revalidates through the shared setup input and runner.
- Decision recorded: Web setup preflight should check writable runtime/config paths, PHP requirements, and whether the web server document root points at
public/; it should offer explicit auto-heal for missing writable files/directories and show concise operator instructions only when a check cannot be repaired automatically. - Decision recorded: The database step should present driver-aware fields with native browser validation where possible. SQLite keeps the project-local default and warns that changing the URL is advanced; the selected driver must match any explicit database URL scheme in the web wizard and CLI so inherited or mismatched server URLs cannot be applied under a different selected driver. MySQL/MariaDB and PostgreSQL expose host, port, database, user, password, an explicit connection test, and optional table prefix fields.
- Decision recorded:
APP_DATABASE_PREFIXis an optional setup/env key for installations that need table prefixes. The web setup defaults to the effectivestudio_prefix, appends a trailing underscore for non-empty submitted prefixes, and centralizes prefix handling through the Doctrine connection wrapper, ORM metadata listener, and migration object naming so DBAL helpers, raw DBAL SQL, migrations, setup seeding, Messenger, and repositories share the same known table prefix behavior without colliding in shared schemas. - Decision recorded: Site-information setup fields should be modular and shared by web and CLI setup where practical. Initial setup may expose selected seed-backed settings such as registration mode, username-change availability, and access-statistics policy without requiring the database-backed admin settings form layer.
- Implemented baseline: CLI and web setup share
SetupInputNormalizerfor database driver and URL parsing, database prefix normalization, boolean values, and default admin email derivation, plusSetupInputValidatorfor supported language, default URI, database URL, database prefix, admin credential, and APP_SECRET length checks. Step-scoped web filtering and interactive CLI prompts stay transport-specific adapters around the shared validation rules. - Decision recorded: The setup review page should show only wizard-relevant data and planned operational steps, not the full seed internals from the generic dry-run log.
- Decision recorded: Web setup execution should use the ActionLog/LiveOperation presentation path with one visible operation entry per setup runner step, and failure pages should keep the wizard state so the user can jump back to the relevant step, for example database connection settings after a connection error.
- Decision recorded:
APP_SETUP_COMPLETEDmust only be marked after every setup runner step has succeeded. Dry-runs, failed writes, failed migrations, failed seeding, failed package discovery, or failed asset rebuilds must leave setup unlocked. - Decision deferred: A later setup mode may support connecting to an existing Studio installation instead of creating a new one. That flow must be explicit, distinguish "new installation" from "use existing installation", authenticate with an active OWNER account and the existing installation's
APP_SECRET, avoid mutating seed data during discovery/adoption, and only apply needed migrations after the operator confirms the existing installation context. - Decision recorded: Test environments must be preconfigured so code review automation and PHPUnit can run without user input.
- Decision recorded:
bin/initmay use bundledbin/composerwhen the system Composer command is missing or unusable. - Decision recorded:
bin/initfirst bootstraps optimized production dependencies without Composer scripts, then runs the environment-appropriate optimized Composer install after Symfony's environment has been resolved. - Decision recorded:
bin/initresolvesAPP_ENVwith Symfony'sDotenv::bootEnv()after Composer packages are installed, then uses that resolved environment to decide whetherasset-map:compileshould run. - Decision recorded:
bin/initdoes not explicitly rerunassets:install,importmap:install, ortailwind:buildbecause the Composer auto-scripts already run them during the final Composer install. - Implemented baseline: Added a callable
SetupRunnerplus CLI adapter inbin/setup. The runner accepts setup input for installer language, site title, default URL, database driver/connection data, admin account data, APP_SECRET, and dry-run mode; validates language against discovered translation catalogues; enforces the shared password policy before setup steps can seed credentials; writes.env.{APP_ENV}.local; runscomposer dump-env {APP_ENV}through the system Composer or bundledbin/composerfallback; applies Doctrine migrations; seedssite.title,site.url,localization.default_language, disabledlocalization.route_prefixes_enabled,content.home_path,user.default_acl_group, user-flow defaults including account-link TTL, deleted-user retention, username-change availability, registration mode, notification recipients, enableduser.menu.enabled,user.menu.sort_order, enabled production-default audit logging settings, default persisted ACL groups starting withregisteredlevel 1, and the admin user with account settings/status plus state markers for created/password/status metadata; and returns aWorkflowResultcarrying anActionLogor halt-on-error context. The CLI adapter can collect missing values through translated interactive prompts in TTY contexts, confirms the admin password interactively, while--jsonand--no-interactionkeep automation non-interactive. - Implemented baseline: Setup seed data remains centralized in
SetupDefaultSeed, while DBAL execution is split into config, admin-account, initial-content, and state-marker seed writers behind theSetupDatabaseSeederfacade. Config seed values share the central DB-free config default provider for non-input settings so setup and post-release runtime fallbacks stay aligned. - Implemented baseline:
/setupnow renders a DB-free web form for local setup flows. The form validates web input, supports dry-run submission, and delegates execution to the sameSetupRunnerused bybin/setupinstead of introducing a separate installer path. - Implemented baseline: Setup subprocess execution now supplies local Composer environment fallbacks for web contexts:
COMPOSER_HOMEdefaults tovar/composer-homewhen unset, andHOMEdefaults tovarwhen the server environment omits it. - Implemented baseline: Added
bin/setup --reset-password={username}and--reset-password:{username}recovery support through a callable password reset runner. The CLI displays UID, username, email, and status before changing a password, asks for confirmation and repeated password entry in TTY contexts, and requires--confirmplus--new-passwordfor non-interactive runs. - Decision recorded: The default test environment should use SQLite unless a feature needs database-specific behavior.
- Decision recorded: PHPUnit bootstrap owns
env:testdatabase initialization directly, applying migrations and deterministic demo seeds without requiringbin/setup. Becausevar/test/test.dbis shared per process, the lifecycle must reject concurrent PHPUnit processes instead of allowing parallel runs to race over database setup. - Decision recorded: The first fixture strategy uses an explicit
tests/Supportdatabase seeder after migrations are applied, then can evolve into fixture builders or dedicated fixture tooling once content entities and schemas are stable. - Decision recorded: Package asset rebuild automation runs Tailwind before AssetMapper compilation and clears cache last. Watchers are optional development tooling, not the production/admin lifecycle mechanism.
- Decision recorded: Public releases need a repeatable release-readiness verification path rather than relying on ad-hoc manual checks.
- Decision recorded: Setup runner, preflight checks, wizard flow, and CLI/web input handling should be modularized into shared step, check, flow, and normalization services. The seeder may stay central because preset content should remain easy to review and manage.
- Decision recorded: Setup seeding should stay easy to handle by separating seed execution from seed data where useful. PHP array seed-data files are an acceptable middle ground: DBAL can keep bootstrap reliable, while the data shape becomes easier to inspect and update.
- Decision recorded: Hard setup and preflight requirements block setup because missing requirements can break product behavior. Optional feature requirements should warn clearly and name the affected feature.
- Decision recorded: CLI and web setup paths must share validation, normalization, database URL handling, table-prefix behavior, default URI validation, admin account validation, and error keys wherever practical.