8.3 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 01-database-schema-backend-api | 01 | execute | 1 |
|
true |
|
Purpose: Establishes the data layer that all subsequent note features depend on. Without this, no notes can be stored or queried. Output: Notes table in database, Note model, Member->notes relationship, NoteFactory for testing.
<execution_context> @/Users/gbanyan/.claude/get-shit-done/workflows/execute-plan.md @/Users/gbanyan/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/01-database-schema-backend-api/01-RESEARCH.md@app/Models/Member.php @app/Models/CustomFieldValue.php @app/Providers/AppServiceProvider.php @database/factories/MemberFactory.php
Task 1: Create notes migration and Note model with polymorphic relationships database/migrations/YYYY_MM_DD_HHMMSS_create_notes_table.php app/Models/Note.php Create migration using `php artisan make:migration create_notes_table`. In the migration: - `$table->id()` - `$table->morphs('notable')` — creates notable_type (string), notable_id (unsignedBigInteger), and composite index on [notable_type, notable_id] automatically - `$table->longText('content')` — note text content - `$table->foreignId('author_user_id')->constrained('users')->cascadeOnDelete()` — links to User who wrote the note - `$table->timestamps()` - `$table->index('created_at')` — for chronological sorting queriesCreate `app/Models/Note.php`:
- Use `HasFactory` trait
- `$fillable`: notable_type, notable_id, content, author_user_id
- `notable()` method returning `$this->morphTo()` (MorphTo relationship)
- `author()` method returning `$this->belongsTo(User::class, 'author_user_id')` (BelongsTo relationship)
- Follow existing model patterns from CustomFieldValue.php (same polymorphic pattern)
Run `php artisan migrate` to apply the migration.
Run `php artisan migrate:status` and confirm the create_notes_table migration shows as "Ran".
Run `php artisan tinker --execute="Schema::hasTable('notes')"` and confirm it returns true.
Run `php artisan tinker --execute="Schema::getColumnListing('notes')"` and confirm columns: id, notable_type, notable_id, content, author_user_id, created_at, updated_at.
Notes table exists in database with all columns (id, notable_type, notable_id, content, author_user_id, created_at, updated_at), composite index on [notable_type, notable_id], and index on created_at. Note model exists with notable() morphTo and author() belongsTo relationships.
Task 2: Add Member relationship, morph map, and test factory
app/Models/Member.php
app/Providers/AppServiceProvider.php
database/factories/NoteFactory.php
In `app/Models/Member.php`:
- Add `use Illuminate\Database\Eloquent\Relations\MorphMany;` import
- Add `notes()` method returning `$this->morphMany(Note::class, 'notable')->orderBy('created_at', 'desc')` — default ordering newest first for display
- Add `use App\Models\Note;` import
- Place the method near existing relationship methods (after payments, user, etc.)
In `app/Providers/AppServiceProvider.php`:
- Add `use Illuminate\Database\Eloquent\Relations\Relation;` import
- Add `use App\Models\Member;` import
- In `boot()` method, add: `Relation::enforceMorphMap(['member' => Member::class]);`
- This ensures 'member' is stored in notable_type column instead of the full class name 'App\Models\Member', protecting against future namespace refactoring
Create `database/factories/NoteFactory.php`:
- Follow existing MemberFactory pattern
- `definition()` returns: notable_type => 'member' (uses morph map alias, NOT Member::class), notable_id => Member::factory(), content => $this->faker->paragraph(), author_user_id => User::factory()
- Add `forMember(Member $member)` state method that sets notable_type => 'member', notable_id => $member->id
- Add `byAuthor(User $user)` state method that sets author_user_id => $user->id
Run `php artisan tinker --execute="use App\Models\Member; use App\Models\Note; echo (new Member)->notes() instanceof \Illuminate\Database\Eloquent\Relations\MorphMany ? 'OK' : 'FAIL';"` and confirm "OK".
Run `php artisan tinker --execute="use Illuminate\Database\Eloquent\Relations\Relation; echo json_encode(Relation::morphMap());"` and confirm output contains "member" key mapping to Member class.
Run `php artisan tinker --execute="use App\Models\Note; echo class_exists(\Database\Factories\NoteFactory::class) ? 'OK' : 'FAIL';"` and confirm "OK".
Member model has notes() morphMany relationship returning notes ordered by created_at desc. AppServiceProvider registers morph map with 'member' => Member::class. NoteFactory exists with definition(), forMember(), and byAuthor() state methods.
Run `php artisan migrate:fresh --seed` to confirm migration works cleanly with existing seeders.
Run `php artisan tinker` and execute:
```php
use App\Models\Member;
use App\Models\User;
use App\Models\Note;
$user = User::first(); $member = Member::first(); $note = $member->notes()->create(['content' => 'Test note', 'author_user_id' => $user->id]); echo $note->id . ' - ' . $note->notable_type . ' - ' . $note->content; echo $note->author->name; echo $member->notes()->count();
All commands should execute without errors. The notable_type should show 'member' (not 'App\Models\Member') due to the morph map.
</verification>
<success_criteria>
1. Notes table exists with all required columns and indexes
2. Note model has working morphTo and belongsTo relationships
3. Member model has working morphMany notes relationship (ordered by created_at desc)
4. Morph map stores 'member' string (not full class name) in notable_type
5. NoteFactory can create notes with forMember() and byAuthor() state methods
6. `php artisan migrate:fresh --seed` runs without errors
</success_criteria>
<output>
After completion, create `.planning/phases/01-database-schema-backend-api/01-01-SUMMARY.md`
</output>