docs: mission, decisions d'architecture, guides de deploiement et contribution

This commit is contained in:
sucupira
2026-07-16 21:05:22 -04:00
parent fbd6527d07
commit 8a9bec0143
4 changed files with 546 additions and 0 deletions
+94
View File
@@ -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 ; `<img loading="lazy">` + `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é).
+87
View File
@@ -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.
+111
View File
@@ -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.
+254
View File
@@ -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").
```