first commit
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
# Activer Code scanning (CodeQL) sur GitHub
|
||||
|
||||
Le workflow [.github/workflows/security.yml](../.github/workflows/security.yml) exécute l’analyse CodeQL pour JavaScript/TypeScript.
|
||||
|
||||
## Comportement actuel
|
||||
|
||||
L’étape `analyze` utilise `upload: false` pour éviter les erreurs lorsque **GitHub Advanced Security / Code scanning** n’est pas encore activé sur le dépôt, ou lorsque les permissions d’upload SARIF ne sont pas disponibles.
|
||||
|
||||
## Activer les résultats dans l’UI GitHub
|
||||
|
||||
1. Sur GitHub : **Settings** → **Code security** (ou **Security** → **Code scanning** selon l’interface).
|
||||
2. Activez **Code scanning** avec le moteur CodeQL (ou laissez les workflows recommandés détecter `.github/workflows/security.yml`).
|
||||
3. Éditez `security.yml` et **supprimez** la ligne suivante dans l’étape `analyze` :
|
||||
|
||||
```yaml
|
||||
upload: false
|
||||
```
|
||||
|
||||
Le comportement par défaut rétablit l’upload des résultats SARIF vers GitHub.
|
||||
|
||||
## Pull requests depuis des forks
|
||||
|
||||
Sur les PR issues de forks, l’upload SARIF peut être restreint pour des raisons de permissions ; le workflow conserve dans ce cas une analyse locale utile sans bloquer la contribution.
|
||||
@@ -0,0 +1,76 @@
|
||||
# Checklist lancement V1 (Ben-to)
|
||||
|
||||
Document opérationnel aligné sur le dépôt : contenu embarqué, qualité, déploiement web, Android / Play Store.
|
||||
|
||||
## 1. Contenu et assets
|
||||
|
||||
- Finaliser les `.bentext` et visuels sous `ressources/` (sprites ingrédients : `ingredient-sprites.bentext` + `ingredients.png`, voir README).
|
||||
- `npm run pipeline:recipes` puis `npm run build:web` — vérifier `apps/web/dist/recipes/catalog.json`.
|
||||
|
||||
## 2. Qualité (gel avant release)
|
||||
|
||||
À la racine du dépôt :
|
||||
|
||||
```bash
|
||||
npm run pipeline:recipes
|
||||
npm run test:ci
|
||||
npm run check:quality
|
||||
```
|
||||
|
||||
Prérequis e2e : navigateurs Playwright (`npx playwright install chromium` si besoin).
|
||||
|
||||
## 3. Web — image Docker et smoke tests
|
||||
|
||||
Build image (identique à une prod type CapRover servant le `dist`) :
|
||||
|
||||
```bash
|
||||
docker build -t ben-to-web:local .
|
||||
docker run --rm -p 8080:3000 ben-to-web:local
|
||||
```
|
||||
|
||||
Smoke manuel (adapter le port) :
|
||||
|
||||
- Page d’accueil charge le builder.
|
||||
- Une URL recette du type `http://localhost:8080/r/<baseId>/<variantId>` ouvre la fiche (IDs présents dans `catalog.json`).
|
||||
- Pages légales : `/a-propos`, `/cgu`, `/mentions-legales`, `/confidentialite`.
|
||||
- SEO fichiers statiques : `/robots.txt` et `/sitemap.xml` pointent vers **[https://ben-to.fr](https://ben-to.fr)** ; les langues passent par l’UI (pas d’URL `/fr/` dédiées).
|
||||
|
||||
## 4. Android — build et signature release
|
||||
|
||||
Chaîne locale :
|
||||
|
||||
```bash
|
||||
npm run pipeline:recipes
|
||||
npm run build:web
|
||||
npm run mobile:sync
|
||||
```
|
||||
|
||||
Signature Play Store :
|
||||
|
||||
1. Créer un keystore (une fois), le placer sous `apps/mobile/android/` (ex. `release.keystore`).
|
||||
2. Copier `apps/mobile/android/keystore.properties.example` → `keystore.properties` et renseigner mots de passe / alias (fichier non versionné).
|
||||
3. Dans Android Studio : **Build > Generate Signed Bundle / APK** ou en CLI `./gradlew bundleRelease` depuis `apps/mobile/android`.
|
||||
|
||||
Sans `keystore.properties`, le type `release` n’applique pas la signature upload — utiliser `bundleDebug` pour tests internes uniquement.
|
||||
|
||||
Tests physiques recommandés : navigation builder, **partager** (plugin Capacitor), lien `/r/...` après navigation vers la recette.
|
||||
|
||||
Retirer tout mode `server.url` / cleartext dans `apps/mobile/capacitor.config.ts` utilisé pour le dev LAN avant publication.
|
||||
|
||||
## 5. Google Play — métadonnées
|
||||
|
||||
- Compte développeur Play Console.
|
||||
- Descriptions, captures d’écran téléphone, icône / feature graphic selon gabarits Google.
|
||||
- Formulaire **sécurité des données** : refléter la réalité (ex. analytics dans `apps/web/src/infra/analytics.ts`, stockage local).
|
||||
- URL **politique de confidentialité** si la déclaration l’exige.
|
||||
- Incrémenter `versionCode` / `versionName` dans `apps/mobile/android/app/build.gradle` pour chaque dépôt Play.
|
||||
|
||||
## 6. CI — artefact Android
|
||||
|
||||
Le workflow `.github/workflows/mobile-release.yml` construit un **AAB debug** (sans keystore Play) pour valider la chaîne Gradle ; la publication production reste signée localement ou via secrets CI ultérieurs.
|
||||
|
||||
## Hors périmètre V1 assumé
|
||||
|
||||
- Pas de compte cloud ni synchro serveur utilisateur : catalogue embarqué, mises à jour par nouvelles versions.
|
||||
- iOS : traiter dans une release dédiée (compte Apple Developer, Xcode).
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Matomo et consentement cookies
|
||||
|
||||
## Activation Matomo
|
||||
|
||||
Le chargement de `matomo.js` et toute mesure d’audience ne sont possibles que si **les deux** variables Vite suivantes sont définies au build :
|
||||
|
||||
|
||||
| Variable | Exemple | Rôle |
|
||||
| --------------------- | -------------------------------- | ---------------------------------------------------------------------------------------- |
|
||||
| `VITE_MATOMO_URL` | `https://analytics.example.com/` | URL du répertoire hébergeant `matomo.js` (slash final recommandé ; il est ajouté sinon). |
|
||||
| `VITE_MATOMO_SITE_ID` | `1` | Identifiant du site dans Matomo. |
|
||||
|
||||
|
||||
Sans ces variables, aucune mesure Matomo n’est initialisée (même après acceptation du bandeau).
|
||||
|
||||
Le **bandeau cookies** s’affiche toutefois dès qu’aucun choix n’est stocké dans `localStorage`, afin de recueillir le consentement avant toute activation possible du tracker.
|
||||
|
||||
Copier `apps/web/.env.example` vers `apps/web/.env.local` pour les essais locaux avec Matomo réel.
|
||||
|
||||
### Image Docker / CapRover
|
||||
|
||||
Les mêmes variables doivent être disponibles **pendant** `npm run build:web`. Le `Dockerfile` expose des `ARG` (valeurs vides par défaut) puis les recopie en `ENV` avant le build, sur le même principe que `PUBLIC_*` sur un autre projet.
|
||||
|
||||
Exemple en local :
|
||||
|
||||
```bash
|
||||
docker build \
|
||||
--build-arg VITE_MATOMO_URL=https://analytics.example.com/ \
|
||||
--build-arg VITE_MATOMO_SITE_ID=1 \
|
||||
-t ben-to-web .
|
||||
```
|
||||
|
||||
Sur CapRover, configurer les **build arguments** équivalents pour l’image (pas seulement les variables d’environnement runtime du conteneur).
|
||||
|
||||
## Comportement
|
||||
|
||||
1. Premier chargement : si aucun choix n’est enregistré dans `localStorage` (clé `ben-to-cookie-consent-v1`), le **bandeau** s’affiche.
|
||||
2. **Accepter** : enregistrement du consentement ; si Matomo est configuré, chargement asynchrone de `matomo.js`, puis suivi des pages vues (SPA incluse) et des événements (`trackEvent` dans `apps/web/src/infra/analytics.ts`).
|
||||
3. **Refuser** : pas de chargement du script ; pas de cookies / hits Matomo.
|
||||
|
||||
Le choix est persisté localement ; pour retester le bandeau, supprimer la clé dans les outils développeur ou utiliser une fenêtre privée.
|
||||
|
||||
## Liens utiles
|
||||
|
||||
- Package consent pur : `@ben-to/privacy/cookie-consent`
|
||||
- Issue produit / conformité : [#39](https://github.com/kazerlelutin/ben-to/issues/39)
|
||||
@@ -0,0 +1,99 @@
|
||||
# En-têtes de sécurité et Content-Security-Policy
|
||||
|
||||
L'application web est durcie par défaut via le plugin Vite [`apps/web/vite-plugin-csp.ts`](../apps/web/vite-plugin-csp.ts). Il injecte une **Content-Security-Policy** dans le HTML de chaque page (et un `serve.json` en build) et émet plusieurs en-têtes de sécurité complémentaires.
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
| En-tête | Valeur | Émis par |
|
||||
| --- | --- | --- |
|
||||
| `Content-Security-Policy` | `default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self'; connect-src 'self'; media-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; frame-src 'none'` | Plugin Vite (dev + build) |
|
||||
| `X-Content-Type-Options` | `nosniff` | Plugin Vite |
|
||||
| `Referrer-Policy` | `strict-origin-when-cross-origin` | Plugin Vite |
|
||||
| `X-Frame-Options` | `DENY` | Plugin Vite |
|
||||
| `Permissions-Policy` | `accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()` | Plugin Vite |
|
||||
|
||||
En **build de production**, le plugin écrit en plus `dist/serve.json` ; le serveur statique `serve` (cf. [`Dockerfile`](../Dockerfile) : `CMD ["serve", "-s", "dist", "-l", "3000"]`) applique les en-têtes déclarés.
|
||||
|
||||
En **dev** (Vite), le plugin injecte la CSP via `<meta http-equiv="Content-Security-Policy">` **et** pose les en-têtes de réponse via un middleware Connect. La CSP dev assouplit `script-src` et `style-src` avec `'unsafe-inline'` + `'unsafe-eval'`, et `connect-src` avec `ws:` / `wss:` pour ne pas casser HMR.
|
||||
|
||||
## Adapter la CSP à Matomo
|
||||
|
||||
Le serveur Matomo est optionnel (cf. [matomo-analytics.md](matomo-analytics.md)). Quand `VITE_MATOMO_URL` est défini au build, son origine est ajoutée à `script-src`, `connect-src` et `img-src` :
|
||||
|
||||
```bash
|
||||
# Build local avec Matomo
|
||||
VITE_MATOMO_URL=https://analytics.example.com/ \
|
||||
npm run build:web
|
||||
```
|
||||
|
||||
La CSP générée ressemblera à :
|
||||
|
||||
```
|
||||
default-src 'self';
|
||||
script-src 'self' 'https://analytics.example.com';
|
||||
style-src 'self';
|
||||
img-src 'self' 'https://analytics.example.com';
|
||||
font-src 'self';
|
||||
connect-src 'self' 'https://analytics.example.com';
|
||||
media-src 'self';
|
||||
object-src 'none';
|
||||
base-uri 'self';
|
||||
form-action 'self';
|
||||
frame-ancestors 'none';
|
||||
frame-src 'none'
|
||||
```
|
||||
|
||||
Sans `VITE_MATOMO_URL`, **aucune origine externe** n'est ajoutée : la surface d'attaque est minimale.
|
||||
|
||||
> **Pourquoi `script-src` autorise `'self'` sans `unsafe-inline` en prod ?** Vite produit un bundle compilé référencé via `<script type="module" src="/assets/...">` (même origine). Aucun script inline n'est généré. Le plugin Matomo injecte un script dynamiquement (cf. [`apps/web/src/infra/matomo.ts`](../apps/web/src/infra/matomo.ts)) : l'URL cible `https://<host Matomo>/matomo.js`, couverte par l'origine ajoutée à `script-src`.
|
||||
>
|
||||
> **Pourquoi `style-src` autorise `'unsafe-inline'` en prod ?** Solid pose des styles inline (`<span style="...">`) sur des nœuds existants (cf. `SpriteTile.tsx`). La directive `style-src` vise les `<style>` statiques et les `style="..."` du HTML, donc l'autorisation est nécessaire. Si on veut durcir davantage à l'avenir : extraire les styles inline vers des classes CSS et passer à `style-src 'self'` strict, ou utiliser des hash/nonces `style-src-attr 'sha256-…'`.
|
||||
|
||||
## Vérification manuelle
|
||||
|
||||
```bash
|
||||
# 1) Build et smoke test local
|
||||
npm run pipeline:recipes
|
||||
npm run build:web
|
||||
npx serve -s apps/web/dist -l 3000 &
|
||||
sleep 1
|
||||
|
||||
# 2) Vérifier les en-têtes
|
||||
curl -sI http://localhost:3000/ | grep -Ei 'content-security-policy|x-frame|x-content|referrer|permissions'
|
||||
|
||||
# 3) Vérifier la balise meta dans une page recette
|
||||
curl -s http://localhost:3000/r/base%3Aonigiri/variant%3Aonigiri-kimchi-mozza \
|
||||
| grep -i 'http-equiv="Content-Security-Policy"'
|
||||
|
||||
# 4) Vérifier que dist/serve.json est correct
|
||||
cat apps/web/dist/serve.json
|
||||
```
|
||||
|
||||
Côté navigateur, onglet **Network** → sélectionner la requête du document → panneau **Headers** : la section « Response Headers » doit afficher les cinq en-têtes ci-dessus. Aucune erreur CSP ne doit apparaître dans la console pour les actions courantes (navigation, partage, fermeture du bandeau cookies).
|
||||
|
||||
## Tests automatisés
|
||||
|
||||
- `apps/web/vite-plugin-csp.unit.test.ts` — helpers purs (construction CSP, sérialisation, injection HTML, `serve.json`).
|
||||
- `apps/web/vite-plugin-csp.int.test.ts` — scénarios Gherkin `@int-csp-*` (`@int-csp-html-injection`, `@int-csp-matomo-origin`, `@int-csp-serve-json`).
|
||||
- `tests/e2e/security-headers.e2e.ts` — vérifie en dev (Playwright + Vite middleware) la présence de la CSP et des en-têtes sur `/` et `/r/...`, et la balise meta dans le HTML rendu.
|
||||
|
||||
Lancer toute la chaîne :
|
||||
|
||||
```bash
|
||||
npm run check:quality
|
||||
npm run test:ci
|
||||
```
|
||||
|
||||
## Hors scope (V1)
|
||||
|
||||
- Subresource Integrity (SRI) sur les bundles Vite — l'absence de CDN rend l'attaque peu probable, mais à étudier dans un ticket dédié.
|
||||
- `report-uri` / `report-to` — pas de collecteur configuré sur la V1.
|
||||
- CSP par nonce / hash pour autoriser des styles Solid inline en prod — non requis tant que la directive `style-src 'self'` n'engendre pas de violation observable.
|
||||
|
||||
## Références
|
||||
|
||||
- Plugin Vite : [`apps/web/vite-plugin-csp.ts`](../apps/web/vite-plugin-csp.ts)
|
||||
- Plugin SEO recette (doit passer par `transformIndexHtml`) : [`apps/web/vite-plugin-recipe-seo.ts`](../apps/web/vite-plugin-recipe-seo.ts)
|
||||
- Issue : [#104](https://github.com/kazerlelutin/ben-to/issues/104)
|
||||
- Spec : [MDN — Content Security Policy (CSP)](https://developer.mozilla.org/docs/Web/HTTP/CSP)
|
||||
- Spec : [MDN — Permissions Policy](https://developer.mozilla.org/docs/Web/HTTP/Headers/Permissions-Policy)
|
||||
@@ -0,0 +1,30 @@
|
||||
# SEO et aperçus sociaux des URLs recette (`/r/...`)
|
||||
|
||||
## Contrainte
|
||||
|
||||
Les robots des réseaux (Facebook, X, LinkedIn, etc.) lisent le **HTML de la première réponse HTTP**. Une SPA qui ne met à jour `<title>` et les balises Open Graph **qu’après exécution du JavaScript** voit souvent des aperçus génériques ou incorrects.
|
||||
|
||||
## Stratégie retenue : pré-rendu statique au build + middleware en développement
|
||||
|
||||
| Phase | Comportement |
|
||||
|--------|----------------|
|
||||
| **`vite build`** | Après génération de `dist/index.html`, le plugin `recipeSeoPlugin` (`apps/web/vite-plugin-recipe-seo.ts`) lit `dist/recipes/catalog.json`, construit pour **chaque couple** (`baseId`, `variantId`) du catalogue un fichier `dist/r/<baseEnc>/<variantEnc>/index.html` avec les mêmes scripts/CSS que la page d’accueil, mais un `<head>` dédié (`og:*`, `twitter:*`, `canonical`, etc.). Les segments de chemin utilisent `encodeURIComponent`, comme le routeur Solid. |
|
||||
| **`vite` (dev)** | Un middleware HTTP intercepte les GET `/r/:base/:variant`, recharge `public/recipes/catalog.json` et `index.html`, puis applique la même injection de métadonnées. Les tests Playwright et le débogage local voient donc des balises correctes sans produire un build. |
|
||||
|
||||
Ce n’est **pas** une solution « meta uniquement côté client » : le HTML servu pour ces URLs contient déjà les bonnes balises.
|
||||
|
||||
### Déploiement
|
||||
|
||||
Le serveur statique ou CDN doit **servir le fichier correspondant à l’URL** lorsqu’il existe (ex. essai `try_files $uri $uri/ ...` côté nginx, ou équivalent). Les chemins `%` dans les noms de dossiers reflètent les IDs catalogue encodés (`base:…` → `base%3A…`).
|
||||
|
||||
### Variable d’environnement
|
||||
|
||||
- **`BEN_TO_SITE_ORIGIN`** : origine canonique pour `og:url`, `canonical` et URLs absolues des images (défaut **`https://ben-to.fr`** au build ; en dev, défaut **`http://localhost:<port>`** sauf si cette variable est définie).
|
||||
|
||||
### Validation manuelle (critères ticket)
|
||||
|
||||
Après déploiement, utiliser par exemple [Facebook Sharing Debugger](https://developers.facebook.com/tools/debug/) ou l’outil cartes Twitter/X pour une URL `/r/...` et vérifier titre, description et image recette.
|
||||
|
||||
### Données
|
||||
|
||||
Les titres et descriptions utilisent la locale **`fr`** (alignée sur `lang="fr"` du document). L’image privilégiée est `recipeCoverImageUrl`, puis `coverImageUrl`, puis le logo sous `/branding/onigiri-logo.png`.
|
||||
@@ -0,0 +1,14 @@
|
||||
# Tickets de travaux (post-MVP)
|
||||
|
||||
Les corps d’issues prêts à l’emploi sont dans ce dossier (`issue-*.body.md`).
|
||||
|
||||
## Créer les issues sur GitHub
|
||||
|
||||
1. S’authentifier : `gh auth login`
|
||||
2. Depuis la racine du dépôt : `./scripts/github/create-post-mvp-issues.sh`
|
||||
|
||||
Le script utilise `gh issue create` et les fichiers `docs/tickets/issue-*.body.md`.
|
||||
|
||||
Sans CLI : **New issue** sur GitHub et choisir un des gabarits sous « Refactor Builder SOLID », « Architecture sans barrels index », « SEO recettes OG » — ou copier-coller le contenu des fichiers `.body.md`.
|
||||
|
||||
Issues créées sur le dépôt de référence : [#19](https://github.com/kazerlelutin/ben-to/issues/19), [#20](https://github.com/kazerlelutin/ben-to/issues/20), [#21](https://github.com/kazerlelutin/ben-to/issues/21).
|
||||
@@ -0,0 +1,25 @@
|
||||
## Contexte
|
||||
|
||||
La logique et l’UI du parcours builder sont concentrées dans `apps/web/src/ui/BuilderFlow.tsx` (fichier très volumineux). Le domaine pur existe déjà dans `packages/features/builder/src/domain.ts`.
|
||||
|
||||
## Objectif
|
||||
|
||||
Réduire la surface « tout-en-un » du flux builder et clarifier les frontières entre UI, état du wizard, et domaine (`@ben-to/builder`).
|
||||
|
||||
## Pistes techniques
|
||||
|
||||
- Extraire par **responsabilité unique** : étapes (base / variante / recette), barre d’actions, feuille recette, navigation « Continuer », synchronisation reset (`builder-reset-bus`).
|
||||
- Introduire des **hooks / ports** testables (ex. `useBuilderSteps`, `useRecipeSheet`) pour isoler les effets et la lecture du catalogue.
|
||||
- **DIP** : l’UI consomme le domaine (`domain.ts`) et des interfaces stables pour le catalogue, sans détails de parsing dispersés.
|
||||
- Conserver / étendre les tests (`*.unit.test.ts`, e2e, Gherkin `@int-builder-*`).
|
||||
|
||||
## Critères d’acceptation
|
||||
|
||||
- [ ] Aucun fichier du flux builder > ~250–300 lignes sans justification documentée en commentaire de module.
|
||||
- [ ] Tests unitaires / intégration et e2e verts ; pas de régression sur le parcours dans `specs/features/builder.feature`.
|
||||
|
||||
## Références
|
||||
|
||||
- `apps/web/src/ui/BuilderFlow.tsx`
|
||||
- `packages/features/builder/src/domain.ts`
|
||||
- `specs/features/builder.feature`
|
||||
@@ -0,0 +1,28 @@
|
||||
## Contexte
|
||||
|
||||
Les packages exposent des barrels `src/index.ts` avec `export * from "..."`. Les alias Vite dans `apps/web/vite.config.ts` pointent vers ces fichiers. Ce pattern complique le suivi des imports réels et la détection de code inutilisé.
|
||||
|
||||
## Objectif
|
||||
|
||||
Supprimer les barrels `index.ts`, migrer vers des imports **explicites**, et **verrouiller** la réintroduction du pattern (règles projet + CI).
|
||||
|
||||
## Travail technique
|
||||
|
||||
1. Remplacer les alias Vite (et chemins TypeScript si besoin) par des modules canoniques nommés (ex. `@ben-to/builder/domain`, `@ben-to/recipes/catalog`) ou par des sous-chemins `package.json` **`exports`** sans fichier nommé `index.ts`.
|
||||
2. Mettre à jour tous les imports (`apps/web`, `packages/**`).
|
||||
3. Supprimer les anciens `**/src/index.ts` après migration.
|
||||
|
||||
## Règles / outillage
|
||||
|
||||
- Étendre `.cursor/rules/ben-to-engineering.mdc` : pas de nouveau barrel `index.ts` ; imports depuis modules nommés.
|
||||
- Optionnel : ESLint `no-restricted-imports` ou script `scripts/quality/` qui échoue si un `**/src/index.ts` barrel réapparaît.
|
||||
|
||||
## Critères d’acceptation
|
||||
|
||||
- [ ] Plus de `export * from` dans des `index.ts` à la racine des packages features/shared concernés.
|
||||
- [ ] CI (`check:quality` ou lint) empêche la réintroduction du pattern (selon le niveau de durcissement retenu).
|
||||
|
||||
## Références
|
||||
|
||||
- `apps/web/vite.config.ts`
|
||||
- `packages/features/*/src/index.ts`, `packages/shared/*/src/index.ts`
|
||||
@@ -0,0 +1,30 @@
|
||||
## Contexte
|
||||
|
||||
Les métadonnées Open Graph et Twitter sont définies une seule fois dans `apps/web/index.html`. Les URLs de recette `/r/...` doivent exposer **titre**, **description** et **image** adaptés au partage.
|
||||
|
||||
**Contrainte SPA** : modifier `<title>` ou les meta **uniquement en JavaScript après chargement** ne suffit souvent pas pour les robots d’aperçu (Facebook, X, LinkedIn) : ils lisent le HTML initial.
|
||||
|
||||
## Objectif
|
||||
|
||||
Pour chaque recette partageable, fournir des métadonnées correctes : `og:title`, `og:description`, `og:image`, `og:url`, `twitter:card` (idéalement `summary_large_image` si visuel adapté), éventuellement `canonical`.
|
||||
|
||||
## Options à trancher (documenter le choix dans README ou `docs/`)
|
||||
|
||||
| Approche | Effort | Aperçus réseaux |
|
||||
|----------|--------|-----------------|
|
||||
| Pré-rendu statique des routes `/r/*` au build (catalogue / pipeline recettes) | Moyen | Bon pour crawlers statiques |
|
||||
| Middleware / route serveur (Worker, reverse proxy, petite app Node) injectant le HTML minimal avec meta | Variable | Très bon si bien déployé |
|
||||
| Meta uniquement côté client (Solid) | Faible | Insuffisant pour la majorité des partages |
|
||||
|
||||
Données : titres localisés, description courte, images de couverture produites par le pipeline recettes.
|
||||
|
||||
## Critères d’acceptation
|
||||
|
||||
- [ ] Partager une URL `/r/...` affiche un aperçu avec **titre et image recette** (validation manuelle : Meta Sharing Debugger / Twitter Card Validator ou équivalent).
|
||||
- [ ] Balises OG/Twitter cohérentes (`og:type`, `og:url`, etc.).
|
||||
- [ ] Documentation de la stratégie retenue (build vs serveur).
|
||||
|
||||
## Références
|
||||
|
||||
- `apps/web/index.html`
|
||||
- Parcours e2e et URL partagée dans `tests/e2e/builder.e2e.ts`
|
||||
Reference in New Issue
Block a user