Source path: app/Http/Controllers/PostController.php
Extracted from supplied specification. Review before copying into application.

<?php
namespace App\Http\Controllers;

use App\Models\{Media, Post};
use Illuminate\Http\Request;

class PostController extends Controller
{
    public function index(Request $r)
    {
        return $r->user()->posts()->with(['targets.socialAccount', 'media'])->latest()->paginate(20);
    }

    public function store(Request $r)
    {
        $data = $r->validate([
            'caption'      => 'required|string|max:5000',
            'accounts'     => 'required|array|min:1',
            'accounts.*'   => 'exists:social_accounts,id',
            'media_ids'    => 'array',
            'media_ids.*'  => 'exists:media,id',
            'scheduled_at' => 'nullable|date|after:now',
        ]);

        $user = $r->user();
        $ownedAccounts = $user->socialAccounts()->whereIn('id', $data['accounts'])->pluck('id');
        abort_if($ownedAccounts->count() !== count($data['accounts']), 403);

        $post = $user->posts()->create([
            'caption' => $data['caption'],
            'status'  => isset($data['scheduled_at']) ? 'scheduled' : 'draft',
            // client sends ISO with offset; stored as UTC
            'scheduled_at' => isset($data['scheduled_at'])
                ? \Carbon\Carbon::parse($data['scheduled_at'])->utc() : null,
        ]);

        foreach ($ownedAccounts as $id) {
            $post->targets()->create(['social_account_id' => $id]);
        }

        if (!empty($data['media_ids'])) {
            Media::where('user_id', $user->id)->whereIn('id', $data['media_ids'])
                ->update(['post_id' => $post->id]);
        }

        return response()->json($post->load('targets', 'media'), 201);
    }

    public function schedule(Request $r, Post $post)
    {
        abort_if($post->user_id !== $r->user()->id, 403);
        $data = $r->validate(['scheduled_at' => 'required|date|after:now']);

        $post->update([
            'status' => 'scheduled',
            'scheduled_at' => \Carbon\Carbon::parse($data['scheduled_at'])->utc(),
        ]);

        return $post;
    }

    public function destroy(Request $r, Post $post)
    {
        abort_if($post->user_id !== $r->user()->id, 403);
        abort_if($post->status === 'publishing', 409, 'Post is publishing.');
        $post->delete();
        return response()->noContent();
    }
}
