diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..bcbdd25 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,94 @@ +# JWE v2 — Décisions d'architecture (Agent Architecte) + +Date : 2026-07-16 · Mission : refonte GeoGuessr souverain (voir `projet_geoguessr_97x.md`) + +## 1. Décision back-end : SvelteKit seul (pas de Strapi) + +**Décision : SvelteKit seul, avec les lieux dans un fichier JSON versionné dans Git.** + +Arguments : + +- **Frugalité OKI** : un seul processus Node à héberger, pas de CMS + admin + DB à maintenir, pas de surface d'attaque supplémentaire. SQLite serait de toute façon peu utile pour un corpus de ~40 lieux statiques. +- **Critère du prompt** (« qui ajoute les lieux ? ») : le corpus est éditorial, produit par l'Agent Contenu et relu. Le workflow Git (pull request = relecture + crédits photos vérifiés) est la modération. Le `docs/contribution.md` documente l'ajout d'un lieu par PR. +- **Livrables finaux** : le guide de déploiement demandé est « SvelteKit + Tile Server » — Strapi n'y figure pas. +- **Anti-triche** : le JSON reste côté serveur (`src/lib/server/`), jamais importé par le client ; les endpoints filtrent les champs. Impossible de faire plus simple. + +Si un jour des contributeurs non-dev doivent saisir des lieux en masse, la porte vers Strapi reste ouverte (le schéma JSON est le content-type tout désigné), mais ce n'est pas le besoin actuel. + +## 2. Architecture des tiles MapLibre + +- **Rendu** : MapLibre GL JS (verrouillé), chargé en lazy (import dynamique uniquement sur les écrans de jeu / exploration). +- **Dev / démo** : tiles vectorielles [OpenFreeMap](https://openfreemap.org) — libres, basées OpenStreetMap, sans clé API. Style **custom OKI** (JSON de style propre, dérivé du style Positron, re-teinté : mer bleu profond caraïbe, terre sable, végétation verte dense, labels sobres — pas le « bleu Google »). +- **Prod auto-hébergée** : `tileserver-gl` + extraits `.mbtiles` OpenStreetMap des 4 régions (Guadeloupe, Martinique, Guyane, La Réunion — quelques dizaines de Mo au total). Procédure dans `docs/deploiement.md`. Le style OKI accepte l'URL des tiles par variable d'environnement (`PUBLIC_TILES_URL`), bascule sans changement de code. +- **Contrainte géographique** : `maxBounds` = enveloppe union des 4 régions (≈ lon −63…57, lat −23…18) + `minZoom`, donc impossible de scroller en Europe/Amérique du Nord. 4 boutons « saut de région » (GUADELOUPE / MARTINIQUE / GUYANE / RÉUNION) replacent la vue sur la région. Limite connue : l'enveloppe rectangulaire inclut l'Atlantique tropical et le Brésil — inoffensif (aucun indice sur le lieu), documenté. +- Attribution © OpenStreetMap contributors affichée. + +## 3. Stratégie Wikipedia / Wikidata + +Principe : **rien de stocké en base**, interroge l'API en temps réel avec cache court, côté serveur uniquement. + +Endpoint serveur : `GET /api/wiki/[qid]` (ex. `Q3077840` = Fort Delgrès — l'exemple `Q2216838` du prompt initial était erroné, corrigé par l'Agent Contenu) + +1. `wbgetentities` sur `www.wikidata.org` → récupère le `sitelink` frwiki (et le libellé fr en fallback). +2. `GET https://fr.wikipedia.org/api/rest_v1/page/summary/{titre}` → `title`, `extract`, `content_urls`, `thumbnail`. +3. Réponse normalisée : `{ qid, title, extract, url, thumbnail, description }`. +4. Pas de sitelink fr ou erreur → `404` : le front bascule sur l'écran **Cas B « Pwen blindé »**. +5. **Cache** : `Map` en mémoire, TTL 24 h (+ `Cache-Control: max-age=3600`). User-Agent explicite (`JWE-OKI/x.y (contact)`) comme demandé par la politique Wikimédia. + +## 4. Arborescence du projet + +``` +JWE/ (dépôt existant — l'ancien PHP est conservé tel quel) +├── app/ ← nouvelle application SvelteKit 2 / Svelte 5 +│ ├── src/ +│ │ ├── lib/ +│ │ │ ├── server/ +│ │ │ │ ├── lieux.ts (accès données + sélection aléatoire + scoring) +│ │ │ │ └── data/lieux.json (corpus 40 lieux — serveur uniquement) +│ │ │ ├── components/ (GameMap, PhotoPanel, ResultPanel, ScoreCard…) +│ │ │ ├── i18n/ (fr.ts, gcf.ts, store) +│ │ │ ├── styles/oki.css (tokens couleurs OKI) +│ │ │ └── utils/ (score.ts, geo.ts) +│ │ ├── routes/ +│ │ │ ├── +layout.svelte (header, switch langue FR/CR) +│ │ │ ├── +page.svelte (accueil : 4 régions, modes, Jouer) +│ │ │ ├── jeu/[mode]/ (écran de jeu split photo/carte) +│ │ │ ├── explorer/ (mode Aprann : carte pleine page) +│ │ │ └── api/ +│ │ │ ├── round/+server.ts (GET : lieu aléatoire SANITISÉ) +│ │ │ ├── guess/+server.ts (POST : {placeId, lat, lon, hints, timeMs} → score + vérité) +│ │ │ ├── lieux/+server.ts (GET : catalogue sanitise pour Explorer) +│ │ │ └── wiki/[qid]/+server.ts (GET : extrait Wikipedia, cache 24 h) +│ │ ├── app.html / app.d.ts +│ │ └── service-worker.ts (PWA) +│ ├── static/ (manifest.webmanifest, icônes, photos éventuelles) +│ └── package.json / svelte.config.js / vite.config.ts +├── docs/ (architecture, déploiement, contribution, audit) +├── content/ (sources de travail de l'Agent Contenu : crédits photos) +└── projet_geoguessr_97x.md +``` + +## 5. Spécifications API REST (anti-triche) + +| Endpoint | Méthode | Payload | Réponse | +|---|---|---|---| +| `/api/round?region=&mode=&exclude=` | GET | — | `{ id, nom, nom_creole, categorie, difficulte, photo{url,credit,alt}, indices[] }` — **jamais** `coordonnees`, `commune`, `region`, `wikidata_id` | +| `/api/guess` | POST | `{ id, lat, lon, hintsUsed, timeMs? }` | `{ distanceKm, score, coordonnees, commune, region, nom, wikidata_id }` | +| `/api/lieux` | GET | — | Catalogue sanitise (sans coordonnées précises : coords arrondies à 0.05° pour l'affichage Explorer uniquement — mode sans score) | +| `/api/wiki/[qid]` | GET | — | `{ title, extract, url, thumbnail }` ou `404` | + +Règles : + +- Le scoring est **recalculé côté serveur** : `score = round(5000 × e^(−d/r))`, `r` selon difficulté du lieu (50/15/5/1 km), pénalité −10 %/indice, bonus temps ≤ +20 % plafonné à 5000. +- Distance : haversine. +- Le client ne reçoit la vérité (coordonnées, commune, wikidata_id) **qu'après** la soumission du marqueur. +- `exclude` : liste d'ids déjà joués (mode Défi 5 rounds, stateless — pas de session serveur nécessaire, pas de leaderboard). + +## 6. Décisions annexes + +- **Adapter** : `adapter-node` (auto-hébergement sobre derrière nginx/caddy). +- **PWA** : manifest + service worker minimal (cache app shell, photos en stale-while-revalidate). +- **i18n** : dictionnaires maison `fr` / `gcf` (créole), store Svelte, `lang` persistée en localStorage. +- **Photos** : URLs Wikimedia Commons (Special:FilePath, `?width=1200`) vérifiées CC par l'Agent Contenu ; `` + `srcset`. +- **A11y / calm tech** : `prefers-reduced-motion` respecté (pas de vol de marqueur), timer informatif non anxiogène, navigation clavier (carte : flèches déplacent le marqueur, Entrée valide). +- **Licence code** : MIT (le dépôt historique était AGPL — la refonte est un nouveau module `app/` sous MIT comme exigé par le prompt ; le `LICENSE` racine reste l'historique, un `app/LICENSE` MIT est ajouté). diff --git a/docs/contribution.md b/docs/contribution.md new file mode 100644 index 0000000..b5481f5 --- /dev/null +++ b/docs/contribution.md @@ -0,0 +1,87 @@ +# JWE — Guide de contribution : ajouter un lieu + +Le corpus de lieux vit dans `app/src/lib/server/data/lieux.json`, versionné dans Git. Ajouter un lieu = une pull request. La revue de PR sert de modération éditoriale (exactitude, crédits photo, licence). + +## 1. Règles d'or d'un bon lieu + +- **Photographiable et identifiable** : le lieu doit avoir une photo libre de qualité (Wikimedia Commons de préférence). +- **Localisé précisément** : coordonnées GPS au lieu près (le score Expert se joue à 1 km). +- **Éditorialement pertinent** : monument, paysage, lieu culturel, rue ordinaire… Le jeu mélange volontairement lieux célèbres et lieux du quotidien. +- **Lacunes assumées** : il est VOLONTAIRE d'inclure des lieux sans page Wikipédia (`wikidata_id: null`) — le jeu affiche alors un écran pédagogique « Pwen blindé » appelant à documenter le territoire. Mais c'est un choix, pas une négligence : vérifiez d'abord qu'aucune page/frwiki ni entité Wikidata n'existe. + +## 2. Schéma du lieu + +```json +{ + "id": "générez un uuid (uuidgen)", + "nom": "Fort Delgrès", + "nom_creole": "Fò Delgrès", + "region": "GUADELOUPE | MARTINIQUE | GUYANE | REUNION", + "commune": "Basse-Terre", + "coordonnees": { "lat": 16.0036, "lon": -61.7319 }, + "categorie": "MONUMENT | LIEU", + "difficulte": "FACILE | MOYEN | DIFFICILE | EXPERT", + "wikidata_id": "Q3077840", + "photo": { + "url": "https://commons.wikimedia.org/wiki/Special:FilePath/FICHIER?width=1200", + "credit": "© Auteur / Wikimedia Commons CC-BY-SA-4.0", + "alt": "Description précise (sert d'alternative textuelle)" + }, + "indices": [ + { "niveau": 1, "texte": "Indice doux" }, + { "niveau": 2, "texte": "Indice précis" } + ] +} +``` + +## 3. Trouver et lier l'identifiant Wikidata + +1. Cherchez le lieu sur https://www.wikidata.org +2. L'identifiant ressemble à `Q3077840`. +3. Vérifiez que l'entité a un lien vers une page **fr.wikipedia** (sitelink) — c'est ce qui permet au jeu d'afficher l'extrait de l'article : + +```bash +curl -s "https://www.wikidata.org/w/api.php?action=wbgetentities&ids=Q3077840&props=sitelinks&format=json" | grep frwiki +``` + +4. **Si le lieu n'a ni page Wikipédia ni entité Wikidata** : mettez `"wikidata_id": null`. C'est une contribution précieuse : le jeu transforme la lacune en appel à contribution. Mieux encore : créez l'entité Wikidata vous-même, puis revenez renseigner l'ID ! + +## 4. Choisir la photo (licence obligatoire) + +1. Cherchez sur https://commons.wikimedia.org une photo nette, paysage de préférence. +2. Licences acceptées : CC BY, CC BY-SA, CC0, domaine public. **Jamais** de « fair use ». +3. Vérifiez la licence et l'auteur via l'API : + +```bash +curl -s "https://commons.wikimedia.org/w/api.php?action=query&titles=File:NOM_DU_FICHIER&prop=imageinfo&iiprop=url|extmetadata&format=json" +``` + +4. L'URL dans le JSON utilise `Special:FilePath` avec `?width=1200` (redimensionnement à la volée côté Wikimedia — pas besoin d'héberger l'image). Testez qu'elle renvoie bien 200. +5. Reportez le crédit exact (auteur + licence) dans `photo.credit` ET dans `content/credits.md`. + +## 5. Valider avant la PR + +```bash +cd app +node -e "const l=require('./src/lib/server/data/lieux.json');console.log(l.length,'lieux')" +npm run check +``` + +Checklist de revue : + +- [ ] coordonnées cohérentes avec la commune déclarée +- [ ] `wikidata_id` vérifié (ou `null` justifié) +- [ ] licence photo CC vérifiée + crédit complet +- [ ] `alt` descriptif (accessibilité) +- [ ] 2 indices progressifs, sans donner la réponse +- [ ] `nom_creole` renseigné quand la forme créole est attestée (sinon, reprendre le nom français — ne pas inventer) + +## 6. Contribuer à Wikipédia / Wikidata (au-delà du jeu) + +Si vous ajoutez un lieu « Pwen blindé », envisagez de documenter le lieu vous-même : + +- Créer un compte et un brouillon d'article : https://fr.wikipedia.org/wiki/Aide:Brouillon +- Créer une entité Wikidata : https://www.wikidata.org/wiki/Wikidata:Main_Page +- Contacter les groupes Wikimédia locaux (Wikimédia France, groupes antillais/guyanais/réunionnais). + +Chaque entité créée enrichit Wikipédia, les cartes libres… et les futurs jeux comme JWE. diff --git a/docs/deploiement.md b/docs/deploiement.md new file mode 100644 index 0000000..1afe0d9 --- /dev/null +++ b/docs/deploiement.md @@ -0,0 +1,111 @@ +# JWE v2 — Guide de déploiement auto-hébergé + +Cible : un petit VPS (1 vCPU / 1 Go RAM suffit) sous Debian/Ubuntu, derrière nginx ou Caddy. Aucun service propriétaire, aucune clé API. + +## 1. Application SvelteKit + +```bash +# Prérequis : Node.js >= 20 (via nodesource ou nvm) +git clone https://codeberg.org/OKI/jwe.git +cd jwe/app +npm ci +npm run build # produit app/build (adapter-node) +``` + +Lancer en production (port 3000 par défaut) : + +```bash +PORT=3000 node build +``` + +Service systemd `/etc/systemd/system/jwe.service` : + +```ini +[Unit] +Description=JWE — jeu de géolocalisation OKI +After=network.target + +[Service] +Type=simple +User=jwe +WorkingDirectory=/srv/jwe/app +Environment=PORT=3000 +Environment=ORIGIN=https://jwe.o-k-i.net +Environment=PUBLIC_TILES_URL=https://tiles.o-k-i.net/styles/oki/style.json +ExecStart=/usr/bin/node build +Restart=on-failure + +[Install] +WantedBy=multi-user.target +``` + +## 2. Reverse proxy (exemple nginx) + +```nginx +server { + server_name jwe.o-k-i.net; + location / { + proxy_pass http://127.0.0.1:3000; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} +# + TLS via certbot +``` + +## 3. Tiles cartographiques auto-hébergées (tileserver-gl) + +Par défaut l'application utilise OpenFreeMap (libre, sans clé). Pour une souveraineté complète, hébergez vos propres tiles OSM des 4 régions. + +### 3.1 Récupérer les extraits OpenStreetMap + +```bash +mkdir -p /srv/tiles && cd /srv/tiles +# Guadeloupe, Martinique, Guyane : extraits Geofabrik +wget https://download.geofabrik.de/north-america/guadeloupe-latest.osm.pbf +wget https://download.geofabrik.de/north-america/martinique-latest.osm.pbf +wget https://download.geofabrik.de/south-america/french-guiana-latest.osm.pbf +# La Réunion +wget https://download.geofabrik.de/africa/reunion-latest.osm.pbf +``` + +### 3.2 Générer les .mbtiles + +Avec [openmaptiles](https://github.com/openmaptiles/openmaptiles) (Docker requis) : générez un `.mbtiles` par région puis fusionnez-les avec `tile-join` (paquet `tippecanoe`) : + +```bash +tile-join -o dom-tom.mbtiles guadeloupe.mbtiles martinique.mbtiles guyane.mbtiles reunion.mbtiles +``` + +(Alternative plus légère : extraire les 4 régions d'un `.mbtiles` Monde basse-résolution `tile-join --bbox=…` par région, puisque la carte de devinette n'a pas besoin d'un zoom très fin partout.) + +### 3.3 Servir avec tileserver-gl + +```bash +docker run --rm -d --name tiles -v /srv/tiles:/data -p 8080:8080 \ + maptiler/tileserver-gl dom-tom.mbtiles +``` + +Copiez le style OKI de l'application (`app/src/lib/map/style-oki.json`) dans `/srv/tiles/styles/oki/`, adaptez son URL de source vers votre `dom-tom.mbtiles`, puis : + +```bash +Environment=PUBLIC_TILES_URL=https://tiles.o-k-i.net/styles/oki/style.json +``` + +### 3.4 Fontes et sprites + +tileserver-gl sert aussi les fontes (glyphs) et sprites référencés par le style. Les fontes open-source utilisées par le style OKI (ex. Noto Sans) se récupèrent via `openmaptiles/fonts` ou `klokantech/tileserver-gl-fonts`. + +## 4. Cache Wikipedia + +Le endpoint `/api/wiki/[qid]` met en cache les extraits 24 h en mémoire. Aucune configuration requise ; pour un cache partagé entre instances, placez nginx en cache proxy devant `/api/wiki/` (respecte déjà `Cache-Control`). + +## 5. Mise à jour + +```bash +cd jwe && git pull && cd app && npm ci && npm run build +systemctl restart jwe +``` + +L'ajout de lieux (voir `docs/contribution.md`) ne demande qu'un rebuild + restart : le corpus est embarqué dans le build. diff --git a/projet_geoguessr_97x.md b/projet_geoguessr_97x.md new file mode 100644 index 0000000..a3e3937 --- /dev/null +++ b/projet_geoguessr_97x.md @@ -0,0 +1,254 @@ +Voici le prompt mis à jour. Les hésitations sur les librairies et les panoramas sont supprimées, et la dimension éducative/Wikipedia est intégrée comme un mécanisme de jeu à part entière (et non plus comme un simple fallback). + +--- + +``` +# Mission : JWE — Jeu de géolocalisation souverain type GeoGuessr +## Refonte complète · Svelte + Strapi/SvelteKit · MapLibre · Photos uniques · Éducation Wikipedia + +--- + +## 1. Contexte et ambition + +### 1.1 Projet source +- **URL actuelle** : https://labola.o-k-i.net/ORGANISATION-KA-INTERNATIONALE/JWE +- **Objet** : refonte complète pour en faire un jeu de géolocalisation dans l'esprit de GeoGuessr, centré sur 4 régions : **Guadeloupe, Martinique, Guyane, La Réunion**. + +### 1.2 Mécanique de jeu verrouillée +- **Pas de Street View, pas de panoramas, pas de 3D.** +- Le joueur voit une **photo unique** d'un lieu (monument, paysage, rue, lieu culturel). +- Il doit placer un marqueur sur une carte pour deviner **la commune** (et par déduction la région). +- Le score est calculé selon la distance entre le marqueur et les coordonnées réelles. +- Après le score : phase éducative basée sur **Wikipedia/Wikidata** (voir §1.3). + +### 1.3 Le pivot éducatif : Wikipedia/Wikidata comme cœur du jeu +JWE n'est pas qu'un jeu de score, c'est un outil de **souveraineté documentaire**. +- Si le lieu photographié possède une page Wikipedia : afficher un extrait de l'article, ses coordonnées Wikidata, et un lien "Lire plus sur Wikipédia". +- **Si le lieu n'a PAS de page Wikipedia ou de données Wikidata** : c'est intentionnel et pédagogique. Le jeu doit afficher un écran spécifique expliquant : + 1. Pourquoi ce lieu n'est pas sur Wikipedia (lacune documentaire). + 2. Pourquoi il est vital que les populations locales documentent leurs propres territoires (représentation numérique, décolonisation du savoir, importance pour les modèles d'IA qui s'entraînent sur ces données, tourisme, transmission). + 3. Un appel à l'action : "Contribuer sur Wikipédia" avec un lien vers l'éditeur Wikipédia pré-rempli (ou des liens vers des tutos OKI/Wikimédiens locaux). +- **L'Agent Contenu doit intentionnellement inclure des lieux sans page Wikipedia** pour tester et démontrer cette fonctionnalité. + +### 1.4 Cible OKI +- **Souverain** : zéro Google, zéro Mapbox. Carte MapLibre + tiles libres. +- **Éthique** : pas de loot boxes, pas de leaderboard forcé, pas d'anxiété. +- **Performant** : jouable sur téléphone en 4G caribéen. +- **Bilingue** : français / créole pour l'interface. + +--- + +## 2. Stack technique (Verrouillée) + +### 2.1 Front-end : Svelte 5 + SvelteKit 2 +- Obligatoire. Compilateur léger, CSS scopé natif, SSR, MIT, PWA. + +### 2.2 Cartographie : MapLibre GL JS (Verrouillé) +- **Obligatoire.** Pas d'évaluation de Cesium, iTowns ou Three.js à faire. +- MapLibre pour la carte de devinette (placement du marqueur) et la carte récapitulative. +- Style cartographique custom OKI (couleurs, fonts, labels) basé sur des tiles OpenStreetMap auto-hébergées ou libres. +- Zoom contraint aux 4 régions (le joueur ne peut pas scroller la carte en Europe ou aux US, ce qui donnerait un indice). + +### 2.3 Back-end : Strapi ou SvelteKit seul (L'Architecte décide) +- **Critère** : qui ajoute les lieux ? Si contributeurs non-devs → Strapi. Si devs uniquement → SvelteKit avec fichiers JSON locaux. +- **Contrainte Wikipedia** : Ne **pas** stocker le texte Wikipedia en base. Le back-end (Strapi ou SvelteKit) doit interroger l'API Wikipedia/Wikidata en temps réel (ou avec un cache court) lors de l'affichage du résultat, à partir de l'ID Wikidata lié au lieu. + +### 2.4 Base de données +- SQLite (frugalité OKI). + +--- + +## 3. Design du jeu + +### 3.1 Types de parties (Modes) + +#### Mode 1 : « Konnèt moniman » (Reconnaître le monument) +- Photo d'un monument. Deviner la commune. +- Pas de limite de temps par défaut. Option timer activable. +- Indices progressifs optionnels (Région → Département → "C'est un fort colonial") avec pénalité de score. + +#### Mode 2 : « Kote mwen ye ? » (Où suis-je ?) +- Photo d'un lieu ordinaire (rue, carrefour, bord de mer, forêt guyanaise). +- Deviner la commune. Timer optionnel. + +#### Mode 3 : « Défi 5 rounds » +- 5 tours consécutifs mélangeant monuments et lieux. +- Résumé final avec la carte montrant les 5 marqueurs vs positions réelles. + +#### Mode 4 : « Aprann » (Explorer) +- Pas de score. Parcourir la carte, cliquer sur les marqueurs, voir les photos et lire les fiches Wikipedia / les appels à contribution. + +### 3.2 Système de score + +#### Formule (adaptée à la taille des communes) +Les communes DOM sont petites. Un écart de 2 km peut signifier "à côté" ou "dans la commune d'à côté". +``` +score = MAX_POINTS × e^(-distance / radius) +``` +- `MAX_POINTS` = 5000. +- `radius` par difficulté : + - Facile : 50 km (tu peux te tromper de commune voisine) + - Moyen : 15 km (tu dois être dans la bonne commune) + - Difficile : 5 km (tu dois être dans le bon quartier) + - Expert : 1 km (précision rue) + +#### Bonus / Pénalités +- Bonus temps (si activé) : max 20%. +- Pénalité indice : -10% par indice utilisé. + +### 3.3 Schéma de données d'un lieu + +```json +{ + "id": "uuid", + "nom": "Fort Delgrès", + "nom_creole": "Fò Delgrès", + "region": "GUADELOUPE", + "commune": "Basse-Terre", + "coordonnees": { "lat": 16.0036, "lon": -61.7319 }, + "categorie": "MONUMENT", + "difficulte": "MOYEN", + "wikidata_id": "Q2216838", + "photo": { + "url": "/assets/fort-delgres.webp", + "credit": "© Collectif OKI / Wikimedia Commons CC-BY-SA", + "alt": "Vue de face du Fort Delgrès en pierre grise surplombant la mer" + }, + "indices": [ + { "niveau": 1, "texte": "Situé dans une capitale régionale" }, + { "niveau": 2, "texte": "C'est un fort historique face à la mer" } + ] +} +``` +*Note : Le texte éducatif vient de l'API Wikipedia via `wikidata_id`. Si `wikidata_id` est null, le front déclenche le mode "Lacune documentaire".* + +--- + +## 4. Répartition des tâches par agent + +### Agent Architecte (exécute en premier) +**Sorties attendues** : +1. **Décision Strapi vs SvelteKit seul** (argumentée). +2. **Architecture des tiles** : Source des tiles MapLibre (style OKI, auto-hébergé via tileserver-gl). +3. **Stratégie Wikipedia/Wikidata** : Comment le front/back récupère l'extrait Wikipedia en français à partir du `wikidata_id`. Endpoints API MWAPI à utiliser, stratégie de cache. +4. **Arborescence du projet** complète. +5. **Spécifications API REST** (sécurité anti-triche : ne jamais envoyer les coordonnées au client avant la soumission du marqueur). + +### Agent Back-end (si Strapi retenu) +**Tâches** : +1. Strapi sur SQLite, zéro telemetry. +2. Content Type `Lieu` (schéma ci-dessus). +3. Endpoints custom sécurisés (random sans coordonnées, soumission guess). +4. Mise en place d'un proxy/cache léger pour les requêtes Wikipedia (pour ne pas se faire bloquer par l'API Wikimédia et accélérer l'affichage). + +### Agent Front-end (SvelteKit) — Le cœur du projet +**Tâches** : + +#### 4.1 Carte MapLibre +- Intégration de MapLibre GL JS. +- Style custom OKI (couleurs, typographie). +- Zoom contraint aux 4 régions (bounds géographiques stricts). +- Marqueur draggable pour la devinette. +- Boutons zoom +/- visibles (pas de geste obligatoire). +- Performance : lazy load de MapLibre (ne charger le JS que sur les écrans de jeu). + +#### 4.2 L'Écran de jeu (Layout split) +- **Mobile** : Photo en haut (60%), Carte en bas (40%), Bouton "Valider" fixe en zone du pouce (tiers inférieur). +- **Desktop** : Photo à gauche (50%), Carte à droite (50%). +- Timer discret si activé (cercle qui se vide, couleurs douces). +- Bouton "Valider ma position" (action primaire unique, effet Von Restorff). +- Bouton "Passer" (secondaire). +- Bouton "Indice" (tertiaire, affiche le texte et la pénalité). + +#### 4.3 L'Écran de résultat (CRUCIAL : Phase éducative) +Après validation, le marqueur vole vers la position réelle (sauf si `prefers-reduced-motion`). + +**Cas A : Le lieu a un `wikidata_id` (Données existantes)** +- Afficher le score et la distance. +- Afficher un panneau éducatif contenant : + - Titre du lieu (lien vers la page Wikipedia). + - Extrait de l'article Wikipedia (récupéré via API). + - Commune et Région. +- Ton : "Tu as trouvé ! Apprends-en plus sur ce lieu." + +**Cas B : Le lieu n'a PAS de `wikidata_id` (Lacune documentaire)** +- Afficher le score et la distance. +- Afficher un panneau **distinct visuellement** (couleur différente, iconographie spécifique) avec un message pédagogique fort : + - *Titre* : "Pwen blindé — Sa pa dokimanté" (Point aveugle — Ce n'est pas documenté). + - *Texte (FR)* : "Ce lieu existe, mais il n'a pas de page sur Wikipédia ni de fiche sur Wikidata. Pour nos régions, c'est un enjeu majeur : si nous ne documentons pas nos propres territoires, notre histoire et notre géographie disparaissent des cartes numériques et des bases de données mondiales (qui alimentent même l'intelligence artificielle)." + - *Texte (CRÉOLE)* : (Équivalent en créole, à intégrer via le système i18n). + - *Call to action* : Bouton "Kontribyé sou Wikipédia" (lien vers l'éditeur Wikipédia avec le titre du lieu pré-rempli dans la barre de recherche, ou lien vers un guide OKI "Comment contribuer à Wikipédia"). +- **Soigner particulièrement cet écran (Peak-End rule de la doctrine OKI)** : c'est ici que le jeu devient un outil politique et éducatif, pas juste un divertissement. + +#### 4.4 Écrans annexes +- **Accueil** : Titre "JWE", 4 cartes régions, choix du mode, bouton "Jouer" en zone pouce. +- **Résultat final** : Carte récapitulative, score total, bouton "Partager" (génère une image canvas à télécharger, pas de share API propriétaire). +- **Explorer** : Carte pleine page avec marqueurs, filtres par région, panneau latéral/bottom sheet avec la fiche Wikipedia ou le message de lacune. + +#### 4.5 Technique +- PWA installable. +- Photos en WebP/AVIF, `srcset`, lazy loading. +- Navigation clavier sur la carte. +- i18n (FR / Créole) pour toute l'UI. + +### Agent Contenu (exécute en parallèle) +**Tâches** : +1. Produire un **JSON de test de 40 lieux** (10/region). +2. **PIÈGE INTENTIONNEL** : Pour chaque région, inclure **2 à 3 lieux réels qui n'ont PAS de page Wikipedia française** (ex: une petite ravine en Guyane, un morne spécifique en Martinique, un calvaire ou une boutique historique en Guadeloupe, un site naturel à La Réunion). Laisser leur `wikidata_id` à `null` dans le JSON. +3. Pour les 7-8 autres lieux par région : fournir le vrai `wikidata_id` (ex: Q2216838 pour Fort Delgrès). +4. Fournir les URLs de photos Wikimedia Commons réelles (vérifier la licence CC). + +### Agent Intégration & QA +**Tâches** : +1. Vérifier l'intégration MapLibre + API Lieux + API Wikipedia. +2. **Tester spécifiquement le Cas B (Lacune documentaire)** : vérifier que le message s'affiche correctement, que le ton est bon, que le lien de contribution fonctionne. +3. Jouer une partie complète. +4. **Checklist d'audit OKI** : + - [ ] Une seule action primaire par écran + - [ ] Mobile : bouton Valider en zone du pouce, carte utilisable au doigt + - [ ] Performance : premier écran < 3s, MapLibre lazy-loadé + - [ ] Éthique : pas de mécanique dopaminergique, score non punitif + - [ ] Éducation : les deux cas (Wiki OK / Wiki Manquant) fonctionnent et sont distincts visuellement + - [ ] Bilinguisme FR/créole présent (y compris dans le message de lacune) + - [ ] PWA installable +5. Mesures Core Web Vuts mobile 4G. + +--- + +## 5. Doctrine UI/UX OKI (Extraits applicables) + +- **Système 1** : L'écran de jeu est immédiatement lisible (Photo | Carte | Valider). +- **Von Restorff** : Le bouton "Valider" est le seul élément fortement coloré. +- **Peak-End** : L'écran de résultat (avec la fiche Wiki ou l'appel à contribution) doit laisser une impression forte et positive. C'est la fin du round, c'est ce dont le joueur se souviendra. +- **Calm technology** : Le timer est informatif, pas anxiogène. +- **Territoire** : Le créole est utilisé dans les micro-interactions ("Bravo !", "Kité sa ye ?", "Pwen blindé"). Les visuels de la carte ne sont pas le default bleu Google, mais un style OKI ancré dans le territoire. + +--- + +## 6. Contraintes transversales + +- **Licence** : MIT pour le code. Crédits obligatoires pour les photos Wikimedia. +- **Zéro dépendance propriétaire** : MapLibre (BSD), Svelte (MIT). Aucune clé API payante. +- **Sécurité** : Les coordonnées réelles ne sont jamais dans le payload initial envoyé au client. +- **Git** : Commits atomiques. + +--- + +## 7. Ordre d'exécution + +1. **Agent Architecte** → Stack, Schema, Stratégie Wiki/MapLibre. +2. **Agent Contenu** → JSON des 40 lieux (avec le piège Wiki manquant). +3. **Agent Back-end** (si Strapi). +4. **Agent Front-end** → SvelteKit, MapLibre, Mécanique de score, Écrans éducatifs (Cas A & B). +5. **Agent QA** → Audit, test du message de lacune documentaire, rapport. + +--- + +## 8. Livrables finaux + +1. Dépôt Git complet. +2. JSON de 40 lieux (avec la structure `wikidata_id: null` pour tester la lacune). +3. Rapport d'audit OKI. +4. Guide de déploiement auto-hébergé (SvelteKit + Tile Server). +5. Guide de contribution ("Comment ajouter un lieu et lier sa page Wikidata"). +```