Files
echo-du-huit/docs/RECHERCHE.md
Pierre Martin 328df2d181 Initialise le projet : documentation et squelette
Extension Firefox pour publier une sélection d'événements du calendrier
Nextcloud de L'Atelier du Huit vers l'agenda de la mairie de Cugnaux.

- README : vue d'ensemble et installation
- CLAUDE.md : guide agent et contraintes structurantes
- docs/RECHERCHE.md : faits techniques vérifiés (CalDAV, formulaire, agenda, ICS)
- docs/DECISIONS.md : choix d'architecture et leur pourquoi
- package.json : Bun comme outil de dev minimaliste (pas de build au runtime)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 23:40:13 +02:00

126 lines
5.3 KiB
Markdown

# Recherche technique — faits vérifiés (2026-06-29)
Document de référence pour l'implémentation. Toutes les valeurs ci-dessous sont
**vérifiées sur le HTML/ICS réel**, pas supposées. Re-vérifier si > 6 mois.
---
## 1. Source : calendrier Nextcloud (CalDAV)
- **URL** : `https://atelier-huit.frama.space/remote.php/dav/calendars/Pierre/latelier-du-huit-sbastien_shared_by_admin/?export`
- **Auth** : session navigateur (cookies). Depuis l'extension → `fetch(url, { credentials: 'include' })` + `host_permissions` sur `https://atelier-huit.frama.space/*`. **Aucun mot de passe stocké.**
- **Réponse** : flux iCalendar brut (VCALENDAR/VEVENT).
- Si non connecté → la requête échoue : prévoir un message "connecte-toi à Nextcloud dans un onglet".
### Cas limites du flux réel (échantillon 2026-06-29, 473 VEVENT)
| Réalité | Chiffre | Conséquence parsing |
|---|---|---|
| VEVENT total | 473 | |
| UID **uniques** | 381 | **Dédoublonner par UID** (récurrences = même UID répété) |
| Récurrents (RRULE) | 54 | Gérer/ignorer les occurrences passées |
| Journée entière (`DTSTART;VALUE=DATE`) | 7 | **Pas d'heure** → le formulaire mairie attend une heure : cas à traiter |
| Avec LOCATION | 51 / 473 | La **majorité n'a pas de lieu** → défaut = adresse du café |
| Avec DESCRIPTION | 142 / 473 | La majorité n'a pas de description → champ souvent vide |
| Fuseaux | `Europe/Paris` **mais aussi `Africa/Lagos`** | Ne PAS supposer Europe/Paris : lire le vrai `TZID` |
> Recommandation parsing : `ical.js` (Mozilla) plutôt que regex maison — gère RRULE, TZID, VALUE=DATE.
---
## 2. Cible : formulaire mairie (Gravity Forms, form id = 6)
URL : `https://www.ville-cugnaux.fr/mes-loisirs/associations/proposer-un-evenement-dans-lagenda/`
### Stratégie de soumission
Content script qui **remplit le DOM par id**, puis **l'utilisateur soumet à la main**.
- Pas de params URL : Gravity Forms n'accepte `?input_X=` que si "population dynamique" est activé par champ côté mairie (non).
- Les tokens CSRF (`gform_currency`, `state_6`, `version_hash`) sont **dans la page** et gérés par le formulaire lui-même : on n'y touche pas. ⚠️ Les tokens du curl capturé sont **par session, non réutilisables**.
### Mapping des champs (ids confirmés présents dans le HTML)
| id DOM | name | Contenu | Source |
|---|---|---|---|
| `#input_6_42` | `input_42` | Organisateur | config (« L'Atelier du Huit ») |
| `#input_6_41` | `input_41` | Email | config |
| `#input_6_1` | `input_1` | Titre | SUMMARY |
| `#input_6_3` | `input_3` | Description (textarea) | DESCRIPTION |
| `#input_6_20` | `input_20` | Thème (select) | mapping (voir §3) |
| `#input_6_31` | `input_31` | Date début `jj/mm/aaaa` | DTSTART |
| `#input_6_32` | `input_32` | Date fin `jj/mm/aaaa` | DTEND |
| `#input_6_38_1` / `#input_6_38_2` | `input_38[]` | Heure début [HH, MM] | DTSTART |
| `#input_6_39_1` / `#input_6_39_2` | `input_39[]` | Heure fin [HH, MM] | DTEND |
| `#input_6_35` (`_1`) | `input_35.1` | Accessibilité (case) | fixe |
| `#input_6_36` | `input_36` | Public ciblé | optionnel |
| `#input_6_40` | `input_40` | Tarifs | défaut « Gratuit » |
| `#nova_address` | `nova_address` | Adresse texte | défaut café |
| `#input_6_18` | `input_18` | `lat\|lng\|adresse` (hidden) | défaut café |
| `#input_6_34` | `input_34` | **Image (file)** | ⚠️ non remplissable par script (sécurité) → manuel |
| `#input_6_23`, `#input_6_43` | | Honeypot | laisser vide |
**Défaut café** : `8 Rue du Pré Vicinal 31270 Cugnaux`
`input_18` = `43.53753132806989|1.342981890597508|8 Rue du Pré Vicinal 31270 Cugnaux`
---
## 3. Valeurs exactes du dropdown Thème (`#input_6_20`)
Chaînes `value` à utiliser telles quelles :
```
Culture
Atelier - Stage
Economie - Emploi
Exposition
Photographie
Rencontre
Spectacle
Enfance - Jeunesse
Jeunesse
Parentalité
Petite enfance
Scolarité
Loisirs
Mobilité
Nature - Environnement
Numérique
Participation citoyenne
Cérémonies officielles
Réunion publique
Santé
Seniors
Solidarité
Sport
```
> Le calendrier Nextcloud n'a pas de thème → prévoir un choix par l'utilisateur dans l'UI, défaut « Culture ».
---
## 4. Vérification publication (agenda public mairie)
URL filtrée par mois :
`https://www.ville-cugnaux.fr/mes-loisirs/agenda/?f=1&theme=&date=periode&date_debut=MM%2FYYYY&date_fin=MM%2FYYYY&public=`
### Structure HTML d'un résultat (confirmée)
Chaque événement publié = `<div class="card card-thumbnail card-event ...">` contenant :
- **Date** : `<time datetime="YYYY-MM-DD">` (ancre de match la plus fiable)
- **Lien direct** : `<a href="https://www.ville-cugnaux.fr/agenda/<slug>/">` — c'est le lien à afficher dans l'extension
- **Titre** : `.card-title > a`
- **Thème** : classe `event_theme-<slug>`
Exemples de liens réels observés : `/agenda/spectacle-jhabite-ici/`, `/agenda/atelier-bebe-gym/`, `/agenda/fete-du-14-juillet-inscription-au-repas-republicain/`.
### Matching Nextcloud ↔ mairie
Comparer **date** (`<time datetime>` vs DTSTART) **+ titre** (normalisé : sans accents/emojis, ou via le slug). Tolérer les écarts mineurs.
---
## 5. Modèle de statut (rappel)
- **ignoré** / **soumis:AAAA-MM-JJ** → tag `CATEGORIES` écrit en CalDAV (partagé, durable)
- **publié** → **dérivé** de l'agenda mairie (§4), donne le lien direct
- **à faire** → futur, ni ignoré, ni soumis, ni publié