# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Interazione - L'utente scrive in italiano. **Rispondi in italiano.** - Codice, commenti, nomi di variabili, commit message, log e documentazione tecnica: **in inglese.** - Nei commit **non aggiungere `Co-Authored-By: Claude`** né altri trailer di attribuzione. ## Stato Struttura, content type, pagine blog, Docker e Caddy sono in piedi. Restano da fare: sitemap e `robots.txt` dinamici, ricerca, e i test (nessun framework ancora configurato). ## Architettura ```text Browser → Caddy ─┬─ dominio pubblico → Nuxt 4 (SSR) → REST Strapi └─ sottodominio CMS → Strapi 5 → PostgreSQL ``` - Strapi è la **sola** fonte di verità editoriale. Niente altro backend (no Express/Nest/Fastify): se serve logica server, sta in Nitro (`frontend/server/`) o in un controller Strapi. - I visitatori pubblici non si autenticano mai. Solo editor/admin usano l'auth Strapi. - **Il browser non parla mai con Strapi.** Le pagine chiamano gli endpoint Nitro in `frontend/server/api/`, che sono l'unico posto dove si costruiscono query Strapi. Così `NUXT_STRAPI_URL` resta l'indirizzo interno Docker, niente CORS e niente token nel client. Se aggiungi una vista, aggiungi l'endpoint lì e tipizza il ritorno in `shared/types/blog.ts`. - Il Markdown dell'articolo è convertito in HTML **nell'endpoint**, non nel componente: il contenuto è già nell'HTML SSR e `marked` resta fuori dal bundle client. - `cms/src/index.ts` (`bootstrap`) dà al ruolo Public solo `find`/`findOne` su Article e Category, e disattiva la registrazione pubblica: non esistono utenti front-end, solo amministratori. Qualsiasi permesso in più va motivato. - Postgres non è esposto pubblicamente. Media su volume persistente, mai binari nel DB. ## Comandi Package manager: quello del lockfile. Se non esiste ancora → `npm`. ```bash # frontend/ npm run dev # dev server npm run build # build produzione npm run typecheck # nuxi typecheck — obbligatorio prima di dichiarare fatto npm run lint # cms/ npm run develop # Strapi con content-type builder attivo npm run build # admin panel npm run start # produzione # stack completo (con Caddy e domini reali) docker compose up -d --build docker compose logs -f cms # stack locale senza domini né TLS: porte su localhost, niente Caddy docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build database cms frontend ``` `docker-compose.dev.yml` va passato **sempre esplicitamente**: non è un `override.yml` proprio per non finire per sbaglio in produzione esponendo le porte. Nessun test framework è ancora configurato. Se ne aggiungi uno, documenta qui il comando per lanciare **un singolo test**. ## Modelli di contenuto | Type | Campi | |---|---| | Article | title, slug (UID da title), content (Markdown), cover, category (rel) | | Category | name, slug | Deliberatamente minimale: **niente Author** (l'unico autore è l'admin), niente tag, nessun campo SEO separato. La meta description è ricavata dall'inizio del body (`summarise` in `frontend/server/utils/strapi.ts`), la data è il `publishedAt` di Draft & Publish, l'immagine social è la cover. Non reintrodurre questi campi senza che servano davvero. Draft & Publish attivo su Article. Le URL pubbliche usano lo **slug**, mai l'id numerico. ## Frontend Rotte: `/`, `/blog`, `/blog/[slug]`, `/category/[slug]`. - SSR o prerender per tutto ciò che è indicizzabile. Mai pagine blog client-only senza motivo scritto. - `