Action Writer
This Skill helps you add or update an Action in app/Actions using the project conventions.
When to use this Skill
Use this Skill when:
- •Creating a new Action
- •Updating an existing Action
Instructions
Quick start
- •Pick the action name (verb-first) and its input/output types.
- •Create the Action class and implement
execute(). - •Add or update unit tests in
tests/Unit/Actions. - •Run the smallest relevant test(s), then
composer journalos:unit.
Step 1: Choose the action name and scope
- •Actions represent a single user intent (example:
LogHealth,CreateBook,ResetWorkData). - •Keep inputs minimal and explicit. Use descriptive parameter names.
- •Decide whether the Action returns a model, a scalar, or nothing (
void).
Step 2: Create the Action class
- •Use Artisan to create the class:
bash
php artisan make:class Actions/ActionName --no-interaction
- •Use
declare(strict_types=1);and theApp\Actionsnamespace. - •Default to
final readonly classwith constructor property promotion. - •If the Action must store a result (ex:
$this->book), keep itfinalbut notreadonly, and declare a private property for the result. - •Always include explicit return types.
Step 3: Implement the action flow
- •Typical flow:
- •validate input
- •perform data changes
- •log user action
- •update last activity date
- •refresh content presence (when journal entry content changes)
- •Validate ownership with
ModelNotFoundExceptionwhen a user does not own a journal or entry. - •Validate input with
ValidationException::withMessages([...])when values are invalid. - •Sanitize user-provided text with
TextSanitizer::plainText(). - •Use Eloquent models and relationships. Avoid
DB::. - •Queue background work on the
lowqueue:
php
LogUserAction::dispatch(...)->onQueue('low');
UpdateUserLastActivityDate::dispatch($user)->onQueue('low');
CheckPresenceOfContentInJournalEntry::dispatch($entry)->onQueue('low');
- •If the Action mutates a journal entry module, reload the relationship before returning:
php
$this->entry->load('moduleHealth');
Step 4: Add tests
- •Create
tests/Unit/Actions/ActionNameTest.php. - •Use
RefreshDatabaseandQueue::fake(). - •Use factories with explicit foreign keys. Never use
for()on factories. - •Cover:
- •happy path
- •invalid input (throws
ValidationException) - •unauthorized access (throws
ModelNotFoundException) - •queued jobs on
lowqueue
Step 5: Run tests and lint
- •Run the smallest relevant test file:
bash
php artisan test tests/Unit/Actions/ActionNameTest.php
- •Run
composer journalos:unit. - •Run Pint:
bash
vendor/bin/pint --dirty