Compare commits
4 Commits
feat/ancho
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 266b364195 | |||
| cb4cd01409 | |||
| a09dbca800 | |||
| 874c630a2a |
46
README.md
46
README.md
@@ -1,47 +1,3 @@
|
||||
# Astro Starter Kit: Minimal
|
||||
|
||||
```sh
|
||||
npm create astro@latest -- --template minimal
|
||||
```
|
||||
|
||||
> 🧑🚀 **Seasoned astronaut?** Delete this file. Have fun!
|
||||
|
||||
## 🚀 Project Structure
|
||||
|
||||
Inside of your Astro project, you'll see the following folders and files:
|
||||
|
||||
```text
|
||||
/
|
||||
├── public/
|
||||
├── src/
|
||||
│ └── pages/
|
||||
│ └── index.astro
|
||||
└── package.json
|
||||
```
|
||||
|
||||
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
|
||||
|
||||
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
|
||||
|
||||
Any static assets, like images, can be placed in the `public/` directory.
|
||||
|
||||
## 🧞 Commands
|
||||
|
||||
All commands are run from the root of the project, from a terminal:
|
||||
|
||||
| Command | Action |
|
||||
| :------------------------ | :----------------------------------------------- |
|
||||
| `npm install` | Installs dependencies |
|
||||
| `npm run dev` | Starts local dev server at `localhost:4321` |
|
||||
| `npm run build` | Build your production site to `./dist/` |
|
||||
| `npm run preview` | Preview your build locally, before deploying |
|
||||
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
|
||||
| `npm run astro -- --help` | Get help using the Astro CLI |
|
||||
|
||||
## 👀 Want to learn more?
|
||||
|
||||
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
|
||||
|
||||
# Archicratie — Web Edition (Atelier éditorial)
|
||||
|
||||
Ce repo contient le site Astro “Archicratie – Web Edition” et sa machine éditoriale :
|
||||
@@ -58,6 +14,7 @@ Ce repo contient le site Astro “Archicratie – Web Edition” et sa machine
|
||||
- **Quickstart (10 min)** : `docs/QUICKSTART.md`
|
||||
- **Manuel de référence** : `docs/MANUEL_REFERENCE.md`
|
||||
- **Contrat de tickets** : `docs/CONTRAT_TICKETS.md`
|
||||
- **Topo logique métier** : `docs/TOPO_LOGIQUE_METIER.md`
|
||||
|
||||
## Commandes clés
|
||||
- Tests complets : `npm test`
|
||||
@@ -65,3 +22,4 @@ Ce repo contient le site Astro “Archicratie – Web Edition” et sa machine
|
||||
- Appliquer un ticket :
|
||||
- `node scripts/apply-ticket.mjs <N> --dry-run`
|
||||
- `node scripts/apply-ticket.mjs <N>`
|
||||
|
||||
|
||||
250
docs/TOPO_LOGIQUE_METIER.md
Normal file
250
docs/TOPO_LOGIQUE_METIER.md
Normal file
@@ -0,0 +1,250 @@
|
||||
# Topo – Logique métier de l’outil éditorial (Web Edition ↔ Gitea ↔ apply-ticket ↔ CI)
|
||||
|
||||
Ce document explique **ce que fait réellement l’outil**, pourquoi il existe, et comment le maintenir **sans casser** la promesse centrale : **citabilité durable + édition traçable + intégration sûre**.
|
||||
|
||||
> Public visé : “commun des mortels” (nouveau contributeur, mainteneur occasionnel, moi dans 6 mois).
|
||||
|
||||
---
|
||||
|
||||
## 0) La promesse (le “pourquoi”)
|
||||
|
||||
On veut un site (Astro) où chaque paragraphe est :
|
||||
- **citable** (URL + ancre stable),
|
||||
- **corrigeable** (ouvrir un ticket pré-rempli depuis le paragraphe),
|
||||
- **réparable de manière sûre** (appliquer la proposition dans les sources sans magie),
|
||||
- **vérifié automatiquement** (tests + build + garde-fous en CI).
|
||||
|
||||
En bref :
|
||||
**Lecture → proposition → ticket → application → tests → build → publication**
|
||||
…sans perdre la traçabilité, ni casser les citations historiques.
|
||||
|
||||
---
|
||||
|
||||
## 1) Glossaire (pas de jargon sans définition)
|
||||
|
||||
- **Ancre** : partie `#...` d’une URL (ex : `#p-8-0e65838d`). Le navigateur saute à l’élément HTML portant cet `id`.
|
||||
- **Paragraphe citable** : un `<p id="p-...">...</p>` dans l’article.
|
||||
- **Ticket / Issue** : demande de correction sur Gitea (ex : #14).
|
||||
- **PR (Pull Request)** : “demande d’ajout / fusion” : une proposition de merge d’une branche vers `master`.
|
||||
- **CI** : tests automatiques exécutés sur le serveur à chaque push/PR.
|
||||
- **Runner** : machine/conteneur qui exécute la CI (chez nous : DS220+ / ds220-runner).
|
||||
- **DEV** : `npm run dev` (serveur Astro à la volée, pas de `dist/`).
|
||||
- **BUILD / PROD-like** : `npm run build` puis servir `dist/` (ce qui ressemble à la prod).
|
||||
|
||||
---
|
||||
|
||||
## 2) Vue d’ensemble : le pipeline (la “machine éditoriale”)
|
||||
|
||||
### 2.1 Le flux humain (ce que fait l’éditeur)
|
||||
1) Lire une page sur “Archicratie – Web Edition”.
|
||||
2) Sur un paragraphe : cliquer **Proposer**.
|
||||
3) Choisir **Type** (Correction / Fact-check) + **Category** (lexique, style, etc.).
|
||||
4) Gitea s’ouvre en **nouvel onglet** avec un ticket pré-rempli.
|
||||
5) L’éditeur écrit la proposition, justifie, et valide le ticket.
|
||||
|
||||
### 2.2 Le flux technique (ce que fait la machine)
|
||||
6) `apply-ticket` récupère le ticket via l’API Gitea.
|
||||
7) Il retrouve le bon fichier source (MDX) + le bon paragraphe (matching sûr).
|
||||
8) Il applique la modification (ou refuse si trop incertain).
|
||||
9) On lance `npm test` → build + test ancres + check JS inline.
|
||||
10) On commit / push.
|
||||
11) La CI revalide automatiquement sur le serveur.
|
||||
|
||||
---
|
||||
|
||||
## 3) Composant A — Le site (Astro) et les outils de paragraphe
|
||||
|
||||
Dans le rendu final, chaque paragraphe important reçoit un `id` de forme :
|
||||
|
||||
- `p-<index>-<hash8>`
|
||||
ex : `p-8-0e65838d`
|
||||
|
||||
Ensuite, un script ajoute des **outils de paragraphe** (“para-tools”) :
|
||||
- **¶** : lien direct sur le paragraphe (ancre)
|
||||
- **Citer** : copie une citation (titre + version + URL sans query-string)
|
||||
- **Proposer** : ouvre la modale (2 étapes), puis ouvre le ticket Gitea
|
||||
|
||||
### Point crucial : progressive enhancement
|
||||
- Si JS marche : UX optimale.
|
||||
- Si JS casse : le site reste lisible, et le lien de proposition reste utilisable au minimum via `href`.
|
||||
|
||||
---
|
||||
|
||||
## 4) Composant B — Contrat des tickets (machine-readable)
|
||||
|
||||
Pour que `apply-ticket` puisse travailler, le ticket doit rester **structuré**.
|
||||
|
||||
Le ticket contient des lignes “clé: valeur” (une par ligne), par ex :
|
||||
- `Chemin: /archicratie/prologue/`
|
||||
- `URL locale: http://localhost:4321/archicratie/prologue/#p-...`
|
||||
- `Ancre: #p-8-...`
|
||||
- `Version: ...`
|
||||
- `Type: type/correction` (ou type/fact-check)
|
||||
- `State: state/recevable` (ou state/a-sourcer)
|
||||
- `Category: cat/lexique` (optionnel)
|
||||
|
||||
**Règle d’or :** ces clés doivent rester simples, stables, sur une ligne chacune.
|
||||
Sinon, scripts + CI + auto-labeling deviennent fragiles.
|
||||
|
||||
---
|
||||
|
||||
## 5) Composant C — apply-ticket (appliquer sans magie)
|
||||
|
||||
`apply-ticket` fait 4 choses :
|
||||
|
||||
1) **Fetch** : récupère le ticket via API (FORGE_TOKEN requis).
|
||||
2) **Parse** : extrait Chemin/Ancre/Proposition/(Texte actuel si présent).
|
||||
3) **Match** : retrouve le paragraphe dans le fichier source (MDX) :
|
||||
- idéal : “Texte actuel (copie exacte…)” → match fort
|
||||
- sinon : match par score → si score trop faible, **refus** (sécurité)
|
||||
4) **Apply** : modifie le fichier source, sans casser le reste.
|
||||
|
||||
### Mode sûr
|
||||
- `--dry-run` : montre BEFORE/AFTER, **n’écrit rien**
|
||||
- mode normal : écrit + propose ensuite `git diff`, `git add`, `git commit`
|
||||
|
||||
---
|
||||
|
||||
## 6) Composant D — Citabilité P0 : ancres, churn test, aliases
|
||||
|
||||
### 6.1 Le problème
|
||||
Si l’ID dépend du contenu, modifier un paragraphe peut changer l’ID.
|
||||
Donc une citation historique `...#ancien` casse.
|
||||
|
||||
### 6.2 La solution robuste (“web native”)
|
||||
On ne “résout” pas l’ancre : **on la fait exister**.
|
||||
|
||||
On maintient un fichier :
|
||||
- `src/anchors/anchor-aliases.json`
|
||||
|
||||
Exemple (par page/chemin) :
|
||||
en json
|
||||
{
|
||||
"/archicratie/prologue/": {
|
||||
"p-8-e7075fe3": "p-8-0e65838d"
|
||||
}
|
||||
}
|
||||
|
||||
Au build, un script injecte dans dist/.../index.html :
|
||||
<span class="para-alias" id="p-8-e7075fe3"></span>
|
||||
<p id="p-8-0e65838d">...</p>
|
||||
|
||||
Résultat :
|
||||
|
||||
le navigateur résout #p-8-e7075fe3 sans JS.
|
||||
|
||||
### 6.3 Pourquoi un fallback JS existe encore ?
|
||||
|
||||
En mode npm run dev, on ne passe pas par dist/, donc pas d’injection build-time.
|
||||
Le fallback JS est un filet :
|
||||
|
||||
utile en DEV,
|
||||
|
||||
utile si un alias manque,
|
||||
|
||||
mais pas la solution principale.
|
||||
|
||||
## 7) Tests & garde-fous (qualité automatique)
|
||||
### 7.1 npm test doit rester “simple et vrai”
|
||||
|
||||
Il exécute :
|
||||
|
||||
npm run build (génère dist)
|
||||
|
||||
npm run test:anchors (stabilité des ancres)
|
||||
|
||||
node scripts/check-inline-js.mjs (évite les scripts inline invalides)
|
||||
|
||||
### 7.2 test:anchors (baseline + churn)
|
||||
|
||||
tests/anchors-baseline.json = snapshot de référence.
|
||||
|
||||
check-anchors compare dist à la baseline.
|
||||
|
||||
Si trop de churn → échec (donc on voit la casse).
|
||||
|
||||
On met à jour la baseline uniquement quand on accepte consciemment la nouvelle réalité :
|
||||
npm run test:anchors:update
|
||||
|
||||
## 8) DEV vs BUILD : comprendre sans se tromper
|
||||
|
||||
npm run dev → serveur Astro “live”, pas de dist/
|
||||
⇒ les alias build-time n’existent pas ⇒ fallback JS peut s’activer.
|
||||
|
||||
npm run build && npx serve dist → rendu final “prod-like”
|
||||
⇒ alias injectés ⇒ citations historiques fonctionnent sans JS.
|
||||
|
||||
Repère immédiat :
|
||||
|
||||
port 4321 = DEV
|
||||
|
||||
port 3000 (serve dist) = PROD-like
|
||||
|
||||
## 9) Rituels opérationnels (les 3 recettes)
|
||||
### Recette 1 — Créer un ticket propre
|
||||
|
||||
Cliquer “Proposer”
|
||||
|
||||
Choisir Type + Category
|
||||
|
||||
Dans Gitea : compléter “Proposition (remplacer par)” + “Justification”
|
||||
|
||||
Ne pas détruire les lignes Chemin / Ancre / Type / State / Category
|
||||
|
||||
### Recette 2 — Appliquer un ticket
|
||||
en bash :
|
||||
node scripts/apply-ticket.mjs <ID> --dry-run
|
||||
node scripts/apply-ticket.mjs <ID>
|
||||
git diff
|
||||
npm test
|
||||
git add ...
|
||||
git commit -m "edit: apply ticket #<ID> (<chemin>#<ancre>)"
|
||||
git push
|
||||
|
||||
### Recette 3 — Quand un ID change (citabilité)
|
||||
|
||||
trouver ancien id + nouveau id
|
||||
|
||||
ajouter alias dans src/anchors/anchor-aliases.json
|
||||
|
||||
npm run build
|
||||
|
||||
vérifier ...#ancien → scroll sur le bon paragraphe
|
||||
|
||||
npm test
|
||||
|
||||
## 10) Règles d’or (invariants non négociables)
|
||||
|
||||
Ne jamais éditer dist/ à la main (artefact).
|
||||
|
||||
Ne jamais sacrifier l’ancre : Chemin + Ancre doivent exister.
|
||||
|
||||
Tickets toujours “parsables” (clés stables ligne-par-ligne).
|
||||
|
||||
apply-ticket doit pouvoir refuser quand c’est ambigu.
|
||||
|
||||
npm test doit rester “le bouton rouge” fiable.
|
||||
|
||||
## 11) Dépannage rapide
|
||||
|
||||
401 invalid token : FORGE_TOKEN absent ou mal exporté.
|
||||
|
||||
Header invalid value : token collé avec des caractères parasites (espaces, retours, texte autour).
|
||||
|
||||
Proposer ouvre 2 onglets / remplace la page : bug d’interception click → vérifier preventDefault + stopPropagation et l’“openInNewTab”.
|
||||
|
||||
Ancien #id ne marche plus :
|
||||
|
||||
en PROD-like : vérifier alias injecté + JSON
|
||||
|
||||
en DEV : normal que fallback JS soit requis
|
||||
|
||||
## 12) Où lire quoi (docs)
|
||||
|
||||
docs/QUICKSTART.md : démarrer vite
|
||||
|
||||
docs/MANUEL_REFERENCE.md : usage complet + procédures
|
||||
|
||||
docs/CONTRAT_TICKETS.md : format strict des issues
|
||||
|
||||
(ce doc) docs/TOPO_LOGIQUE_METIER.md : la logique qui relie tout
|
||||
@@ -92,7 +92,8 @@ const GITEA_REPO = import.meta.env.PUBLIC_GITEA_REPO ?? "";
|
||||
const replacement = document.querySelector(`[id^="${prefix}"]`);
|
||||
if (!replacement) return;
|
||||
|
||||
history.replaceState(null, "", `${window.location.pathname}#${replacement.id}`);
|
||||
console.warn("[anchors] legacy hash fallback used:", `#${oldId}`, "→", `#${replacement.id}`);
|
||||
// On ne réécrit PAS le hash : on garde la citabilité historique visible.
|
||||
replacement.scrollIntoView({ block: "start" });
|
||||
})();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user