# Agent Coding Guide: Laravel + React SPA with SWR & Zustand Use this for coding guide and use agent-tasks.md for backlog and tracking progress. ## 1. Project Structure **Backend (Laravel):** - Standard folders: - `app/Http/Controllers` (thin, validate, call services) - `app/Services` (business logic) - `routes/api.php` (API endpoints, RESTful JSON) - `app/Models` (Eloquent ORM) - `app/Http/Resources` (format API responses) - Use Laravel Sanctum for SPA authentication. **Frontend (React):** - React app inside `/resources/js/react` for seamless Laravel integration. - Functional components with hooks. - React Router for client-side routing. - **Zustand** for global state management. - **SWR** for all server data fetching and caching. - Axios as HTTP client used within SWR fetcher function. ## 2. Code & Style **Backend (Laravel/PHP):** - PSR-12 standard. - Controllers handle request, validation, call service methods, return API Resources. - Services contain business logic. - Use JSON responses throughout. **Frontend (React/JS):** - Functional components with hooks and JSX. - Manage UI state (modals, forms) locally or via Zustand. - Use Axios inside SWR for API calls to leverage SWR caching and revalidation. - Leverage SWR hooks (`useSWR`) for data fetching with automatic caching, re-fetching, and error handling—avoid manual state for server data. - Use Zustand only for client state that doesn’t come from API (e.g., UI toggles, theme, user session info). - Use React Router for SPA navigation, avoiding full page reloads. ## 3. Example Usage ### Zustand Store (Client UI State) ```js // store/useStore.js import create from 'zustand'; export const useStore = create(set => ({ isModalOpen: false, openModal: () => set({ isModalOpen: true }), closeModal: () => set({ isModalOpen: false }), editingPlayer: null, setEditingPlayer: (player) => set({ editingPlayer: player }), })); ``` ### SWR Data Fetching with Axios ```js // utils/api.js import axios from 'axios'; export const apiClient = axios.create({ baseURL: '/api', withCredentials: true, }); export const fetcher = url => apiClient.get(url).then(res => res.data); // components/PlayerList.js import useSWR from 'swr'; import { fetcher } from '../utils/api'; import { useStore } from '../store/useStore'; function PlayerList() { const { data, error } = useSWR('/players', fetcher); const { openModal, setEditingPlayer } = useStore(); if (error) return
Failed to load
; if (!data) return
Loading...
; const handleEdit = (player) => { setEditingPlayer(player); openModal(); }; return ( ); } ```