# AGENTS.md — Piedra Total Perú

Guía para agentes de IA y desarrolladores que trabajen en este repositorio.

## Proyecto

Sitio de catálogo de **piedra natural peruana** (piedra laja, piedra de cantera) para Lima y todo
el Perú. El sitio público es server-rendered (Blade) y SEO-first; el panel de administración es
Filament. El e-commerce (carrito, checkout, pagos, envíos, cuentas, inventario) está **fuera de
alcance** por ahora.

Idioma: **español** para UI, contenido y copy de dominio; **inglés** para identificadores de código,
columnas de base de datos, nombres de clases y mensajes de commit.

## Stack (verificado — no regresar)

| Capa | Versión |
|------|---------|
| PHP | 8.4 (Docker `php:8.4-fpm`; `composer.json` requiere `^8.3`) |
| Laravel | **13** |
| Livewire | **4** (SFC; `Route::livewire()` disponible) |
| Filament | **5** (requiere Livewire 4 + Tailwind 4) |
| Tailwind CSS | **4** — CSS-first `@theme` en `resources/css/app.css`; **NO existe `tailwind.config.js`**; plugin Vite `@tailwindcss/vite` |
| MySQL | **8** (`mysql:8.4`) |
| Redis | 7 (cache, sesión y colas) |
| Vite | 8 |
| Tests | **Pest 4** (PHPUnit 12) |
| Contenedores | **Docker Compose** — `app` (php-fpm), `web` (nginx), `db` (MySQL), `redis`, `node` (perfil `tools`) |

### Entorno local

- Todo se ejecuta **dentro de Docker**; el PHP/Node del host no se usa.
- La web está publicada en **`8001:80`** (el puerto 8000 está ocupado por otro proyecto).
- En Windows usar **`127.0.0.1`**, nunca `localhost` (resuelve a IPv6 `::1` y expira).
- Comandos: `docker compose exec app php artisan ...`, `docker compose exec app php artisan test`,
  `docker compose run --rm node npm run build`.
- No ejecutar `cd` dentro de comandos; usar el directorio de trabajo del proyecto.

## Arquitectura y reglas de capas

Flujo del módulo de administración:

```
Filament (presentación delgada) → Service (lógica de negocio) → Repository (acceso a datos) → Eloquent
```

- **Controladores y recursos/páginas Filament son delgados.** Solo routing, validación de formulario,
  esquemas, etiquetas y navegación. Sin reglas de negocio.
- **Servicios** en `app/Services/`: lógica de negocio, transacciones, orquestación de slug/SEO,
  adjuntar media, regeneración de sitemap.
- **Repositorios** en `app/Repositories/`:
  - Interfaces en `app/Repositories/Contracts/` (`*RepositoryInterface`).
  - Implementaciones Eloquent en `app/Repositories/Eloquent/` (`Eloquent*Repository`).
  - Todo el *query building* vive aquí; nunca se filtra el query builder hacia arriba.
  - Métodos con intención de negocio (`findBySlug`, `published`, `paginateFiltered`, `attachMedia`, `sync`).
- **DTOs** en `app/Data/` (`ProductData`, `PostData`, `PageData`, `ProjectData`, `SeoData`): el estado
  de los formularios Filament se normaliza a DTOs antes de llegar a un servicio.
- **Prohibido `DB::` y query building fuera de repositorios/servicios.** Los modelos Eloquent solo
  tienen relaciones, scopes y accessors.
- Bindings de interfaces → implementaciones en `app/Providers/RepositoryServiceProvider.php`.
- `declare(strict_types=1);` en toda clase PHP nueva y tipos de retorno explícitos.

### Render público

- Páginas públicas = **controladores delgados + Blade** (no Livewire full-page) para entregar HTML
  completo a crawlers. Livewire se usa solo para islas interactivas:
  `ProductCatalog`, `ProfileSelector`, `QuoteCalculator`, `ContactForm`, `CompanyQuoteForm`,
  `ProjectGallery`, `MediaLibraryPicker`.
- SEO centralizado en `resources/views/components/seo-meta.blade.php` y
  `resources/views/components/json-ld/`; cada página emite `lang="es-PE"`, **exactamente un `<h1>`**,
  title/description/canonical/OG/Twitter y JSON-LD parseable.
- Sitemap: `SitemapService` + comando `sitemap:generate`; en producción encolado, en local/testing síncrono.

### Diseño

- Tokens de marca en `resources/css/app.css` con `@theme` de Tailwind 4. **Sin hex crudo** en vistas;
  usar los tokens (`stone-*`, `terracota-*`, `slate-*`, `success-600`, `error-600`).
- Gotchas de Tailwind 4: `shadow-sm` → `shadow-xs`; el color de borde por defecto es `currentColor`,
  así que todo componente con borde debe declarar un color explícito.
- El panel Filament usa su propio tema (`resources/css/filament/admin/theme.css`); no mezclar tokens públicos.

## Testing

- Framework: **Pest 4**. Ejecutar con `docker compose exec app php artisan test`.
- Estrategia **strict TDD**: RED → GREEN → REFACTOR. Cada escenario de spec mapea a al menos un test.
- Tests de feature usan HTTP tests de Laravel y `RefreshDatabase`; SQLite en memoria (`phpunit.xml`).
- Factories y seeders proveen fixtures.
- **No debilitar ni eliminar tests para que pasen.** Si un test falla, arreglar la implementación.
- Formateo: `docker compose exec app vendor/bin/pint`.

## Datos

- Entidad canónica del catálogo: **`Product`** = línea de piedra (Ayacuchana, Talamoye, Arequipeña,
  Pizarra Negra, Verde Esmeralda). No existe un modelo `StoneLine` separado.
- Filtros del catálogo: tabla genérica `taxonomies` (`type` = `use` | `color`) + pivote `product_taxonomy`.
- Media: modelo polimórfico propio `media` (no `spatie/laravel-medialibrary`), reutilizable y
  re-adjuntable a producto/post/página/proyecto.
- Slugs vía trait `HasSlug` (`Str::slug($v, '-', 'es')` + sufijos `-2`, `-3`). SEO vía trait `HasSeo`.

## Documentación de referencia

- `openspec/changes/platform-foundation/proposal.md` — intención y alcance.
- `openspec/changes/platform-foundation/design.md` — diseño técnico y decisiones.
- `openspec/changes/platform-foundation/tasks.md` — desglose de tareas por fase.
- `README.md` — bootstrap, comandos y credenciales de desarrollo.
