Skip to content

Development Workflow

How a normal day of development looks at Volāre: start the stack, pick up a task, branch, commit, open a PR and get it deployed. If you have not set up your machine yet, start with Installation.

flowchart LR
  A[ClickUp task] -->|/task-work| B[Branch CU-id_slug]
  B --> C[Code + tests]
  C -->|/commit| D[Commits with Refs: CU-id]
  D -->|/pr-create| E[Pull request]
  E -->|CI + review| F[Merge to master]
  F -->|tag-on-merge + build| G[Images in ECR]
  G -->|infra-volare deploy| H[Staging / Production]

Each arrow labelled with a /command is a Claude Code skill that does that step for you (see Slash Commands). The last two steps are described in Deployment.

Run each block from the repository root:

Terminal window
# Backend containers (Arkana + API + queues + database)
cd backend && ./vendor/bin/sail up -d
Terminal window
# The Web (separate terminal)
cd frontend && pnpm dev
Terminal window
# These docs (optional, separate terminal)
cd docs && pnpm dev
Service URL Purpose
Arkana http://localhost/admin FilamentPHP back office
Backend API http://localhost/api Laravel API
Swagger http://localhost/api/documentation API docs
Telescope http://localhost/telescope Debug dashboard
The Web http://localhost:4321 Astro website
Documentation http://localhost:4322 This site
Mailpit http://localhost:8025 Email testing

Work is tracked in ClickUp. Never commit to master directly — every change goes through a branch and a pull request.

Branches follow ClickUp’s auto-branch template, <taskId>_<slug>, so ClickUp links the branch back to the task:

CU-869dtaf1r_bogus-multi-stop-domestic-flight-legs

/task-work <task-id> creates it for you from a fresh origin/master.

Title format: type(scope): description (Conventional Commits). The PR title is checked by the pr-title-check GitHub Action, and because PRs are squash-merged it becomes the commit on master — and decides the next version number (feat → minor, anything else → patch).

  • Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert
  • Scopes: frontend, backend (required; use backend,frontend for both)
  • Task reference: in the commit body as a trailer, Refs: CU-<taskId> — never in the title
  • Language: English, imperative mood (“add”, not “added”)
Terminal window
# Good
git commit -m "feat(backend): add user dashboard with profile management" -m "Refs: CU-869dtaf1r"
git commit -m "fix(backend): booking validation for empty dates" -m "Refs: CU-869dtaf1r"
# Bad
git commit -m "CU-869dtaf1r feat(backend): add user dashboard" # task ref in title
git commit -m "fix stuff"
git commit -m "WIP"

Do not add AI attribution (Co-Authored-By: Claude) to commits.

Use Claude Code slash commands for common operations:

Skill Description
/commit [message] Create commit with Conventional Commits format
/pr-create Create PR (runs PHPStan check for PHP changes)
/fix-phpstan [path] Run PHPStan and fix errors
/rebase-master Rebase onto latest master
/update-master Switch to master, pull changes, and sync dependencies (local only)
/prune-branches Delete local branches whose remote tracking branch has been deleted
/task-create [description] Create a ClickUp task from a description or plan
/task-work [task-id] Start working on a ClickUp task (setup branch)
/review-comment [text] Evaluate PR review comment validity
/update-docs Update documentation for changed services
/work-report [period] Generate work report/changelog (default: this week)
/db-backup [description] Create a PostgreSQL backup and upload to S3
/db-restore [filename] Download a backup from S3 and restore locally

.claude/settings.json wires automation around edits:

  • SessionStart (startup): runs scripts/setup_env.sh asynchronously to prepare the environment
  • PreToolUse (Edit/Write): on backend PHP, .claude/hooks/require-skill.sh blocks the edit until the matching MUST skill (laravel-best-practices, testing-best-practices, filament-development, mcp-development) is loaded in the session; on frontend/src/**/*.astro|tsx, block-raw-hex.sh rejects raw hex colours so components use the design-system tokens
  • Notification: notify-google-chat.sh forwards Claude Code notifications to Google Chat
  • PostToolUse (Edit/Write): on backend/**/*.php files runs Pint on the edited file only through Sail; on docs/src/content/docs/**/*.md files runs npx markdownlint-cli2 --fix

Canonical local CI entrypoints defined in backend/composer.json:

Terminal window
./vendor/bin/sail composer test # config:clear + lint:check + analyse:check + phpstan + tests
./vendor/bin/sail composer lint # Pint (parallel)
./vendor/bin/sail composer analyse # PHPStan
./vendor/bin/sail composer test:type-coverage # Pest type coverage (min 100)
./vendor/bin/sail composer dev # serve + queue:listen + pail + vite concurrently

All PHP code must pass PHPStan Level 6 analysis:

Terminal window
# Run PHPStan
./vendor/bin/sail exec laravel.test ./vendor/bin/phpstan analyse
# Auto-fix with slash command
/fix-phpstan

Format code with Laravel Pint:

Terminal window
./vendor/bin/sail pint

Run tests with Pest:

Terminal window
# All tests
./vendor/bin/sail artisan test
# Specific test
./vendor/bin/sail artisan test --filter=BookingTest
# With coverage
./vendor/bin/sail artisan test --coverage

Claude Code handles general backend work (models, Filament resources, tests, debugging) directly in the main session, guided by the MUST skills listed in backend/AGENTS.md (laravel-best-practices, testing-best-practices, filament-development, mcp-development), each enforced by the PreToolUse hook. Specialized agents cover narrow domains:

Agent Use For
@aerticket-api-agent Questions about the AerTicket API
@intermundial-api-agent Intermundial Nexus API for travel insurance
@documentation-agent Auditing, pruning, and keeping docs synchronized with code
@offer-doctor Diagnosing why auto-generated travel offers are missing or fail
Terminal window
# Create migration
./vendor/bin/sail artisan make:migration create_bookings_table
# Run migrations
./vendor/bin/sail artisan migrate
# Rollback
./vendor/bin/sail artisan migrate:rollback
# Fresh with seeders
./vendor/bin/sail artisan migrate:fresh --seed
Terminal window
# Create seeder
./vendor/bin/sail artisan make:seeder BookingSeeder
# Run seeders
./vendor/bin/sail artisan db:seed
# Specific seeder
./vendor/bin/sail artisan db:seed --class=BookingSeeder

After running seeders (db:seed), populate your local environment with test data. Run in this order:

Terminal window
# 1. Seed base data (suppliers, airports, markets)
./vendor/bin/sail artisan db:seed
# 2. Generate hotels
./vendor/bin/sail artisan suppliers:hotels:generate --hotels-per-city=2
# 3. Generate activities
./vendor/bin/sail artisan suppliers:activities:generate --activities-per-city=2
# 4. Generate services linked to hotels and activities
./vendor/bin/sail artisan suppliers:services:generate --type=hotel --count=10
./vendor/bin/sail artisan suppliers:services:generate --type=activity --count=10
# 5. Generate products with flight configs
./vendor/bin/sail artisan products:generate --templates=5 --per-market=1

All commands are interactive when options are omitted, and blocked from running in production.

For detailed options of each command, see Suppliers — Test Data Generation and Products — Test Data Generation.

Interactive PHP shell for debugging:

Terminal window
./vendor/bin/sail artisan tinker
# Example queries
>>> User::count()
>>> Booking::with('user')->first()
>>> Product::where('active', true)->get()
Terminal window
# Process jobs
./vendor/bin/sail artisan queue:work
# List failed jobs
./vendor/bin/sail artisan queue:failed
# Retry failed job
./vendor/bin/sail artisan queue:retry {id}
# Clear failed jobs
./vendor/bin/sail artisan queue:flush

Access at http://localhost/telescope for:

  • Request/response inspection
  • Database queries
  • Queue jobs
  • Exceptions
  • Logs

Use the Laravel Boost MCP tools:

Terminal window
# Get last error
mcp__laravel-boost__last-error
# Query database
mcp__laravel-boost__database-query "SELECT * FROM users LIMIT 5"
# Execute tinker code
mcp__laravel-boost__tinker "User::count()"
# Search docs
mcp__laravel-boost__search-docs ["queue jobs", "redis"]
  1. Run tests: ./vendor/bin/sail artisan test
  2. Run PHPStan: /fix-phpstan
  3. Format code: ./vendor/bin/sail pint
  4. Update documentation if needed

Use the slash command:

Terminal window
/pr-create

This will:

  1. Check for uncommitted changes
  2. Run PHPStan if PHP files changed
  3. Push branch to remote
  4. Create PR with template

PRs require:

  • Passing CI checks (the Pest suite on SQLite, the Pint style check, and the advisory PostgreSQL lane)
  • Code review approval
  • Updated documentation (if applicable)

PHPStan is not a CI check: it runs locally through composer test and the /pr-create gate. Docs-content and backend-test PRs skip review and merge through the auto-merge path. The full workflow matrix lives in PR Merge Paths.