Local Development
Docker services, Make commands, and daily development workflow
Local Development
Docker Services
docker compose up -d
| Service | Container | Access | Purpose |
|---|---|---|---|
| PHP (app) | php | http://localhost | Symfony + FrankenPHP |
| PostgreSQL | database | localhost:5432 | Database |
| Redis | redis | localhost:6379 | Cache + message queue |
| Mailpit | mailer | http://localhost:8025 (UI) / localhost:1025 (SMTP) | Email testing |
Make Commands
| Command | Description |
|---|---|
make test | Run all tests (unit + functional) |
make test-unit | Run unit tests only |
make test-functional | Run functional tests only |
make phpstan | Run PHPStan static analysis |
make csfix | Fix code style with PHP CS Fixer |
make bash | Open a shell in the PHP container |
make stripe-sync-plans | Sync plan config to Stripe |
make dokploy | Access Dokploy deployment menu |
make generate-jwt-keys | Generate JWT key pair |
Database
Run Migrations
docker compose exec php bin/console doctrine:migrations:migrate
Create a New Migration
After modifying an ORM mapping file:
docker compose exec php bin/console doctrine:migrations:diff
Reset Database
docker compose exec php bin/console doctrine:database:drop --force
docker compose exec php bin/console doctrine:database:create
docker compose exec php bin/console doctrine:migrations:migrate --no-interaction
Never use
doctrine:schema:update --force. Always use migrations.
Running Tests
# All tests
make test
# Unit tests only
make test-unit
# Functional tests only
make test-functional
# Single test file
docker compose exec php vendor/bin/phpunit tests/Unit/UserManagement/SignUpHandlerTest.php
# Single test method
docker compose exec php vendor/bin/phpunit --filter testMethodName
Code Quality
# Static analysis
make phpstan
# Code style (auto-fix)
make csfix
Run both before pushing to avoid CI failures.
Viewing Emails
In development, all emails are caught by Mailpit. Open http://localhost:8025 to view sent emails — registration confirmations, password resets, etc.
Console Commands
| Command | Description |
|---|---|
bin/console app:user:promote-admin {email} | Promote a user to admin role |
bin/console app:stripe:sync-plans | Sync plan definitions to Stripe |
bin/console app:stripe:sync-plans --dry-run | Preview sync without making changes |
bin/console app:dokploy | Dokploy deployment helper (JWT mounts, DB) |
bin/console lexik:jwt:generate-keypair | Generate JWT public/private key pair |
bin/console doctrine:migrations:migrate | Run pending migrations |
bin/console doctrine:migrations:diff | Generate migration from mapping changes |
All commands should be run inside the PHP container:
docker compose exec php bin/console <command>
Debugging with Xdebug
Xdebug is pre-installed in the dev image. Configure it via the XDEBUG_MODE environment variable in compose.yaml:
XDEBUG_MODE: debug # Step debugging
XDEBUG_MODE: off # Disabled (default for performance)
XDEBUG_MODE: trace # Function trace
The PHP IDE config is set to serverName=symfony. Configure your IDE's path mappings:
| Local path | Container path |
|---|---|
./ | /app |
API Documentation
The interactive Swagger UI is available at http://localhost/api/doc during development. The raw OpenAPI spec is at http://localhost/api/doc/openapi.yaml.