README gets step-by-step instructions for both: secrets generation and the local stack on one side, DNS records, firewall, environment variables, TLS and backups on the other. CLAUDE.md records the decisions that are not visible in the code: why the browser never reaches Strapi, why the content model stays this small, and where the public permissions are granted.
122 lines
5.6 KiB
Markdown
122 lines
5.6 KiB
Markdown
# 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.
|
|
- `<script setup lang="ts">`, Composition API. Convenzioni Nuxt standard (`pages/`, `components/`,
|
|
`composables/`, `layouts/`, `server/`).
|
|
- Un solo punto di accesso a Strapi: un composable/util tipizzato. Non sparpagliare `$fetch` nelle pagine.
|
|
- Tipizza esplicitamente il confine API. Niente `any` — `unknown` + narrowing.
|
|
- Query Strapi: richiedi solo i campi e le relazioni che servono (`fields`, `populate` mirati).
|
|
Gestisci sempre 404, lista vuota, errore API.
|
|
- Ogni articolo indicizzabile: title unico, meta description, canonical, Open Graph, JSON-LD
|
|
`BlogPosting`, gerarchia heading semantica. Il contenuto deve esistere nell'HTML server-rendered.
|
|
- Accessibilità non negoziabile: focus visibile, input etichettati, alt significativi, link
|
|
descrittivi, navigazione da tastiera.
|
|
|
|
Il riferimento Hostinger è solo ispirazione visiva. Non copiare codice o asset.
|
|
|
|
## Priorità
|
|
|
|
Correttezza e integrità dati → sicurezza → semplicità → SEO/a11y → performance.
|
|
|
|
Nessuna dipendenza, astrazione o servizio senza un bisogno concreto e attuale. Preferisci i
|
|
built-in Strapi al reimplementare funzioni CMS in Nuxt.
|
|
|
|
## Vincoli
|
|
|
|
- Mai committare `.env`, segreti, token, credenziali, chiavi. Mantieni `.env.example` sanificato.
|
|
- Mai hard-codare domini di produzione, URL privilegiati o credenziali. Vanno in env var.
|
|
- Non indebolire auth, CORS, TLS o security header per comodità. Least privilege sui ruoli Strapi.
|
|
- Richiedono **approvazione esplicita**: operazioni distruttive, migrazioni irreversibili, modifiche
|
|
a dati o configurazione di produzione, cambi di credenziali.
|
|
- Non riformattare file non correlati, non fare refactor collaterali, non riscrivere la history,
|
|
non force-push.
|
|
- Le decisioni architetturali di questo file non si cambiano in silenzio: spiega il trade-off prima.
|
|
|
|
## Prima di dichiarare completo
|
|
|
|
Lint → test → typecheck → build dell'app toccata, con gli script del `package.json` relativo.
|
|
Non affermare che un check è passato se non l'hai eseguito. Chiudi riassumendo cosa è cambiato e
|
|
quali rischi restano aperti.
|