34109-vm/agent.md
2025-09-19 13:31:11 +00:00

97 lines
2.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 doesnt 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 <div>Failed to load</div>;
if (!data) return <div>Loading...</div>;
const handleEdit = (player) => {
setEditingPlayer(player);
openModal();
};
return (
<ul>
{data.players.map(player => (
<li key={player.id}>
{player.name}
<button onClick={() => handleEdit(player)}>Edit</button>
</li>
))}
</ul>
);
}
```