[{"data":1,"prerenderedAt":82},["ShallowReactive",2],{"blog-building-ai-features-in-laravel":3,"blogs-all":20},{"data":4},{"slug":5,"category":6,"title":7,"description":8,"cover":9,"tags":10,"readTime":14,"date":15,"updatedAt":16,"seo":17,"content":19},"building-ai-features-in-laravel","AI","Building AI Features in Laravel with the Claude API","How I integrated Claude API into a SaaS platform to automate repetitive data entry workflows — and what I got wrong before I got it right.",null,[11,6,12,13],"Laravel","Claude API","SaaS","6 min read","2026-05-01","2026-08-07",{"title":7,"description":18,"ogImage":9},"How I integrated Claude API into a Laravel SaaS to automate data entry — queues, caching, defensive parsing, and real production lessons from SP360.","## The Problem Worth Solving\n\nAt Smart Provider LLC, our operators were spending hours every day copy-pasting information between systems. Same data, different screens, over and over. Nobody enjoys that kind of work, and it's exactly the kind of thing an LLM is genuinely good at replacing.\n\nSo I built the automation layer. Here's what that actually looked like in practice — including what I got wrong first.\n\n## Calling Claude from Laravel\n\nI used Laravel's HTTP client directly. No third-party SDK, no extra dependency for straightforward use cases.\n\n```php\n$response = Http::withHeaders([\n    'x-api-key'         => config('services.claude.key'),\n    'anthropic-version' => '2023-06-01',\n    'content-type'      => 'application\u002Fjson',\n])->post('https:\u002F\u002Fapi.anthropic.com\u002Fv1\u002Fmessages', [\n    'model'      => 'claude-sonnet-4-6',\n    'max_tokens' => 1024,\n    'system'     => 'You are a data extraction assistant. Return only valid JSON. If a field cannot be found, return null for that field.',\n    'messages'   => [\n        ['role' => 'user', 'content' => $prompt],\n    ],\n]);\n\n$result = $response->json('content.0.text');\n```\n\nSimple enough. The real complexity is in everything around the API call.\n\n## What I Got Wrong First\n\nVersion one called the Claude API synchronously inside a controller. It worked fine — until a slow response held up the entire request cycle and users started hitting timeouts.\n\nThe fix is obvious in hindsight: AI calls belong in queues.\n\n```php\n\u002F\u002F Wrong — blocks the web request\npublic function process(Request $request): JsonResponse\n{\n    $result = $this->claude->extract($request->input('data'));\n    return response()->json($result);\n}\n\n\u002F\u002F Right — dispatch and return immediately\npublic function process(Request $request): JsonResponse\n{\n    ProcessAIExtraction::dispatch($request->input('data'));\n    return response()->json(['status' => 'processing']);\n}\n```\n\n## Three Rules That Stuck\n\n**Queue every AI call.** A 3-second Claude response in a synchronous web request is a user experience problem. Dispatch a job, return a job ID, let the frontend poll or use websockets for the result.\n\n**Cache identical prompts.** Same input should hit the cache, not the API. A quick MD5 hash on the prompt content is all you need for a cache key.\n\n```php\n$cacheKey = 'claude_extraction_' . md5($prompt);\n\nreturn Cache::remember($cacheKey, now()->addHours(24), function () use ($prompt) {\n    return $this->callClaude($prompt);\n});\n```\n\n**Parse defensively.** LLMs don't always return exactly what you asked for. Validate the response shape before you try to use it. When it fails, log the raw output and flag the record for manual review — don't silently discard the failure.\n\n```php\n$data = json_decode($result, true);\n\nif (!isset($data['customer_name']) || !array_key_exists('address', $data)) {\n    Log::warning('Unexpected Claude response', ['raw' => $result]);\n    throw new AIExtractionException('Invalid response structure');\n}\n```\n\n## The Outcome\n\nAfter the automation was stable in production: roughly 60% reduction in manual operator work. The operators still review the AI output — they're not removed from the loop. The mindless copy-paste is just gone.\n\nThat's the right framing for AI in a business context. Augment the human, don't try to replace them entirely.",{"data":21},[22,32,44,47,59,70],{"slug":23,"category":6,"title":24,"description":25,"cover":9,"tags":26,"readTime":28,"date":29,"updatedAt":16,"seo":30},"prompt-engineering-for-developers","Prompt Engineering for Developers: What Actually Works in Production","Practical techniques I use when integrating Claude and OpenAI APIs into real applications — output format control, system prompts, few-shot examples, and defensive parsing.",[6,12,27,11],"OpenAI","8 min read","2026-05-18",{"title":24,"description":31,"ogImage":9},"Format control, system prompts, few-shot examples, defensive parsing — practical prompt engineering from a year of integrating Claude and OpenAI APIs.",{"slug":33,"category":34,"title":35,"description":36,"cover":9,"tags":37,"readTime":28,"date":40,"updatedAt":16,"seo":41},"mysql-query-optimization-laravel","Database","MySQL Query Optimization in Laravel: What I Fixed in Production","Real slow-query problems I diagnosed and fixed in a production SaaS — N+1 queries, missing indexes, Eloquent gotchas, and when to drop to raw SQL.",[11,38,34,39],"MySQL","Performance","2026-05-10",{"title":42,"description":43,"ogImage":9},"MySQL Query Optimization in Laravel: Real Production Fixes","N+1 queries, missing indexes, Eloquent gotchas — real slow-query problems I diagnosed and fixed in a production Laravel SaaS. Before and after code included.",{"slug":5,"category":6,"title":7,"description":8,"cover":9,"tags":45,"readTime":14,"date":15,"updatedAt":16,"seo":46},[11,6,12,13],{"title":7,"description":18,"ogImage":9},{"slug":48,"category":49,"title":50,"description":51,"cover":9,"tags":52,"readTime":55,"date":56,"updatedAt":16,"seo":57},"nuxt-4-full-stack-with-laravel-api","Full-Stack","Nuxt 4 + Laravel API: The Full-Stack Setup I Actually Ship","How I structure a Nuxt 4 frontend with a Laravel REST API — auth composable, consistent response shape, error handling, and the lessons from two years of running this in production.",[53,11,49,54],"Nuxt","API","7 min read","2026-04-18",{"title":50,"description":58,"ogImage":9},"My production-tested Nuxt 4 + Laravel 11 setup — $fetch composable, Sanctum cookie auth, consistent API responses, lessons from two years running this stack.",{"slug":60,"category":61,"title":62,"description":63,"cover":9,"tags":64,"readTime":55,"date":67,"updatedAt":16,"seo":68},"laravel-queue-jobs-real-world","Backend","Laravel Queues in Production: What Nobody Tells You","Beyond the docs — real patterns for reliable queue jobs, retry strategies, and monitoring that I use in a production SaaS application.",[11,65,61,66],"Queues","Production","2026-04-15",{"title":62,"description":69,"ogImage":9},"Real patterns for reliable Laravel queue jobs — timeouts, idempotency, cache locks, and Horizon config I use in a production SaaS application.",{"slug":71,"category":72,"title":73,"description":74,"cover":9,"tags":75,"readTime":78,"date":79,"updatedAt":16,"seo":80},"vue-3-composition-api-patterns","Frontend","Vue 3 Composition API Patterns I Use Every Day","Practical composable patterns — async state management, form handling, and reusable logic that keeps Vue 3 codebases clean without premature abstraction.",[76,77,72],"Vue","TypeScript","5 min read","2026-04-05",{"title":73,"description":81,"ogImage":9},"Practical composables for async state, form validation, and reusable logic in Vue 3 — patterns I use in every Nuxt project, with real code.",1787435163461]