feat: add Post model, migration, and factory

Adds the Post model belonging to Site (required, cascade-deletes with
the site) and SocialAccount (nullable, nulled out on account delete).
Foundation for the Scheduled Posts feature; later tasks build the
Livewire CRUD UI and API on top of this model.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Doar Mihai
2026-07-18 17:07:48 +03:00
co-authored by Claude Sonnet 5
parent 4293475ce1
commit f746c5d6a0
4 changed files with 190 additions and 0 deletions
+85
View File
@@ -0,0 +1,85 @@
<?php
use App\Models\Post;
use App\Models\Site;
use App\Models\SocialAccount;
test('a post can be created with required fields only', function () {
$site = Site::factory()->create();
$post = Post::create([
'site_id' => $site->id,
'type' => 'blog',
'body' => 'Hello world',
]);
$fresh = $post->fresh();
expect($fresh)
->site_id->toBe($site->id)
->type->toBe('blog')
->body->toBe('Hello world')
->status->toBe('draft')
->social_account_id->toBeNull()
->title->toBeNull()
->scheduled_at->toBeNull();
});
test('a post can be created with an account, title, status, and schedule', function () {
$site = Site::factory()->create();
$account = SocialAccount::factory()->create();
$post = Post::create([
'site_id' => $site->id,
'social_account_id' => $account->id,
'type' => 'twitter',
'title' => 'Launch day',
'body' => 'We just launched!',
'status' => 'scheduled',
'scheduled_at' => '2026-08-01 09:00:00',
]);
$fresh = $post->fresh();
expect($fresh)
->social_account_id->toBe($account->id)
->title->toBe('Launch day')
->status->toBe('scheduled')
->scheduled_at->not->toBeNull();
});
test('a post belongs to a site', function () {
$site = Site::factory()->create();
$post = Post::factory()->create(['site_id' => $site->id]);
expect($post->site)->toBeInstanceOf(Site::class);
expect($post->site->id)->toBe($site->id);
});
test('a post can belong to a social account', function () {
$account = SocialAccount::factory()->create();
$post = Post::factory()->create(['social_account_id' => $account->id]);
expect($post->socialAccount)->toBeInstanceOf(SocialAccount::class);
expect($post->socialAccount->id)->toBe($account->id);
});
test('deleting a site cascades and deletes its posts', function () {
$site = Site::factory()->create();
$post = Post::factory()->create(['site_id' => $site->id]);
$site->delete();
expect(Post::find($post->id))->toBeNull();
});
test('deleting a social account nulls out the post link but keeps the post', function () {
$account = SocialAccount::factory()->create();
$post = Post::factory()->create(['social_account_id' => $account->id]);
$account->delete();
expect($post->fresh())
->not->toBeNull()
->social_account_id->toBeNull();
});