# CLAUDE.md — dyncoll.v2 Istruzioni per agenti AI (e umani) che lavorano su questo repository. ## 1. Cos'è **dyncoll.v2** è la riscrittura della piattaforma *Dynamic Collections Plus*: catalogo e curatela di collezioni digitali di reperti archeologici. Obiettivo trasversale della v2: esporre i dati secondo lo standard di harvesting **KSamsök 2 Linked Art** del Riksantikvarieämbetet (RAÄ) / SweDigArch, così da essere raccoglibili dall'aggregatore nazionale svedese. - v1 (legacy, in produzione): `../dyncoll.v1` — PHP MPA procedurale, MySQL. - Documentazione di mapping (sorgente di verità): `../workfile/K2_tech_doc260430/shm-2b/`. - Contesto e decisioni storiche: file di memoria in `../` (`memory/MEMORY.md` e collegati). ## 2. Stack | Layer | Tecnologia | |---|---| | Backend | Laravel (PHP 8.3+/8.4), API-only | | Auth | Sanctum + Fortify (2FA TOTP via `pragmarx/google2fa`) | | Code/cache | Redis + Horizon | | DB | MySQL 8.4 (schema definito da migration Laravel) | | OpenAPI | **scegliere UNO** tra `darkaonline/l5-swagger` o `dedoc/scramble` (ora ci sono entrambi) | | Linked Art | `ml/json-ld` (serializzazione) + `opis/json-schema` (validazione contro gli schema RAÄ) | | Frontend | Vite + TypeScript, MPA con isole, Tailwind v4 + daisyUI, Leaflet | | Docs | MkDocs Material (`documentation/`) | | Qualità | SonarQube locale (`http://sonar.local`) | ## 3. Architettura dati (decisione chiave) - **v2 ha il proprio DB**, schema da migration Laravel — NON si appoggia in read-only al DB di v1. - I dati arrivano da v1 tramite un **comando ETL idempotente** (`php artisan v1:import`), non via dump/restore manuale (gli schemi divergono volutamente). - Due connessioni in `config/database.php`: `mysql` (v2, scrivibile) e `legacy` (v1, **sola lettura**, variabili `DB_LEGACY_*`). Lo stesso ETL serve sia per i refresh di sviluppo sia per il cutover. - Progettare lo schema v2 **già orientato al Linked Art**: identificatori `canonical`/`uuid` stabili, vocabolari come tabelle con colonna URI, audit `created/modified` puliti. ## 4. Mapping Linked Art — vincoli da rispettare Quando si genera JSON-LD (vedi `mapping-protocol-key-facts` in memoria): - Reperto → `HumanMadeObject` (E22). Documento annidato, **non** CRM piatto. - Ogni record porta `RecordProvenance` (license, dateCreated/Modified, `ingestedAt`+`provider` autogenerati). - Distinzione `id` (URI di retrieval dereferenziabile) vs `canonical` (id stabile `kulturarvsdata.se/...`). - **Classi CRM astratte vietate** come tipo concreto: E1,E2,E3,E14–E19,E24,E28,E31,E32,E41,E63,E64,E70,E71,E72,E77,E83,E90,E92,E93,E96,E99. - Ogni record generato DEVE validare contro `LinkedArtRecord-1.0.0.schema.json` (test obbligatorio). - Endpoint Provider da implementare (path sotto `/linkedart/v1`): Tier 1 `/batch` (MUST), Tier 2 `/changes` + `/objects/{id}` (SHOULD), Tier 3 Search (MAY). Gli endpoint devono essere conformi a `protokoll-openapi/raa-linkedart-service-1.0.0.yaml`. ## 5. Regole di commit e qualità Esiste un **pre-commit hook** (`.git/hooks/pre-commit`) che blocca il commit se: 1. **REUSE / licenze**: ogni file deve avere copyright + licenza SPDX (header o `REUSE.toml`). Licenza codice prevista: **EUPL-1.2**; docs/dati: **CC-BY-4.0**. 2. **Test + coverage** (PHP via PHPUnit, frontend via Vitest) sui file staged. 3. **SonarQube**: quality gate (`sonar.qualitygate.wait=true`) deve passare. Token letto da `$SONAR_TOKEN` o da `.git/sonar.token` (mai in chiaro nel repo). Conseguenze pratiche: - Aggiungere header SPDX a ogni nuovo file, altrimenti il commit fallisce. - Mantenere/aggiornare i test: nuovo codice senza test fa fallire la quality gate. - Backend e frontend devono essere up (`docker compose up`) perché l'hook gira i test nei container. ## 6. Segreti e ambiente - `.env` e `.git/sonar.token` **non si versionano mai** (vedi `.gitignore`). - Le variabili sono documentate in `.env.example`: aggiornarlo quando se ne aggiungono. - Nomi DB canonici (Laravel): `DB_DATABASE`, `DB_USERNAME`, `DB_PASSWORD`, `DB_ROOT_PASSWORD`. I compose devono mappare le `MYSQL_*` da questi (non introdurre `DB_NAME`/`DB_USER` paralleli). ## 6bis. Workflow host/container (IMPORTANTE — leggere prima di lanciare comandi) Regola d'oro: **chi scrive file lo fa come utente host (`beppe`, UID 1000); mai mischiare `node_modules` musl (container Alpine) e glibc (host).** Usare i target del `Makefile`. | Operazione | Dove | Comando | |---|---|---| | Editare `composer.json` / `package.json` / codice | HOST | editor / tool agente (sempre beppe-owned) | | Avviare lo stack di sviluppo (Vite HMR + backend + …) | CONTAINER | `make up` | | `composer install/update/require` | HOST | `make be-install` / `make be-update` / `make composer c="…"` | | Aggiornare deps frontend: edita `package.json` (host) → | HOST + rebuild img | `make fe-install` poi `make fe-rebuild` | | artisan con servizi (`migrate`, `db:*`, `queue`, `tinker`, `v1:import`) | CONTAINER come UID host | `make migrate` / `make import` / `make artisan c="…"` | | Permessi `storage` per php-fpm (www-data) | HOST, una tantum | `make permissions` | Motivi e asimmetria backend/frontend: - **Backend**: host PHP 8.4 == container; `vendor/` è codice PHP portabile ed è **bind-montato** (`./backend:/var/www/html`), quindi composer gira sull'host e il container lo vede subito. `config.platform` in `composer.json` copre le estensioni mancanti sull'host (redis, gd, bcmath). - **Frontend**: il dev server di Vite gira **nel container** (`make up`, stage `development`). Il sorgente è bind-montato (`./frontend:/app`) → HMR; i `node_modules` **non** sono bind-montati ma vivono in un **volume anonimo** (`/app/node_modules`), così quelli musl dell'immagine schermano quelli glibc dell'host (mai mischiati). Si installano nella *build dell'immagine*, mai in un container in esecuzione. `npm install` su host serve solo a `package-lock` + type-check IDE; dopo modifiche a `package.json` rigenerare l'immagine con `make fe-rebuild`. - I comandi artisan con servizi girano nel container (dove `db`, `redis`, `mailpit` risolvono) ma con `-u $(id -u):$(id -g)` per non creare file root-owned. **Regole per l'agente AI:** - Editare `composer.json`/`package.json`/codice coi propri tool (host, beppe-owned): OK. - NON lanciare `composer install/update` o `npm install` di propria iniziativa (l'ambiente host dell'utente è autoritativo). Se serve, usare i target `make` qui sopra. - Per artisan che tocca i servizi usare **sempre** `make artisan c="…"` (container come UID host). - Non bind-montare mai `node_modules` in un container Alpine. > Nota drift: l'IDE/type-check usa il Node dell'host (20.19/npm 9); il dev server di Vite usa il > Node 24 dell'immagine. Conviene comunque allineare l'host a Node 22/24 LTS (Vite 8 richiede ≥ 20.19/22.12). ## 7. Comandi utili Usare i target del `Makefile` (incapsulano la strategia host/container del §6bis): ```bash make up # avvia l'intero stack dev (Vite HMR + backend + db + redis + docs + mailpit) make migrate # artisan migrate (container come UID host) make import # ETL da v1 (quando implementato) make artisan c="test --coverage-clover=coverage.xml" # test backend make be-update # composer update (host) make fe-install # npm install host (package-lock + type-check IDE) make fe-rebuild # ricostruisce l'immagine frontend dopo modifiche a package.json make permissions # fix permessi storage (una tantum, sudo) make help # elenco completo ``` Frontend in dev: `make up` → Vite con HMR su `https://dyncoll-dev.local` (Traefik) o `http://localhost:${APP_FRONTEND_DEVPORT}`. Le modifiche al sorgente si ricaricano da sole; per nuove dipendenze npm: edita `package.json` → `make fe-install` → `make fe-rebuild`. ## 8. Convenzioni di codice - PHP: PSR-12, formattato con **Laravel Pint** (`./vendor/bin/pint`). - TypeScript: `strict` attivo (vedi `frontend/tsconfig.json`); evitare `any`. - Commenti in italiano ammessi (coerenti col resto del repo). - Non reintrodurre pattern v1 non sicuri: **query parametrizzate** sempre, mai interpolazione in SQL. ## 9. Stato dello scaffolding Lo scaffolding iniziale è stato adattato da un altro progetto ("Valdarno Trails"/RMV) e contiene residui da ripulire (riferimenti RMV in `frontend/vite.config.ts`, `frontend/frontend.Dockerfile`, `frontend/nginx.conf`) e alcuni bug nei compose/Dockerfile. Verificare sempre lo stato reale dei file prima di darli per buoni; vedere le note di review.