Compare commits
34 Commits
docs/ops-r
...
chore/url-
| Author | SHA1 | Date | |
|---|---|---|---|
| 672e6d03d0 | |||
| 2881fdaf01 | |||
| db98a3787b | |||
| 78eb9cbb58 | |||
| ab3758bbc2 | |||
| 12d3d81518 | |||
| e2468be522 | |||
| dc2826df08 | |||
| 3e4df18b88 | |||
| a2d1df427d | |||
| ab63511d81 | |||
| e5d831cb61 | |||
| cab9e9cf2d | |||
| c7704ada8a | |||
| 010601be63 | |||
| add688602a | |||
| 3f3c717185 | |||
| b5f32da0c8 | |||
| 6e7ed8e041 | |||
| 90f79a7ee7 | |||
| b5663891a1 | |||
| a74b95e775 | |||
| b78eb4fc7b | |||
| 80c047369f | |||
| d7c158a0fc | |||
| 30f0ef4164 | |||
| d2963673c9 | |||
| d59e10dfc6 | |||
| 214f930e56 | |||
| 9e903607bb | |||
| 8b7cfdfd48 | |||
| c12b6015ab | |||
| f7f6b8f770 | |||
| ae8ec42349 |
3
.env
@@ -1,3 +0,0 @@
|
||||
PUBLIC_GITEA_BASE=https://gitea.archicratie.trans-hands.synology.me
|
||||
PUBLIC_GITEA_OWNER=Archicratia
|
||||
PUBLIC_GITEA_REPO=archicratie-edition
|
||||
@@ -1,4 +0,0 @@
|
||||
PUBLIC_GITEA_BASE=https://gitea.archicratie.trans-hands.synology.me
|
||||
PUBLIC_GITEA_OWNER=Archicratia
|
||||
PUBLIC_GITEA_REPO=archicratie-edition
|
||||
PUBLIC_SITE=https://archicratie.trans-hands.synology.me
|
||||
@@ -1,5 +0,0 @@
|
||||
FORGE_API=http://192.168.1.20:3000
|
||||
FORGE_BASE=https://gitea.archicratie.trans-hands.synology.me
|
||||
FORGE_TOKEN=aW73wpfJ4MiN2!3UU69qL*vWF9$9V7f@2
|
||||
PUBLIC_GITEA_OWNER=Archicratia
|
||||
PUBLIC_GITEA_REPO=archicratie-edition
|
||||
@@ -1,6 +0,0 @@
|
||||
PUBLIC_SITE=https://archicratie.trans-hands.synology.me
|
||||
PUBLIC_RELEASE=0.1.0
|
||||
|
||||
PUBLIC_GITEA_BASE=https://gitea.archicratie.trans-hands.synology.me
|
||||
PUBLIC_GITEA_OWNER=Archicratia
|
||||
PUBLIC_GITEA_REPO=archicratie-edition
|
||||
102
astro.config.mjs
@@ -10,41 +10,101 @@ import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
||||
import rehypeDetailsSections from "./scripts/rehype-details-sections.mjs";
|
||||
import rehypeParagraphIds from "./src/plugins/rehype-paragraph-ids.js";
|
||||
|
||||
const must = (name, fn) => {
|
||||
if (typeof fn !== "function") {
|
||||
throw new Error(`[astro.config] rehype plugin "${name}" is not a function (export default vs named?)`);
|
||||
}
|
||||
return fn;
|
||||
};
|
||||
/**
|
||||
* Cast minimal pour satisfaire @ts-check sans dépendre de types internes Astro/Unified.
|
||||
* @param {unknown} x
|
||||
* @returns {any}
|
||||
*/
|
||||
const asAny = (x) => /** @type {any} */ (x);
|
||||
|
||||
/**
|
||||
* @param {any} node
|
||||
* @param {string} cls
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasClass(node, cls) {
|
||||
const cn = node?.properties?.className;
|
||||
if (Array.isArray(cn)) return cn.includes(cls);
|
||||
if (typeof cn === "string") return cn.split(/\s+/).includes(cls);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rehype plugin: retire les ids dupliqués en gardant en priorité:
|
||||
* 1) span.details-anchor
|
||||
* 2) h1..h6
|
||||
* 3) sinon: premier rencontré
|
||||
* @returns {(tree: any) => void}
|
||||
*/
|
||||
function rehypeDedupeIds() {
|
||||
/** @param {any} tree */
|
||||
return (tree) => {
|
||||
/** @type {Map<string, Array<{node:any, pref:number, idx:number}>>} */
|
||||
const occ = new Map();
|
||||
let idx = 0;
|
||||
|
||||
/** @param {any} node */
|
||||
const walk = (node) => {
|
||||
if (!node || typeof node !== "object") return;
|
||||
|
||||
if (node.type === "element") {
|
||||
const id = node.properties?.id;
|
||||
if (typeof id === "string" && id) {
|
||||
let pref = 2;
|
||||
if (node.tagName === "span" && hasClass(node, "details-anchor")) pref = 0;
|
||||
else if (/^h[1-6]$/.test(String(node.tagName || ""))) pref = 1;
|
||||
|
||||
const arr = occ.get(id) || [];
|
||||
arr.push({ node, pref, idx: idx++ });
|
||||
occ.set(id, arr);
|
||||
}
|
||||
|
||||
const children = node.children;
|
||||
if (Array.isArray(children)) for (const c of children) walk(c);
|
||||
} else if (Array.isArray(node.children)) {
|
||||
for (const c of node.children) walk(c);
|
||||
}
|
||||
};
|
||||
|
||||
walk(tree);
|
||||
|
||||
for (const [id, items] of occ.entries()) {
|
||||
if (items.length <= 1) continue;
|
||||
|
||||
items.sort((a, b) => (a.pref - b.pref) || (a.idx - b.idx));
|
||||
const keep = items[0];
|
||||
|
||||
for (let i = 1; i < items.length; i++) {
|
||||
const n = items[i].node;
|
||||
if (n?.properties?.id === id) delete n.properties.id;
|
||||
}
|
||||
|
||||
// safety: on s'assure qu'un seul garde bien l'id
|
||||
if (keep?.node?.properties) keep.node.properties.id = id;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
output: "static",
|
||||
trailingSlash: "always",
|
||||
|
||||
site: process.env.PUBLIC_SITE ?? "http://localhost:4321",
|
||||
|
||||
integrations: [
|
||||
mdx(),
|
||||
// Important: MDX hérite du pipeline markdown (ids p-… + autres plugins)
|
||||
mdx({ extendMarkdownConfig: true }),
|
||||
sitemap({
|
||||
filter: (page) => !page.includes("/api/") && !page.endsWith("/robots.txt"),
|
||||
}),
|
||||
],
|
||||
|
||||
// ✅ Plugins appliqués AU MDX
|
||||
mdx: {
|
||||
// ✅ MDX hérite déjà de markdown.rehypePlugins
|
||||
// donc ici on ne met QUE le spécifique MDX
|
||||
rehypePlugins: [
|
||||
must("rehype-details-sections", rehypeDetailsSections),
|
||||
],
|
||||
},
|
||||
|
||||
// ✅ Plugins appliqués au Markdown non-MDX
|
||||
markdown: {
|
||||
rehypePlugins: [
|
||||
must("rehype-slug", rehypeSlug),
|
||||
[must("rehype-autolink-headings", rehypeAutolinkHeadings), { behavior: "append" }],
|
||||
must("rehype-paragraph-ids", rehypeParagraphIds),
|
||||
asAny(rehypeSlug),
|
||||
[asAny(rehypeAutolinkHeadings), { behavior: "append" }],
|
||||
asAny(rehypeDetailsSections),
|
||||
asAny(rehypeParagraphIds),
|
||||
asAny(rehypeDedupeIds),
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
7
bridge/Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM node:22-bookworm-slim
|
||||
WORKDIR /app
|
||||
COPY package.json package-lock.json* ./
|
||||
RUN npm install --omit=dev
|
||||
COPY server.mjs ./
|
||||
EXPOSE 8787
|
||||
CMD ["node","server.mjs"]
|
||||
15
bridge/docker-compose-bridge.yml
Normal file
@@ -0,0 +1,15 @@
|
||||
services:
|
||||
issue_bridge:
|
||||
build: ./bridge
|
||||
environment:
|
||||
GITEA_API_BASE: "http://gitea:3000"
|
||||
GITEA_TOKEN: "${GITEA_TOKEN}"
|
||||
GITEA_OWNER: "Archicratia"
|
||||
GITEA_REPO: "archicratie-edition"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- internal
|
||||
|
||||
networks:
|
||||
internal:
|
||||
external: true
|
||||
10
bridge/package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "issue-bridge",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"express": "^4.19.2",
|
||||
"multer": "^1.4.5-lts.1"
|
||||
}
|
||||
}
|
||||
|
||||
89
bridge/server.mjs
Normal file
@@ -0,0 +1,89 @@
|
||||
import express from "express";
|
||||
import multer from "multer";
|
||||
|
||||
const app = express();
|
||||
const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 25 * 1024 * 1024 } }); // 25 MB
|
||||
|
||||
const {
|
||||
GITEA_API_BASE, // ex: http://gitea:3000 (ou https://forge.tld)
|
||||
GITEA_TOKEN, // PAT du bot
|
||||
GITEA_OWNER, // owner/org
|
||||
GITEA_REPO // repo
|
||||
} = process.env;
|
||||
|
||||
function mustEnv(name) {
|
||||
if (!process.env[name]) throw new Error(`Missing env ${name}`);
|
||||
}
|
||||
["GITEA_API_BASE","GITEA_TOKEN","GITEA_OWNER","GITEA_REPO"].forEach(mustEnv);
|
||||
|
||||
function isEditor(req) {
|
||||
// Adapte selon tes headers Authelia. Souvent Remote-Groups / Remote-User.
|
||||
const groups = String(req.header("Remote-Groups") || req.header("X-Remote-Groups") || "");
|
||||
return groups.split(/[,\s]+/).includes("editors");
|
||||
}
|
||||
|
||||
async function giteaFetch(path, init = {}) {
|
||||
const url = String(GITEA_API_BASE).replace(/\/+$/, "") + path;
|
||||
const headers = new Headers(init.headers || {});
|
||||
headers.set("Authorization", `token ${GITEA_TOKEN}`);
|
||||
return fetch(url, { ...init, headers });
|
||||
}
|
||||
|
||||
app.get("/health", (_req, res) => res.json({ ok: true }));
|
||||
|
||||
app.post("/media", upload.single("file"), async (req, res) => {
|
||||
try {
|
||||
if (!isEditor(req)) return res.status(403).json({ ok: false, error: "forbidden" });
|
||||
|
||||
const file = req.file;
|
||||
const title = String(req.body.title || "").trim();
|
||||
const body = String(req.body.body || "").trim();
|
||||
const suggestedName = String(req.body.suggestedName || "").trim();
|
||||
|
||||
if (!file) return res.status(400).json({ ok: false, error: "missing_file" });
|
||||
if (!title) return res.status(400).json({ ok: false, error: "missing_title" });
|
||||
if (!body) return res.status(400).json({ ok: false, error: "missing_body" });
|
||||
|
||||
// 1) Create issue
|
||||
const r1 = await giteaFetch(`/api/v1/repos/${encodeURIComponent(GITEA_OWNER)}/${encodeURIComponent(GITEA_REPO)}/issues`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ title, body })
|
||||
});
|
||||
|
||||
if (!r1.ok) {
|
||||
const t = await r1.text().catch(() => "");
|
||||
return res.status(502).json({ ok: false, step: "create_issue", status: r1.status, detail: t.slice(0, 2000) });
|
||||
}
|
||||
|
||||
const issue = await r1.json();
|
||||
const index = issue?.number ?? issue?.index;
|
||||
const issueUrl = issue?.html_url;
|
||||
|
||||
if (!index) return res.status(502).json({ ok: false, step: "create_issue", error: "missing_issue_index" });
|
||||
|
||||
// 2) Upload attachment (multipart field name = "attachment") :contentReference[oaicite:1]{index=1}
|
||||
const fd = new FormData();
|
||||
fd.append("attachment", new Blob([file.buffer], { type: file.mimetype || "application/octet-stream" }), file.originalname);
|
||||
|
||||
const q = suggestedName ? `?name=${encodeURIComponent(suggestedName)}` : "";
|
||||
const r2 = await giteaFetch(`/api/v1/repos/${encodeURIComponent(GITEA_OWNER)}/${encodeURIComponent(GITEA_REPO)}/issues/${encodeURIComponent(String(index))}/assets${q}`, {
|
||||
method: "POST",
|
||||
body: fd
|
||||
});
|
||||
|
||||
if (!r2.ok) {
|
||||
const t = await r2.text().catch(() => "");
|
||||
return res.status(502).json({ ok: false, step: "upload_asset", status: r2.status, detail: t.slice(0, 2000), issueUrl });
|
||||
}
|
||||
|
||||
const asset = await r2.json().catch(() => ({}));
|
||||
return res.json({ ok: true, issueUrl, issueIndex: index, asset });
|
||||
} catch (e) {
|
||||
return res.status(500).json({ ok: false, error: String(e?.message || e) });
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(8787, "0.0.0.0", () => {
|
||||
console.log("issue-bridge listening on :8787");
|
||||
});
|
||||
@@ -1,6 +1,3 @@
|
||||
# `docs/CONFIG-ENV.md`
|
||||
|
||||
```md
|
||||
# CONFIG-ENV — variables, priorités, injection build
|
||||
|
||||
## 0) Ce que la prod doit garantir
|
||||
@@ -13,6 +10,15 @@ Si un seul de ces 3 paramètres est faux → on obtient :
|
||||
- 404 / redirect login inattendu
|
||||
- ou un repo/owner incorrect
|
||||
|
||||
|
||||
# Diagnostic — “Proposer” (résumé)
|
||||
|
||||
**Symptôme :** clic “Proposer” → 404 / login / mauvais repo
|
||||
**Cause la plus fréquente :** `PUBLIC_GITEA_OWNER` (casse sensible) ou `PUBLIC_GITEA_REPO` faux.
|
||||
|
||||
➡️ Procédure complète (pas-à-pas + commandes) : voir `docs/TROUBLESHOOTING.md#proposer-404`.
|
||||
|
||||
|
||||
## 1) Variables utilisées (publique, côté build Astro)
|
||||
|
||||
- `PUBLIC_GITEA_BASE`
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# Déploiement production (Synology DS220+ / DSM 7.3) — Astro → Nginx statique
|
||||
|
||||
> ✅ **CANONIQUE** — Procédure de référence “prod DS220+ / DSM 7.3”.
|
||||
|
||||
> Toute modif de déploiement doit être faite **ici**, via PR sur Gitea/main (pas d’édition à la main en prod).
|
||||
|
||||
> Périmètre : build Docker (Node→Nginx), blue/green 8081/8082, Reverse Proxy DSM, smoke, rollback.
|
||||
|
||||
> Dépendances critiques : variables PUBLIC_GITEA_* (sinon “Proposer” part en 404/login loop).
|
||||
|
||||
> Voir aussi : OPS-REFERENCE.md (index), OPS_COCKPIT.md (checklist), TROUBLESHOOTING.md (incidents).
|
||||
|
||||
Dernière mise à jour : 2026-02-01
|
||||
|
||||
Ce document décrit une mise en place stable sur NAS :
|
||||
@@ -73,6 +83,17 @@ for f in .env .env.local .env.production .env.production.local; do
|
||||
[ -f "$f" ] && echo "---- $f" && grep -nE '^PUBLIC_GITEA_(BASE|OWNER|REPO)=' "$f" || true
|
||||
done
|
||||
|
||||
En cas d’échec :
|
||||
- 404 / login loop / mauvais repo → `docs/TROUBLESHOOTING.md#proposer-404`
|
||||
- double onglet → `docs/TROUBLESHOOTING.md#proposer-double-onglet`
|
||||
|
||||
## Diagnostic — “Proposer” (résumé)
|
||||
|
||||
**Symptôme :** clic “Proposer” → 404 / login / mauvais repo
|
||||
**Cause la plus fréquente :** `PUBLIC_GITEA_OWNER` (casse sensible) ou `PUBLIC_GITEA_REPO` faux.
|
||||
|
||||
➡️ Procédure complète (pas-à-pas + commandes) : voir `docs/TROUBLESHOOTING.md#proposer-404`.
|
||||
|
||||
## 5) Reverse Proxy DSM (le point clé)
|
||||
|
||||
### DSM 7.3 :
|
||||
|
||||
57
docs/FEATURE-PROPOSER.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# FEATURE — “Proposer” (édition par paragraphe → issue Gitea)
|
||||
|
||||
Dernière mise à jour : 2026-02-01
|
||||
|
||||
Cette feature permet à un lecteur de proposer une correction/amélioration d’un paragraphe, en générant une issue pré-remplie dans Gitea.
|
||||
|
||||
---
|
||||
|
||||
## 0) Objectif fonctionnel
|
||||
Depuis une page chapitre :
|
||||
1) clic sur **Proposer** sur un paragraphe
|
||||
2) choix #1 (type)
|
||||
3) choix #2 (state/catégorie selon UI)
|
||||
4) ouverture d’un seul onglet vers Gitea : `/issues/new?...`
|
||||
5) issue pré-remplie avec :
|
||||
- chemin / URL / ancre
|
||||
- texte actuel (citation)
|
||||
- champs “Proposition / Justification”
|
||||
6) l’utilisateur valide, et le runner/CI traite.
|
||||
|
||||
---
|
||||
|
||||
## 1) Dépendances de configuration (critique)
|
||||
|
||||
Le lien Gitea est construit à partir de variables publiques injectées au build Astro :
|
||||
|
||||
- `PUBLIC_GITEA_BASE` (ex: `https://gitea.archicratie.trans-hands.synology.me`)
|
||||
- `PUBLIC_GITEA_OWNER` (**casse sensible**, ex: `Archicratia`)
|
||||
- `PUBLIC_GITEA_REPO` (ex: `archicratie-edition`)
|
||||
|
||||
### Symptômes si mauvais
|
||||
- mauvais repo → 404
|
||||
- redirect login inattendu
|
||||
- création d’issues impossible
|
||||
|
||||
---
|
||||
|
||||
## 2) Contrat “une seule ouverture d’onglet”
|
||||
Le flow ne doit jamais ouvrir deux onglets.
|
||||
|
||||
### Contrat
|
||||
- pas de `window.open(...)`
|
||||
- un seul `a.target="_blank"` (ou équivalent) déclenché
|
||||
- sur click : handler doit neutraliser les propagations parasites
|
||||
|
||||
## Diagnostic (canonique)
|
||||
|
||||
Le diagnostic détaillé est centralisé dans `docs/TROUBLESHOOTING.md` pour éviter les doublons.
|
||||
|
||||
- 404 / non autorisé / redirect login :
|
||||
- voir : `TROUBLESHOOTING.md#proposer-404`
|
||||
- cause la plus fréquente : `PUBLIC_GITEA_OWNER/REPO` faux (souvent casse)
|
||||
|
||||
- Double onglet :
|
||||
- voir : `TROUBLESHOOTING.md#proposer-double-onglet`
|
||||
- cause la plus fréquente : double handler (bubbling) ou `window.open` + `a.click()`
|
||||
|
||||
@@ -1,6 +1,46 @@
|
||||
OPS — Déploiement Archicratie Web Edition (Mac Studio → DS220+)
|
||||
# OPS — Déploiement Archicratie Web Edition (Mac Studio → DS220+)
|
||||
Objectif : déployer une nouvelle version du site sur le NAS (DS220+) sans jamais casser la prod, en utilisant un schéma blue/green piloté par DSM Reverse Proxy, avec une procédure robuste même quand docker compose build est instable sur le NAS.
|
||||
|
||||
> 🟧 **LEGACY / HISTORIQUE** — Ce document n’est plus la source de vérité.
|
||||
|
||||
> Référence actuelle : docs/DEPLOY_PROD_SYNOLOGY_DS220.md (canonique).
|
||||
|
||||
> Statut : gelé (on n’édite plus que pour ajouter un lien vers le canonique, si nécessaire).
|
||||
|
||||
> Raison : doublon → risque de divergence → risque d’erreur en prod.
|
||||
|
||||
> Si tu lis ceci pour déployer : stop → ouvre le canonique.
|
||||
|
||||
> ⚠️ LEGACY — Ne pas suivre pour déployer.
|
||||
> Doc conservé pour historique.
|
||||
> Canon : `DEPLOY_PROD_SYNOLOGY_DS220.md` + `OPS-SYNC-TRIPLE-SOURCE.md`.
|
||||
|
||||
## Pourquoi ce doc existe encore
|
||||
|
||||
- Historique : il capture des repères (domaines, ports, logique blue/green) tels qu’ils ont été consolidés pendant la phase d’implémentation.
|
||||
- Sécurité : éviter la divergence documentaire (un seul pas-à-pas officiel).
|
||||
- Maintenance : si tu dois déployer, tu suis le canonique ; ici tu ne viens que pour comprendre “d’où ça vient”.
|
||||
|
||||
## Ce qu’il faut faire aujourd’hui (canonique)
|
||||
|
||||
➡️ Déploiement = `docs/DEPLOY_PROD_SYNOLOGY_DS220.md` (procédure détaillée, à jour).
|
||||
|
||||
## Schéma (résumé, sans commandes)
|
||||
|
||||
- Ne jamais toucher au slot live.
|
||||
- Construire/tester sur l’autre slot.
|
||||
- Smoke test.
|
||||
- Bascule DSM Reverse Proxy (8081 ↔ 8082).
|
||||
- Rollback DSM si besoin.
|
||||
|
||||
<details>
|
||||
|
||||
> 🚫 NE PAS UTILISER POUR PROD — ARCHIVE UNIQUEMENT
|
||||
|
||||
<summary>Archive — ancien pas-à-pas (NE PAS SUIVRE)</summary>
|
||||
|
||||
> ⚠️ Archive. Ce contenu est conservé pour mémoire.
|
||||
|
||||
## 0) Repères essentiels
|
||||
Noms & domaines
|
||||
• Site public (prod) : https://archicratie.trans-hands.synology.me
|
||||
@@ -383,3 +423,5 @@ Fix standard (dans le vrai dossier site/) :
|
||||
rm -rf node_modules .astro dist
|
||||
npm ci
|
||||
npm run dev
|
||||
|
||||
</details>
|
||||
|
||||
@@ -4,7 +4,7 @@ Document “pivot” : liens, invariants, conventions, commandes réflexes.
|
||||
|
||||
## 0) Invariants (à ne pas casser)
|
||||
|
||||
- **Source de vérité Git** : `origin/main` sur :contentReference[oaicite:0]{index=0}.
|
||||
- **Source de vérité Git** : origin/main (repo Archicratia/archicratie-edition sur Gitea).
|
||||
- **Prod** : conteneur `archicratie-web-*` (nginx) derrière reverse proxy DSM.
|
||||
- **Config “Proposer”** : dépend de `PUBLIC_GITEA_BASE`, `PUBLIC_GITEA_OWNER`, `PUBLIC_GITEA_REPO` injectés au build.
|
||||
- **Branches** : `main` = travail ; `master` = legacy/compat (alignée mais protégée).
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# OPS Runbook — Archicratie Web (NAS Synology DS220 + Gitea)
|
||||
|
||||
> 🟦 **ALIAS (résumé)** — Runbook 1-page pour opérer vite sans se tromper.
|
||||
|
||||
> La procédure détaillée **canonique** est : docs/DEPLOY_PROD_SYNOLOGY_DS220.md.
|
||||
|
||||
> Source Git : Gitea/main ; déploiement = rebuild depuis main ; pas de hotfix non versionné.
|
||||
|
||||
> Déploiement : build sur slot inactif → smoke → bascule DSM → rollback si besoin.
|
||||
|
||||
> Incidents connus : voir docs/TROUBLESHOOTING.md.
|
||||
|
||||
## 0. Objectif
|
||||
Ce document décrit la procédure **exacte** pour :
|
||||
- maintenir un état cohérent entre **Local (Mac Studio)**, **Gitea**, **NAS (prod)** ;
|
||||
|
||||
122
docs/OPS-SYNC-TRIPLE-SOURCE.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# OPS-SYNC-TRIPLE-SOURCE — Mac Studio / Gitea / NAS (prod)
|
||||
|
||||
Dernière mise à jour : 2026-02-01
|
||||
|
||||
Ce document décrit la synchronisation **sans ambiguïté** entre :
|
||||
- **Local (Mac Studio)** : édition / écriture / préparation PR
|
||||
- **Gitea** : **vérité canonique** (branche `main`)
|
||||
- **NAS Synology DS220+** : déploiement (blue/green) à partir de `main`
|
||||
|
||||
---
|
||||
|
||||
## 0) Invariants (à ne jamais violer)
|
||||
|
||||
1) **Gitea `main` = source de vérité.**
|
||||
2) Le NAS ne doit pas “inventer” du code : pas d’édition manuelle non versionnée en prod (sauf hotfix temporaire immédiatement reporté dans une PR).
|
||||
3) Le bouton “Proposer” dépend de `PUBLIC_GITEA_*` : une valeur fausse → 404 / redirect login / mauvais repo.
|
||||
4) Les secrets (tokens) **ne doivent jamais** entrer dans le repo : `.env*` ignorés, token injecté uniquement via variable d’environnement locale/CI.
|
||||
|
||||
---
|
||||
|
||||
## 1) Topologie réelle (ce que nous avons)
|
||||
|
||||
### 1.1 Local (Mac Studio)
|
||||
- Dev et documentation.
|
||||
- Git complet.
|
||||
- On fait : branches, commits, push, PR, merge.
|
||||
|
||||
### 1.2 Gitea
|
||||
- Repo canonique : `Archicratia/archicratie-edition`.
|
||||
- `main` = défaut + protégée.
|
||||
- Toute modif arrive via PR.
|
||||
|
||||
### 1.3 NAS (prod)
|
||||
- Chemin canonique :
|
||||
- `/volume2/docker/archicratie-web/releases/<timestamp>/app`
|
||||
- `/volume2/docker/archicratie-web/current` → symlink vers la release active
|
||||
- Blue/Green :
|
||||
- `web_blue` sur `127.0.0.1:8081`
|
||||
- `web_green` sur `127.0.0.1:8082`
|
||||
- Reverse proxy DSM : bascule 8081 ↔ 8082.
|
||||
|
||||
---
|
||||
|
||||
## 2) Règle d’or : qui écrit quoi, où ?
|
||||
|
||||
### 2.1 Toute écriture “source” se fait sur Mac Studio
|
||||
- Code Astro
|
||||
- Scripts
|
||||
- Docs `docs/*.md`
|
||||
- `.gitignore`
|
||||
|
||||
### 2.2 Gitea ne reçoit que via PR
|
||||
- Push sur branche feature/docs
|
||||
- PR → CI → merge
|
||||
|
||||
### 2.3 NAS ne fait que :
|
||||
- `git reset --hard origin/main` (alignement)
|
||||
- build image + restart slot blue/green
|
||||
- smoke test
|
||||
- bascule reverse proxy DSM
|
||||
|
||||
---
|
||||
|
||||
## 3) Procédure standard (la seule à utiliser)
|
||||
|
||||
### Étape A — Mac Studio → Gitea (PR)
|
||||
1) `git checkout -b feat/...` ou `docs/...`
|
||||
2) commits propres et atomiques
|
||||
3) `git push -u origin <branch>`
|
||||
4) PR dans Gitea → CI OK → merge dans `main`
|
||||
|
||||
### Étape B — NAS : aligner `current` sur `origin/main`
|
||||
Sur NAS, git n’est pas forcément installé : on utilise un conteneur git.
|
||||
en sh :
|
||||
|
||||
APP="/volume2/docker/archicratie-web/current"
|
||||
U_ID="$(id -u)"; G_ID="$(id -g)"
|
||||
|
||||
sudo docker run --rm --network host \
|
||||
-u "$U_ID:$G_ID" -e HOME=/tmp \
|
||||
-v "$APP":/repo -w /repo \
|
||||
--entrypoint sh alpine/git -lc '
|
||||
set -eu
|
||||
git config --global --add safe.directory /repo
|
||||
git config http.sslVerify false
|
||||
|
||||
git fetch origin --prune
|
||||
git checkout -B main
|
||||
git reset --hard origin/main
|
||||
git status -sb
|
||||
'
|
||||
|
||||
### Étape C — NAS : rebuild du slot inactif + smoke + bascule
|
||||
|
||||
Rebuild de l’image (slot inactif recommandé).
|
||||
|
||||
docker compose up -d --force-recreate --no-build web_green (ou blue)
|
||||
|
||||
smoke test via script ou curl
|
||||
|
||||
bascule DSM vers le port du slot actif
|
||||
|
||||
## 4) Checkpoints rapides (sanity)
|
||||
### 4.1 Vérifier que NAS = origin/main
|
||||
|
||||
git rev-parse --short HEAD sur NAS (via alpine/git)
|
||||
|
||||
doit égaler origin/main.
|
||||
|
||||
### 4.2 Vérifier “Proposer” (points minimum)
|
||||
|
||||
PUBLIC_GITEA_OWNER=Archicratia (casse sensible)
|
||||
|
||||
PUBLIC_GITEA_REPO=archicratie-edition
|
||||
|
||||
Flow : Proposer → choix 1 → choix 2 → onglet Gitea /issues/new?... OK
|
||||
|
||||
## 5) Rollback
|
||||
|
||||
DSM reverse proxy : repasser sur l’autre port (8081/8082).
|
||||
|
||||
En cas de code cassé : réaligner NAS sur origin/main précédent (tag/release) ou repointer /current vers une release précédente.
|
||||
122
docs/RUNBOOK-PR-AUTO-GITEA.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# RUNBOOK — Créer une Demande d’ajout (PR) “automatique” depuis un push (Gitea)
|
||||
|
||||
## Objectif
|
||||
Pousser une branche depuis le Mac vers Gitea et obtenir le workflow standard :
|
||||
1) branche dédiée
|
||||
2) push
|
||||
3) suggestion “Nouvelle demande d’ajout” (bandeau vert) OU lien terminal
|
||||
4) création PR via UI
|
||||
5) merge (main protégé)
|
||||
|
||||
> Important : Gitea ne crée pas une PR automatiquement.
|
||||
> Il affiche une *suggestion* (bandeau vert) ou imprime un lien “Create a new pull request” lors du push.
|
||||
|
||||
---
|
||||
|
||||
## Pré-check (obligatoire, 10 secondes)
|
||||
en bash :
|
||||
|
||||
git status -sb
|
||||
git fetch origin --prune
|
||||
git branch --show-current
|
||||
|
||||
Procédure standard (zéro surprise)
|
||||
### 1) Se remettre propre sur main
|
||||
|
||||
git checkout main
|
||||
git pull --ff-only
|
||||
|
||||
### 2) Créer une branche AVANT de modifier / ajouter des fichiers
|
||||
|
||||
git switch -c docs/<YYYY-MM-DD>-<sujet-court>
|
||||
|
||||
### 3) Ajouter/modifier tes fichiers dans docs/
|
||||
|
||||
Exemple :
|
||||
|
||||
docs/auth-stack.md
|
||||
|
||||
docs/runbook-....
|
||||
|
||||
### 4) Vérifier ce qui va partir
|
||||
|
||||
git status -sb
|
||||
git diff
|
||||
|
||||
### 5) Commit
|
||||
|
||||
git add docs/
|
||||
git commit -m "docs: <résumé clair>"
|
||||
|
||||
### 6) Vérifier que ta branche a bien des commits “devant” main (SINON pas de PR possible)
|
||||
|
||||
git fetch origin
|
||||
git log --oneline origin/main..HEAD
|
||||
|
||||
Si ça n’affiche rien : tu n’as rien à proposer (branche identique à main).
|
||||
|
||||
### 7) Push (méthode la plus robuste)
|
||||
|
||||
git push -u origin HEAD
|
||||
|
||||
### 8) Créer la PR (2 chemins fiables)
|
||||
# Chemin A — le plus simple : utiliser le lien imprimé dans le terminal
|
||||
|
||||
Après le push, Gitea affiche généralement :
|
||||
“Create a new pull request for '<ta-branche>': <URL>”
|
||||
➡️ Ouvre cette URL, clique “Créer la demande d’ajout”.
|
||||
|
||||
# Chemin B — via l’UI Gitea (si tu veux le bandeau vert)
|
||||
|
||||
Va sur le dépôt
|
||||
|
||||
Onglet “Demandes d’ajout”
|
||||
|
||||
Clique “Nouvelle demande d’ajout”
|
||||
|
||||
Source branch = ta branche, Target = main
|
||||
|
||||
Créer
|
||||
|
||||
## Pourquoi le bandeau vert peut ne PAS apparaître (et ce que ça signifie)
|
||||
|
||||
Ta branche est identique à main
|
||||
|
||||
# Diagnostic :
|
||||
|
||||
git fetch origin
|
||||
git diff --name-status origin/main..HEAD
|
||||
|
||||
Si vide => normal, pas de suggestion.
|
||||
|
||||
Tu n’es pas sur la bonne branche
|
||||
|
||||
# Diagnostic :
|
||||
|
||||
git branch --show-current
|
||||
|
||||
Tu regardes l’UI au mauvais endroit
|
||||
|
||||
Solution : utilise le bouton “Nouvelle demande d’ajout” ou le lien du terminal (chemin A).
|
||||
|
||||
Anti-bêtise (optionnel mais recommandé)
|
||||
Empêcher de commit sur main par erreur (hook local)
|
||||
|
||||
# Créer .git/hooks/pre-commit :
|
||||
|
||||
#!/bin/sh
|
||||
b="$(git branch --show-current)"
|
||||
if [ "$b" = "main" ]; then
|
||||
echo "❌ Refus: commit interdit sur main. Crée une branche."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Puis :
|
||||
|
||||
chmod +x .git/hooks/pre-commit
|
||||
|
||||
## Rappel : main protégé
|
||||
|
||||
Si main est protégé, tu ne merges PAS par git push origin main.
|
||||
Tu merges via la PR (UI), après CI verte.
|
||||
|
||||
217
docs/TROUBLESHOOTING.md
Normal file
@@ -0,0 +1,217 @@
|
||||
# TROUBLESHOOTING — Archicratie Web / NAS / Gitea
|
||||
|
||||
Dernière mise à jour : 2026-02-01
|
||||
|
||||
Ce document liste les symptômes rencontrés et les remèdes **concrets**.
|
||||
|
||||
---
|
||||
|
||||
## 0) Réflexe unique
|
||||
Toujours isoler : **Local**, **Gitea**, **NAS**, **Navigateur**.
|
||||
|
||||
- Si ça marche sur `127.0.0.1:8082` mais pas sur le domaine → proxy/cache.
|
||||
- Si ça marche après login Gitea mais pas via “Proposer” → variables `PUBLIC_GITEA_*`.
|
||||
- Si push refusé → branch protection (normal).
|
||||
|
||||
---
|
||||
|
||||
<a id="proposer-404"></a>
|
||||
## 1) “Proposer” ouvre Gitea mais retourne 404 / non autorisé
|
||||
|
||||
### Symptôme
|
||||
Nouvel onglet :
|
||||
- 404 Not Found / “n’existe pas ou pas autorisé”
|
||||
- ou redirect `/user/login`
|
||||
|
||||
### Cause la plus fréquente
|
||||
URL pointe vers **mauvais owner/repo** (casse sensible) :
|
||||
- `archicratia/archicratie-web` au lieu de `Archicratia/archicratie-edition`
|
||||
|
||||
### Diagnostic
|
||||
Sur NAS (ou dans le HTML généré), vérifier l’URL ouverte :
|
||||
- doit contenir : `/Archicratia/archicratie-edition/issues/new`
|
||||
|
||||
### Fix
|
||||
Dans `.env` de build prod (NAS) :
|
||||
- `PUBLIC_GITEA_OWNER=Archicratia`
|
||||
- `PUBLIC_GITEA_REPO=archicratie-edition`
|
||||
Puis rebuild + restart du container + smoke.
|
||||
|
||||
---
|
||||
|
||||
<a id="proposer-double-onglet"></a>
|
||||
## 2) Double onglet à la validation du flow “Proposer”
|
||||
|
||||
### Symptôme
|
||||
Deux onglets s’ouvrent au moment de valider (après choix 1 / choix 2).
|
||||
|
||||
### Causes possibles
|
||||
- handler JS déclenché deux fois (bubbling)
|
||||
- présence d’un `window.open` + `a.click()` simultanément
|
||||
- bouton “Proposer” est un `<a target=_blank>` et un autre handler ouvre aussi.
|
||||
|
||||
### Diagnostic rapide (devtools navigateur)
|
||||
Chercher `window.open` dans la page générée :
|
||||
- la commande doit retourner 0 lignes.
|
||||
|
||||
Sur NAS :
|
||||
en sh :
|
||||
|
||||
curl -fsS http://127.0.0.1:8082/archicratie/archicrat-ia/chapitre-4/ > /tmp/page.html
|
||||
grep -n "window.open" /tmp/page.html | head
|
||||
|
||||
Fix
|
||||
|
||||
garder un seul mécanisme d’ouverture
|
||||
|
||||
sur click : preventDefault() + stopImmediatePropagation()
|
||||
|
||||
<a id="Favicon-504-erreurs"></a>
|
||||
## 3) Favicon 504 / erreurs console sur favicon
|
||||
|
||||
# Symptôme
|
||||
|
||||
Console navigateur : GET /favicon.ico 504
|
||||
|
||||
# Cause fréquente
|
||||
|
||||
Cache du navigateur (ancienne erreur conservée).
|
||||
|
||||
# Diagnostic
|
||||
|
||||
Comparer :
|
||||
|
||||
curl -I http://127.0.0.1:8082/favicon.ico
|
||||
|
||||
curl -kI https://<domaine>/favicon.ico
|
||||
|
||||
Si curl = 200 et navigateur = 504 → cache.
|
||||
|
||||
# Fix
|
||||
|
||||
Désactiver cache dans l’onglet Réseau (devtools)
|
||||
|
||||
hard refresh
|
||||
|
||||
vérifier droits fichiers dans dist/
|
||||
|
||||
## 4) Sur NAS : git: command not found
|
||||
# Symptôme
|
||||
|
||||
git fetch impossible sur le NAS.
|
||||
|
||||
# Cause
|
||||
|
||||
Git non installé sur DSM shell.
|
||||
|
||||
# Fix standard (recommandé)
|
||||
|
||||
Utiliser un conteneur git :
|
||||
|
||||
APP="/volume2/docker/archicratie-web/current"
|
||||
U_ID="$(id -u)"; G_ID="$(id -g)"
|
||||
|
||||
sudo docker run --rm --network host \
|
||||
-u "$U_ID:$G_ID" -e HOME=/tmp \
|
||||
-v "$APP":/repo -w /repo \
|
||||
--entrypoint sh alpine/git -lc '
|
||||
set -eu
|
||||
git config --global --add safe.directory /repo
|
||||
git config http.sslVerify false
|
||||
git fetch origin --prune
|
||||
git status -sb
|
||||
'
|
||||
|
||||
## 5) Git : “dubious ownership in repository”
|
||||
# Symptôme
|
||||
|
||||
fatal: detected dubious ownership
|
||||
|
||||
# Fix
|
||||
|
||||
Dans le conteneur git (ou machine locale) :
|
||||
git config --global --add safe.directory /repo
|
||||
|
||||
## 6) Git : non-fast-forward au push
|
||||
# Symptôme
|
||||
|
||||
rejected (non-fast-forward)
|
||||
|
||||
# Cause
|
||||
|
||||
Ta branche locale est en retard vs remote.
|
||||
|
||||
# Fix
|
||||
|
||||
En général :
|
||||
|
||||
on fait une PR depuis une branche
|
||||
|
||||
ou on rebase/merge origin/main avant push
|
||||
|
||||
Sur une branche de travail :
|
||||
git fetch origin
|
||||
git rebase origin/main
|
||||
# ou
|
||||
git merge origin/main
|
||||
|
||||
## 7) Gitea : “Not allowed to push to protected branch main”
|
||||
# Symptôme
|
||||
|
||||
pre-receive hook declined
|
||||
|
||||
# Cause
|
||||
|
||||
Protection de branche (normal/attendu).
|
||||
|
||||
# Fix
|
||||
|
||||
Push sur une branche
|
||||
|
||||
Ouvrir PR
|
||||
|
||||
Merger via UI Gitea
|
||||
|
||||
## 8) Docker build : BuildKit / buildx / API version
|
||||
# Symptômes typiques
|
||||
|
||||
the --network option requires BuildKit
|
||||
|
||||
BuildKit is enabled but the buildx component is missing
|
||||
|
||||
client version ... too new. Maximum supported API version ...
|
||||
|
||||
# Fix “robuste” (principe)
|
||||
|
||||
installer buildx si nécessaire
|
||||
|
||||
si DSM/docker API ancienne : définir DOCKER_API_VERSION=<compatible> (selon ton environnement)
|
||||
|
||||
garder le build en --network host si nécessaire
|
||||
|
||||
## 9) Container Manager / Docker : “database is locked” (logging driver db)
|
||||
# Symptôme
|
||||
|
||||
failed to initialize logging driver : database is locked
|
||||
|
||||
# Cause
|
||||
|
||||
Le driver de logs Docker est db (Synology) et sa DB est verrouillée.
|
||||
|
||||
# Fix rapide
|
||||
|
||||
Redémarrer “Container Manager” depuis le centre de paquets DSM.
|
||||
|
||||
Vérifier que le conteneur redémarre ensuite.
|
||||
|
||||
## 10) Checklist “tout marche”
|
||||
|
||||
curl -I http://127.0.0.1:8082/ => 200
|
||||
|
||||
curl -kI https://<domaine>/ => 200
|
||||
|
||||
PUBLIC_GITEA_* corrects
|
||||
|
||||
“Proposer” : 1 onglet, pas de 404, issue pré-remplie
|
||||
|
||||
CI passe sur PR merge
|
||||
@@ -63,7 +63,7 @@ Si l’ID exact n’existe plus :
|
||||
But : éviter les “liens morts” historiques quand une régénération d’IDs a eu lieu.
|
||||
|
||||
Limite : c’est un fallback de dernier recours (moins déterministe qu’un alias explicite).
|
||||
Le mécanisme recommandé reste : `docs/anchor-aliases.json` + injection au build.
|
||||
Le mécanisme recommandé reste : `src/anchors/anchor-aliases.json` + injection au build.
|
||||
|
||||
_______________________________________
|
||||
|
||||
@@ -87,7 +87,7 @@ Les IDs d’ancres générés (ou dérivés) peuvent changer :
|
||||
|
||||
## 2) Le mapping d’alias
|
||||
|
||||
- Fichier versionné (ex) : `docs/anchor-aliases.json`
|
||||
- Fichier versionné (ex) : `src/anchors/anchor-aliases.json`
|
||||
- Format : `oldId -> newId` par page
|
||||
|
||||
Ex en json :
|
||||
|
||||
201
docs/auth-stack.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# Auth Stack — LLDAP + Authelia + Redis (DSM 7.3 / Synology DS220+)
|
||||
|
||||
## Objectif
|
||||
Fournir une pile d’authentification robuste (anti-lockout) pour protéger des services web via reverse-proxy :
|
||||
- Annuaire utilisateurs : **LLDAP**
|
||||
- Portail / SSO / MFA : **Authelia**
|
||||
- Cache/sessions (optionnel selon config) : **Redis**
|
||||
- Exposition publique : **Reverse proxy** (Synology / Nginx / Traefik) vers Authelia
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
### Composants
|
||||
- **LLDAP**
|
||||
- UI admin (HTTP) : `127.0.0.1:17170`
|
||||
- LDAP : `127.0.0.1:3890`
|
||||
- Base : sqlite dans `/volume2/docker/auth/data/lldap`
|
||||
|
||||
- **Authelia**
|
||||
- API/portal : `127.0.0.1:9091`
|
||||
- Stockage : sqlite dans `/volume2/docker/auth/data/authelia/db.sqlite3`
|
||||
- Accès externe : via reverse proxy -> `https://auth.<domaine>`
|
||||
|
||||
- **Redis**
|
||||
- Local uniquement : `127.0.0.1:6379`
|
||||
- (peut servir plus tard à sessions/rate-limit selon config)
|
||||
|
||||
### Exposition réseau (principe de sécurité)
|
||||
- Tous les services **bindés sur 127.0.0.1** (loopback NAS)
|
||||
- Seul le **reverse proxy** expose `https://auth.<domaine>` vers `127.0.0.1:9091`
|
||||
|
||||
---
|
||||
|
||||
## Fichiers de référence
|
||||
|
||||
### 1) docker-compose.auth.yml
|
||||
- Déploie redis + lldap + authelia.
|
||||
- Recommandation DSM : **network_mode: host** + bind sur localhost.
|
||||
- Supprime les aléas “bridge + DNS + subnets”
|
||||
- Évite les timeouts LDAP sporadiques.
|
||||
|
||||
### 2) /volume2/docker/auth/compose/.env
|
||||
Variables attendues :
|
||||
|
||||
#### LLDAP
|
||||
- `LLDAP_JWT_SECRET=...` (random 32+)
|
||||
- `LLDAP_KEY_SEED=...` (random 32+)
|
||||
- `LLDAP_LDAP_USER_PASS=...` (mot de passe admin LLDAP)
|
||||
|
||||
#### Authelia
|
||||
- `AUTHELIA_JWT_SECRET=...` (utilisé ici comme source pour reset_password)
|
||||
- `AUTHELIA_SESSION_SECRET=...`
|
||||
- `AUTHELIA_STORAGE_ENCRYPTION_KEY=...`
|
||||
|
||||
> Ne jamais committer `.env`. Stocker dans DSM / secrets.
|
||||
|
||||
### 3) /volume2/docker/auth/config/authelia/configuration.yml
|
||||
- LDAP address en mode robuste : `ldap://127.0.0.1:3890`
|
||||
- Cookie domain : `archicratie.trans-hands.synology.me`
|
||||
- `authelia_url` : `https://auth.archicratie.trans-hands.synology.me`
|
||||
- `default_redirection_url` : service principal (ex: gitea)
|
||||
|
||||
---
|
||||
|
||||
## Procédures opératoires
|
||||
|
||||
### Restart safe (redémarrage propre)
|
||||
en bash :
|
||||
cd /volume2/docker/auth/compose
|
||||
sudo docker compose --env-file .env -f docker-compose.auth.yml down --remove-orphans
|
||||
sudo docker compose --env-file .env -f docker-compose.auth.yml up -d --force-recreate
|
||||
|
||||
### Tests santé (sans dépendances DSM)
|
||||
curl -fsS http://127.0.0.1:17170/ >/dev/null && echo "LLDAP UI OK"
|
||||
curl -fsS http://127.0.0.1:9091/api/health && echo "AUTHELIA LOCAL OK"
|
||||
curl -kfsS https://auth.archicratie.trans-hands.synology.me/api/health && echo "AUTHELIA HTTPS OK"
|
||||
|
||||
### Test TCP LDAP :
|
||||
sudo docker run --rm --network host nicolaka/netshoot:latest sh -lc 'nc -vz -w2 127.0.0.1 3890'
|
||||
|
||||
### Rotate secrets (rotation)
|
||||
|
||||
# Principes :
|
||||
|
||||
Rotation = redémarrage forcé d’Authelia (sessions invalidées)
|
||||
|
||||
Rotation de LLDAP_KEY_SEED est sensible : peut affecter chiffrement des mots de passe.
|
||||
|
||||
# Procédure conseillée :
|
||||
|
||||
Sauvegarder DBs :
|
||||
|
||||
/volume2/docker/auth/data/lldap/users.db
|
||||
|
||||
/volume2/docker/auth/data/authelia/db.sqlite3
|
||||
|
||||
Changer d’abord secrets Authelia (AUTHELIA_SESSION_SECRET, AUTHELIA_STORAGE_ENCRYPTION_KEY)
|
||||
|
||||
docker compose up -d --force-recreate authelia
|
||||
|
||||
Vérifier /api/health + login.
|
||||
|
||||
Reset admin LLDAP (break-glass)
|
||||
|
||||
# Si tu perds le mot de passe admin :
|
||||
|
||||
Activer temporairement LLDAP_FORCE_LDAP_USER_PASS_RESET=true dans l’environnement LLDAP
|
||||
|
||||
Redémarrer LLDAP une seule fois
|
||||
|
||||
Désactiver immédiatement après.
|
||||
|
||||
⚠️ Ne jamais laisser ce flag en permanence : il force le reset à chaque boot.
|
||||
|
||||
## Checklist anti-lockout (indispensable)
|
||||
### 1) Accès direct local (bypass)
|
||||
|
||||
LLDAP UI accessible en local : http://127.0.0.1:17170
|
||||
|
||||
Authelia health local : http://127.0.0.1:9091/api/health
|
||||
|
||||
### 2) Règle Authelia : domaine auth en bypass
|
||||
|
||||
Dans configuration.yml :
|
||||
access_control:
|
||||
rules:
|
||||
- domain: "auth.<domaine>"
|
||||
policy: bypass
|
||||
|
||||
But : pouvoir charger le portail même si les règles des autres domaines cassent.
|
||||
|
||||
### 3) Route de secours reverse-proxy
|
||||
|
||||
Prévoir une route non protégée (ou protégée différemment) pour pouvoir corriger :
|
||||
|
||||
ex: https://admin.<domaine>/ ou un vhost interne LAN-only.
|
||||
|
||||
### 4) Fenêtre privée pour tester
|
||||
|
||||
Toujours tester login/authelia dans un onglet privé pour éviter cookies “fantômes”.
|
||||
|
||||
## Troubleshooting (ce qu’on a rencontré et résolu)
|
||||
### A) YAML/Compose cassé (tabs, doublons)
|
||||
|
||||
# Symptômes :
|
||||
|
||||
mapping key "ports" already defined
|
||||
|
||||
found character that cannot start any token
|
||||
|
||||
# Fix :
|
||||
|
||||
supprimer tabs
|
||||
|
||||
supprimer doublons (volumes/ports/networks)
|
||||
|
||||
valider : docker compose ... config
|
||||
|
||||
### B) Substitution foireuse des variables dans healthcheck
|
||||
|
||||
# Problème :
|
||||
|
||||
$VAR évalué par compose au parse-time
|
||||
|
||||
# Fix :
|
||||
|
||||
utiliser $$VAR dans CMD-SHELL si nécessaire.
|
||||
|
||||
### C) /config monté read-only
|
||||
|
||||
# Symptômes :
|
||||
|
||||
chown: /config/... Read-only file system
|
||||
|
||||
# Fix :
|
||||
|
||||
monter /config en :rw si Authelia doit écrire des backups/keys.
|
||||
|
||||
### D) Timeouts LDAP aléatoires en bridge
|
||||
|
||||
# Symptômes :
|
||||
|
||||
dial tcp <ip>:3890: i/o timeout
|
||||
|
||||
IP Docker “surprise” (subnet 192.168.32.0/20 etc.)
|
||||
|
||||
# Fix robuste DSM :
|
||||
|
||||
passer en network_mode: host + bind 127.0.0.1
|
||||
|
||||
Authelia -> ldap://127.0.0.1:3890
|
||||
|
||||
### E) “Authelia OK mais Gitea redemande login”
|
||||
|
||||
# Normal :
|
||||
|
||||
tant que Gitea n’est pas configuré en OIDC vers Authelia, ce n’est pas du SSO.
|
||||
|
||||
Authelia protège l’accès, mais ne crée pas de session Gitea.
|
||||
|
||||
@@ -0,0 +1,427 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1600"
|
||||
height="900"
|
||||
viewBox="0 0 1600 900"
|
||||
version="1.1"
|
||||
id="svg49"
|
||||
sodipodi:docname="archicratie-web-edition-blue-green-runbook-verbatim-v2.svg"
|
||||
inkscape:version="1.3-alpha (95f74fb, 2023-03-31)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview49"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.82625"
|
||||
inkscape:cx="726.17247"
|
||||
inkscape:cy="401.21029"
|
||||
inkscape:window-width="1472"
|
||||
inkscape:window-height="1022"
|
||||
inkscape:window-x="234"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg49" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<!-- Fond clair lisible partout -->
|
||||
<linearGradient
|
||||
id="bg"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#ffffff"
|
||||
id="stop1" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#f1f5f9"
|
||||
id="stop2" />
|
||||
</linearGradient>
|
||||
<!-- Flèches -->
|
||||
<marker
|
||||
id="arrow"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#334155"
|
||||
id="path2" />
|
||||
</marker>
|
||||
<marker
|
||||
id="arrowA"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#2563eb"
|
||||
id="path3" />
|
||||
</marker>
|
||||
<marker
|
||||
id="arrowG"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#059669"
|
||||
id="path4" />
|
||||
</marker>
|
||||
<!-- Styles SANS variables CSS (compat max) -->
|
||||
<style
|
||||
id="style4"><![CDATA[
|
||||
.title{font:800 28px/1.2 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#0f172a}
|
||||
.subtitle{font:500 14px/1.3 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#475569}
|
||||
.h{font:800 16px/1.2 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#0f172a}
|
||||
.t{font:500 13px/1.35 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#111827}
|
||||
.s{font:500 12px/1.35 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#475569}
|
||||
.mono{font:600 12px/1.35 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono','Courier New',monospace;fill:#0f172a}
|
||||
|
||||
/* Cadres lisibles */
|
||||
.box{fill:#ffffff;stroke:#0ea5e9;stroke-width:1.4}
|
||||
.box2{fill:#f8fafc;stroke:#94a3b8;stroke-width:1.2}
|
||||
|
||||
/* Pills */
|
||||
.chip{fill:#dbeafe;stroke:#2563eb;stroke-width:1}
|
||||
.chip2{fill:#d1fae5;stroke:#059669;stroke-width:1}
|
||||
.chipW{fill:#fef3c7;stroke:#d97706;stroke-width:1}
|
||||
.chipD{fill:#fee2e2;stroke:#dc2626;stroke-width:1}
|
||||
|
||||
/* Traits / flèches */
|
||||
.line{stroke:#334155;stroke-width:1.4;fill:none}
|
||||
.dash{stroke-dasharray:6 6}
|
||||
.arrow{stroke:#334155;stroke-width:1.8;fill:none;marker-end:url(#arrow)}
|
||||
.arrowA{stroke:#2563eb;stroke-width:2.0;fill:none;marker-end:url(#arrowA)}
|
||||
.arrowG{stroke:#059669;stroke-width:2.0;fill:none;marker-end:url(#arrowG)}
|
||||
]]></style>
|
||||
</defs>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="1600"
|
||||
height="900"
|
||||
fill="url(#bg)"
|
||||
id="rect4" />
|
||||
<text
|
||||
x="40"
|
||||
y="56"
|
||||
class="title"
|
||||
id="text4">Archicratie — Runbook Blue/Green (v2, verbatim)</text>
|
||||
<text
|
||||
x="40"
|
||||
y="84"
|
||||
class="subtitle"
|
||||
id="text5">Mise à jour 2026-02-20 — release-pack → releases/<ts>/app → current → docker compose web_blue/web_green</text>
|
||||
<rect
|
||||
x="40"
|
||||
y="130"
|
||||
width="500"
|
||||
height="240"
|
||||
class="box"
|
||||
id="rect5" />
|
||||
<text
|
||||
x="58"
|
||||
y="160"
|
||||
class="h"
|
||||
id="text6">0) Pré-requis</text>
|
||||
<text
|
||||
x="58"
|
||||
y="184"
|
||||
class="t"
|
||||
id="text7">main protégé → travail via branches + PR</text>
|
||||
<text
|
||||
x="58"
|
||||
y="202"
|
||||
class="t"
|
||||
id="text8">CI doit rester source de vérité</text>
|
||||
<text
|
||||
x="58"
|
||||
y="220"
|
||||
class="t"
|
||||
id="text9">Éviter d'éditer une release en prod (hotfix = exception)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="238"
|
||||
class="s"
|
||||
id="text10">Si hotfix: on le re-synchronise ensuite dans Git (cf. étape 5)</text>
|
||||
<rect
|
||||
x="40"
|
||||
y="400"
|
||||
width="500"
|
||||
height="260"
|
||||
class="box2"
|
||||
id="rect10" />
|
||||
<text
|
||||
x="58"
|
||||
y="430"
|
||||
class="h"
|
||||
id="text11">1) Préparer une release (atelier DEV)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="454"
|
||||
class="mono"
|
||||
id="text12">npm ci && npm run build</text>
|
||||
<text
|
||||
x="58"
|
||||
y="472"
|
||||
class="mono"
|
||||
id="text13">release-pack.sh → tarball/artefact</text>
|
||||
<text
|
||||
x="58"
|
||||
y="490"
|
||||
class="mono"
|
||||
id="text14">inclut dist/ + pagefind + indexes + build stamp</text>
|
||||
<text
|
||||
x="58"
|
||||
y="508"
|
||||
class="t"
|
||||
id="text15">ouvrir PR → merge → CI</text>
|
||||
<rect
|
||||
x="40"
|
||||
y="690"
|
||||
width="500"
|
||||
height="170"
|
||||
class="box"
|
||||
id="rect15" />
|
||||
<text
|
||||
x="58"
|
||||
y="720"
|
||||
class="h"
|
||||
id="text16">2) Déposer sur NAS</text>
|
||||
<text
|
||||
x="58"
|
||||
y="744"
|
||||
class="mono"
|
||||
id="text17">/volume2/docker/archicratie-web/releases/<ts>/app</text>
|
||||
<text
|
||||
x="58"
|
||||
y="762"
|
||||
class="mono"
|
||||
id="text18">current → pointe vers la release active</text>
|
||||
<text
|
||||
x="58"
|
||||
y="780"
|
||||
class="t"
|
||||
id="text19">build context docker = current OU release/app (selon compose)</text>
|
||||
<rect
|
||||
x="600"
|
||||
y="130"
|
||||
width="520"
|
||||
height="210"
|
||||
class="box"
|
||||
id="rect19" />
|
||||
<text
|
||||
x="618"
|
||||
y="160"
|
||||
class="h"
|
||||
id="text20">3) Build images</text>
|
||||
<text
|
||||
x="618"
|
||||
y="184"
|
||||
class="mono"
|
||||
id="text21">sudo env DOCKER_API_VERSION=1.43 \</text>
|
||||
<text
|
||||
x="618"
|
||||
y="202"
|
||||
class="mono"
|
||||
id="text22">docker compose -f docker-compose.yml build --no-cache \</text>
|
||||
<text
|
||||
x="618"
|
||||
y="220"
|
||||
class="mono"
|
||||
id="text23"> web_blue web_green</text>
|
||||
<text
|
||||
x="618"
|
||||
y="238"
|
||||
class="s"
|
||||
id="text24">les 2 images doivent builder OK</text>
|
||||
<rect
|
||||
x="639.93951"
|
||||
y="378.7897"
|
||||
width="480.06052"
|
||||
height="241.21028"
|
||||
class="box2"
|
||||
id="rect24" />
|
||||
<text
|
||||
x="658"
|
||||
y="410"
|
||||
class="h"
|
||||
id="text25"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16px;line-height:1.2;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">4) Switch trafic (blue ↔ green)</text>
|
||||
<text
|
||||
x="658"
|
||||
y="434"
|
||||
class="t"
|
||||
id="text26"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">déterminer couleur active (proxy / conf)</text>
|
||||
<text
|
||||
x="658"
|
||||
y="452"
|
||||
class="t"
|
||||
id="text27"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">mettre à jour routing vers l'autre couleur</text>
|
||||
<text
|
||||
x="658"
|
||||
y="470"
|
||||
class="t"
|
||||
id="text28"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">reload proxy, vérifier 200/302</text>
|
||||
<text
|
||||
x="658"
|
||||
y="488"
|
||||
class="mono"
|
||||
id="text29"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">curl -sSI -H 'Host: staging.*' http://127.0.0.1:18080/</text>
|
||||
<text
|
||||
x="658"
|
||||
y="506"
|
||||
class="s"
|
||||
id="text30"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">rollback = revenir à l'ancienne couleur</text>
|
||||
<rect
|
||||
x="600"
|
||||
y="660"
|
||||
width="520"
|
||||
height="210"
|
||||
class="box"
|
||||
id="rect30" />
|
||||
<text
|
||||
x="618"
|
||||
y="690"
|
||||
class="h"
|
||||
id="text31">5) Hotfix de release → re-synchroniser Git (step8)</text>
|
||||
<text
|
||||
x="618"
|
||||
y="714"
|
||||
class="t"
|
||||
id="text32">A) NAS: find src -mtime -3 → liste fichiers</text>
|
||||
<text
|
||||
x="618"
|
||||
y="732"
|
||||
class="t"
|
||||
id="text33">B) NAS: tar -czf /tmp/hotfix.tgz -T liste</text>
|
||||
<text
|
||||
x="618"
|
||||
y="750"
|
||||
class="t"
|
||||
id="text34">C) sha256 + manifest, puis scp vers Mac</text>
|
||||
<text
|
||||
x="618"
|
||||
y="768"
|
||||
class="t"
|
||||
id="text35">D) Mac: tar -xzf → rsync --checksum vers repo</text>
|
||||
<text
|
||||
x="618"
|
||||
y="786"
|
||||
class="t"
|
||||
id="text36">E) commit sur branche dédiée → push → PR vers main</text>
|
||||
<rect
|
||||
x="1180"
|
||||
y="160"
|
||||
width="380"
|
||||
height="520"
|
||||
class="box2"
|
||||
id="rect36" />
|
||||
<text
|
||||
x="1198"
|
||||
y="190"
|
||||
class="h"
|
||||
id="text37">Arborescence NAS (rappel)</text>
|
||||
<text
|
||||
x="1198"
|
||||
y="214"
|
||||
class="mono"
|
||||
id="text38">/volume2/docker/archicratie-web/</text>
|
||||
<text
|
||||
x="1198"
|
||||
y="232"
|
||||
class="mono"
|
||||
id="text39"> releases/</text>
|
||||
<text
|
||||
x="1198"
|
||||
y="250"
|
||||
class="mono"
|
||||
id="text40"> 20260219-103222/</text>
|
||||
<text
|
||||
x="1198"
|
||||
y="268"
|
||||
class="mono"
|
||||
id="text41"> app/ (ctx build)</text>
|
||||
<text
|
||||
x="1198"
|
||||
y="286"
|
||||
class="mono"
|
||||
id="text42"> current -> releases/…/app</text>
|
||||
<text
|
||||
x="1198"
|
||||
y="304"
|
||||
class="mono"
|
||||
id="text43"> compose/ docker-compose.yml</text>
|
||||
<text
|
||||
x="1198"
|
||||
y="322"
|
||||
class="s"
|
||||
id="text44">compose.expanded.yml t'indique le build.context effectif</text>
|
||||
<path
|
||||
d="M 540,520 H 642.36006"
|
||||
class="arrowA"
|
||||
id="path44"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
x="545"
|
||||
y="500"
|
||||
class="s"
|
||||
id="text45">→ NAS + build</text>
|
||||
<path
|
||||
d="M860 340 C860 360 860 360 860 380"
|
||||
class="arrowA"
|
||||
id="path45" />
|
||||
<text
|
||||
x="875"
|
||||
y="365"
|
||||
class="s"
|
||||
id="text46">images OK</text>
|
||||
<path
|
||||
d="M860 620 C860 640 860 640 860 660"
|
||||
class="arrowG"
|
||||
id="path46" />
|
||||
<text
|
||||
x="875"
|
||||
y="645"
|
||||
class="s"
|
||||
id="text47">si hotfix</text>
|
||||
<rect
|
||||
x="40"
|
||||
y="20"
|
||||
width="1520"
|
||||
height="80"
|
||||
class="box2"
|
||||
id="rect47" />
|
||||
<text
|
||||
x="58"
|
||||
y="50"
|
||||
class="h"
|
||||
id="text48">Règle d'or</text>
|
||||
<text
|
||||
x="58"
|
||||
y="74"
|
||||
class="t"
|
||||
id="text49">La release doit être reproductible depuis Git. Toute modif manuelle en prod doit finir: (a) re-sync dans une branche, (b) PR, (c) merge, (d) prochaine release propre.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,551 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1600"
|
||||
height="1020"
|
||||
viewBox="0 0 1600 1020"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="archicratie-web-edition-blue-green-runbook-verbatim.svg"
|
||||
inkscape:version="1.3-alpha (95f74fb, 2023-03-31)"
|
||||
inkscape:export-filename="out/archicratie-web-edition-blue-green-runbook-verbatim.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#111111"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="1"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.0606602"
|
||||
inkscape:cx="675.05126"
|
||||
inkscape:cy="300.28467"
|
||||
inkscape:window-width="1472"
|
||||
inkscape:window-height="1022"
|
||||
inkscape:window-x="222"
|
||||
inkscape:window-y="74"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<style
|
||||
id="style1"><![CDATA[
|
||||
.bg { fill: #fff; }
|
||||
.outer { fill: #fff; stroke: #111; stroke-width: 3; rx: 18; }
|
||||
.box { fill: #fff; stroke: #111; stroke-width: 2; rx: 14; }
|
||||
.ok { fill: #eafff1; stroke: #1a7f37; stroke-width: 2; rx: 14; }
|
||||
.warn { fill: #fff0f0; stroke: #b42318; stroke-width: 2; rx: 14; }
|
||||
.title { font: 800 40px system-ui, -apple-system, Segoe UI, Roboto, Arial; fill: #111; }
|
||||
.subtitle { font: 500 16px system-ui, -apple-system, Segoe UI, Roboto, Arial; fill: #333; }
|
||||
.h2 { font: 800 24px system-ui, -apple-system, Segoe UI, Roboto, Arial; fill: #111; }
|
||||
.h3 { font: 800 20px system-ui, -apple-system, Segoe UI, Roboto, Arial; fill: #111; }
|
||||
.txt { font: 500 16px system-ui, -apple-system, Segoe UI, Roboto, Arial; fill: #111; }
|
||||
.small { font: 500 12px system-ui, -apple-system, Segoe UI, Roboto, Arial; fill: #333; }
|
||||
.mono { font: 500 12px ui-monospace, SFMono-Regular, Menlo, monospace; fill: #111; }
|
||||
.arrow { stroke: #111; stroke-width: 2; fill: none; marker-end: url(#arrow); }
|
||||
.arrowThin { stroke: #111; stroke-width: 1.5; fill: none; marker-end: url(#arrow); }
|
||||
.cap { stroke-linecap: round; stroke-linejoin: round; }
|
||||
]]></style>
|
||||
<marker
|
||||
id="arrow"
|
||||
viewBox="0 0 10 10"
|
||||
refX="9"
|
||||
refY="5"
|
||||
markerWidth="8"
|
||||
markerHeight="8"
|
||||
orient="auto-start-reverse">
|
||||
<path
|
||||
d="M 0 0 L 10 5 L 0 10 z"
|
||||
fill="#111"
|
||||
id="path1" />
|
||||
</marker>
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<!-- Title -->
|
||||
<text
|
||||
x="40"
|
||||
y="55"
|
||||
class="title"
|
||||
id="text1">Archicratie – Web Edition : Blue/Green Runbook visuel (VERBATIM)</text>
|
||||
<text
|
||||
x="40"
|
||||
y="88"
|
||||
class="subtitle"
|
||||
id="text2">Cible : déployer une nouvelle version sur le slot inactif (8081/8082), basculer via Traefik (dynamic/20-archicratie-backend.yml), vérifier (smoke tests), rollback en 30s si besoin.</text>
|
||||
<!-- Outer frame -->
|
||||
<rect
|
||||
x="30"
|
||||
y="110"
|
||||
width="1540"
|
||||
height="870"
|
||||
class="outer"
|
||||
id="rect2" />
|
||||
<!-- Invariants box -->
|
||||
<rect
|
||||
x="60"
|
||||
y="140"
|
||||
width="1480"
|
||||
height="130"
|
||||
class="box"
|
||||
id="rect3" />
|
||||
<text
|
||||
x="90"
|
||||
y="175"
|
||||
class="h2"
|
||||
id="text3">Invariants (ce qui évite de casser la prod)</text>
|
||||
<text
|
||||
x="90"
|
||||
y="198"
|
||||
class="txt"
|
||||
id="text4">• Les 2 slots existent en parallèle : archicratie-web-blue = 127.0.0.1:8081 et archicratie-web-green = 127.0.0.1:8082.</text>
|
||||
<text
|
||||
x="90"
|
||||
y="220"
|
||||
class="txt"
|
||||
id="text5">• Traefik edge écoute :18080 et choisit le slot LIVE via /volume2/docker/edge/config/dynamic/20-archicratie-backend.yml.</text>
|
||||
<text
|
||||
x="90"
|
||||
y="242"
|
||||
class="txt"
|
||||
id="text7">• Une seule cible active dans Traefik (pas de load-balance non déterministe). Rollback = remettre l’URL précédente dans le même fichier.</text>
|
||||
<!-- RIGUEUR ABSOLUE (ajout non destructif) -->
|
||||
<rect
|
||||
x="64"
|
||||
y="269"
|
||||
width="1480"
|
||||
height="30"
|
||||
rx="12"
|
||||
class="warn"
|
||||
id="rect-rigueur" />
|
||||
<text
|
||||
x="84"
|
||||
y="289"
|
||||
class="txt"
|
||||
id="text-rigueur"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:16px;line-height:normal;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">• RIGUEUR ABSOLUE : STAGING = slot INACTIF (opposé au LIVE). LIVE = 20-archicratie-backend.yml ; STAGING = 21-archicratie-staging.yml.</text>
|
||||
<!-- Step columns -->
|
||||
<!-- Column 1 -->
|
||||
<rect
|
||||
x="60"
|
||||
y="300"
|
||||
width="470"
|
||||
height="610"
|
||||
class="box"
|
||||
id="rect4" />
|
||||
<text
|
||||
x="90"
|
||||
y="335"
|
||||
class="h2"
|
||||
id="text8">Étape 1 — Build & déployer</text>
|
||||
<text
|
||||
x="90"
|
||||
y="365"
|
||||
class="h3"
|
||||
id="text9">But</text>
|
||||
<text
|
||||
x="90"
|
||||
y="387"
|
||||
class="txt"
|
||||
id="text10">Mettre la nouvelle version sur le slot inactif</text>
|
||||
<text
|
||||
x="90"
|
||||
y="409"
|
||||
class="txt"
|
||||
id="text11">(sans toucher au slot LIVE actuel).</text>
|
||||
<!-- Où box -->
|
||||
<rect
|
||||
x="90"
|
||||
y="435"
|
||||
width="410"
|
||||
height="210"
|
||||
class="box"
|
||||
id="rect5" />
|
||||
<text
|
||||
x="110"
|
||||
y="465"
|
||||
class="h3"
|
||||
id="text12">Où</text>
|
||||
<text
|
||||
x="110"
|
||||
y="490"
|
||||
class="mono"
|
||||
id="text13">/volume2/docker/archicratie-web/current/</text>
|
||||
<text
|
||||
x="110"
|
||||
y="515"
|
||||
class="txt"
|
||||
id="text14">Compose : docker-compose.yml</text>
|
||||
<text
|
||||
x="110"
|
||||
y="545"
|
||||
class="txt"
|
||||
id="text15">Slots :</text>
|
||||
<text
|
||||
x="140"
|
||||
y="568"
|
||||
class="mono"
|
||||
id="text16">web_blue → 127.0.0.1:8081</text>
|
||||
<text
|
||||
x="140"
|
||||
y="590"
|
||||
class="mono"
|
||||
id="text17">web_green → 127.0.0.1:8082</text>
|
||||
<text
|
||||
x="110"
|
||||
y="622"
|
||||
class="small"
|
||||
id="text18">Le build injecte aussi PUBLIC_GITEA_* via build args</text>
|
||||
<text
|
||||
x="110"
|
||||
y="640"
|
||||
class="small"
|
||||
id="text19">(déjà dans ton compose).</text>
|
||||
<!-- Commands box -->
|
||||
<rect
|
||||
x="90"
|
||||
y="665"
|
||||
width="410"
|
||||
height="225"
|
||||
class="box"
|
||||
id="rect6" />
|
||||
<text
|
||||
x="110"
|
||||
y="695"
|
||||
class="h3"
|
||||
id="text20">Commandes (safe)</text>
|
||||
<text
|
||||
x="110"
|
||||
y="720"
|
||||
class="txt"
|
||||
id="text21">1) Choisir le slot cible (inactif)</text>
|
||||
<text
|
||||
x="100"
|
||||
y="742"
|
||||
class="small"
|
||||
id="text22"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:normal;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Astuce : le LIVE = ce que pointe Traefik dans 20-archicratie-backend.yml</text>
|
||||
<text
|
||||
x="110"
|
||||
y="770"
|
||||
class="txt"
|
||||
id="text23">2) Build + redémarrer uniquement ce slot</text>
|
||||
<text
|
||||
x="130"
|
||||
y="794"
|
||||
class="mono"
|
||||
id="text24">cd /volume2/docker/archicratie-web/current</text>
|
||||
<text
|
||||
x="130"
|
||||
y="814"
|
||||
class="mono"
|
||||
id="text25">sudo docker compose build web_green</text>
|
||||
<text
|
||||
x="130"
|
||||
y="834"
|
||||
class="mono"
|
||||
id="text26">sudo docker compose up -d --no-deps web_green</text>
|
||||
<text
|
||||
x="110"
|
||||
y="862"
|
||||
class="small"
|
||||
id="text27">Remplace web_green par web_blue selon la cible.</text>
|
||||
<text
|
||||
x="110"
|
||||
y="880"
|
||||
class="small"
|
||||
id="text28">Ne pas toucher l’autre service.</text>
|
||||
<!-- Arrow to column 2 -->
|
||||
<path
|
||||
d="M 530 605 L 560 605"
|
||||
class="arrow cap"
|
||||
id="path6" />
|
||||
<!-- Column 2 -->
|
||||
<rect
|
||||
x="560"
|
||||
y="300"
|
||||
width="470"
|
||||
height="610"
|
||||
class="box"
|
||||
id="rect7" />
|
||||
<text
|
||||
x="590"
|
||||
y="335"
|
||||
class="h2"
|
||||
id="text29">Étape 2 — Switch Traefik (LIVE)</text>
|
||||
<text
|
||||
x="590"
|
||||
y="365"
|
||||
class="h3"
|
||||
id="text30">But</text>
|
||||
<text
|
||||
x="590"
|
||||
y="387"
|
||||
class="txt"
|
||||
id="text31">Basculer le LIVE en modifiant 1 fichier</text>
|
||||
<text
|
||||
x="590"
|
||||
y="409"
|
||||
class="txt"
|
||||
id="text32">et laisser Traefik recharger automatiquement.</text>
|
||||
<!-- Canon file box -->
|
||||
<rect
|
||||
x="565.48694"
|
||||
y="433.11438"
|
||||
width="458.08331"
|
||||
height="176.31372"
|
||||
class="box"
|
||||
id="rect8"
|
||||
ry="0" />
|
||||
<text
|
||||
x="610"
|
||||
y="465"
|
||||
class="h3"
|
||||
id="text33">Fichier canonique (LIVE switch)</text>
|
||||
<text
|
||||
x="572"
|
||||
y="490"
|
||||
class="mono"
|
||||
id="text34"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">/volume2/docker/edge/config/dynamic/20-archicratie-backend.yml</text>
|
||||
<text
|
||||
x="610"
|
||||
y="520"
|
||||
class="txt"
|
||||
id="text35">Contient :</text>
|
||||
<text
|
||||
x="588"
|
||||
y="545"
|
||||
class="mono"
|
||||
id="text36"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">http.services.archicratie_web.loadBalancer.servers[0].url</text>
|
||||
<text
|
||||
x="610"
|
||||
y="575"
|
||||
class="txt"
|
||||
id="text37">Ex : http://127.0.0.1:8082 (green)</text>
|
||||
<text
|
||||
x="610"
|
||||
y="597"
|
||||
class="txt"
|
||||
id="text38">ou http://127.0.0.1:8081 (blue)</text>
|
||||
<!-- Procedure warn box -->
|
||||
<rect
|
||||
x="567.37256"
|
||||
y="621.88562"
|
||||
width="454.31201"
|
||||
height="279.4281"
|
||||
class="warn"
|
||||
id="rect9" />
|
||||
<text
|
||||
x="610"
|
||||
y="644"
|
||||
class="h3"
|
||||
id="text39"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:20px;line-height:normal;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Procédure (anti-casse)</text>
|
||||
<text
|
||||
x="576"
|
||||
y="668"
|
||||
class="txt"
|
||||
id="text40"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:16px;line-height:normal;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">1) Backup horodaté du fichier</text>
|
||||
<text
|
||||
x="591"
|
||||
y="690"
|
||||
class="mono"
|
||||
id="text41"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">cd /volume2/docker/edge/config/dynamic</text>
|
||||
<text
|
||||
x="577"
|
||||
y="712"
|
||||
class="mono"
|
||||
id="text42"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2"
|
||||
x="577"
|
||||
y="712">sudo cp 20-archicratie-backend.yml</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3"
|
||||
x="577"
|
||||
y="727">20-archicratie-backend.yml.bak.$(date +%F-%H%M%S)</tspan></text>
|
||||
<text
|
||||
x="576"
|
||||
y="752"
|
||||
class="txt"
|
||||
id="text43"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:16px;line-height:normal;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">2) Éditer l’URL (un seul backend)</text>
|
||||
<text
|
||||
x="591"
|
||||
y="774"
|
||||
class="mono"
|
||||
id="text44"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">sudo vi 20-archicratie-backend.yml</text>
|
||||
<text
|
||||
x="591"
|
||||
y="788"
|
||||
class="small"
|
||||
id="text47"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:normal;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Changer uniquement la valeur url : 8081 ↔ 8082</text>
|
||||
<text
|
||||
x="571"
|
||||
y="810"
|
||||
class="txt"
|
||||
id="text45bis"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:16px;line-height:normal;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4"
|
||||
x="571"
|
||||
y="810">2bis) Mettre à jour 21-archicratie-staging.yml sur l’autre port</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5"
|
||||
x="571"
|
||||
y="830">(opposé au LIVE)</tspan></text>
|
||||
<text
|
||||
x="571"
|
||||
y="856"
|
||||
class="txt"
|
||||
id="text45"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:16px;line-height:normal;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">3) Traefik recharge (watch=true)</text>
|
||||
<text
|
||||
x="591"
|
||||
y="878"
|
||||
class="small"
|
||||
id="text46"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan71"
|
||||
x="591"
|
||||
y="878">Pas de restart requis si provider file watch=true</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan72"
|
||||
x="591"
|
||||
y="893">(ton traefik.yml).</tspan></text>
|
||||
<!-- Arrow to column 3 -->
|
||||
<path
|
||||
d="M 1030 605 L 1060 605"
|
||||
class="arrow cap"
|
||||
id="path7" />
|
||||
<!-- Column 3 -->
|
||||
<rect
|
||||
x="1060"
|
||||
y="300"
|
||||
width="480"
|
||||
height="610"
|
||||
class="box"
|
||||
id="rect10" />
|
||||
<text
|
||||
x="1090"
|
||||
y="335"
|
||||
class="h2"
|
||||
id="text48">Étape 3 — Smoke tests</text>
|
||||
<text
|
||||
x="1090"
|
||||
y="365"
|
||||
class="h3"
|
||||
id="text49">But</text>
|
||||
<text
|
||||
x="1090"
|
||||
y="387"
|
||||
class="txt"
|
||||
id="text50">Prouver que le nouveau LIVE répond,</text>
|
||||
<text
|
||||
x="1090"
|
||||
y="409"
|
||||
class="txt"
|
||||
id="text51">et que l’auth (Authelia/whoami) est OK.</text>
|
||||
<!-- Slot direct ok box -->
|
||||
<rect
|
||||
x="1090"
|
||||
y="435"
|
||||
width="420"
|
||||
height="185"
|
||||
class="ok"
|
||||
id="rect11" />
|
||||
<text
|
||||
x="1110"
|
||||
y="465"
|
||||
class="h3"
|
||||
id="text52">Tests “slot direct” (preuve build)</text>
|
||||
<text
|
||||
x="1110"
|
||||
y="490"
|
||||
class="txt"
|
||||
id="text53">Le slot construit doit répondre en 200 :</text>
|
||||
<text
|
||||
x="1130"
|
||||
y="515"
|
||||
class="mono"
|
||||
id="text54">curl -sS -I http://127.0.0.1:8081/ | head -n 12</text>
|
||||
<text
|
||||
x="1130"
|
||||
y="540"
|
||||
class="mono"
|
||||
id="text55">curl -sS -I http://127.0.0.1:8082/ | head -n 12</text>
|
||||
<text
|
||||
x="1110"
|
||||
y="570"
|
||||
class="small"
|
||||
id="text56">L’un des deux peut rester l’ancien LIVE.</text>
|
||||
<text
|
||||
x="1110"
|
||||
y="590"
|
||||
class="small"
|
||||
id="text57">L’objectif est que le slot cible soit OK.</text>
|
||||
<!-- Edge tests box -->
|
||||
<rect
|
||||
x="1090"
|
||||
y="638.4342"
|
||||
width="420"
|
||||
height="251.56581"
|
||||
class="box"
|
||||
id="rect54" />
|
||||
<text
|
||||
x="1110"
|
||||
y="675"
|
||||
class="h3"
|
||||
id="text57b"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:20px;line-height:normal;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Tests “edge” (preuve routage + auth)</text>
|
||||
<text
|
||||
x="1110"
|
||||
y="700"
|
||||
class="txt"
|
||||
id="text57c"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:16px;line-height:normal;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Host rules : tester AVEC Host header :</text>
|
||||
<text
|
||||
x="1130"
|
||||
y="724"
|
||||
class="mono"
|
||||
id="text57d"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan57d1"
|
||||
x="1130"
|
||||
y="724">curl -sS -I -H 'Host:</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan57d2"
|
||||
x="1130"
|
||||
y="739">archicratie.trans-hands.synology.me'</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="1130"
|
||||
y="754"
|
||||
id="tspan57d3">http://127.0.0.1:18080/ | head -n 20</tspan></text>
|
||||
<text
|
||||
x="1130"
|
||||
y="780"
|
||||
class="mono"
|
||||
id="text58"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace"><tspan
|
||||
id="tspan1" /></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,437 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1600"
|
||||
height="900"
|
||||
viewBox="0 0 1600 900"
|
||||
version="1.1"
|
||||
id="svg43"
|
||||
sodipodi:docname="archicratie-web-edition-edge-routing-verbatim-v2.svg"
|
||||
inkscape:version="1.3-alpha (95f74fb, 2023-03-31)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview43"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.82625"
|
||||
inkscape:cx="424.81089"
|
||||
inkscape:cy="464.14523"
|
||||
inkscape:window-width="1472"
|
||||
inkscape:window-height="1022"
|
||||
inkscape:window-x="234"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg43" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<!-- Fond clair lisible partout -->
|
||||
<linearGradient
|
||||
id="bg"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#ffffff"
|
||||
id="stop1" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#f1f5f9"
|
||||
id="stop2" />
|
||||
</linearGradient>
|
||||
<!-- Flèches -->
|
||||
<marker
|
||||
id="arrow"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#334155"
|
||||
id="path2" />
|
||||
</marker>
|
||||
<marker
|
||||
id="arrowA"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#2563eb"
|
||||
id="path3" />
|
||||
</marker>
|
||||
<marker
|
||||
id="arrowG"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#059669"
|
||||
id="path4" />
|
||||
</marker>
|
||||
<!-- Styles SANS variables CSS (compat max) -->
|
||||
<style
|
||||
id="style4"><![CDATA[
|
||||
.title{font:800 28px/1.2 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#0f172a}
|
||||
.subtitle{font:500 14px/1.3 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#475569}
|
||||
.h{font:800 16px/1.2 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#0f172a}
|
||||
.t{font:500 13px/1.35 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#111827}
|
||||
.s{font:500 12px/1.35 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#475569}
|
||||
.mono{font:600 12px/1.35 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono','Courier New',monospace;fill:#0f172a}
|
||||
|
||||
/* Cadres lisibles */
|
||||
.box{fill:#ffffff;stroke:#0ea5e9;stroke-width:1.4}
|
||||
.box2{fill:#f8fafc;stroke:#94a3b8;stroke-width:1.2}
|
||||
|
||||
/* Pills */
|
||||
.chip{fill:#dbeafe;stroke:#2563eb;stroke-width:1}
|
||||
.chip2{fill:#d1fae5;stroke:#059669;stroke-width:1}
|
||||
.chipW{fill:#fef3c7;stroke:#d97706;stroke-width:1}
|
||||
.chipD{fill:#fee2e2;stroke:#dc2626;stroke-width:1}
|
||||
|
||||
/* Traits / flèches */
|
||||
.line{stroke:#334155;stroke-width:1.4;fill:none}
|
||||
.dash{stroke-dasharray:6 6}
|
||||
.arrow{stroke:#334155;stroke-width:1.8;fill:none;marker-end:url(#arrow)}
|
||||
.arrowA{stroke:#2563eb;stroke-width:2.0;fill:none;marker-end:url(#arrowA)}
|
||||
.arrowG{stroke:#059669;stroke-width:2.0;fill:none;marker-end:url(#arrowG)}
|
||||
]]></style>
|
||||
</defs>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="1600"
|
||||
height="900"
|
||||
fill="url(#bg)"
|
||||
id="rect4" />
|
||||
<text
|
||||
x="40"
|
||||
y="56"
|
||||
class="title"
|
||||
id="text4">Archicratie — Edge routing (v2, verbatim)</text>
|
||||
<text
|
||||
x="40"
|
||||
y="84"
|
||||
class="subtitle"
|
||||
id="text5">Mise à jour 2026-02-20 — Host routing + Authelia + Blue/Green web_*</text>
|
||||
<rect
|
||||
x="40"
|
||||
y="140"
|
||||
width="420"
|
||||
height="180"
|
||||
class="box"
|
||||
id="rect5" />
|
||||
<text
|
||||
x="58"
|
||||
y="170"
|
||||
class="h"
|
||||
id="text6">Client (navigateur)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="194"
|
||||
class="t"
|
||||
id="text7">https://archicratie.* / https://staging.archicratie.*</text>
|
||||
<text
|
||||
x="58"
|
||||
y="212"
|
||||
class="t"
|
||||
id="text8">cookies authelia_session</text>
|
||||
<text
|
||||
x="58"
|
||||
y="230"
|
||||
class="s"
|
||||
id="text9">HEAD/GET → 302 si non auth</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="320"
|
||||
width="110"
|
||||
height="28"
|
||||
class="chip2"
|
||||
id="rect9" />
|
||||
<text
|
||||
x="74"
|
||||
y="339"
|
||||
class="mono"
|
||||
id="text10">HTTPS 443</text>
|
||||
<rect
|
||||
x="520"
|
||||
y="120"
|
||||
width="520"
|
||||
height="260"
|
||||
class="box"
|
||||
id="rect10" />
|
||||
<text
|
||||
x="538"
|
||||
y="150"
|
||||
class="h"
|
||||
id="text11">Reverse-proxy (Nginx / DSM)</text>
|
||||
<text
|
||||
x="538"
|
||||
y="174"
|
||||
class="t"
|
||||
id="text12">Routage par Host</text>
|
||||
<text
|
||||
x="538"
|
||||
y="192"
|
||||
class="t"
|
||||
id="text13">auth_request → Authelia</text>
|
||||
<text
|
||||
x="538"
|
||||
y="210"
|
||||
class="t"
|
||||
id="text14">proxy_pass → service web_blue ou web_green</text>
|
||||
<text
|
||||
x="538"
|
||||
y="228"
|
||||
class="t"
|
||||
id="text15">headers: X-Forwarded-* + Host</text>
|
||||
<text
|
||||
x="538"
|
||||
y="246"
|
||||
class="s"
|
||||
id="text16">en local: curl -H 'Host: ...' http://127.0.0.1:18080/</text>
|
||||
<rect
|
||||
x="540"
|
||||
y="320"
|
||||
width="142"
|
||||
height="28"
|
||||
class="chip"
|
||||
id="rect16" />
|
||||
<text
|
||||
x="554"
|
||||
y="339"
|
||||
class="mono"
|
||||
id="text17">auth_request</text>
|
||||
<rect
|
||||
x="520"
|
||||
y="420"
|
||||
width="520"
|
||||
height="210"
|
||||
class="box2"
|
||||
id="rect17" />
|
||||
<text
|
||||
x="538"
|
||||
y="450"
|
||||
class="h"
|
||||
id="text18">Auth stack</text>
|
||||
<text
|
||||
x="538"
|
||||
y="474"
|
||||
class="t"
|
||||
id="text19">Authelia (portal login)</text>
|
||||
<text
|
||||
x="538"
|
||||
y="492"
|
||||
class="t"
|
||||
id="text20">LLDAP (backend LDAP)</text>
|
||||
<text
|
||||
x="538"
|
||||
y="510"
|
||||
class="t"
|
||||
id="text21">Redis (sessions / storage)</text>
|
||||
<text
|
||||
x="538"
|
||||
y="528"
|
||||
class="s"
|
||||
id="text22">auth.* domain</text>
|
||||
<rect
|
||||
x="540"
|
||||
y="600"
|
||||
width="250"
|
||||
height="28"
|
||||
class="chipW"
|
||||
id="rect22" />
|
||||
<text
|
||||
x="554"
|
||||
y="619"
|
||||
class="mono"
|
||||
id="text23">302 → auth.*?rd=...</text>
|
||||
<rect
|
||||
x="1175.0378"
|
||||
y="237.57942"
|
||||
width="384.96219"
|
||||
height="162.42058"
|
||||
class="box"
|
||||
id="rect23" />
|
||||
<text
|
||||
x="1198"
|
||||
y="270"
|
||||
class="h"
|
||||
id="text24"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16px;line-height:1.2;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Service web_blue (container)</text>
|
||||
<text
|
||||
x="1198"
|
||||
y="294"
|
||||
class="mono"
|
||||
id="text25"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">nginx static (dist/)</text>
|
||||
<text
|
||||
x="1198"
|
||||
y="312"
|
||||
class="mono"
|
||||
id="text26"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">/pagefind/*, /assets/*</text>
|
||||
<rect
|
||||
x="1172.6172"
|
||||
y="417.57944"
|
||||
width="387.38275"
|
||||
height="162.42058"
|
||||
class="box"
|
||||
id="rect26" />
|
||||
<text
|
||||
x="1198"
|
||||
y="450"
|
||||
class="h"
|
||||
id="text27"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16px;line-height:1.2;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Service web_green (container)</text>
|
||||
<text
|
||||
x="1198"
|
||||
y="474"
|
||||
class="mono"
|
||||
id="text28"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">nginx static (dist/)</text>
|
||||
<text
|
||||
x="1198"
|
||||
y="492"
|
||||
class="mono"
|
||||
id="text29"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">build identique, couleur swap</text>
|
||||
<rect
|
||||
x="1120"
|
||||
y="600"
|
||||
width="230"
|
||||
height="28"
|
||||
class="chip2"
|
||||
id="rect29" />
|
||||
<text
|
||||
x="1134"
|
||||
y="619"
|
||||
class="mono"
|
||||
id="text30"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">une seule couleur active</text>
|
||||
<rect
|
||||
x="40"
|
||||
y="410"
|
||||
width="420"
|
||||
height="220"
|
||||
class="box2"
|
||||
id="rect30" />
|
||||
<text
|
||||
x="58"
|
||||
y="440"
|
||||
class="h"
|
||||
id="text31">Atelier DEV (local)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="464"
|
||||
class="mono"
|
||||
id="text32">astro dev : http://localhost:4321</text>
|
||||
<text
|
||||
x="58"
|
||||
y="482"
|
||||
class="mono"
|
||||
id="text33">pas d'authelia</text>
|
||||
<text
|
||||
x="58"
|
||||
y="500"
|
||||
class="mono"
|
||||
id="text34">predev génère:</text>
|
||||
<text
|
||||
x="58"
|
||||
y="518"
|
||||
class="mono"
|
||||
id="text35"> /annotations-index.json</text>
|
||||
<text
|
||||
x="58"
|
||||
y="536"
|
||||
class="mono"
|
||||
id="text36"> /para-index.json</text>
|
||||
<text
|
||||
x="58"
|
||||
y="554"
|
||||
class="s"
|
||||
id="text37">404 = index manquant (relancer predev/dev)</text>
|
||||
<path
|
||||
d="M460 230 C500 230 500 230 520 230"
|
||||
class="arrow"
|
||||
id="path37" />
|
||||
<text
|
||||
x="465"
|
||||
y="210"
|
||||
class="s"
|
||||
id="text38"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial"><tspan
|
||||
style="font-size:14.6667px"
|
||||
id="tspan45">requête</tspan></text>
|
||||
<path
|
||||
d="M780 380 C780 410 780 410 780 420"
|
||||
class="arrow"
|
||||
id="path38" />
|
||||
<text
|
||||
x="795"
|
||||
y="410"
|
||||
class="s"
|
||||
id="text39">auth_request</text>
|
||||
<path
|
||||
d="m 1040,332 h 132.6172"
|
||||
class="arrowA"
|
||||
id="path39"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
d="m 1040,464 131.407,2.42057"
|
||||
class="arrowA"
|
||||
id="path40"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
x="1045"
|
||||
y="317"
|
||||
class="s"
|
||||
id="text40"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial"><tspan
|
||||
style="font-size:14.6667px"
|
||||
id="tspan44">proxy_pass (active)</tspan></text>
|
||||
<path
|
||||
d="M780 630 C780 700 340 700 250 630"
|
||||
class="arrow"
|
||||
id="path41" />
|
||||
<text
|
||||
x="462.36005"
|
||||
y="707.89716"
|
||||
class="s"
|
||||
id="text41"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial"><tspan
|
||||
id="tspan43"
|
||||
style="font-size:14.6667px">callback + cookie</tspan></text>
|
||||
<rect
|
||||
x="40"
|
||||
y="820"
|
||||
width="1520"
|
||||
height="60"
|
||||
class="box2"
|
||||
id="rect41" />
|
||||
<text
|
||||
x="58"
|
||||
y="850"
|
||||
class="h"
|
||||
id="text42">Note importante (debug)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="874"
|
||||
class="s"
|
||||
id="text43">Si tu testes via loopback (127.0.0.1:18080), la directive Host détermine la vhost. Sans Host correct, tu peux tomber sur une autre conf.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
324
docs/diagrams/archicratie-web-edition-edge-routing-verbatim.svg
Normal file
@@ -0,0 +1,324 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1600"
|
||||
height="820"
|
||||
viewBox="0 0 1600 820"
|
||||
version="1.1"
|
||||
id="svg36"
|
||||
sodipodi:docname="archicratie-web-edition-edge-routing-verbatim.svg"
|
||||
inkscape:version="1.3-alpha (95f74fb, 2023-03-31)"
|
||||
inkscape:export-filename="out/archicratie-web-edition-edge-routing-verbatim.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview36"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.82625"
|
||||
inkscape:cx="665.65809"
|
||||
inkscape:cy="354.00908"
|
||||
inkscape:window-width="1472"
|
||||
inkscape:window-height="1022"
|
||||
inkscape:window-x="234"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg36" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<marker
|
||||
id="arrow"
|
||||
viewBox="0 0 10 10"
|
||||
refX="9.5"
|
||||
refY="5"
|
||||
markerWidth="8"
|
||||
markerHeight="8"
|
||||
orient="auto-start-reverse">
|
||||
<path
|
||||
d="M 0 0 L 10 5 L 0 10 z"
|
||||
fill="#222"
|
||||
id="path1" />
|
||||
</marker>
|
||||
<style
|
||||
id="style1">
|
||||
.title { font: 700 22px sans-serif; fill:#111; }
|
||||
.small { font: 12px sans-serif; fill:#111; }
|
||||
.h2 { font: 700 16px sans-serif; fill:#111; }
|
||||
.txt { font: 13px sans-serif; fill:#111; }
|
||||
.mono { font: 12px ui-monospace, SFMono-Regular, Menlo, monospace; fill:#111; }
|
||||
.zone { fill:#f3f3f3; stroke:#111; stroke-width:2; }
|
||||
.box { fill:#fafafa; stroke:#222; stroke-width:1.5; }
|
||||
.note { fill:#fff; stroke:#666; stroke-width:1.2; }
|
||||
.line { stroke:#222; stroke-width:2; fill:none; marker-end:url(#arrow); }
|
||||
.dash { stroke:#222; stroke-width:2; fill:none; stroke-dasharray:7 6; marker-end:url(#arrow); }
|
||||
</style>
|
||||
</defs>
|
||||
<text
|
||||
x="40"
|
||||
y="45"
|
||||
class="title"
|
||||
id="text1">Edge Traefik (verbatim) — routers Host(...) + middlewares + services</text>
|
||||
<text
|
||||
x="40"
|
||||
y="75"
|
||||
class="small"
|
||||
id="text2">Source : /volume2/docker/edge/config/dynamic/10-core.yml + 20-archicratie-backend.yml + 21-archicratie-staging.yml + 30-lldap-ui.yml</text>
|
||||
<rect
|
||||
x="35"
|
||||
y="110"
|
||||
width="1530"
|
||||
height="670"
|
||||
rx="18"
|
||||
class="zone"
|
||||
id="rect2" />
|
||||
<text
|
||||
x="60"
|
||||
y="145"
|
||||
class="h2"
|
||||
id="text3">Traefik : entryPoint web = :18080 — provider file (dynamic/) watch=true</text>
|
||||
<!-- Middlewares -->
|
||||
<rect
|
||||
x="60"
|
||||
y="185"
|
||||
width="601.60364"
|
||||
height="196.36914"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect3" />
|
||||
<text
|
||||
x="80"
|
||||
y="215"
|
||||
class="h2"
|
||||
id="text4">Middlewares (10-core.yml)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="242"
|
||||
class="txt"
|
||||
id="text5">sanitize-remote : purge Remote-* + force X-Forwarded-Proto/Port</text>
|
||||
<text
|
||||
x="80"
|
||||
y="264"
|
||||
class="txt"
|
||||
id="text6">authelia : forwardAuth → <tspan
|
||||
class="mono"
|
||||
id="tspan5">http://127.0.0.1:9091/api/authz/forward-auth</tspan></text>
|
||||
<text
|
||||
x="80"
|
||||
y="286"
|
||||
class="txt"
|
||||
id="text7">chain-auth : [sanitize-remote, authelia]</text>
|
||||
<!-- Routers -->
|
||||
<rect
|
||||
x="60"
|
||||
y="415"
|
||||
width="823.08624"
|
||||
height="205.02269"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect7" />
|
||||
<text
|
||||
x="80"
|
||||
y="445"
|
||||
class="h2"
|
||||
id="text8">Routers</text>
|
||||
<text
|
||||
x="80"
|
||||
y="472"
|
||||
class="mono"
|
||||
id="text9">archicratie</text>
|
||||
<text
|
||||
x="200"
|
||||
y="472"
|
||||
class="txt"
|
||||
id="text10">Host(archicratie.trans-hands.synology.me) + chain-auth → service archicratie_web</text>
|
||||
<text
|
||||
x="80"
|
||||
y="498"
|
||||
class="mono"
|
||||
id="text11">archicratie-authinfo</text>
|
||||
<text
|
||||
x="290"
|
||||
y="498"
|
||||
class="txt"
|
||||
id="text12">Host(archicratie…) PathPrefix(/_auth/whoami) + chain-auth → whoami</text>
|
||||
<text
|
||||
x="80"
|
||||
y="524"
|
||||
class="mono"
|
||||
id="text13">gitea</text>
|
||||
<text
|
||||
x="200"
|
||||
y="524"
|
||||
class="txt"
|
||||
id="text14">Host(gitea.archicratie.trans-hands.synology.me) + sanitize-remote → gitea_web</text>
|
||||
<text
|
||||
x="80"
|
||||
y="550"
|
||||
class="mono"
|
||||
id="text15">archicratie-staging</text>
|
||||
<text
|
||||
x="290"
|
||||
y="550"
|
||||
class="txt"
|
||||
id="text16">Host(staging.archicratie.trans-hands.synology.me) + chain-auth → archicratie_blue</text>
|
||||
<text
|
||||
x="80"
|
||||
y="576"
|
||||
class="mono"
|
||||
id="text17">lldap-ui</text>
|
||||
<text
|
||||
x="200"
|
||||
y="576"
|
||||
class="txt"
|
||||
id="text18">Host(lldap.archicratie.trans-hands.synology.me) + chain-auth → lldap_ui</text>
|
||||
<rect
|
||||
x="925.50684"
|
||||
y="181.36914"
|
||||
width="614.49316"
|
||||
height="553.63086"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect18" />
|
||||
<text
|
||||
x="985"
|
||||
y="215"
|
||||
class="h2"
|
||||
id="text19"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:16px;line-height:normal;font-family:sans-serif">Services (loadBalancer → url)</text>
|
||||
<text
|
||||
x="985"
|
||||
y="250"
|
||||
class="mono"
|
||||
id="text20"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">whoami</text>
|
||||
<text
|
||||
x="1120"
|
||||
y="250"
|
||||
class="txt"
|
||||
id="text21"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">→ <tspan
|
||||
class="mono"
|
||||
id="tspan20"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">http://127.0.0.1:18081</tspan> (edge-whoami)</text>
|
||||
<text
|
||||
x="985"
|
||||
y="285"
|
||||
class="mono"
|
||||
id="text22"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">gitea_web</text>
|
||||
<text
|
||||
x="1120"
|
||||
y="285"
|
||||
class="txt"
|
||||
id="text23"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">→ <tspan
|
||||
class="mono"
|
||||
id="tspan22"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">http://127.0.0.1:3000</tspan> (Gitea)</text>
|
||||
<text
|
||||
x="985"
|
||||
y="320"
|
||||
class="mono"
|
||||
id="text24"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">archicratie_web</text>
|
||||
<text
|
||||
x="1120"
|
||||
y="320"
|
||||
class="txt"
|
||||
id="text25"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">→ défini par <tspan
|
||||
class="mono"
|
||||
id="tspan24"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">20-archicratie-backend.yml</tspan></text>
|
||||
<text
|
||||
x="1140"
|
||||
y="345"
|
||||
class="txt"
|
||||
id="text26"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• actuel : <tspan
|
||||
class="mono"
|
||||
id="tspan25"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">http://127.0.0.1:8082</tspan> (green)</text>
|
||||
<text
|
||||
x="985"
|
||||
y="390"
|
||||
class="mono"
|
||||
id="text27"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">archicratie_blue</text>
|
||||
<text
|
||||
x="1170"
|
||||
y="390"
|
||||
class="txt"
|
||||
id="text28"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">→ <tspan
|
||||
class="mono"
|
||||
id="tspan27"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">http://127.0.0.1:8081</tspan> (staging)</text>
|
||||
<text
|
||||
x="985"
|
||||
y="435"
|
||||
class="mono"
|
||||
id="text29"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">lldap_ui</text>
|
||||
<text
|
||||
x="1120"
|
||||
y="435"
|
||||
class="txt"
|
||||
id="text30"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">→ <tspan
|
||||
class="mono"
|
||||
id="tspan29"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">http://127.0.0.1:17170</tspan> (LLDAP UI)</text>
|
||||
<rect
|
||||
x="954.1377"
|
||||
y="493.94855"
|
||||
width="560.8623"
|
||||
height="216.05144"
|
||||
rx="12"
|
||||
class="note"
|
||||
id="rect30" />
|
||||
<text
|
||||
x="975"
|
||||
y="530"
|
||||
class="h2"
|
||||
id="text31"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:16px;line-height:normal;font-family:sans-serif">Interprétation debug (safe)</text>
|
||||
<text
|
||||
x="975"
|
||||
y="555"
|
||||
class="txt"
|
||||
id="text32"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• Si tu testes sans Host header sur :18080 → 404 (normal)</text>
|
||||
<text
|
||||
x="975"
|
||||
y="577"
|
||||
class="txt"
|
||||
id="text33"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• Si archicratie → 302 auth.* : Authelia forward-auth OK</text>
|
||||
<text
|
||||
x="975"
|
||||
y="599"
|
||||
class="txt"
|
||||
id="text34"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• Si /_auth/whoami → 302 auth.* : gate OK (non-auth)</text>
|
||||
<text
|
||||
x="975"
|
||||
y="621"
|
||||
class="txt"
|
||||
id="text35"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• Pour basculer blue/green : modifier 20-archicratie-backend.yml (8081 ↔ 8082)</text>
|
||||
<text
|
||||
x="975"
|
||||
y="643"
|
||||
class="small"
|
||||
id="text36"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif">But : une seule cible active (évite load-balance non déterministe).</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
870
docs/diagrams/archicratie-web-edition-git-ci-workflow-v1.svg
Normal file
@@ -0,0 +1,870 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1500"
|
||||
height="940"
|
||||
viewBox="0 0 1500 940"
|
||||
role="img"
|
||||
aria-label="Workflow Git CI - main protégé, PR, CI, release-pack, déploiement blue/green"
|
||||
version="1.1"
|
||||
id="svg93"
|
||||
sodipodi:docname="archicratie-web-edition-git-ci-workflow-v1.svg"
|
||||
inkscape:version="1.3-alpha (95f74fb, 2023-03-31)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview93"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.88133333"
|
||||
inkscape:cx="253.02572"
|
||||
inkscape:cy="536.11952"
|
||||
inkscape:window-width="1472"
|
||||
inkscape:window-height="1022"
|
||||
inkscape:window-x="234"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg93" />
|
||||
<defs
|
||||
id="defs2">
|
||||
<style
|
||||
id="style1">
|
||||
/* ✅ Version “Inkscape-safe” : pas de var(), pas de rgba() */
|
||||
.canvasBg { fill:#f8fafc; stroke:#e2e8f0; stroke-width:1; }
|
||||
|
||||
.title { font:800 26px/1.2 ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; fill:#0f172a; }
|
||||
.subtitle { font:600 14px/1.4 ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; fill:#475569; }
|
||||
.laneTitle { font:800 14px/1 ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; fill:#0f172a; letter-spacing:.2px; }
|
||||
.laneNote { font:600 12px/1.4 ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; fill:#475569; }
|
||||
.boxTitle { font:800 14px/1.2 ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; fill:#0f172a; }
|
||||
.boxText { font:600 12px/1.35 ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; fill:#475569; }
|
||||
.mono { font:700 11px/1.35 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace; fill:#334155; }
|
||||
|
||||
.lane { fill:#f1f5f9; fill-opacity:.70; stroke:#cbd5e1; stroke-width:1; }
|
||||
.laneAlt { fill:#e2e8f0; fill-opacity:.55; stroke:#cbd5e1; stroke-width:1; }
|
||||
|
||||
.box { fill:#ffffff; fill-opacity:.92; stroke:#94a3b8; stroke-width:1.4; }
|
||||
.boxAlt { fill:#f8fafc; fill-opacity:.92; stroke:#94a3b8; stroke-width:1.4; }
|
||||
|
||||
.tag { font:800 10px/1 ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; }
|
||||
.tagOk { fill:#16a34a; }
|
||||
.tagWarn { fill:#f59e0b; }
|
||||
.tagInfo { fill:#2563eb; }
|
||||
.tagDanger { fill:#dc2626; }
|
||||
|
||||
.arrow { stroke:#64748b; stroke-width:2.2; fill:none; marker-end:url(#arrowHead); }
|
||||
.arrowSoft { stroke:#94a3b8; stroke-width:2; fill:none; marker-end:url(#arrowHeadSoft); }
|
||||
.dashed { stroke-dasharray:7 6; }
|
||||
|
||||
.callout { fill:#ffffff; fill-opacity:.70; stroke:#cbd5e1; stroke-width:1.1; }
|
||||
.small { font:600 11px/1.35 ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; fill:#475569; }
|
||||
</style>
|
||||
<marker
|
||||
id="arrowHead"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="5"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L10,5 L0,10 Z"
|
||||
fill="#64748b"
|
||||
id="path1" />
|
||||
</marker>
|
||||
<marker
|
||||
id="arrowHeadSoft"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="5"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L10,5 L0,10 Z"
|
||||
fill="#94a3b8"
|
||||
id="path2" />
|
||||
</marker>
|
||||
</defs>
|
||||
<!-- ✅ Fond explicite + bordure douce -->
|
||||
<rect
|
||||
x="0.5"
|
||||
y="0.5"
|
||||
width="1499"
|
||||
height="939"
|
||||
class="canvasBg"
|
||||
rx="26"
|
||||
id="rect2" />
|
||||
<!-- Header -->
|
||||
<text
|
||||
x="44"
|
||||
y="54"
|
||||
class="title"
|
||||
id="text2">Archicratie — Workflow Git “pro” (main protégé) + CI + Release + Blue/Green</text>
|
||||
<text
|
||||
x="44"
|
||||
y="82"
|
||||
class="subtitle"
|
||||
id="text3">
|
||||
Objectif : partir d’un hotfix appliqué (si besoin), le remettre proprement sous Git (branche → PR → CI → merge),
|
||||
puis produire une release packagée et déployer sans régression.
|
||||
</text>
|
||||
<!-- Lanes -->
|
||||
<rect
|
||||
x="40"
|
||||
y="115"
|
||||
width="440"
|
||||
height="770"
|
||||
class="lane"
|
||||
rx="18"
|
||||
id="rect3" />
|
||||
<rect
|
||||
x="520"
|
||||
y="115"
|
||||
width="430"
|
||||
height="770"
|
||||
class="laneAlt"
|
||||
rx="18"
|
||||
id="rect4" />
|
||||
<rect
|
||||
x="980"
|
||||
y="115"
|
||||
width="250"
|
||||
height="770"
|
||||
class="lane"
|
||||
rx="18"
|
||||
id="rect5" />
|
||||
<rect
|
||||
x="1250"
|
||||
y="115"
|
||||
width="210"
|
||||
height="770"
|
||||
class="laneAlt"
|
||||
rx="18"
|
||||
id="rect6" />
|
||||
<text
|
||||
x="60"
|
||||
y="142"
|
||||
class="laneTitle"
|
||||
id="text6"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:14px;line-height:1;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">Atelier DEV (Mac Studio)</text>
|
||||
<text
|
||||
x="60"
|
||||
y="164"
|
||||
class="laneNote"
|
||||
id="text7"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.4;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">Travail local, build, commit, push de branche</text>
|
||||
<text
|
||||
x="540"
|
||||
y="148"
|
||||
class="laneTitle"
|
||||
id="text8">Gitea (remote)</text>
|
||||
<text
|
||||
x="540"
|
||||
y="170"
|
||||
class="laneNote"
|
||||
id="text9">main verrouillé · PR obligatoire · historique canon</text>
|
||||
<text
|
||||
x="1000"
|
||||
y="148"
|
||||
class="laneTitle"
|
||||
id="text10">CI (CI.yaml)</text>
|
||||
<text
|
||||
x="1000"
|
||||
y="170"
|
||||
class="laneNote"
|
||||
id="text11">build checks · gate de merge</text>
|
||||
<text
|
||||
x="1270"
|
||||
y="148"
|
||||
class="laneTitle"
|
||||
id="text12">NAS (Prod)</text>
|
||||
<text
|
||||
x="1270"
|
||||
y="170"
|
||||
class="laneNote"
|
||||
id="text13">release-pack + blue/green</text>
|
||||
<!-- Boxes: Mac -->
|
||||
<rect
|
||||
x="70"
|
||||
y="170"
|
||||
width="380"
|
||||
height="105"
|
||||
class="box"
|
||||
rx="16"
|
||||
id="rect13" />
|
||||
<text
|
||||
x="92"
|
||||
y="198"
|
||||
class="boxTitle"
|
||||
id="text14"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:14px;line-height:1.2;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">1) Se baser sur main (canon)</text>
|
||||
<text
|
||||
x="92"
|
||||
y="220"
|
||||
class="boxText"
|
||||
id="text15"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">Synchroniser le dépôt local sur le dernier état validé.</text>
|
||||
<text
|
||||
x="92"
|
||||
y="242"
|
||||
class="mono"
|
||||
id="text16"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">git checkout main git pull --ff-only</text>
|
||||
<text
|
||||
x="92"
|
||||
y="264"
|
||||
class="small"
|
||||
id="text17"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial"><tspan
|
||||
class="tag tagInfo"
|
||||
id="tspan16"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:10px;line-height:1;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">INFO</tspan> main est protégé : pas de commit direct.</text>
|
||||
<rect
|
||||
x="70"
|
||||
y="300"
|
||||
width="380"
|
||||
height="125"
|
||||
class="boxAlt"
|
||||
rx="16"
|
||||
id="rect17" />
|
||||
<text
|
||||
x="92"
|
||||
y="328"
|
||||
class="boxTitle"
|
||||
id="text18"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:14px;line-height:1.2;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">2) Créer une branche dédiée “hotfix sync”</text>
|
||||
<text
|
||||
x="92"
|
||||
y="350"
|
||||
class="boxText"
|
||||
id="text19"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">Nom explicite + date. Toute la synchro se fait ici.</text>
|
||||
<text
|
||||
x="92"
|
||||
y="372"
|
||||
class="mono"
|
||||
id="text20"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">git checkout -b chore/step8-sync-hotfix-YYYYMMDD</text>
|
||||
<text
|
||||
x="92"
|
||||
y="394"
|
||||
class="small"
|
||||
id="text21"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan94"
|
||||
x="92"
|
||||
y="394"><tspan
|
||||
class="tag tagWarn"
|
||||
id="tspan20"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:10px;line-height:1;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">MANUEL</tspan> Optionnel : appliquer un pack hotfix (tar/sha/rsync)</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan95"
|
||||
x="92"
|
||||
y="408.85001">si prod a bougé.</tspan></text>
|
||||
<rect
|
||||
x="70"
|
||||
y="455"
|
||||
width="380"
|
||||
height="160"
|
||||
class="box"
|
||||
rx="16"
|
||||
id="rect21" />
|
||||
<text
|
||||
x="92"
|
||||
y="483"
|
||||
class="boxTitle"
|
||||
id="text22"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:14px;line-height:1.2;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">3) Appliquer les changements vérifier</text>
|
||||
<text
|
||||
x="72"
|
||||
y="505"
|
||||
class="boxText"
|
||||
id="text23"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">Copier/merge les fichiers (rsync/checksum), puis tester build/dev.</text>
|
||||
<text
|
||||
x="92"
|
||||
y="527"
|
||||
class="mono"
|
||||
id="text24"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">rm -rf .astro node_modules/.vite</text>
|
||||
<text
|
||||
x="92"
|
||||
y="548"
|
||||
class="mono"
|
||||
id="text25"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">npm i npm run build</text>
|
||||
<text
|
||||
x="92"
|
||||
y="569"
|
||||
class="mono"
|
||||
id="text26"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">npm run dev</text>
|
||||
<text
|
||||
x="92"
|
||||
y="593"
|
||||
class="small"
|
||||
id="text27"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial"><tspan
|
||||
class="tag tagOk"
|
||||
id="tspan26"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:10px;line-height:1;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">OK</tspan> On ne push que si build + postbuild passent.</text>
|
||||
<rect
|
||||
x="70"
|
||||
y="640"
|
||||
width="380"
|
||||
height="145"
|
||||
class="boxAlt"
|
||||
rx="16"
|
||||
id="rect27" />
|
||||
<text
|
||||
x="92"
|
||||
y="668"
|
||||
class="boxTitle"
|
||||
id="text28"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:14px;line-height:1.2;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">4) Commit propre + diff lisible</text>
|
||||
<text
|
||||
x="92"
|
||||
y="690"
|
||||
class="boxText"
|
||||
id="text29"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">Inspecter, puis commiter en message clair (hotfix étape X).</text>
|
||||
<text
|
||||
x="92"
|
||||
y="712"
|
||||
class="mono"
|
||||
id="text30"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">git status git diff</text>
|
||||
<text
|
||||
x="92"
|
||||
y="733"
|
||||
class="mono"
|
||||
id="text31"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan96"
|
||||
x="92"
|
||||
y="733">git add -A git commit -m "step8: sync hotfix</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan97"
|
||||
x="92"
|
||||
y="747.84998">(SidePanel/reading)"</tspan></text>
|
||||
<text
|
||||
x="92"
|
||||
y="770"
|
||||
class="small"
|
||||
id="text32"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial"><tspan
|
||||
class="tag tagInfo"
|
||||
id="tspan31"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:10px;line-height:1;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">TIP</tspan> Garder le commit “gros” mais unique si c’est un backport prod.</text>
|
||||
<rect
|
||||
x="70"
|
||||
y="805"
|
||||
width="380"
|
||||
height="65"
|
||||
class="box"
|
||||
rx="16"
|
||||
id="rect32" />
|
||||
<text
|
||||
x="92"
|
||||
y="833"
|
||||
class="boxTitle"
|
||||
id="text33"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:14px;line-height:1.2;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">5) Push de branche vers Gitea</text>
|
||||
<text
|
||||
x="92"
|
||||
y="855"
|
||||
class="mono"
|
||||
id="text34"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">git push -u origin chore/step8-sync-hotfix-YYYYMMDD</text>
|
||||
<!-- Boxes: Gitea -->
|
||||
<rect
|
||||
x="536.38428"
|
||||
y="241.13464"
|
||||
width="396.0968"
|
||||
height="123.86536"
|
||||
class="box"
|
||||
rx="16"
|
||||
id="rect34" />
|
||||
<text
|
||||
x="572"
|
||||
y="268"
|
||||
class="boxTitle"
|
||||
id="text35">6) Ouvrir une PR vers main</text>
|
||||
<text
|
||||
x="554"
|
||||
y="290"
|
||||
class="boxText"
|
||||
id="text36"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">main protégé → PR obligatoire. Décrire : “backport hotfix prod”.</text>
|
||||
<text
|
||||
x="554"
|
||||
y="312"
|
||||
class="small"
|
||||
id="text37"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial"><tspan
|
||||
class="tag tagWarn"
|
||||
id="tspan36"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:10px;line-height:1;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">MANUEL</tspan> Ajouter contexte : fichiers touchés, risque, checks attendus.</text>
|
||||
<text
|
||||
x="572"
|
||||
y="334"
|
||||
class="small"
|
||||
id="text38"><tspan
|
||||
class="tag tagInfo"
|
||||
id="tspan37">INFO</tspan> La PR déclenche CI.yaml (pipeline de validation).</text>
|
||||
<rect
|
||||
x="538.65356"
|
||||
y="396.13464"
|
||||
width="389.28894"
|
||||
height="135"
|
||||
class="boxAlt"
|
||||
rx="16"
|
||||
id="rect38" />
|
||||
<text
|
||||
x="572"
|
||||
y="423"
|
||||
class="boxTitle"
|
||||
id="text39">7) Review + décisions</text>
|
||||
<text
|
||||
x="552"
|
||||
y="445"
|
||||
class="boxText"
|
||||
id="text40"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">Lecture diff, vérif logique, pas de secrets, pas de régressions UI.</text>
|
||||
<text
|
||||
x="572"
|
||||
y="468"
|
||||
class="small"
|
||||
id="text41"><tspan
|
||||
class="tag tagDanger"
|
||||
id="tspan40">STOP</tspan> Si CI rouge : corriger sur la branche, push → CI relancé.</text>
|
||||
<text
|
||||
x="572"
|
||||
y="490"
|
||||
class="small"
|
||||
id="text42"><tspan
|
||||
class="tag tagOk"
|
||||
id="tspan41">OK</tspan> Si CI vert + review OK : merge autorisé.</text>
|
||||
<rect
|
||||
x="537.51892"
|
||||
y="548.65356"
|
||||
width="390.42358"
|
||||
height="138.82753"
|
||||
class="box"
|
||||
rx="16"
|
||||
id="rect42" />
|
||||
<text
|
||||
x="572"
|
||||
y="588"
|
||||
class="boxTitle"
|
||||
id="text43">8) Merge PR → main (canon)</text>
|
||||
<text
|
||||
x="572"
|
||||
y="610"
|
||||
class="boxText"
|
||||
id="text44"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan107"
|
||||
x="572"
|
||||
y="610">main devient l’unique source officielle.</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan108"
|
||||
x="572"
|
||||
y="626.20001">La prod se recale dessus.</tspan></text>
|
||||
<text
|
||||
x="572"
|
||||
y="646"
|
||||
class="mono"
|
||||
id="text45"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">Merge (UI Gitea) → origin/main updated</text>
|
||||
<text
|
||||
x="572"
|
||||
y="668"
|
||||
class="small"
|
||||
id="text46"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial"><tspan
|
||||
class="tag tagInfo"
|
||||
id="tspan45"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:10px;line-height:1;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">INFO</tspan> Optionnel : tagger une release (vX.Y / date).</text>
|
||||
<rect
|
||||
x="550"
|
||||
y="705"
|
||||
width="370"
|
||||
height="145"
|
||||
class="boxAlt"
|
||||
rx="16"
|
||||
id="rect46" />
|
||||
<text
|
||||
x="572"
|
||||
y="733"
|
||||
class="boxTitle"
|
||||
id="text47">9) Préparer une release packagée</text>
|
||||
<text
|
||||
x="572"
|
||||
y="755"
|
||||
class="boxText"
|
||||
id="text48"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan105"
|
||||
x="572"
|
||||
y="755">Générer un paquet de release reproductible</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan106"
|
||||
x="572"
|
||||
y="771.20001">(sources + scripts + config).</tspan></text>
|
||||
<text
|
||||
x="572"
|
||||
y="791"
|
||||
class="mono"
|
||||
id="text49"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">./release-pack.sh</text>
|
||||
<text
|
||||
x="572"
|
||||
y="813"
|
||||
class="small"
|
||||
id="text50"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial"><tspan
|
||||
class="tag tagWarn"
|
||||
id="tspan49"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:10px;line-height:1;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">MANUEL</tspan> Le pack sert au déploiement sur NAS (blue/green).</text>
|
||||
<text
|
||||
x="572"
|
||||
y="835"
|
||||
class="small"
|
||||
id="text51"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial"><tspan
|
||||
class="tag tagInfo"
|
||||
id="tspan50"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:10px;line-height:1;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">TIP</tspan> Conserver checksum + manifest (traçabilité).</text>
|
||||
<!-- Boxes: CI -->
|
||||
<rect
|
||||
x="1000"
|
||||
y="260"
|
||||
width="210"
|
||||
height="160"
|
||||
class="box"
|
||||
rx="16"
|
||||
id="rect51" />
|
||||
<text
|
||||
x="1018"
|
||||
y="288"
|
||||
class="boxTitle"
|
||||
id="text52">CI : checks</text>
|
||||
<text
|
||||
x="1018"
|
||||
y="310"
|
||||
class="boxText"
|
||||
id="text53">npm ci</text>
|
||||
<text
|
||||
x="1018"
|
||||
y="330"
|
||||
class="boxText"
|
||||
id="text54">astro build</text>
|
||||
<text
|
||||
x="1018"
|
||||
y="350"
|
||||
class="boxText"
|
||||
id="text55">postbuild scripts</text>
|
||||
<text
|
||||
x="1018"
|
||||
y="370"
|
||||
class="boxText"
|
||||
id="text56">pagefind</text>
|
||||
<text
|
||||
x="1018"
|
||||
y="394"
|
||||
class="small"
|
||||
id="text57"><tspan
|
||||
class="tag tagOk"
|
||||
id="tspan56">PASS</tspan> → merge autorisé</text>
|
||||
<text
|
||||
x="1018"
|
||||
y="414"
|
||||
class="small"
|
||||
id="text58"><tspan
|
||||
class="tag tagDanger"
|
||||
id="tspan57">FAIL</tspan> → corriger branche</text>
|
||||
<rect
|
||||
x="1000"
|
||||
y="450"
|
||||
width="210"
|
||||
height="105"
|
||||
class="boxAlt"
|
||||
rx="16"
|
||||
id="rect58" />
|
||||
<text
|
||||
x="1018"
|
||||
y="478"
|
||||
class="boxTitle"
|
||||
id="text59">Artefacts</text>
|
||||
<text
|
||||
x="1018"
|
||||
y="500"
|
||||
class="boxText"
|
||||
id="text60">Logs + traces</text>
|
||||
<text
|
||||
x="1018"
|
||||
y="520"
|
||||
class="boxText"
|
||||
id="text61">Optionnel : build artefact</text>
|
||||
<text
|
||||
x="1018"
|
||||
y="540"
|
||||
class="small"
|
||||
id="text62"><tspan
|
||||
class="tag tagInfo"
|
||||
id="tspan61">INFO</tspan> Sert au diagnostic rapide.</text>
|
||||
<!-- Boxes: NAS -->
|
||||
<rect
|
||||
x="1270"
|
||||
y="260"
|
||||
width="170"
|
||||
height="155"
|
||||
class="box"
|
||||
rx="16"
|
||||
id="rect62" />
|
||||
<text
|
||||
x="1288"
|
||||
y="288"
|
||||
class="boxTitle"
|
||||
id="text63">Déploiement</text>
|
||||
<text
|
||||
x="1288"
|
||||
y="312"
|
||||
class="boxText"
|
||||
id="text64">Importer release</text>
|
||||
<text
|
||||
x="1288"
|
||||
y="332"
|
||||
class="boxText"
|
||||
id="text65">docker build</text>
|
||||
<text
|
||||
x="1288"
|
||||
y="352"
|
||||
class="boxText"
|
||||
id="text66">web_blue / web_green</text>
|
||||
<text
|
||||
x="1288"
|
||||
y="376"
|
||||
class="boxText"
|
||||
id="text67">switch proxy</text>
|
||||
<text
|
||||
x="1288"
|
||||
y="398"
|
||||
class="small"
|
||||
id="text68"><tspan
|
||||
class="tag tagOk"
|
||||
id="tspan67">OK</tspan> rollback possible</text>
|
||||
<rect
|
||||
x="1270"
|
||||
y="450"
|
||||
width="170"
|
||||
height="140"
|
||||
class="boxAlt"
|
||||
rx="16"
|
||||
id="rect68" />
|
||||
<text
|
||||
x="1288"
|
||||
y="478"
|
||||
class="boxTitle"
|
||||
id="text69">Runbook</text>
|
||||
<text
|
||||
x="1288"
|
||||
y="500"
|
||||
class="boxText"
|
||||
id="text70">healthchecks</text>
|
||||
<text
|
||||
x="1288"
|
||||
y="520"
|
||||
class="boxText"
|
||||
id="text71">logs</text>
|
||||
<text
|
||||
x="1288"
|
||||
y="540"
|
||||
class="boxText"
|
||||
id="text72">validation UI</text>
|
||||
<text
|
||||
x="1288"
|
||||
y="566"
|
||||
class="small"
|
||||
id="text73"><tspan
|
||||
class="tag tagWarn"
|
||||
id="tspan72">MANUEL</tspan> staging d’abord</text>
|
||||
<rect
|
||||
x="1270"
|
||||
y="640"
|
||||
width="170"
|
||||
height="210"
|
||||
class="box"
|
||||
rx="16"
|
||||
id="rect73" />
|
||||
<text
|
||||
x="1288"
|
||||
y="668"
|
||||
class="boxTitle"
|
||||
id="text74">Hotfix prod</text>
|
||||
<text
|
||||
x="1288"
|
||||
y="690"
|
||||
class="boxText"
|
||||
id="text75">À éviter si possible</text>
|
||||
<text
|
||||
x="1288"
|
||||
y="710"
|
||||
class="boxText"
|
||||
id="text76">Si nécessaire :</text>
|
||||
<text
|
||||
x="1288"
|
||||
y="732"
|
||||
class="boxText"
|
||||
id="text77">pack (tar+sha)</text>
|
||||
<text
|
||||
x="1288"
|
||||
y="754"
|
||||
class="boxText"
|
||||
id="text78">→ rapatrier DEV</text>
|
||||
<text
|
||||
x="1288"
|
||||
y="778"
|
||||
class="small"
|
||||
id="text79"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan109"
|
||||
x="1288"
|
||||
y="778"><tspan
|
||||
style="fill:#ff0000"
|
||||
id="tspan111">RISK</tspan> Toujours backporter</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan110"
|
||||
x="1288"
|
||||
y="792.84998">via PR.</tspan></text>
|
||||
<!-- Callout -->
|
||||
<rect
|
||||
x="988.19214"
|
||||
y="665.28741"
|
||||
width="231.68678"
|
||||
height="196.73224"
|
||||
class="callout"
|
||||
rx="14"
|
||||
id="rect79" />
|
||||
<text
|
||||
x="999"
|
||||
y="701"
|
||||
class="boxTitle"
|
||||
id="text80"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:14px;line-height:1.2;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">Règle d’or</text>
|
||||
<text
|
||||
x="999"
|
||||
y="725"
|
||||
class="boxText"
|
||||
id="text81"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan98"
|
||||
x="999"
|
||||
y="725">Le NAS n’est pas le dépôt source.</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan99"
|
||||
x="999"
|
||||
y="741.20001">Même si un hotfix a été fait en prod,</tspan></text>
|
||||
<text
|
||||
x="999"
|
||||
y="760"
|
||||
class="boxText"
|
||||
id="text82"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan100"
|
||||
x="999"
|
||||
y="760">l’état final “vrai” doit être : branche</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan101"
|
||||
x="999"
|
||||
y="776.20001">→ PR → CI → merge main → release</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="999"
|
||||
y="792.87439"
|
||||
id="tspan102">→ deploy.</tspan></text>
|
||||
<text
|
||||
x="999"
|
||||
y="812"
|
||||
class="small"
|
||||
id="text83"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:11px;line-height:1.35;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan103"
|
||||
x="999"
|
||||
y="812"><tspan
|
||||
class="tag tagOk"
|
||||
id="tspan82"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:10px;line-height:1;font-family:ui-sans-serif, system-ui, '-apple-system', 'Segoe UI', Roboto, Helvetica, Arial">BUT</tspan> Passation étape 9 = base Git propre</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan104"
|
||||
x="999"
|
||||
y="826.84998">+ reproductible.</tspan></text>
|
||||
<!-- Arrows -->
|
||||
<path
|
||||
class="arrow"
|
||||
d="m 450,222.34493 c 50,0 46.38427,58.78971 86.38427,78.78971"
|
||||
id="path83"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
class="arrow"
|
||||
d="m 450,835 c 50,0 60,-15 100,-55"
|
||||
id="path84" />
|
||||
<path
|
||||
class="arrow"
|
||||
d="M 931.75492,299.19062 C 995.29501,300.15129 924.67474,339.65204 1000,340"
|
||||
id="path85"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
class="arrowSoft dashed"
|
||||
d="M 888.63843,365 C 909.06203,422.26929 925.80938,435.71104 1000,500"
|
||||
id="path86"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
class="arrow"
|
||||
d="M1210 340 C1240 340, 1245 340, 1270 340"
|
||||
id="path87" />
|
||||
<path
|
||||
class="arrow"
|
||||
d="M920 620 C980 620, 1000 620, 1080 620"
|
||||
id="path88" />
|
||||
<path
|
||||
class="arrow"
|
||||
d="m 920,620 c 60,0 311.3313,0.2118 347.7307,-236.67171"
|
||||
id="path89"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
class="arrowSoft dashed"
|
||||
d="m 1269.652,672.90469 c -83.9636,0.6354 -155.1134,-27.51891 -348.51736,-27.76853"
|
||||
id="path90"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<!-- Footnote -->
|
||||
<text
|
||||
x="44"
|
||||
y="916"
|
||||
class="subtitle"
|
||||
id="text93">
|
||||
Légende : <tspan
|
||||
class="tag tagInfo"
|
||||
id="tspan90">INFO</tspan> invariant / contexte · <tspan
|
||||
class="tag tagWarn"
|
||||
id="tspan91">MANUEL</tspan> action humaine ·
|
||||
<tspan
|
||||
class="tag tagOk"
|
||||
id="tspan92">OK</tspan> attendu · <tspan
|
||||
class="tag tagDanger"
|
||||
id="tspan93">STOP</tspan> bloquant.
|
||||
</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 29 KiB |
537
docs/diagrams/archicratie-web-edition-global-verbatim-v2.svg
Normal file
@@ -0,0 +1,537 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1600"
|
||||
height="900"
|
||||
viewBox="0 0 1600 900"
|
||||
version="1.1"
|
||||
id="svg57"
|
||||
sodipodi:docname="archicratie-web-edition-global-verbatim-v2.svg"
|
||||
inkscape:version="1.3-alpha (95f74fb, 2023-03-31)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview57"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.82625"
|
||||
inkscape:cx="540.99849"
|
||||
inkscape:cy="369.74281"
|
||||
inkscape:window-width="1472"
|
||||
inkscape:window-height="1022"
|
||||
inkscape:window-x="234"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg57" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<!-- Fond clair lisible partout -->
|
||||
<linearGradient
|
||||
id="bg"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#ffffff"
|
||||
id="stop1" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#f1f5f9"
|
||||
id="stop2" />
|
||||
</linearGradient>
|
||||
<!-- Flèches -->
|
||||
<marker
|
||||
id="arrow"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#334155"
|
||||
id="path2" />
|
||||
</marker>
|
||||
<marker
|
||||
id="arrowA"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#2563eb"
|
||||
id="path3" />
|
||||
</marker>
|
||||
<marker
|
||||
id="arrowG"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#059669"
|
||||
id="path4" />
|
||||
</marker>
|
||||
<!-- Styles SANS variables CSS (compat max) -->
|
||||
<style
|
||||
id="style4"><![CDATA[
|
||||
.title{font:800 28px/1.2 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#0f172a}
|
||||
.subtitle{font:500 14px/1.3 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#475569}
|
||||
.h{font:800 16px/1.2 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#0f172a}
|
||||
.t{font:500 13px/1.35 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#111827}
|
||||
.s{font:500 12px/1.35 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#475569}
|
||||
.mono{font:600 12px/1.35 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono','Courier New',monospace;fill:#0f172a}
|
||||
|
||||
/* Cadres lisibles */
|
||||
.box{fill:#ffffff;stroke:#0ea5e9;stroke-width:1.4}
|
||||
.box2{fill:#f8fafc;stroke:#94a3b8;stroke-width:1.2}
|
||||
|
||||
/* Pills */
|
||||
.chip{fill:#dbeafe;stroke:#2563eb;stroke-width:1}
|
||||
.chip2{fill:#d1fae5;stroke:#059669;stroke-width:1}
|
||||
.chipW{fill:#fef3c7;stroke:#d97706;stroke-width:1}
|
||||
.chipD{fill:#fee2e2;stroke:#dc2626;stroke-width:1}
|
||||
|
||||
/* Traits / flèches */
|
||||
.line{stroke:#334155;stroke-width:1.4;fill:none}
|
||||
.dash{stroke-dasharray:6 6}
|
||||
.arrow{stroke:#334155;stroke-width:1.8;fill:none;marker-end:url(#arrow)}
|
||||
.arrowA{stroke:#2563eb;stroke-width:2.0;fill:none;marker-end:url(#arrowA)}
|
||||
.arrowG{stroke:#059669;stroke-width:2.0;fill:none;marker-end:url(#arrowG)}
|
||||
]]></style>
|
||||
</defs>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="1600"
|
||||
height="900"
|
||||
fill="url(#bg)"
|
||||
id="rect4" />
|
||||
<text
|
||||
x="40"
|
||||
y="56"
|
||||
class="title"
|
||||
id="text4">Archicratie — Vue globale (v2, verbatim)</text>
|
||||
<text
|
||||
x="40"
|
||||
y="84"
|
||||
class="subtitle"
|
||||
id="text5">Étape 8 (hotfix UI + sync Git) — mise à jour 2026-02-20 — Astro static + Pagefind + Authelia + Blue/Green</text>
|
||||
<rect
|
||||
x="40"
|
||||
y="120"
|
||||
width="470"
|
||||
height="290"
|
||||
class="box"
|
||||
id="rect5" />
|
||||
<text
|
||||
x="58"
|
||||
y="150"
|
||||
class="h"
|
||||
id="text6">Atelier DEV (Mac Studio)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="174"
|
||||
class="mono"
|
||||
id="text7">repo git (branches, PR vers main)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="192"
|
||||
class="mono"
|
||||
id="text8">npm run dev → http://localhost:4321</text>
|
||||
<text
|
||||
x="58"
|
||||
y="210"
|
||||
class="mono"
|
||||
id="text9">npm run build → dist/ (static)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="228"
|
||||
class="mono"
|
||||
id="text10">postbuild:</text>
|
||||
<text
|
||||
x="58"
|
||||
y="246"
|
||||
class="mono"
|
||||
id="text11"> inject-anchor-aliases.mjs</text>
|
||||
<text
|
||||
x="58"
|
||||
y="264"
|
||||
class="mono"
|
||||
id="text12"> dedupe-ids-dist.mjs</text>
|
||||
<text
|
||||
x="58"
|
||||
y="282"
|
||||
class="mono"
|
||||
id="text13"> build-para-index.mjs → dist/para-index.json</text>
|
||||
<text
|
||||
x="58"
|
||||
y="300"
|
||||
class="mono"
|
||||
id="text14"> build-annotations-index.mjs → dist/annotations-index.json</text>
|
||||
<text
|
||||
x="58"
|
||||
y="318"
|
||||
class="mono"
|
||||
id="text15"> pagefind → dist/pagefind/</text>
|
||||
<text
|
||||
x="58"
|
||||
y="336"
|
||||
class="s"
|
||||
id="text16">predev: build public/para-index.json + public/annotations-index.json</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="420"
|
||||
width="206"
|
||||
height="28"
|
||||
class="chip2"
|
||||
id="rect16" />
|
||||
<text
|
||||
x="74"
|
||||
y="439"
|
||||
class="mono"
|
||||
id="text17">dist/ + pagefind + indexes</text>
|
||||
<rect
|
||||
x="300"
|
||||
y="420"
|
||||
width="198"
|
||||
height="28"
|
||||
class="chip"
|
||||
id="rect17" />
|
||||
<text
|
||||
x="314"
|
||||
y="439"
|
||||
class="mono"
|
||||
id="text18"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">public/*-index.json</text>
|
||||
<rect
|
||||
x="40"
|
||||
y="470"
|
||||
width="470"
|
||||
height="330"
|
||||
class="box2"
|
||||
id="rect18" />
|
||||
<text
|
||||
x="58"
|
||||
y="500"
|
||||
class="h"
|
||||
id="text19">UI Lecture / Édition (dans le site)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="524"
|
||||
class="t"
|
||||
id="text20">EditionLayout.astro (globals + meta)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="542"
|
||||
class="t"
|
||||
id="text21">SidePanel.astro (reading-follow + annotations + propose)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="560"
|
||||
class="t"
|
||||
id="text22">LevelToggle.astro (Niveaux)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="578"
|
||||
class="t"
|
||||
id="text23">global.css (UX lecture + TOC-local sync)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="596"
|
||||
class="s"
|
||||
id="text24">SidePanel consomme para-index + annotations-index</text>
|
||||
<text
|
||||
x="58"
|
||||
y="614"
|
||||
class="s"
|
||||
id="text25">ProposeModal ouvre une issue Gitea (direct ou via bridge)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="632"
|
||||
class="mono"
|
||||
id="text26">env publics: PUBLIC_GITEA_* + PUBLIC_ISSUE_BRIDGE_PATH</text>
|
||||
<rect
|
||||
x="673.92584"
|
||||
y="119.57942"
|
||||
width="344.13016"
|
||||
height="250"
|
||||
class="box"
|
||||
id="rect26" />
|
||||
<text
|
||||
x="723"
|
||||
y="180"
|
||||
class="h"
|
||||
id="text27"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16px;line-height:1.2;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Gitea (sur NAS) — source of truth</text>
|
||||
<text
|
||||
x="723"
|
||||
y="204"
|
||||
class="t"
|
||||
id="text28"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">main protégé (push direct interdit)</text>
|
||||
<text
|
||||
x="723"
|
||||
y="222"
|
||||
class="t"
|
||||
id="text29"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">branches de travail → PR → merge</text>
|
||||
<text
|
||||
x="723"
|
||||
y="240"
|
||||
class="t"
|
||||
id="text30"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">CI (workflow) : build + checks + artefacts</text>
|
||||
<text
|
||||
x="723"
|
||||
y="258"
|
||||
class="t"
|
||||
id="text31"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">issues + labels (tickets)</text>
|
||||
<rect
|
||||
x="745"
|
||||
y="320"
|
||||
width="126"
|
||||
height="28"
|
||||
class="chip2"
|
||||
id="rect31" />
|
||||
<text
|
||||
x="759"
|
||||
y="339"
|
||||
class="mono"
|
||||
id="text32"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">PR → CI.yaml</text>
|
||||
<rect
|
||||
x="565"
|
||||
y="430"
|
||||
width="470"
|
||||
height="160"
|
||||
class="box2"
|
||||
id="rect32" />
|
||||
<text
|
||||
x="583"
|
||||
y="460"
|
||||
class="h"
|
||||
id="text33">Hotfix de release → re-sync Git (méthode step8)</text>
|
||||
<text
|
||||
x="583"
|
||||
y="484"
|
||||
class="t"
|
||||
id="text34">1) lister fichiers modifiés sur NAS</text>
|
||||
<text
|
||||
x="583"
|
||||
y="502"
|
||||
class="t"
|
||||
id="text35">2) tar + sha256 → transfert</text>
|
||||
<text
|
||||
x="583"
|
||||
y="520"
|
||||
class="t"
|
||||
id="text36">3) rsync --checksum vers repo local</text>
|
||||
<text
|
||||
x="583"
|
||||
y="538"
|
||||
class="t"
|
||||
id="text37">4) commit sur branche dédiée + push + PR</text>
|
||||
<rect
|
||||
x="1183.1921"
|
||||
y="122.42058"
|
||||
width="376.80786"
|
||||
height="247.57942"
|
||||
class="box"
|
||||
id="rect37" />
|
||||
<text
|
||||
x="1228"
|
||||
y="150"
|
||||
class="h"
|
||||
id="text38"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16px;line-height:1.2;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">NAS DS220+ — runtime Blue/Green</text>
|
||||
<text
|
||||
x="1228"
|
||||
y="174"
|
||||
class="mono"
|
||||
id="text39"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">/volume2/docker/archicratie-web/</text>
|
||||
<text
|
||||
x="1228"
|
||||
y="192"
|
||||
class="mono"
|
||||
id="text40"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">releases/<timestamp>/app (build context)</text>
|
||||
<text
|
||||
x="1228"
|
||||
y="210"
|
||||
class="mono"
|
||||
id="text41"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">current → release active</text>
|
||||
<text
|
||||
x="1228"
|
||||
y="228"
|
||||
class="mono"
|
||||
id="text42"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">docker compose: web_blue / web_green</text>
|
||||
<text
|
||||
x="1228"
|
||||
y="246"
|
||||
class="s"
|
||||
id="text43"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">une seule couleur sert le trafic (reverse-proxy)</text>
|
||||
<rect
|
||||
x="1210"
|
||||
y="310"
|
||||
width="322"
|
||||
height="28"
|
||||
class="chipW"
|
||||
id="rect43" />
|
||||
<text
|
||||
x="1224"
|
||||
y="329"
|
||||
class="mono"
|
||||
id="text44"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">docker compose build --no-cache web_*</text>
|
||||
<rect
|
||||
x="1184.4025"
|
||||
y="393.94858"
|
||||
width="375.59756"
|
||||
height="246.05144"
|
||||
class="box2"
|
||||
id="rect44" />
|
||||
<text
|
||||
x="1208"
|
||||
y="430"
|
||||
class="h"
|
||||
id="text45"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16px;line-height:1.2;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Edge & Auth</text>
|
||||
<text
|
||||
x="1208"
|
||||
y="454"
|
||||
class="t"
|
||||
id="text46"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Reverse-proxy (Nginx) protège le site</text>
|
||||
<text
|
||||
x="1208"
|
||||
y="472"
|
||||
class="t"
|
||||
id="text47"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Authelia (SSO) + LLDAP (LDAP) + Redis</text>
|
||||
<text
|
||||
x="1208"
|
||||
y="490"
|
||||
class="t"
|
||||
id="text48"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">302 vers auth.* si non authentifié</text>
|
||||
<text
|
||||
x="1208"
|
||||
y="508"
|
||||
class="t"
|
||||
id="text49"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Host header: staging.* / archicratie.*</text>
|
||||
<text
|
||||
x="1208"
|
||||
y="526"
|
||||
class="s"
|
||||
id="text50"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">/_auth/whoami utilisé en check côté client (peut 404 en local)</text>
|
||||
<path
|
||||
d="m 510,260 163.92587,-1.21029"
|
||||
class="arrowA"
|
||||
id="path50"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
x="514"
|
||||
y="245"
|
||||
class="s"
|
||||
id="text51"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial"><tspan
|
||||
style="font-size:14.6667px"
|
||||
id="tspan57">git push (branche) + PR</tspan></text>
|
||||
<path
|
||||
d="m 1016.8457,240 h 166.3464"
|
||||
class="arrowA"
|
||||
id="path51"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
x="1025.3177"
|
||||
y="206.9062"
|
||||
class="s"
|
||||
id="text52"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan58"
|
||||
x="1025.3177"
|
||||
y="206.9062"
|
||||
style="font-size:14.6667px">CI/artefact</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan59"
|
||||
x="1025.3177"
|
||||
y="226.70625"
|
||||
style="font-size:14.6667px">→ déploiement release</tspan></text>
|
||||
<path
|
||||
d="M1420 650 C1480 650 1520 650 1560 650"
|
||||
class="arrow"
|
||||
id="path52" />
|
||||
<text
|
||||
x="1420"
|
||||
y="632"
|
||||
class="s"
|
||||
id="text53">HTTPS → navigateur</text>
|
||||
<path
|
||||
d="M 510,640.25719 C 540,640.25719 540,520 565,520"
|
||||
class="arrow"
|
||||
id="path53"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<text
|
||||
x="534.84113"
|
||||
y="620.20575"
|
||||
class="s"
|
||||
id="text54"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial"><tspan
|
||||
style="font-size:14.6667px"
|
||||
id="tspan60">Propose → issue</tspan></text>
|
||||
<path
|
||||
d="m 1181.9818,520 -145.7715,-1.21029"
|
||||
class="arrowG"
|
||||
id="path54"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
d="M565 520 C520 520 520 520 510 520"
|
||||
class="arrowG"
|
||||
id="path55" />
|
||||
<text
|
||||
x="800"
|
||||
y="505"
|
||||
class="s"
|
||||
id="text55">tar+sha256 → scp → rsync --checksum</text>
|
||||
<rect
|
||||
x="40"
|
||||
y="820"
|
||||
width="1520"
|
||||
height="60"
|
||||
class="box2"
|
||||
id="rect55" />
|
||||
<text
|
||||
x="58"
|
||||
y="850"
|
||||
class="h"
|
||||
id="text56">Légende</text>
|
||||
<text
|
||||
x="58"
|
||||
y="874"
|
||||
class="s"
|
||||
id="text57"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial"><tspan
|
||||
style="font-size:14.6667px"
|
||||
id="tspan61">Bleu = flux Git/CI · Vert = flux de re-sync hotfix · Orange = build runtime · Le reste = navigation/HTTP</tspan></text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 17 KiB |
828
docs/diagrams/archicratie-web-edition-global-verbatim.svg
Normal file
@@ -0,0 +1,828 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1600"
|
||||
height="1020"
|
||||
viewBox="0 0 1600 1020"
|
||||
version="1.1"
|
||||
id="svg80"
|
||||
sodipodi:docname="archicratie-web-edition-global-verbatim.svg"
|
||||
inkscape:version="1.3-alpha (95f74fb, 2023-03-31)"
|
||||
inkscape:export-filename="out/archicratie-web-edition-global-verbatim.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview80"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.82625"
|
||||
inkscape:cx="594.25113"
|
||||
inkscape:cy="481.08926"
|
||||
inkscape:window-width="1472"
|
||||
inkscape:window-height="1022"
|
||||
inkscape:window-x="234"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg80" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<marker
|
||||
id="arrow"
|
||||
viewBox="0 0 10 10"
|
||||
refX="9.5"
|
||||
refY="5"
|
||||
markerWidth="8"
|
||||
markerHeight="8"
|
||||
orient="auto-start-reverse">
|
||||
<path
|
||||
d="M 0 0 L 10 5 L 0 10 z"
|
||||
fill="#222"
|
||||
id="path1" />
|
||||
</marker>
|
||||
<style
|
||||
id="style1">
|
||||
.title { font: 700 22px sans-serif; fill:#111; }
|
||||
.small { font: 12px sans-serif; fill:#111; }
|
||||
.h2 { font: 700 16px sans-serif; fill:#111; }
|
||||
.h3 { font: 700 14px sans-serif; fill:#111; }
|
||||
.txt { font: 13px sans-serif; fill:#111; }
|
||||
.mono { font: 12px ui-monospace, SFMono-Regular, Menlo, monospace; fill:#111; }
|
||||
.zone { fill:#f3f3f3; stroke:#111; stroke-width:2; }
|
||||
.box { fill:#fafafa; stroke:#222; stroke-width:1.5; }
|
||||
.note { fill:#fff; stroke:#666; stroke-width:1.2; }
|
||||
.line { stroke:#222; stroke-width:2; fill:none; marker-end:url(#arrow); }
|
||||
.dash { stroke:#222; stroke-width:2; fill:none; stroke-dasharray:7 6; marker-end:url(#arrow); }
|
||||
</style>
|
||||
</defs>
|
||||
<!-- Header -->
|
||||
<text
|
||||
x="40"
|
||||
y="45"
|
||||
class="title"
|
||||
id="text1">Archicratie – Web Edition : schéma global VERBATIM (Mac Studio ↔ NAS Synology DS220+)</text>
|
||||
<text
|
||||
x="40"
|
||||
y="75"
|
||||
class="small"
|
||||
id="text2">Factuel (capturé sur ton NAS) : DSM (TLS) → Traefik :18080 (file provider) → routers Host(...) → (Authelia forward-auth) → backends (blue/green). Gitea via Traefik sans chain-auth.</text>
|
||||
<!-- LOCAL -->
|
||||
<rect
|
||||
x="35"
|
||||
y="110"
|
||||
width="520"
|
||||
height="880"
|
||||
rx="18"
|
||||
class="zone"
|
||||
id="rect2" />
|
||||
<text
|
||||
x="60"
|
||||
y="145"
|
||||
class="h2"
|
||||
id="text3">LOCAL — Mac Studio (atelier)</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="175"
|
||||
width="470"
|
||||
height="110"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect3" />
|
||||
<text
|
||||
x="80"
|
||||
y="205"
|
||||
class="h2"
|
||||
id="text4">Repo site (Astro)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="232"
|
||||
class="txt"
|
||||
id="text5">• build statique → dist/</text>
|
||||
<text
|
||||
x="80"
|
||||
y="254"
|
||||
class="txt"
|
||||
id="text6">• postbuild : inject aliases + dedupe IDs + indexes + pagefind</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="305"
|
||||
width="470"
|
||||
height="115"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect6" />
|
||||
<text
|
||||
x="80"
|
||||
y="335"
|
||||
class="h2"
|
||||
id="text7">Tooling (scripts/)</text>
|
||||
<text
|
||||
x="66"
|
||||
y="360"
|
||||
class="txt"
|
||||
id="text8"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• scripts/inject-anchor-aliases.mjs</text>
|
||||
<text
|
||||
x="66"
|
||||
y="382"
|
||||
class="txt"
|
||||
id="text9"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• scripts/apply-ticket.mjs --alias</text>
|
||||
<text
|
||||
x="66"
|
||||
y="404"
|
||||
class="txt"
|
||||
id="text10"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• scripts/check-anchor-aliases.mjs + verify-anchor-aliases-in-dist.mjs</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="445"
|
||||
width="470"
|
||||
height="105"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect10" />
|
||||
<text
|
||||
x="80"
|
||||
y="475"
|
||||
class="h2"
|
||||
id="text11">Déploiement (release pack)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="500"
|
||||
class="txt"
|
||||
id="text12">• build Docker avec ARG/ENV : PUBLIC_GITEA_BASE/OWNER/REPO</text>
|
||||
<text
|
||||
x="80"
|
||||
y="522"
|
||||
class="txt"
|
||||
id="text13">• pousse/maj sur NAS (containers web_blue/web_green)</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="569"
|
||||
width="470"
|
||||
height="165"
|
||||
rx="12"
|
||||
class="note"
|
||||
id="rect13" />
|
||||
<text
|
||||
x="80"
|
||||
y="605"
|
||||
class="h2"
|
||||
id="text14">Repères “vrais” côté site</text>
|
||||
<text
|
||||
x="80"
|
||||
y="632"
|
||||
class="txt"
|
||||
id="text15">• whoami runtime : <tspan
|
||||
class="mono"
|
||||
id="tspan14">/_auth/whoami</tspan></text>
|
||||
<text
|
||||
x="80"
|
||||
y="654"
|
||||
class="txt"
|
||||
id="text16">• variables injectées : <tspan
|
||||
class="mono"
|
||||
id="tspan15">PUBLIC_GITEA_BASE/OWNER/REPO</tspan></text>
|
||||
<text
|
||||
x="80"
|
||||
y="676"
|
||||
class="txt"
|
||||
id="text17">• anchors canon : <tspan
|
||||
class="mono"
|
||||
id="tspan16">src/anchors/anchor-aliases.json</tspan></text>
|
||||
<text
|
||||
x="80"
|
||||
y="698"
|
||||
class="txt"
|
||||
id="text18">• injection build-time : <tspan
|
||||
class="mono"
|
||||
id="tspan17">scripts/inject-anchor-aliases.mjs</tspan></text>
|
||||
<!-- NAS -->
|
||||
<rect
|
||||
x="590"
|
||||
y="110"
|
||||
width="975"
|
||||
height="880"
|
||||
rx="18"
|
||||
class="zone"
|
||||
id="rect18" />
|
||||
<text
|
||||
x="615"
|
||||
y="145"
|
||||
class="h2"
|
||||
id="text19">DISTANT — NAS Synology DS220+ (DSM + Container Manager)</text>
|
||||
<!-- Users -->
|
||||
<rect
|
||||
x="615"
|
||||
y="175"
|
||||
width="270"
|
||||
height="90"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect19" />
|
||||
<text
|
||||
x="635"
|
||||
y="205"
|
||||
class="h2"
|
||||
id="text20">Utilisateurs</text>
|
||||
<text
|
||||
x="635"
|
||||
y="230"
|
||||
class="txt"
|
||||
id="text21">• Web (public)</text>
|
||||
<text
|
||||
x="635"
|
||||
y="252"
|
||||
class="txt"
|
||||
id="text22">• Éditeurs (groupe LDAP)</text>
|
||||
<!-- DSM RP -->
|
||||
<rect
|
||||
x="905"
|
||||
y="175"
|
||||
width="630"
|
||||
height="120"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect22" />
|
||||
<text
|
||||
x="930"
|
||||
y="205"
|
||||
class="h2"
|
||||
id="text23">DSM Reverse Proxy (TLS terminé ici)</text>
|
||||
<text
|
||||
x="930"
|
||||
y="230"
|
||||
class="txt"
|
||||
id="text24">• Host archicratie.trans-hands.synology.me → 127.0.0.1:18080</text>
|
||||
<text
|
||||
x="930"
|
||||
y="252"
|
||||
class="txt"
|
||||
id="text25">• Host gitea.archicratie.trans-hands.synology.me → 127.0.0.1:18080</text>
|
||||
<text
|
||||
x="930"
|
||||
y="274"
|
||||
class="txt"
|
||||
id="text26">• (idem staging.*, lldap.* si routés via Traefik)</text>
|
||||
<!-- Edge Traefik -->
|
||||
<rect
|
||||
x="1012.7156"
|
||||
y="321.2103"
|
||||
width="522.28442"
|
||||
height="148.78972"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect26" />
|
||||
<text
|
||||
x="1050"
|
||||
y="350"
|
||||
class="h2"
|
||||
id="text27"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:16px;line-height:normal;font-family:sans-serif">edge-traefik (traefik:v2.11) — network_mode: host</text>
|
||||
<text
|
||||
x="1050"
|
||||
y="375"
|
||||
class="txt"
|
||||
id="text28"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• entryPoint web : <tspan
|
||||
class="mono"
|
||||
id="tspan27"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">:18080</tspan></text>
|
||||
<text
|
||||
x="1050"
|
||||
y="397"
|
||||
class="txt"
|
||||
id="text29"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• provider file : <tspan
|
||||
class="mono"
|
||||
id="tspan28"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">/etc/traefik/dynamic</tspan> (watch: true)</text>
|
||||
<text
|
||||
x="1050"
|
||||
y="419"
|
||||
class="txt"
|
||||
id="text30"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• Host rules (routers) + middlewares (chain-auth / sanitize-remote)</text>
|
||||
<text
|
||||
x="1050"
|
||||
y="441"
|
||||
class="small"
|
||||
id="text31"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif">Tes 404 initiaux venaient d’un test sans Host: les routers utilisent Host(...)</text>
|
||||
<!-- Dynamic files -->
|
||||
<rect
|
||||
x="615"
|
||||
y="290"
|
||||
width="270"
|
||||
height="180"
|
||||
rx="12"
|
||||
class="note"
|
||||
id="rect31" />
|
||||
<text
|
||||
x="623"
|
||||
y="320"
|
||||
class="h2"
|
||||
id="text32"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:16px;line-height:normal;font-family:sans-serif">Fichiers dynamiques (edge)</text>
|
||||
<text
|
||||
x="623"
|
||||
y="345"
|
||||
class="mono"
|
||||
id="text33"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">/volume2/docker/edge/config/dynamic/</text>
|
||||
<text
|
||||
x="623"
|
||||
y="368"
|
||||
class="txt"
|
||||
id="text34"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• 10-core.yml (routers + chain-auth)</text>
|
||||
<text
|
||||
x="623"
|
||||
y="390"
|
||||
class="txt"
|
||||
id="text35"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• 20-archicratie-backend.yml (slot actif)</text>
|
||||
<text
|
||||
x="623"
|
||||
y="412"
|
||||
class="txt"
|
||||
id="text36"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan88"
|
||||
x="623"
|
||||
y="412">• 21-archicratie-staging.yml</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan89"
|
||||
x="623"
|
||||
y="428.25">(staging→8081)</tspan></text>
|
||||
<text
|
||||
x="623"
|
||||
y="448"
|
||||
class="txt"
|
||||
id="text37"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• 30-lldap-ui.yml (lldap UI)</text>
|
||||
<!-- Auth stack -->
|
||||
<rect
|
||||
x="615"
|
||||
y="495"
|
||||
width="376.80786"
|
||||
height="258.41147"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect37" />
|
||||
<text
|
||||
x="635"
|
||||
y="525"
|
||||
class="h2"
|
||||
id="text38">Auth stack (auth)</text>
|
||||
<text
|
||||
x="635"
|
||||
y="550"
|
||||
class="txt"
|
||||
id="text39">auth-authelia (authelia:4.39.13) — host</text>
|
||||
<text
|
||||
x="635"
|
||||
y="572"
|
||||
class="txt"
|
||||
id="text40"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan92"
|
||||
x="635"
|
||||
y="572">• forward-auth :</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan93"
|
||||
x="635"
|
||||
y="588.25">http://127.0.0.1:9091/api/authz/forward-auth</tspan></text>
|
||||
<text
|
||||
x="635"
|
||||
y="614"
|
||||
class="txt"
|
||||
id="text41"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">auth-lldap (lldap:stable)</text>
|
||||
<text
|
||||
x="635"
|
||||
y="640"
|
||||
class="txt"
|
||||
id="text42"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• LDAP : <tspan
|
||||
class="mono"
|
||||
id="tspan41"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">127.0.0.1:3890</tspan> • UI : <tspan
|
||||
class="mono"
|
||||
id="tspan42"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">127.0.0.1:17170</tspan></text>
|
||||
<text
|
||||
x="635"
|
||||
y="662"
|
||||
class="txt"
|
||||
id="text43"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">auth-redis (redis:7-alpine)</text>
|
||||
<text
|
||||
x="635"
|
||||
y="684"
|
||||
class="txt"
|
||||
id="text44"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• exposé : <tspan
|
||||
class="mono"
|
||||
id="tspan43"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">127.0.0.1:6380</tspan></text>
|
||||
<text
|
||||
x="635"
|
||||
y="708"
|
||||
class="small"
|
||||
id="text45"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan94"
|
||||
x="635"
|
||||
y="708">Traefik injecte Remote-* via forward-auth,</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan95"
|
||||
x="635"
|
||||
y="723">et purge l’entrée (sanitize-remote).</tspan></text>
|
||||
<!-- Whoami service -->
|
||||
<rect
|
||||
x="1110"
|
||||
y="495"
|
||||
width="365.69592"
|
||||
height="117.57942"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect45" />
|
||||
<text
|
||||
x="1135"
|
||||
y="525"
|
||||
class="h2"
|
||||
id="text46">edge-whoami (traefik/whoami)</text>
|
||||
<text
|
||||
x="1135"
|
||||
y="550"
|
||||
class="txt"
|
||||
id="text47">• exposé : <tspan
|
||||
class="mono"
|
||||
id="tspan46">127.0.0.1:18081 → 80</tspan></text>
|
||||
<text
|
||||
x="1135"
|
||||
y="572"
|
||||
class="txt"
|
||||
id="text48">• router Traefik : <tspan
|
||||
class="mono"
|
||||
id="tspan47">PathPrefix('/_auth/whoami')</tspan></text>
|
||||
<text
|
||||
x="1135"
|
||||
y="594"
|
||||
class="txt"
|
||||
id="text49">• protégé par <tspan
|
||||
class="mono"
|
||||
id="tspan48">chain-auth</tspan> (302 login si non auth)</text>
|
||||
<!-- Web blue/green -->
|
||||
<rect
|
||||
x="1047.9349"
|
||||
y="639.94855"
|
||||
width="224.96217"
|
||||
height="116.11195"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect49" />
|
||||
<text
|
||||
x="1070"
|
||||
y="670"
|
||||
class="h2"
|
||||
id="text50"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:16px;line-height:normal;font-family:sans-serif">archicratie-web-blue</text>
|
||||
<text
|
||||
x="1070"
|
||||
y="695"
|
||||
class="txt"
|
||||
id="text51"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• 127.0.0.1:8081 → 80</text>
|
||||
<text
|
||||
x="1070"
|
||||
y="717"
|
||||
class="txt"
|
||||
id="text52"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• Nginx sert dist/</text>
|
||||
<text
|
||||
x="1070"
|
||||
y="739"
|
||||
class="small"
|
||||
id="text53"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif">slot blue (staging cible 8081)</text>
|
||||
<rect
|
||||
x="1295"
|
||||
y="640"
|
||||
width="240.69592"
|
||||
height="116.11195"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect53" />
|
||||
<text
|
||||
x="1320"
|
||||
y="670"
|
||||
class="h2"
|
||||
id="text54"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:16px;line-height:normal;font-family:sans-serif">archicratie-web-green</text>
|
||||
<text
|
||||
x="1320"
|
||||
y="695"
|
||||
class="txt"
|
||||
id="text55"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• 127.0.0.1:8082 → 80</text>
|
||||
<text
|
||||
x="1320"
|
||||
y="717"
|
||||
class="txt"
|
||||
id="text56"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• Nginx sert dist/</text>
|
||||
<text
|
||||
x="1320"
|
||||
y="739"
|
||||
class="small"
|
||||
id="text57"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif">slot green (backend actuel)</text>
|
||||
<rect
|
||||
x="1156.7399"
|
||||
y="778.21478"
|
||||
width="374.62918"
|
||||
height="105.4161"
|
||||
rx="12"
|
||||
class="note"
|
||||
id="rect57" />
|
||||
<text
|
||||
x="1190.2118"
|
||||
y="797.89716"
|
||||
class="txt"
|
||||
id="text58"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif"><tspan
|
||||
id="tspan96"
|
||||
x="1190.2118"
|
||||
y="797.89716"
|
||||
sodipodi:role="line">Bascule blue/green (Traefik) :</tspan><tspan
|
||||
x="1190.2118"
|
||||
y="814.14716"
|
||||
id="tspan104"
|
||||
sodipodi:role="line">modifier <tspan
|
||||
class="mono"
|
||||
id="tspan57"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">dynamic/20-archicratie-backend.yml</tspan></tspan><tspan
|
||||
id="tspan97"
|
||||
x="1190.2118"
|
||||
y="830.39716"
|
||||
sodipodi:role="line">→ url 8081/8082 (un seul backend actif)</tspan></text>
|
||||
<text
|
||||
x="1202.3751"
|
||||
y="858.05145"
|
||||
class="small"
|
||||
id="text59"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan101"
|
||||
x="1202.3751"
|
||||
y="858.05145">Actuellement (d’après ton dump) :<tspan
|
||||
class="mono"
|
||||
id="tspan58"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace"></tspan></tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan102"
|
||||
x="1202.3751"
|
||||
y="873.05145"><tspan
|
||||
class="mono"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace"
|
||||
id="tspan103">archicratie_web → http://127.0.0.1:8082</tspan></tspan></text>
|
||||
<!-- Gitea + Runner -->
|
||||
<rect
|
||||
x="615"
|
||||
y="790"
|
||||
width="440.12103"
|
||||
height="180.57489"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect59" />
|
||||
<text
|
||||
x="635"
|
||||
y="820"
|
||||
class="h2"
|
||||
id="text60"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:16px;line-height:normal;font-family:sans-serif">Gitea (actuel)</text>
|
||||
<text
|
||||
x="635"
|
||||
y="845"
|
||||
class="txt"
|
||||
id="text61"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• conteneur : <tspan
|
||||
class="mono"
|
||||
id="tspan60"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">gitea-old-2026-02-09-105211</tspan></text>
|
||||
<text
|
||||
x="635"
|
||||
y="867"
|
||||
class="txt"
|
||||
id="text62"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• port : <tspan
|
||||
class="mono"
|
||||
id="tspan61"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">0.0.0.0:3000</tspan> (Traefik route aussi vers 127.0.0.1:3000)</text>
|
||||
<text
|
||||
x="635"
|
||||
y="889"
|
||||
class="txt"
|
||||
id="text63"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan90"
|
||||
x="635"
|
||||
y="889">• router Traefik : Host(gitea.archicratie...)</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan91"
|
||||
x="635"
|
||||
y="905.25">+ middleware sanitize-remote (pas chain-auth)</tspan></text>
|
||||
<text
|
||||
x="635"
|
||||
y="929"
|
||||
class="small"
|
||||
id="text64"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan99"
|
||||
x="635"
|
||||
y="929">“Proposer” dépend de PUBLIC_GITEA_* corrects</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan100"
|
||||
x="635"
|
||||
y="944">(owner casse sensible).</tspan></text>
|
||||
<rect
|
||||
x="1160"
|
||||
y="895"
|
||||
width="375"
|
||||
height="85"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect64" />
|
||||
<text
|
||||
x="1185"
|
||||
y="925"
|
||||
class="h2"
|
||||
id="text65"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:16px;line-height:normal;font-family:sans-serif">gitea-act-runner</text>
|
||||
<text
|
||||
x="1185"
|
||||
y="950"
|
||||
class="txt"
|
||||
id="text66"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• image : <tspan
|
||||
class="mono"
|
||||
id="tspan65"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">gitea/act_runner:0.2.11</tspan></text>
|
||||
<text
|
||||
x="1185"
|
||||
y="972"
|
||||
class="small"
|
||||
id="text67"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif">CI : labels / checks (anchors, aliases, etc.).</text>
|
||||
<!-- Connections -->
|
||||
<path
|
||||
d="M 885 220 L 905 220"
|
||||
class="line"
|
||||
id="path67" />
|
||||
<!-- Users -> DSM -->
|
||||
<path
|
||||
d="M 1220 295 L 1220 320"
|
||||
class="line"
|
||||
id="path68" />
|
||||
<!-- DSM -> Traefik -->
|
||||
<!-- Traefik -> auth (forward auth) -->
|
||||
<path
|
||||
d="m 1005,420 -45,75"
|
||||
class="dash"
|
||||
id="path69" />
|
||||
<text
|
||||
x="120.96539"
|
||||
y="1057.8674"
|
||||
class="small"
|
||||
id="text69"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif"
|
||||
transform="rotate(-57.013356)">forward-auth</text>
|
||||
<!-- Traefik -> whoami -->
|
||||
<path
|
||||
d="M 1220 470 L 1220 495"
|
||||
class="line"
|
||||
id="path70" />
|
||||
<!-- Traefik -> web service -->
|
||||
<path
|
||||
d="m 1082.9955,470 -0.3782,168.78971"
|
||||
class="dash"
|
||||
id="path71"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
d="m 1500,470 -0.416,170"
|
||||
class="dash"
|
||||
id="path72"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<!-- Traefik -> gitea -->
|
||||
<path
|
||||
d="m 1034.826,471.21029 1.3616,315.67322"
|
||||
class="dash"
|
||||
id="path73"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<!-- Gitea -> runner -->
|
||||
<path
|
||||
d="m 1060,890 98.7897,59.52345"
|
||||
class="line"
|
||||
id="path74"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<!-- Local -> NAS (release/deploy) -->
|
||||
<path
|
||||
d="M 530 505 L 615 505"
|
||||
class="line"
|
||||
id="path75" />
|
||||
<!-- Legend -->
|
||||
<rect
|
||||
x="61.210289"
|
||||
y="750.47656"
|
||||
width="467.57938"
|
||||
height="215.31776"
|
||||
rx="12"
|
||||
class="note"
|
||||
id="rect75" />
|
||||
<text
|
||||
x="80"
|
||||
y="777"
|
||||
class="h2"
|
||||
id="text75"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:16px;line-height:normal;font-family:sans-serif">Lecture (opérationnelle)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="798"
|
||||
class="txt"
|
||||
id="text76"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan86"
|
||||
x="80"
|
||||
y="798">1) Web public : DSM → Traefik :18080 → Host(archicratie...)</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan87"
|
||||
x="80"
|
||||
y="814.40051">→ chain-auth → backend (8081/8082)</tspan></text>
|
||||
<text
|
||||
x="80"
|
||||
y="836"
|
||||
class="txt"
|
||||
id="text77"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan84"
|
||||
x="80"
|
||||
y="836">2) Gate éditeurs : site appelle /_auth/whoami</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan85"
|
||||
x="80"
|
||||
y="852.25">→ Traefik route vers edge-whoami (protégé)</tspan></text>
|
||||
<text
|
||||
x="80"
|
||||
y="874"
|
||||
class="txt"
|
||||
id="text78"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan82"
|
||||
x="80"
|
||||
y="874">3) Gitea : Host(gitea...) → Traefik → 127.0.0.1:3000</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan83"
|
||||
x="80"
|
||||
y="890.40051">(sanitize-remote)</tspan></text>
|
||||
<text
|
||||
x="80"
|
||||
y="912"
|
||||
class="txt"
|
||||
id="text79"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan80"
|
||||
x="80"
|
||||
y="912">4) Blue/green : changer <tspan
|
||||
class="mono"
|
||||
id="tspan78"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">dynamic/20-archicratie-backend.yml</tspan></tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan81"
|
||||
x="80"
|
||||
y="928.25">(un seul backend actif)</tspan></text>
|
||||
<text
|
||||
x="80"
|
||||
y="950"
|
||||
class="small"
|
||||
id="text80"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif">NB : un test sans Host sur :18080 renvoie 404 (normal, Host rules).</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 26 KiB |
409
docs/diagrams/archicratie-web-edition-machine-editoriale-v2.svg
Normal file
@@ -0,0 +1,409 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1600"
|
||||
height="900"
|
||||
viewBox="0 0 1600 900"
|
||||
version="1.1"
|
||||
id="svg43"
|
||||
sodipodi:docname="archicratie-web-edition-machine-editoriale-v2.svg"
|
||||
inkscape:version="1.3-alpha (95f74fb, 2023-03-31)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview43"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.82625"
|
||||
inkscape:cx="1108.6233"
|
||||
inkscape:cy="435.09834"
|
||||
inkscape:window-width="1472"
|
||||
inkscape:window-height="1022"
|
||||
inkscape:window-x="234"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg43" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<!-- Fond clair lisible partout -->
|
||||
<linearGradient
|
||||
id="bg"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#ffffff"
|
||||
id="stop1" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#f1f5f9"
|
||||
id="stop2" />
|
||||
</linearGradient>
|
||||
<!-- Flèches -->
|
||||
<marker
|
||||
id="arrow"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#334155"
|
||||
id="path2" />
|
||||
</marker>
|
||||
<marker
|
||||
id="arrowA"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#2563eb"
|
||||
id="path3" />
|
||||
</marker>
|
||||
<marker
|
||||
id="arrowG"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#059669"
|
||||
id="path4" />
|
||||
</marker>
|
||||
<!-- Styles SANS variables CSS (compat max) -->
|
||||
<style
|
||||
id="style4"><![CDATA[
|
||||
.title{font:800 28px/1.2 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#0f172a}
|
||||
.subtitle{font:500 14px/1.3 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#475569}
|
||||
.h{font:800 16px/1.2 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#0f172a}
|
||||
.t{font:500 13px/1.35 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#111827}
|
||||
.s{font:500 12px/1.35 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#475569}
|
||||
.mono{font:600 12px/1.35 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono','Courier New',monospace;fill:#0f172a}
|
||||
|
||||
/* Cadres lisibles */
|
||||
.box{fill:#ffffff;stroke:#0ea5e9;stroke-width:1.4}
|
||||
.box2{fill:#f8fafc;stroke:#94a3b8;stroke-width:1.2}
|
||||
|
||||
/* Pills */
|
||||
.chip{fill:#dbeafe;stroke:#2563eb;stroke-width:1}
|
||||
.chip2{fill:#d1fae5;stroke:#059669;stroke-width:1}
|
||||
.chipW{fill:#fef3c7;stroke:#d97706;stroke-width:1}
|
||||
.chipD{fill:#fee2e2;stroke:#dc2626;stroke-width:1}
|
||||
|
||||
/* Traits / flèches */
|
||||
.line{stroke:#334155;stroke-width:1.4;fill:none}
|
||||
.dash{stroke-dasharray:6 6}
|
||||
.arrow{stroke:#334155;stroke-width:1.8;fill:none;marker-end:url(#arrow)}
|
||||
.arrowA{stroke:#2563eb;stroke-width:2.0;fill:none;marker-end:url(#arrowA)}
|
||||
.arrowG{stroke:#059669;stroke-width:2.0;fill:none;marker-end:url(#arrowG)}
|
||||
]]></style>
|
||||
</defs>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="1600"
|
||||
height="900"
|
||||
fill="url(#bg)"
|
||||
id="rect4" />
|
||||
<text
|
||||
x="40"
|
||||
y="56"
|
||||
class="title"
|
||||
id="text4">Archicratie — Machine éditoriale (v2)</text>
|
||||
<text
|
||||
x="40"
|
||||
y="84"
|
||||
class="subtitle"
|
||||
id="text5">De la source au site (lecture + annotations + propositions) — 2026-02-20</text>
|
||||
<rect
|
||||
x="40"
|
||||
y="140"
|
||||
width="460"
|
||||
height="256.62631"
|
||||
class="box"
|
||||
id="rect5" />
|
||||
<text
|
||||
x="118"
|
||||
y="230"
|
||||
class="h"
|
||||
id="text6"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16px;line-height:1.2;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Sources (repo)</text>
|
||||
<text
|
||||
x="118"
|
||||
y="254"
|
||||
class="t"
|
||||
id="text7"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Contenu : src/content/** (MD/MDX)</text>
|
||||
<text
|
||||
x="118"
|
||||
y="272"
|
||||
class="t"
|
||||
id="text8"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Annotations : src/annotations/** (YAML)</text>
|
||||
<text
|
||||
x="118"
|
||||
y="290"
|
||||
class="t"
|
||||
id="text9"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">UI : src/layouts + src/components + global.css</text>
|
||||
<text
|
||||
x="118"
|
||||
y="308"
|
||||
class="s"
|
||||
id="text10"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Plugin paragraph-ids ajoute des ids stables sur paragraphes</text>
|
||||
<rect
|
||||
x="560"
|
||||
y="140"
|
||||
width="500"
|
||||
height="260"
|
||||
class="box"
|
||||
id="rect10" />
|
||||
<text
|
||||
x="698"
|
||||
y="230"
|
||||
class="h"
|
||||
id="text11"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16px;line-height:1.2;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Build (Astro static)</text>
|
||||
<text
|
||||
x="698"
|
||||
y="254"
|
||||
class="t"
|
||||
id="text12"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">astro build → dist/**/index.html</text>
|
||||
<text
|
||||
x="698"
|
||||
y="272"
|
||||
class="t"
|
||||
id="text13"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">meta Pagefind: edition/level/status/version</text>
|
||||
<text
|
||||
x="698"
|
||||
y="290"
|
||||
class="t"
|
||||
id="text14"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Layout : EditionLayout + SiteLayout</text>
|
||||
<text
|
||||
x="698"
|
||||
y="308"
|
||||
class="s"
|
||||
id="text15"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">data-pagefind-body = zone indexée</text>
|
||||
<rect
|
||||
x="560"
|
||||
y="430"
|
||||
width="497.57944"
|
||||
height="249.74281"
|
||||
class="box2"
|
||||
id="rect15" />
|
||||
<text
|
||||
x="658"
|
||||
y="520"
|
||||
class="h"
|
||||
id="text16"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16px;line-height:1.2;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Postbuild (qualité + recherche + indexes)</text>
|
||||
<text
|
||||
x="658"
|
||||
y="544"
|
||||
class="t"
|
||||
id="text17"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Aliases d'ancres (backward compat)</text>
|
||||
<text
|
||||
x="658"
|
||||
y="562"
|
||||
class="t"
|
||||
id="text18"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Dédoublonnage d'IDs (anti-régression)</text>
|
||||
<text
|
||||
x="658"
|
||||
y="580"
|
||||
class="t"
|
||||
id="text19"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Index des paragraphes (para-index)</text>
|
||||
<text
|
||||
x="658"
|
||||
y="598"
|
||||
class="t"
|
||||
id="text20"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Index des annotations (annotations-index)</text>
|
||||
<text
|
||||
x="658"
|
||||
y="616"
|
||||
class="t"
|
||||
id="text21"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Pagefind (recherche full-text)</text>
|
||||
<rect
|
||||
x="1120"
|
||||
y="140"
|
||||
width="436.36914"
|
||||
height="259.36459"
|
||||
class="box"
|
||||
id="rect21" />
|
||||
<text
|
||||
x="1238"
|
||||
y="210"
|
||||
class="h"
|
||||
id="text22"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16px;line-height:1.2;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Artefacts (dist/)</text>
|
||||
<text
|
||||
x="1238"
|
||||
y="234"
|
||||
class="mono"
|
||||
id="text23"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">HTML statique + assets</text>
|
||||
<text
|
||||
x="1238"
|
||||
y="252"
|
||||
class="mono"
|
||||
id="text24"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">dist/pagefind/**</text>
|
||||
<text
|
||||
x="1238"
|
||||
y="270"
|
||||
class="mono"
|
||||
id="text25"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">dist/para-index.json</text>
|
||||
<text
|
||||
x="1238"
|
||||
y="288"
|
||||
class="mono"
|
||||
id="text26"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">dist/annotations-index.json</text>
|
||||
<text
|
||||
x="1238"
|
||||
y="306"
|
||||
class="s"
|
||||
id="text27"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">(en dev) recopiés dans public/*-index.json</text>
|
||||
<rect
|
||||
x="1120"
|
||||
y="430"
|
||||
width="436.36917"
|
||||
height="249.48566"
|
||||
class="box2"
|
||||
id="rect27" />
|
||||
<text
|
||||
x="1178"
|
||||
y="520"
|
||||
class="h"
|
||||
id="text28"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16px;line-height:1.2;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Runtime navigateur (lecture)</text>
|
||||
<text
|
||||
x="1178"
|
||||
y="544"
|
||||
class="t"
|
||||
id="text29"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">LocalToc sync (H2/H3)</text>
|
||||
<text
|
||||
x="1178"
|
||||
y="562"
|
||||
class="t"
|
||||
id="text30"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">banner-follow + reading-follow__inner</text>
|
||||
<text
|
||||
x="1178"
|
||||
y="580"
|
||||
class="t"
|
||||
id="text31"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">SidePanel: niveaux + annotations + propose</text>
|
||||
<text
|
||||
x="1178"
|
||||
y="598"
|
||||
class="s"
|
||||
id="text32"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Comportement lecture: H2/H3 unifiés (plus d’accordéon gênant)</text>
|
||||
<rect
|
||||
x="40"
|
||||
y="430"
|
||||
width="460"
|
||||
height="250"
|
||||
class="box2"
|
||||
id="rect32" />
|
||||
<text
|
||||
x="138"
|
||||
y="524"
|
||||
class="h"
|
||||
id="text33"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16px;line-height:1.2;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Flux “Proposer” (tickets)</text>
|
||||
<text
|
||||
x="138"
|
||||
y="548"
|
||||
class="t"
|
||||
id="text34"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">UI collecte: page + paragraphe + type + message</text>
|
||||
<text
|
||||
x="138"
|
||||
y="566"
|
||||
class="t"
|
||||
id="text35"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Création d'issue Gitea (labels)</text>
|
||||
<text
|
||||
x="138"
|
||||
y="584"
|
||||
class="t"
|
||||
id="text36"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Lien retour: issue → page + id</text>
|
||||
<text
|
||||
x="138"
|
||||
y="602"
|
||||
class="s"
|
||||
id="text37"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Option: bridge same-origin pour éviter CORS/auth</text>
|
||||
<path
|
||||
d="M500 250 C530 250 530 250 560 250"
|
||||
class="arrowA"
|
||||
id="path37" />
|
||||
<path
|
||||
d="M810 400 C810 420 810 420 810 430"
|
||||
class="arrowA"
|
||||
id="path38" />
|
||||
<path
|
||||
d="M1060 250 C1090 250 1090 250 1120 250"
|
||||
class="arrowA"
|
||||
id="path39" />
|
||||
<path
|
||||
d="M 1338.7897,398.15432 1340,430"
|
||||
class="arrow"
|
||||
id="path40"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
d="M500 540 C620 540 620 520 560 520"
|
||||
class="arrow"
|
||||
id="path41" />
|
||||
<text
|
||||
x="520"
|
||||
y="525"
|
||||
class="s"
|
||||
id="text41">issues</text>
|
||||
<rect
|
||||
x="40"
|
||||
y="820"
|
||||
width="1520"
|
||||
height="60"
|
||||
class="box2"
|
||||
id="rect41" />
|
||||
<text
|
||||
x="58"
|
||||
y="850"
|
||||
class="h"
|
||||
id="text42">Conseil de maintenance</text>
|
||||
<text
|
||||
x="58"
|
||||
y="874"
|
||||
class="s"
|
||||
id="text43">Toute évolution UI/indices doit rester déterministe : build identique sur Mac, CI, et NAS. En cas de hotfix, re-sync via PR.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 15 KiB |
596
docs/diagrams/archicratie-web-edition-machine-editoriale-v3.svg
Normal file
@@ -0,0 +1,596 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1500"
|
||||
height="940"
|
||||
viewBox="0 0 1500 940"
|
||||
role="img"
|
||||
aria-label="Archicratie — Machine éditoriale (synthèse) : DEV/PROD, indices, postbuild, proposer/bridge"
|
||||
version="1.1"
|
||||
id="svg71"
|
||||
sodipodi:docname="archicratie-web-edition-machine-editoriale-v3.svg"
|
||||
inkscape:version="1.3-alpha (95f74fb, 2023-03-31)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview71"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.88133333"
|
||||
inkscape:cx="794.25113"
|
||||
inkscape:cy="350.03782"
|
||||
inkscape:window-width="1472"
|
||||
inkscape:window-height="1022"
|
||||
inkscape:window-x="234"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg71" />
|
||||
<defs
|
||||
id="defs2">
|
||||
<style
|
||||
id="style1">
|
||||
/* Inkscape-safe: pas de CSS variables, fond explicite */
|
||||
.title{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; font-size:26px; font-weight:800; fill:#0f172a;}
|
||||
.sub{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; font-size:14px; font-weight:600; fill:#475569;}
|
||||
.laneT{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; font-size:14px; font-weight:800; fill:#0f172a; letter-spacing:.2px;}
|
||||
.laneN{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; font-size:12px; font-weight:600; fill:#475569;}
|
||||
.h{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; font-size:14px; font-weight:800; fill:#0f172a;}
|
||||
.p{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; font-size:12px; font-weight:600; fill:#475569;}
|
||||
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace; font-size:11px; font-weight:700; fill:#334155;}
|
||||
.small{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; font-size:11px; font-weight:600; fill:#475569;}
|
||||
|
||||
.canvas{fill:#f8fafc; stroke:#e2e8f0; stroke-width:1;}
|
||||
.lane{fill:#f1f5f9; stroke:#cbd5e1; stroke-width:1;}
|
||||
.laneAlt{fill:#eef2f7; stroke:#cbd5e1; stroke-width:1;}
|
||||
|
||||
.box{fill:#ffffff; stroke:#94a3b8; stroke-width:1.4;}
|
||||
.boxAlt{fill:#f8fafc; stroke:#94a3b8; stroke-width:1.4;}
|
||||
.call{fill:#ffffff; fill-opacity:.72; stroke:#cbd5e1; stroke-width:1.1;}
|
||||
|
||||
.arrow{stroke:#64748b; stroke-width:2.2; fill:none; marker-end:url(#ah);}
|
||||
.arrowSoft{stroke:#94a3b8; stroke-width:2; fill:none; marker-end:url(#ahSoft);}
|
||||
.dash{stroke-dasharray:7 6;}
|
||||
</style>
|
||||
<marker
|
||||
id="ah"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="5"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L10,5 L0,10 Z"
|
||||
fill="#64748b"
|
||||
id="path1" />
|
||||
</marker>
|
||||
<marker
|
||||
id="ahSoft"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="5"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L10,5 L0,10 Z"
|
||||
fill="#94a3b8"
|
||||
id="path2" />
|
||||
</marker>
|
||||
</defs>
|
||||
<!-- Fond explicite -->
|
||||
<rect
|
||||
x="0.5"
|
||||
y="0.5"
|
||||
width="1499"
|
||||
height="939"
|
||||
rx="26"
|
||||
class="canvas"
|
||||
id="rect2" />
|
||||
<!-- Titre -->
|
||||
<text
|
||||
x="44"
|
||||
y="54"
|
||||
class="title"
|
||||
id="text2">Archicratie — Machine éditoriale (synthèse “exploitation + onboarding”)</text>
|
||||
<text
|
||||
x="44"
|
||||
y="82"
|
||||
class="sub"
|
||||
id="text3">Inclut : DEV vs PROD (indices), ordre exact du postbuild, et fork “Proposer” (direct vs bridge same-origin).</text>
|
||||
<!-- Lanes -->
|
||||
<rect
|
||||
x="40"
|
||||
y="115"
|
||||
width="390"
|
||||
height="770"
|
||||
rx="18"
|
||||
class="lane"
|
||||
id="rect3" />
|
||||
<rect
|
||||
x="450"
|
||||
y="115"
|
||||
width="390"
|
||||
height="770"
|
||||
rx="18"
|
||||
class="laneAlt"
|
||||
id="rect4" />
|
||||
<rect
|
||||
x="860"
|
||||
y="115"
|
||||
width="330"
|
||||
height="770"
|
||||
rx="18"
|
||||
class="lane"
|
||||
id="rect5" />
|
||||
<rect
|
||||
x="1210"
|
||||
y="115"
|
||||
width="250"
|
||||
height="770"
|
||||
rx="18"
|
||||
class="laneAlt"
|
||||
id="rect6" />
|
||||
<text
|
||||
x="60"
|
||||
y="148"
|
||||
class="laneT"
|
||||
id="text6">1) Sources & vérité éditoriale</text>
|
||||
<text
|
||||
x="60"
|
||||
y="170"
|
||||
class="laneN"
|
||||
id="text7">Ce qui est versionné (canon) et transforme l’édition</text>
|
||||
<text
|
||||
x="470"
|
||||
y="148"
|
||||
class="laneT"
|
||||
id="text8">2) Build Astro (static)</text>
|
||||
<text
|
||||
x="470"
|
||||
y="170"
|
||||
class="laneN"
|
||||
id="text9">Rendu HTML + UI d’édition (EditionLayout)</text>
|
||||
<text
|
||||
x="880"
|
||||
y="148"
|
||||
class="laneT"
|
||||
id="text10">3) Postbuild (ordre exact)</text>
|
||||
<text
|
||||
x="880"
|
||||
y="170"
|
||||
class="laneN"
|
||||
id="text11">Anti-régressions + index + recherche</text>
|
||||
<text
|
||||
x="1230"
|
||||
y="148"
|
||||
class="laneT"
|
||||
id="text12">4) Runtime & feedback</text>
|
||||
<text
|
||||
x="1230"
|
||||
y="170"
|
||||
class="laneN"
|
||||
id="text13">DEV (public) / PROD (dist) + Proposer</text>
|
||||
<!-- Lane 1 -->
|
||||
<rect
|
||||
x="70"
|
||||
y="210"
|
||||
width="330"
|
||||
height="135"
|
||||
rx="16"
|
||||
class="box"
|
||||
id="rect13" />
|
||||
<text
|
||||
x="92"
|
||||
y="238"
|
||||
class="h"
|
||||
id="text14">Sources amont (traçabilité)</text>
|
||||
<text
|
||||
x="92"
|
||||
y="260"
|
||||
class="p"
|
||||
id="text15">Fichiers “sources/” (docx/pdf) + historiques.</text>
|
||||
<text
|
||||
x="92"
|
||||
y="282"
|
||||
class="mono"
|
||||
id="text16">sources/** (non servi tel quel)</text>
|
||||
<text
|
||||
x="92"
|
||||
y="304"
|
||||
class="small"
|
||||
id="text17">→ import/pipeline vers le contenu canon.</text>
|
||||
<rect
|
||||
x="70"
|
||||
y="365"
|
||||
width="330"
|
||||
height="190"
|
||||
rx="16"
|
||||
class="boxAlt"
|
||||
id="rect17" />
|
||||
<text
|
||||
x="92"
|
||||
y="393"
|
||||
class="h"
|
||||
id="text18">Contenu canon (site)</text>
|
||||
<text
|
||||
x="92"
|
||||
y="415"
|
||||
class="p"
|
||||
id="text19">Pages : MD/MDX (Astro content)</text>
|
||||
<text
|
||||
x="92"
|
||||
y="437"
|
||||
class="mono"
|
||||
id="text20">src/content/**</text>
|
||||
<text
|
||||
x="92"
|
||||
y="461"
|
||||
class="p"
|
||||
id="text21">Annotations : YAML</text>
|
||||
<text
|
||||
x="92"
|
||||
y="483"
|
||||
class="mono"
|
||||
id="text22">src/annotations/**</text>
|
||||
<text
|
||||
x="78"
|
||||
y="507"
|
||||
class="small"
|
||||
id="text23">Ces deux entrées alimentent l’UI (SidePanel, highlights, etc.).</text>
|
||||
<rect
|
||||
x="70"
|
||||
y="575"
|
||||
width="330"
|
||||
height="140"
|
||||
rx="16"
|
||||
class="box"
|
||||
id="rect23" />
|
||||
<text
|
||||
x="92"
|
||||
y="603"
|
||||
class="h"
|
||||
id="text24">Scripts d’import / qualité</text>
|
||||
<text
|
||||
x="92"
|
||||
y="625"
|
||||
class="p"
|
||||
id="text25">Import DOCX, contrôle d’IDs, aliases, etc.</text>
|
||||
<text
|
||||
x="92"
|
||||
y="647"
|
||||
class="mono"
|
||||
id="text26">scripts/*.mjs</text>
|
||||
<text
|
||||
x="86"
|
||||
y="671"
|
||||
class="small"
|
||||
id="text27">Objectif : build reproductible + pas de régression d’ancres.</text>
|
||||
<!-- Lane 2 -->
|
||||
<rect
|
||||
x="480"
|
||||
y="210"
|
||||
width="330"
|
||||
height="170"
|
||||
rx="16"
|
||||
class="box"
|
||||
id="rect27" />
|
||||
<text
|
||||
x="502"
|
||||
y="238"
|
||||
class="h"
|
||||
id="text28">EditionLayout (UI d’édition)</text>
|
||||
<text
|
||||
x="502"
|
||||
y="260"
|
||||
class="p"
|
||||
id="text29"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan71"
|
||||
x="502"
|
||||
y="260">SiteNav + TOC global + TOC local + reading-follow</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan72"
|
||||
x="502"
|
||||
y="275">+ SidePanel.</tspan></text>
|
||||
<text
|
||||
x="508"
|
||||
y="300"
|
||||
class="mono"
|
||||
id="text30">src/layouts/EditionLayout.astro</text>
|
||||
<text
|
||||
x="508"
|
||||
y="322"
|
||||
class="mono"
|
||||
id="text31">src/components/SidePanel.astro</text>
|
||||
<text
|
||||
x="508"
|
||||
y="344"
|
||||
class="small"
|
||||
id="text32"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan73"
|
||||
x="508"
|
||||
y="344">Globals boot (flags/env)</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan74"
|
||||
x="508"
|
||||
y="357.75">+ interactions “Propos / Réfs / Illus / Com”.</tspan></text>
|
||||
<rect
|
||||
x="480"
|
||||
y="400"
|
||||
width="330"
|
||||
height="160"
|
||||
rx="16"
|
||||
class="boxAlt"
|
||||
id="rect32" />
|
||||
<text
|
||||
x="502"
|
||||
y="428"
|
||||
class="h"
|
||||
id="text33">Build statique</text>
|
||||
<text
|
||||
x="502"
|
||||
y="450"
|
||||
class="p"
|
||||
id="text34">Astro génère HTML & assets.</text>
|
||||
<text
|
||||
x="502"
|
||||
y="472"
|
||||
class="mono"
|
||||
id="text35">npm run build → astro build</text>
|
||||
<text
|
||||
x="502"
|
||||
y="496"
|
||||
class="p"
|
||||
id="text36">Sortie :</text>
|
||||
<text
|
||||
x="502"
|
||||
y="518"
|
||||
class="mono"
|
||||
id="text37">dist/**</text>
|
||||
<!-- Lane 3 -->
|
||||
<rect
|
||||
x="890"
|
||||
y="210"
|
||||
width="270"
|
||||
height="265"
|
||||
rx="16"
|
||||
class="box"
|
||||
id="rect37" />
|
||||
<text
|
||||
x="912"
|
||||
y="238"
|
||||
class="h"
|
||||
id="text38">Postbuild : ordre exact (fixe)</text>
|
||||
<text
|
||||
x="912"
|
||||
y="264"
|
||||
class="mono"
|
||||
id="text39">1) inject-anchor-aliases.mjs</text>
|
||||
<text
|
||||
x="912"
|
||||
y="286"
|
||||
class="mono"
|
||||
id="text40">2) dedupe-ids-dist.mjs</text>
|
||||
<text
|
||||
x="912"
|
||||
y="308"
|
||||
class="mono"
|
||||
id="text41">3) build-para-index.mjs</text>
|
||||
<text
|
||||
x="912"
|
||||
y="330"
|
||||
class="mono"
|
||||
id="text42">4) build-annotations-index.mjs</text>
|
||||
<text
|
||||
x="912"
|
||||
y="352"
|
||||
class="mono"
|
||||
id="text43">5) pagefind</text>
|
||||
<text
|
||||
x="912"
|
||||
y="380"
|
||||
class="p"
|
||||
id="text44">Sorties PROD :</text>
|
||||
<text
|
||||
x="912"
|
||||
y="402"
|
||||
class="mono"
|
||||
id="text45">dist/para-index.json</text>
|
||||
<text
|
||||
x="912"
|
||||
y="424"
|
||||
class="mono"
|
||||
id="text46">dist/annotations-index.json</text>
|
||||
<text
|
||||
x="912"
|
||||
y="446"
|
||||
class="mono"
|
||||
id="text47">dist/pagefind/**</text>
|
||||
<!-- Lane 4 -->
|
||||
<rect
|
||||
x="1230"
|
||||
y="210"
|
||||
width="210"
|
||||
height="200"
|
||||
rx="16"
|
||||
class="box"
|
||||
id="rect47" />
|
||||
<text
|
||||
x="1252"
|
||||
y="238"
|
||||
class="h"
|
||||
id="text48">DEV vs PROD : indices</text>
|
||||
<text
|
||||
x="1252"
|
||||
y="262"
|
||||
class="p"
|
||||
id="text49">PROD (statique) lit dans :</text>
|
||||
<text
|
||||
x="1252"
|
||||
y="284"
|
||||
class="mono"
|
||||
id="text50">dist/*.json</text>
|
||||
<text
|
||||
x="1252"
|
||||
y="308"
|
||||
class="p"
|
||||
id="text51">DEV (astro dev) sert depuis :</text>
|
||||
<text
|
||||
x="1252"
|
||||
y="330"
|
||||
class="mono"
|
||||
id="text52">public/*.json</text>
|
||||
<text
|
||||
x="1252"
|
||||
y="356"
|
||||
class="small"
|
||||
id="text53"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan75"
|
||||
x="1252"
|
||||
y="356">DEV : predev copie/génère</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan76"
|
||||
x="1252"
|
||||
y="369.75">les index pour éviter les 404.</tspan></text>
|
||||
<rect
|
||||
x="1230"
|
||||
y="430"
|
||||
width="210"
|
||||
height="215"
|
||||
rx="16"
|
||||
class="boxAlt"
|
||||
id="rect53" />
|
||||
<text
|
||||
x="1252"
|
||||
y="458"
|
||||
class="h"
|
||||
id="text54">“Proposer” : 2 modes</text>
|
||||
<text
|
||||
x="1252"
|
||||
y="482"
|
||||
class="p"
|
||||
id="text55">A) Direct client → Gitea API</text>
|
||||
<text
|
||||
x="1252"
|
||||
y="504"
|
||||
class="small"
|
||||
id="text56">⚠️ CORS/auth/token (déconseillé)</text>
|
||||
<text
|
||||
x="1252"
|
||||
y="536"
|
||||
class="p"
|
||||
id="text57">B) Bridge same-origin (reco)</text>
|
||||
<text
|
||||
x="1252"
|
||||
y="558"
|
||||
class="mono"
|
||||
id="text58">PUBLIC_ISSUE_BRIDGE_PATH</text>
|
||||
<text
|
||||
x="1252"
|
||||
y="582"
|
||||
class="small"
|
||||
id="text59"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan77"
|
||||
x="1252"
|
||||
y="582">UI → bridge → Gitea</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan78"
|
||||
x="1252"
|
||||
y="596.18488">(secrets côté serveur)</tspan></text>
|
||||
<rect
|
||||
x="1230"
|
||||
y="665"
|
||||
width="210"
|
||||
height="120"
|
||||
rx="16"
|
||||
class="box"
|
||||
id="rect59" />
|
||||
<text
|
||||
x="1252"
|
||||
y="693"
|
||||
class="h"
|
||||
id="text60">Gitea (Issues)</text>
|
||||
<text
|
||||
x="1252"
|
||||
y="717"
|
||||
class="p"
|
||||
id="text61">Création + suivi</text>
|
||||
<text
|
||||
x="1252"
|
||||
y="739"
|
||||
class="mono"
|
||||
id="text62">/issues/new</text>
|
||||
<text
|
||||
x="1232"
|
||||
y="763"
|
||||
class="small"
|
||||
id="text63">Labels/assignee selon règles d’équipe.</text>
|
||||
<!-- Callout (rappel pro) -->
|
||||
<rect
|
||||
x="470"
|
||||
y="590"
|
||||
width="720"
|
||||
height="120"
|
||||
rx="14"
|
||||
class="call"
|
||||
id="rect63" />
|
||||
<text
|
||||
x="490"
|
||||
y="618"
|
||||
class="h"
|
||||
id="text64">Rappel “pro” (anti régression)</text>
|
||||
<text
|
||||
x="490"
|
||||
y="642"
|
||||
class="p"
|
||||
id="text65">• L’ordre du postbuild ne doit pas changer sans raison : il garantit ancres stables + index cohérents.</text>
|
||||
<text
|
||||
x="490"
|
||||
y="664"
|
||||
class="p"
|
||||
id="text66">• DEV sert des index dans <tspan
|
||||
class="mono"
|
||||
id="tspan65">public/</tspan> ; PROD lit dans <tspan
|
||||
class="mono"
|
||||
id="tspan66">dist/</tspan>.</text>
|
||||
<text
|
||||
x="490"
|
||||
y="686"
|
||||
class="p"
|
||||
id="text67">• Pour “Proposer”, préférer le bridge same-origin : pas de token côté navigateur.</text>
|
||||
<!-- Arrows -->
|
||||
<path
|
||||
class="arrow"
|
||||
d="M400 460 C430 460, 450 450, 480 480"
|
||||
id="path67" />
|
||||
<path
|
||||
class="arrow"
|
||||
d="M810 480 C840 480, 860 470, 890 430"
|
||||
id="path68" />
|
||||
<path
|
||||
class="arrowSoft dash"
|
||||
d="M1030 460 C1120 500, 1180 520, 1230 330"
|
||||
id="path69" />
|
||||
<path
|
||||
class="arrow"
|
||||
d="M1180 590 C1210 590, 1220 590, 1230 540"
|
||||
id="path70" />
|
||||
<path
|
||||
class="arrow"
|
||||
d="M1340 645 C1340 660, 1340 660, 1340 665"
|
||||
id="path71" />
|
||||
<!-- Foot -->
|
||||
<text
|
||||
x="44"
|
||||
y="916"
|
||||
class="sub"
|
||||
id="text71">Astuce : si Inkscape affichait “noir”, c’était très souvent des CSS variables. Ici : couleurs explicites + fond explicite.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,510 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1600"
|
||||
height="900"
|
||||
viewBox="0 0 1600 900"
|
||||
version="1.1"
|
||||
id="svg53"
|
||||
sodipodi:docname="archicratie-web-edition-machine-editoriale-verbatim-v2.svg"
|
||||
inkscape:version="1.3-alpha (95f74fb, 2023-03-31)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview53"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.82625"
|
||||
inkscape:cx="655.97579"
|
||||
inkscape:cy="478.66868"
|
||||
inkscape:window-width="1472"
|
||||
inkscape:window-height="1022"
|
||||
inkscape:window-x="234"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg53" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<!-- Fond clair lisible partout -->
|
||||
<linearGradient
|
||||
id="bg"
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="1">
|
||||
<stop
|
||||
offset="0"
|
||||
stop-color="#ffffff"
|
||||
id="stop1" />
|
||||
<stop
|
||||
offset="1"
|
||||
stop-color="#f1f5f9"
|
||||
id="stop2" />
|
||||
</linearGradient>
|
||||
<!-- Flèches -->
|
||||
<marker
|
||||
id="arrow"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#334155"
|
||||
id="path2" />
|
||||
</marker>
|
||||
<marker
|
||||
id="arrowA"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#2563eb"
|
||||
id="path3" />
|
||||
</marker>
|
||||
<marker
|
||||
id="arrowG"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="3"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L9,3 L0,6 Z"
|
||||
fill="#059669"
|
||||
id="path4" />
|
||||
</marker>
|
||||
<!-- Styles SANS variables CSS (compat max) -->
|
||||
<style
|
||||
id="style4"><![CDATA[
|
||||
.title{font:800 28px/1.2 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#0f172a}
|
||||
.subtitle{font:500 14px/1.3 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#475569}
|
||||
.h{font:800 16px/1.2 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#0f172a}
|
||||
.t{font:500 13px/1.35 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#111827}
|
||||
.s{font:500 12px/1.35 system-ui,-apple-system,Segoe UI,Roboto,Arial;fill:#475569}
|
||||
.mono{font:600 12px/1.35 ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono','Courier New',monospace;fill:#0f172a}
|
||||
|
||||
/* Cadres lisibles */
|
||||
.box{fill:#ffffff;stroke:#0ea5e9;stroke-width:1.4}
|
||||
.box2{fill:#f8fafc;stroke:#94a3b8;stroke-width:1.2}
|
||||
|
||||
/* Pills */
|
||||
.chip{fill:#dbeafe;stroke:#2563eb;stroke-width:1}
|
||||
.chip2{fill:#d1fae5;stroke:#059669;stroke-width:1}
|
||||
.chipW{fill:#fef3c7;stroke:#d97706;stroke-width:1}
|
||||
.chipD{fill:#fee2e2;stroke:#dc2626;stroke-width:1}
|
||||
|
||||
/* Traits / flèches */
|
||||
.line{stroke:#334155;stroke-width:1.4;fill:none}
|
||||
.dash{stroke-dasharray:6 6}
|
||||
.arrow{stroke:#334155;stroke-width:1.8;fill:none;marker-end:url(#arrow)}
|
||||
.arrowA{stroke:#2563eb;stroke-width:2.0;fill:none;marker-end:url(#arrowA)}
|
||||
.arrowG{stroke:#059669;stroke-width:2.0;fill:none;marker-end:url(#arrowG)}
|
||||
]]></style>
|
||||
</defs>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="1600"
|
||||
height="900"
|
||||
fill="url(#bg)"
|
||||
id="rect4" />
|
||||
<text
|
||||
x="40"
|
||||
y="56"
|
||||
class="title"
|
||||
id="text4">Archicratie — Machine éditoriale (v2, verbatim)</text>
|
||||
<text
|
||||
x="40"
|
||||
y="84"
|
||||
class="subtitle"
|
||||
id="text5">Détails scripts/fichiers — 2026-02-20</text>
|
||||
<rect
|
||||
x="40"
|
||||
y="140"
|
||||
width="460"
|
||||
height="236.05144"
|
||||
class="box"
|
||||
id="rect5" />
|
||||
<text
|
||||
x="58"
|
||||
y="170"
|
||||
class="h"
|
||||
id="text6">Sources (repo)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="194"
|
||||
class="t"
|
||||
id="text7">Contenu : src/content/** (MD/MDX)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="212"
|
||||
class="t"
|
||||
id="text8">Annotations : src/annotations/** (YAML)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="230"
|
||||
class="t"
|
||||
id="text9">UI : src/layouts + src/components + global.css</text>
|
||||
<text
|
||||
x="58"
|
||||
y="248"
|
||||
class="s"
|
||||
id="text10">Plugin paragraph-ids ajoute des ids stables sur paragraphes</text>
|
||||
<rect
|
||||
x="166"
|
||||
y="296"
|
||||
width="190"
|
||||
height="28"
|
||||
class="chip"
|
||||
id="rect10" />
|
||||
<text
|
||||
x="180"
|
||||
y="315"
|
||||
class="mono"
|
||||
id="text11"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">rehype-paragraph-ids.js</text>
|
||||
<rect
|
||||
x="560"
|
||||
y="140"
|
||||
width="500"
|
||||
height="239.42511"
|
||||
class="box"
|
||||
id="rect11" />
|
||||
<text
|
||||
x="578"
|
||||
y="170"
|
||||
class="h"
|
||||
id="text12">Build (Astro static)</text>
|
||||
<text
|
||||
x="578"
|
||||
y="194"
|
||||
class="t"
|
||||
id="text13">astro build → dist/**/index.html</text>
|
||||
<text
|
||||
x="578"
|
||||
y="212"
|
||||
class="t"
|
||||
id="text14">meta Pagefind: edition/level/status/version</text>
|
||||
<text
|
||||
x="578"
|
||||
y="230"
|
||||
class="t"
|
||||
id="text15">Layout : EditionLayout + SiteLayout</text>
|
||||
<text
|
||||
x="578"
|
||||
y="248"
|
||||
class="s"
|
||||
id="text16">data-pagefind-body = zone indexée</text>
|
||||
<rect
|
||||
x="750"
|
||||
y="300"
|
||||
width="128"
|
||||
height="28"
|
||||
class="chip2"
|
||||
id="rect16" />
|
||||
<text
|
||||
x="764"
|
||||
y="319"
|
||||
class="mono"
|
||||
id="text17"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">npm run build</text>
|
||||
<rect
|
||||
x="560"
|
||||
y="430"
|
||||
width="500"
|
||||
height="280"
|
||||
class="box2"
|
||||
id="rect17" />
|
||||
<text
|
||||
x="578"
|
||||
y="460"
|
||||
class="h"
|
||||
id="text18">Postbuild (qualité + recherche + indexes)</text>
|
||||
<text
|
||||
x="578"
|
||||
y="484"
|
||||
class="t"
|
||||
id="text19">Aliases d'ancres (backward compat)</text>
|
||||
<text
|
||||
x="578"
|
||||
y="502"
|
||||
class="t"
|
||||
id="text20">Dédoublonnage d'IDs (anti-régression)</text>
|
||||
<text
|
||||
x="578"
|
||||
y="520"
|
||||
class="t"
|
||||
id="text21">Index des paragraphes (para-index)</text>
|
||||
<text
|
||||
x="578"
|
||||
y="538"
|
||||
class="t"
|
||||
id="text22">Index des annotations (annotations-index)</text>
|
||||
<text
|
||||
x="578"
|
||||
y="556"
|
||||
class="t"
|
||||
id="text23">Pagefind (recherche full-text)</text>
|
||||
<rect
|
||||
x="690.71106"
|
||||
y="578.59302"
|
||||
width="246"
|
||||
height="28"
|
||||
class="chip"
|
||||
id="rect23" />
|
||||
<text
|
||||
x="704.71106"
|
||||
y="597.59302"
|
||||
class="mono"
|
||||
id="text24"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">inject-anchor-aliases.mjs</text>
|
||||
<rect
|
||||
x="705"
|
||||
y="622"
|
||||
width="214"
|
||||
height="28"
|
||||
class="chip"
|
||||
id="rect24" />
|
||||
<text
|
||||
x="719"
|
||||
y="641"
|
||||
class="mono"
|
||||
id="text25"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">dedupe-ids-dist.mjs</text>
|
||||
<rect
|
||||
x="710.3858"
|
||||
y="664.52344"
|
||||
width="206"
|
||||
height="28"
|
||||
class="chip2"
|
||||
id="rect25" />
|
||||
<text
|
||||
x="724.3858"
|
||||
y="683.52344"
|
||||
class="mono"
|
||||
id="text26"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">build-para-index.mjs</text>
|
||||
<rect
|
||||
x="1265"
|
||||
y="660"
|
||||
width="254"
|
||||
height="28"
|
||||
class="chip2"
|
||||
id="rect26" />
|
||||
<text
|
||||
x="1279"
|
||||
y="679"
|
||||
class="mono"
|
||||
id="text27">build-annotations-index.mjs</text>
|
||||
<rect
|
||||
x="1120"
|
||||
y="140"
|
||||
width="440"
|
||||
height="240"
|
||||
class="box"
|
||||
id="rect27" />
|
||||
<text
|
||||
x="1138"
|
||||
y="170"
|
||||
class="h"
|
||||
id="text28">Artefacts (dist/)</text>
|
||||
<text
|
||||
x="1138"
|
||||
y="194"
|
||||
class="mono"
|
||||
id="text29">HTML statique + assets</text>
|
||||
<text
|
||||
x="1138"
|
||||
y="212"
|
||||
class="mono"
|
||||
id="text30">dist/pagefind/**</text>
|
||||
<text
|
||||
x="1138"
|
||||
y="230"
|
||||
class="mono"
|
||||
id="text31">dist/para-index.json</text>
|
||||
<text
|
||||
x="1138"
|
||||
y="248"
|
||||
class="mono"
|
||||
id="text32">dist/annotations-index.json</text>
|
||||
<text
|
||||
x="1138"
|
||||
y="266"
|
||||
class="s"
|
||||
id="text33">(en dev) recopiés dans public/*-index.json</text>
|
||||
<rect
|
||||
x="1120"
|
||||
y="430"
|
||||
width="441.2103"
|
||||
height="280.95309"
|
||||
class="box2"
|
||||
id="rect33" />
|
||||
<text
|
||||
x="1138"
|
||||
y="460"
|
||||
class="h"
|
||||
id="text34">Runtime navigateur (lecture)</text>
|
||||
<text
|
||||
x="1138"
|
||||
y="484"
|
||||
class="t"
|
||||
id="text35">LocalToc sync (H2/H3)</text>
|
||||
<text
|
||||
x="1138"
|
||||
y="502"
|
||||
class="t"
|
||||
id="text36">banner-follow + reading-follow__inner</text>
|
||||
<text
|
||||
x="1138"
|
||||
y="520"
|
||||
class="t"
|
||||
id="text37">SidePanel: niveaux + annotations + propose</text>
|
||||
<text
|
||||
x="1138"
|
||||
y="538"
|
||||
class="s"
|
||||
id="text38">Comportement lecture: H2/H3 unifiés (plus d’accordéon gênant)</text>
|
||||
<rect
|
||||
x="1263.4493"
|
||||
y="588.65356"
|
||||
width="150"
|
||||
height="28"
|
||||
class="chip2"
|
||||
id="rect38" />
|
||||
<text
|
||||
x="1277.4493"
|
||||
y="607.65356"
|
||||
class="mono"
|
||||
id="text39"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">SidePanel.astro</text>
|
||||
<rect
|
||||
x="1260.8547"
|
||||
y="633.4342"
|
||||
width="160"
|
||||
height="28"
|
||||
class="chip"
|
||||
id="rect39" />
|
||||
<text
|
||||
x="1274.8547"
|
||||
y="652.4342"
|
||||
class="mono"
|
||||
id="text40"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">LevelToggle.astro</text>
|
||||
<rect
|
||||
x="41.210289"
|
||||
y="431.52798"
|
||||
width="462.42056"
|
||||
height="275.41605"
|
||||
class="box2"
|
||||
id="rect40" />
|
||||
<text
|
||||
x="58"
|
||||
y="470"
|
||||
class="h"
|
||||
id="text41"
|
||||
style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:16px;line-height:1.2;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Flux “Proposer” (tickets)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="494"
|
||||
class="t"
|
||||
id="text42"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">UI collecte: page + paragraphe + type + message</text>
|
||||
<text
|
||||
x="58"
|
||||
y="512"
|
||||
class="t"
|
||||
id="text43"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Création d'issue Gitea (labels)</text>
|
||||
<text
|
||||
x="58"
|
||||
y="530"
|
||||
class="t"
|
||||
id="text44"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:13px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Lien retour: issue → page + id</text>
|
||||
<text
|
||||
x="58"
|
||||
y="548"
|
||||
class="s"
|
||||
id="text45"
|
||||
style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:12px;line-height:1.35;font-family:system-ui, '-apple-system', 'Segoe UI', Roboto, Arial">Option: bridge same-origin pour éviter CORS/auth</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="610"
|
||||
width="150"
|
||||
height="28"
|
||||
class="chip"
|
||||
id="rect45" />
|
||||
<text
|
||||
x="74"
|
||||
y="629"
|
||||
class="mono"
|
||||
id="text46"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">PUBLIC_GITEA_*</text>
|
||||
<rect
|
||||
x="230"
|
||||
y="610"
|
||||
width="262"
|
||||
height="28"
|
||||
class="chip2"
|
||||
id="rect46" />
|
||||
<text
|
||||
x="244"
|
||||
y="629"
|
||||
class="mono"
|
||||
id="text47"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:12px;line-height:1.35;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace">PUBLIC_ISSUE_BRIDGE_PATH</text>
|
||||
<path
|
||||
d="M500 250 C530 250 530 250 560 250"
|
||||
class="arrowA"
|
||||
id="path47" />
|
||||
<path
|
||||
d="M810 400 C810 420 810 420 810 430"
|
||||
class="arrowA"
|
||||
id="path48" />
|
||||
<path
|
||||
d="M1060 250 C1090 250 1090 250 1120 250"
|
||||
class="arrowA"
|
||||
id="path49" />
|
||||
<path
|
||||
d="M1340 380 C1340 410 1340 410 1340 430"
|
||||
class="arrow"
|
||||
id="path50" />
|
||||
<path
|
||||
d="M500 540 C620 540 620 520 560 520"
|
||||
class="arrow"
|
||||
id="path51" />
|
||||
<text
|
||||
x="520"
|
||||
y="525"
|
||||
class="s"
|
||||
id="text51">issues</text>
|
||||
<rect
|
||||
x="40"
|
||||
y="820"
|
||||
width="1520"
|
||||
height="60"
|
||||
class="box2"
|
||||
id="rect51" />
|
||||
<text
|
||||
x="58"
|
||||
y="850"
|
||||
class="h"
|
||||
id="text52">Conseil de maintenance</text>
|
||||
<text
|
||||
x="58"
|
||||
y="874"
|
||||
class="s"
|
||||
id="text53">Toute évolution UI/indices doit rester déterministe : build identique sur Mac, CI, et NAS. En cas de hotfix, re-sync via PR.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,613 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1500"
|
||||
height="1050"
|
||||
viewBox="0 0 1500 1050"
|
||||
role="img"
|
||||
aria-label="Archicratie — Machine éditoriale (verbatim) : scripts, indices DEV/PROD, postbuild exact, proposer direct vs bridge"
|
||||
version="1.1"
|
||||
id="svg77"
|
||||
sodipodi:docname="archicratie-web-edition-machine-editoriale-verbatim-v3.svg"
|
||||
inkscape:version="1.3-alpha (95f74fb, 2023-03-31)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview77"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.83714286"
|
||||
inkscape:cx="756.14334"
|
||||
inkscape:cy="367.32082"
|
||||
inkscape:window-width="1472"
|
||||
inkscape:window-height="1022"
|
||||
inkscape:window-x="234"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg77" />
|
||||
<defs
|
||||
id="defs2">
|
||||
<style
|
||||
id="style1">
|
||||
/* Inkscape-safe: pas de CSS variables */
|
||||
.title{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; font-size:26px; font-weight:900; fill:#0f172a;}
|
||||
.sub{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; font-size:14px; font-weight:650; fill:#475569;}
|
||||
.laneT{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; font-size:14px; font-weight:900; fill:#0f172a;}
|
||||
.laneN{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; font-size:12px; font-weight:650; fill:#475569;}
|
||||
.h{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; font-size:14px; font-weight:900; fill:#0f172a;}
|
||||
.p{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; font-size:12px; font-weight:650; fill:#475569;}
|
||||
.small{font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial; font-size:11px; font-weight:650; fill:#475569;}
|
||||
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace; font-size:11px; font-weight:800; fill:#334155;}
|
||||
|
||||
.canvas{fill:#f8fafc; stroke:#e2e8f0; stroke-width:1;}
|
||||
.lane{fill:#f1f5f9; stroke:#cbd5e1; stroke-width:1;}
|
||||
.laneAlt{fill:#eef2f7; stroke:#cbd5e1; stroke-width:1;}
|
||||
.box{fill:#ffffff; stroke:#94a3b8; stroke-width:1.4;}
|
||||
.boxAlt{fill:#f8fafc; stroke:#94a3b8; stroke-width:1.4;}
|
||||
.call{fill:#ffffff; fill-opacity:.72; stroke:#cbd5e1; stroke-width:1.1;}
|
||||
|
||||
.arrow{stroke:#64748b; stroke-width:2.2; fill:none; marker-end:url(#ah);}
|
||||
.arrowSoft{stroke:#94a3b8; stroke-width:2; fill:none; marker-end:url(#ahSoft);}
|
||||
.dash{stroke-dasharray:7 6;}
|
||||
</style>
|
||||
<marker
|
||||
id="ah"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="5"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L10,5 L0,10 Z"
|
||||
fill="#64748b"
|
||||
id="path1" />
|
||||
</marker>
|
||||
<marker
|
||||
id="ahSoft"
|
||||
markerWidth="10"
|
||||
markerHeight="10"
|
||||
refX="9"
|
||||
refY="5"
|
||||
orient="auto">
|
||||
<path
|
||||
d="M0,0 L10,5 L0,10 Z"
|
||||
fill="#94a3b8"
|
||||
id="path2" />
|
||||
</marker>
|
||||
</defs>
|
||||
<rect
|
||||
x="0.5"
|
||||
y="0.5"
|
||||
width="1499"
|
||||
height="1049"
|
||||
rx="26"
|
||||
class="canvas"
|
||||
id="rect2" />
|
||||
<text
|
||||
x="44"
|
||||
y="54"
|
||||
class="title"
|
||||
id="text2">Archicratie — Machine éditoriale (verbatim technique)</text>
|
||||
<text
|
||||
x="44"
|
||||
y="82"
|
||||
class="sub"
|
||||
id="text3">3 ajouts “pro” inclus : (1) indices DEV vs PROD, (2) fork Proposer direct vs bridge, (3) ordre postbuild exact.</text>
|
||||
<!-- Lanes -->
|
||||
<rect
|
||||
x="40"
|
||||
y="115"
|
||||
width="420"
|
||||
height="880"
|
||||
rx="18"
|
||||
class="lane"
|
||||
id="rect3" />
|
||||
<rect
|
||||
x="480"
|
||||
y="115"
|
||||
width="520"
|
||||
height="880"
|
||||
rx="18"
|
||||
class="laneAlt"
|
||||
id="rect4" />
|
||||
<rect
|
||||
x="1020"
|
||||
y="115"
|
||||
width="440"
|
||||
height="880"
|
||||
rx="18"
|
||||
class="lane"
|
||||
id="rect5" />
|
||||
<text
|
||||
x="60"
|
||||
y="148"
|
||||
class="laneT"
|
||||
id="text5">A) Entrées & canon</text>
|
||||
<text
|
||||
x="60"
|
||||
y="170"
|
||||
class="laneN"
|
||||
id="text6">Ce qui est versionné et alimente la build</text>
|
||||
<text
|
||||
x="500"
|
||||
y="148"
|
||||
class="laneT"
|
||||
id="text7">B) Build + postbuild</text>
|
||||
<text
|
||||
x="500"
|
||||
y="170"
|
||||
class="laneN"
|
||||
id="text8">Astro (static) + scripts (ordre fixe)</text>
|
||||
<text
|
||||
x="1040"
|
||||
y="148"
|
||||
class="laneT"
|
||||
id="text9">C) Runtime (DEV/PROD) + “Proposer”</text>
|
||||
<text
|
||||
x="1040"
|
||||
y="170"
|
||||
class="laneN"
|
||||
id="text10">Indices servis, UI, et création d’issues</text>
|
||||
<!-- A) Entrées -->
|
||||
<rect
|
||||
x="70"
|
||||
y="210"
|
||||
width="360"
|
||||
height="165"
|
||||
rx="16"
|
||||
class="box"
|
||||
id="rect10" />
|
||||
<text
|
||||
x="92"
|
||||
y="238"
|
||||
class="h"
|
||||
id="text11">Contenu canon (pages)</text>
|
||||
<text
|
||||
x="92"
|
||||
y="260"
|
||||
class="p"
|
||||
id="text12">Astro Content : MD / MDX (pages, chapitres, etc.)</text>
|
||||
<text
|
||||
x="92"
|
||||
y="284"
|
||||
class="mono"
|
||||
id="text13">src/content/**</text>
|
||||
<text
|
||||
x="92"
|
||||
y="310"
|
||||
class="small"
|
||||
id="text14">Layouts/TOC/reading-follow consomment ces pages.</text>
|
||||
<text
|
||||
x="92"
|
||||
y="334"
|
||||
class="small"
|
||||
id="text15">Les IDs de paragraphes doivent rester stables (anti-régression).</text>
|
||||
<rect
|
||||
x="70"
|
||||
y="395"
|
||||
width="360"
|
||||
height="190"
|
||||
rx="16"
|
||||
class="boxAlt"
|
||||
id="rect15" />
|
||||
<text
|
||||
x="92"
|
||||
y="423"
|
||||
class="h"
|
||||
id="text16">Annotations (surcouche)</text>
|
||||
<text
|
||||
x="92"
|
||||
y="445"
|
||||
class="p"
|
||||
id="text17">YAML : notes, refs, illus, commentaires par paragraphe.</text>
|
||||
<text
|
||||
x="92"
|
||||
y="468"
|
||||
class="mono"
|
||||
id="text18">src/annotations/**</text>
|
||||
<text
|
||||
x="92"
|
||||
y="494"
|
||||
class="p"
|
||||
id="text19">Indexé en JSON pour le SidePanel :</text>
|
||||
<text
|
||||
x="92"
|
||||
y="516"
|
||||
class="mono"
|
||||
id="text20">dist/annotations-index.json (PROD)</text>
|
||||
<text
|
||||
x="92"
|
||||
y="538"
|
||||
class="mono"
|
||||
id="text21">public/annotations-index.json (DEV)</text>
|
||||
<rect
|
||||
x="70"
|
||||
y="605"
|
||||
width="360"
|
||||
height="170"
|
||||
rx="16"
|
||||
class="box"
|
||||
id="rect21" />
|
||||
<text
|
||||
x="92"
|
||||
y="633"
|
||||
class="h"
|
||||
id="text22">Scripts (import & qualité)</text>
|
||||
<text
|
||||
x="92"
|
||||
y="655"
|
||||
class="p"
|
||||
id="text23">Import DOCX, checks d’IDs, aliases d’ancres, etc.</text>
|
||||
<text
|
||||
x="92"
|
||||
y="678"
|
||||
class="mono"
|
||||
id="text24">scripts/import-docx.mjs</text>
|
||||
<text
|
||||
x="92"
|
||||
y="700"
|
||||
class="mono"
|
||||
id="text25">scripts/check-anchors.mjs</text>
|
||||
<text
|
||||
x="92"
|
||||
y="724"
|
||||
class="small"
|
||||
id="text26">Objectif : build reproductible + compat backward (ancres).</text>
|
||||
<!-- B) Build + postbuild -->
|
||||
<rect
|
||||
x="510"
|
||||
y="210"
|
||||
width="460"
|
||||
height="190"
|
||||
rx="16"
|
||||
class="box"
|
||||
id="rect26" />
|
||||
<text
|
||||
x="532"
|
||||
y="238"
|
||||
class="h"
|
||||
id="text27">Build Astro (static)</text>
|
||||
<text
|
||||
x="532"
|
||||
y="260"
|
||||
class="p"
|
||||
id="text28">Génère le HTML + assets + routes (output: static).</text>
|
||||
<text
|
||||
x="532"
|
||||
y="284"
|
||||
class="mono"
|
||||
id="text29">npm run build</text>
|
||||
<text
|
||||
x="532"
|
||||
y="306"
|
||||
class="mono"
|
||||
id="text30">→ astro build → dist/**</text>
|
||||
<text
|
||||
x="532"
|
||||
y="330"
|
||||
class="p"
|
||||
id="text31">UI d’édition (côté pages) :</text>
|
||||
<text
|
||||
x="532"
|
||||
y="352"
|
||||
class="mono"
|
||||
id="text32">src/layouts/EditionLayout.astro</text>
|
||||
<text
|
||||
x="532"
|
||||
y="374"
|
||||
class="mono"
|
||||
id="text33">src/components/SidePanel.astro</text>
|
||||
<rect
|
||||
x="510"
|
||||
y="420"
|
||||
width="460"
|
||||
height="330"
|
||||
rx="16"
|
||||
class="boxAlt"
|
||||
id="rect33" />
|
||||
<text
|
||||
x="532"
|
||||
y="448"
|
||||
class="h"
|
||||
id="text34">Postbuild (ordre exact = contrat)</text>
|
||||
<text
|
||||
x="532"
|
||||
y="472"
|
||||
class="p"
|
||||
id="text35">À conserver tel quel pour éviter les régressions.</text>
|
||||
<text
|
||||
x="532"
|
||||
y="500"
|
||||
class="mono"
|
||||
id="text36">1) node scripts/inject-anchor-aliases.mjs</text>
|
||||
<text
|
||||
x="532"
|
||||
y="522"
|
||||
class="mono"
|
||||
id="text37">2) node scripts/dedupe-ids-dist.mjs</text>
|
||||
<text
|
||||
x="532"
|
||||
y="544"
|
||||
class="mono"
|
||||
id="text38"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan79"
|
||||
x="532"
|
||||
y="544">3) node scripts/build-para-index.mjs</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan80"
|
||||
x="532"
|
||||
y="557.75">--in dist --out dist/para-index.json</tspan></text>
|
||||
<text
|
||||
x="532"
|
||||
y="578"
|
||||
class="mono"
|
||||
id="text39"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan81"
|
||||
x="532"
|
||||
y="578">4) node scripts/build-annotations-index.mjs</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan82"
|
||||
x="532"
|
||||
y="591.75">--in src/annotations --out dist/annotations-index.json</tspan></text>
|
||||
<text
|
||||
x="532"
|
||||
y="612"
|
||||
class="mono"
|
||||
id="text40">5) npx pagefind --site dist (→ dist/pagefind/**)</text>
|
||||
<text
|
||||
x="532"
|
||||
y="638"
|
||||
class="p"
|
||||
id="text41">Sorties PROD (statique) :</text>
|
||||
<text
|
||||
x="532"
|
||||
y="660"
|
||||
class="mono"
|
||||
id="text42">dist/para-index.json</text>
|
||||
<text
|
||||
x="532"
|
||||
y="682"
|
||||
class="mono"
|
||||
id="text43">dist/annotations-index.json</text>
|
||||
<text
|
||||
x="532"
|
||||
y="704"
|
||||
class="mono"
|
||||
id="text44">dist/pagefind/**</text>
|
||||
<text
|
||||
x="532"
|
||||
y="736"
|
||||
class="small"
|
||||
id="text45">Mini-règle : inject (aliases) AVANT dedupe, et indices AVANT pagefind.</text>
|
||||
<rect
|
||||
x="510"
|
||||
y="770"
|
||||
width="460"
|
||||
height="195"
|
||||
rx="16"
|
||||
class="box"
|
||||
id="rect45" />
|
||||
<text
|
||||
x="532"
|
||||
y="798"
|
||||
class="h"
|
||||
id="text46">DEV server : indices “public/” (mini-ajout #1)</text>
|
||||
<text
|
||||
x="532"
|
||||
y="822"
|
||||
class="p"
|
||||
id="text47">En DEV, l’UI lit via HTTP depuis <tspan
|
||||
class="mono"
|
||||
id="tspan46">public/</tspan> (pas <tspan
|
||||
class="mono"
|
||||
id="tspan47">dist/</tspan>).</text>
|
||||
<text
|
||||
x="532"
|
||||
y="846"
|
||||
class="mono"
|
||||
id="text48">predev: build-annotations-index → public/annotations-index.json</text>
|
||||
<text
|
||||
x="532"
|
||||
y="868"
|
||||
class="mono"
|
||||
id="text49">predev: build-para-index (depuis dist) → public/para-index.json</text>
|
||||
<text
|
||||
x="532"
|
||||
y="892"
|
||||
class="small"
|
||||
id="text50">Si ces fichiers manquent : 404 (normal) → relancer <tspan
|
||||
class="mono"
|
||||
id="tspan49">npm run dev</tspan> (predev).</text>
|
||||
<!-- C) Runtime + proposer -->
|
||||
<rect
|
||||
x="1050"
|
||||
y="210"
|
||||
width="380"
|
||||
height="200"
|
||||
rx="16"
|
||||
class="box"
|
||||
id="rect50" />
|
||||
<text
|
||||
x="1072"
|
||||
y="238"
|
||||
class="h"
|
||||
id="text51">Runtime PROD</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="262"
|
||||
class="p"
|
||||
id="text52">Site statique servi depuis dist/**</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="286"
|
||||
class="mono"
|
||||
id="text53">dist/*.html</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="308"
|
||||
class="mono"
|
||||
id="text54">dist/para-index.json</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="330"
|
||||
class="mono"
|
||||
id="text55">dist/annotations-index.json</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="352"
|
||||
class="mono"
|
||||
id="text56">dist/pagefind/**</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="378"
|
||||
class="small"
|
||||
id="text57">Ces artefacts sont reproductibles via CI.</text>
|
||||
<rect
|
||||
x="1050"
|
||||
y="430"
|
||||
width="380"
|
||||
height="250"
|
||||
rx="16"
|
||||
class="boxAlt"
|
||||
id="rect57" />
|
||||
<text
|
||||
x="1072"
|
||||
y="458"
|
||||
class="h"
|
||||
id="text58">“Proposer” (mini-ajout #2)</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="482"
|
||||
class="p"
|
||||
id="text59">Depuis SidePanel / ProposeModal (UI).</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="512"
|
||||
class="p"
|
||||
id="text60">Mode A — Direct navigateur → Gitea API</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="534"
|
||||
class="small"
|
||||
id="text61">⚠️ CORS + auth + token : fragile / déconseillé.</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="566"
|
||||
class="p"
|
||||
id="text62">Mode B — Bridge same-origin (recommandé)</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="588"
|
||||
class="mono"
|
||||
id="text63">PUBLIC_ISSUE_BRIDGE_PATH (ex: /bridge/issues)</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="612"
|
||||
class="small"
|
||||
id="text64">Le serveur/proxy ajoute l’auth (secrets) et appelle Gitea côté backend.</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="638"
|
||||
class="small"
|
||||
id="text65">Résultat : pas de secret exposé au client + moins de soucis CORS.</text>
|
||||
<rect
|
||||
x="1050"
|
||||
y="700"
|
||||
width="380"
|
||||
height="165"
|
||||
rx="16"
|
||||
class="box"
|
||||
id="rect65" />
|
||||
<text
|
||||
x="1072"
|
||||
y="728"
|
||||
class="h"
|
||||
id="text66">Gitea : Issues</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="752"
|
||||
class="p"
|
||||
id="text67">Création de tickets (PR/CI séparés du flux éditorial)</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="776"
|
||||
class="mono"
|
||||
id="text68">/issues/new</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="798"
|
||||
class="mono"
|
||||
id="text69">labels / assignee / templates</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="828"
|
||||
class="small"
|
||||
id="text70">Le workflow Git/PR/CI reste la source canon (pas la prod).</text>
|
||||
<!-- Callout -->
|
||||
<rect
|
||||
x="1050"
|
||||
y="885"
|
||||
width="380"
|
||||
height="95.972694"
|
||||
rx="14"
|
||||
class="call"
|
||||
id="rect70" />
|
||||
<text
|
||||
x="1072"
|
||||
y="912"
|
||||
class="h"
|
||||
id="text71">Mini-ajout #3 — ordre postbuild</text>
|
||||
<text
|
||||
x="1072"
|
||||
y="936"
|
||||
class="p"
|
||||
id="text72"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan77"
|
||||
x="1072"
|
||||
y="936">inject-anchor-aliases → dedupe-ids → para-index</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan78"
|
||||
x="1072"
|
||||
y="951.47437">→ annotations-index → pagefind</tspan></text>
|
||||
<text
|
||||
x="1072"
|
||||
y="968"
|
||||
class="small"
|
||||
id="text73">C’est le “contrat” anti-régression : si tu changes l’ordre, tu re-tests tout.</text>
|
||||
<!-- Arrows (liaisons principales) -->
|
||||
<path
|
||||
class="arrow"
|
||||
d="M430 300 C455 300, 475 300, 510 300"
|
||||
id="path73" />
|
||||
<path
|
||||
class="arrow"
|
||||
d="M430 500 C455 500, 480 490, 510 520"
|
||||
id="path74" />
|
||||
<path
|
||||
class="arrow"
|
||||
d="M970 330 C1000 330, 1010 330, 1050 330"
|
||||
id="path75" />
|
||||
<path
|
||||
class="arrowSoft dash"
|
||||
d="M 967.84983,823.85666 C 1006.4505,737.84983 1012.5597,719.6587 1050,610"
|
||||
id="path76"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
class="arrow"
|
||||
d="M1240 680 C1240 695, 1240 695, 1240 700"
|
||||
id="path77" />
|
||||
<text
|
||||
x="44"
|
||||
y="1028"
|
||||
class="sub"
|
||||
id="text77">Inkscape-safe : couleurs & fond explicites (zéro var()).</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,634 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1600"
|
||||
height="1020"
|
||||
viewBox="0 0 1600 1020"
|
||||
version="1.1"
|
||||
id="svg77"
|
||||
sodipodi:docname="archicratie-web-edition-machine-editoriale-verbatim.svg"
|
||||
inkscape:version="1.3-alpha (95f74fb, 2023-03-31)"
|
||||
inkscape:export-filename="out/archicratie-web-edition-machine-editoriale-verbatim.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview77"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.82625"
|
||||
inkscape:cx="524.05446"
|
||||
inkscape:cy="684.41755"
|
||||
inkscape:window-width="1472"
|
||||
inkscape:window-height="1022"
|
||||
inkscape:window-x="235"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg77" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<marker
|
||||
id="arrow"
|
||||
viewBox="0 0 10 10"
|
||||
refX="9.5"
|
||||
refY="5"
|
||||
markerWidth="8"
|
||||
markerHeight="8"
|
||||
orient="auto-start-reverse">
|
||||
<path
|
||||
d="M 0 0 L 10 5 L 0 10 z"
|
||||
fill="#222"
|
||||
id="path1" />
|
||||
</marker>
|
||||
<style
|
||||
id="style1">
|
||||
.title { font: 700 22px sans-serif; fill:#111; }
|
||||
.small { font: 12px sans-serif; fill:#111; }
|
||||
.h2 { font: 700 16px sans-serif; fill:#111; }
|
||||
.h3 { font: 700 14px sans-serif; fill:#111; }
|
||||
.txt { font: 13px sans-serif; fill:#111; }
|
||||
.mono { font: 12px ui-monospace, SFMono-Regular, Menlo, monospace; fill:#111; }
|
||||
.zone { fill:#f3f3f3; stroke:#111; stroke-width:2; }
|
||||
.box { fill:#fafafa; stroke:#222; stroke-width:1.5; }
|
||||
.note { fill:#fff; stroke:#666; stroke-width:1.2; }
|
||||
.line { stroke:#222; stroke-width:2; fill:none; marker-end:url(#arrow); }
|
||||
.dash { stroke:#222; stroke-width:2; fill:none; stroke-dasharray:7 6; marker-end:url(#arrow); }
|
||||
</style>
|
||||
</defs>
|
||||
<!-- Header -->
|
||||
<text
|
||||
x="40"
|
||||
y="45"
|
||||
class="title"
|
||||
id="text1">Archicratie – Web Edition : Machine éditoriale VERBATIM (Proposer / Citer / /_auth/whoami / aliases / apply-ticket)</text>
|
||||
<text
|
||||
x="40"
|
||||
y="75"
|
||||
class="small"
|
||||
id="text2">Sources “vraies” : src/layouts/EditionLayout.astro (WHOAMI_PATH="/_auth/whoami", GITEA_* via import.meta.env.PUBLIC_*), src/anchors/anchor-aliases.json, scripts/inject-anchor-aliases.mjs, scripts/apply-ticket.mjs --alias.</text>
|
||||
<!-- ZONE A: Runtime -->
|
||||
<rect
|
||||
x="35"
|
||||
y="110"
|
||||
width="1530"
|
||||
height="420"
|
||||
rx="18"
|
||||
class="zone"
|
||||
id="rect2" />
|
||||
<text
|
||||
x="60"
|
||||
y="145"
|
||||
class="h2"
|
||||
id="text3">A — Runtime (navigateur) : paragraphe → outils (¶ / Citer / Proposer) → issue Gitea</text>
|
||||
<!-- Reader -->
|
||||
<rect
|
||||
x="60"
|
||||
y="175"
|
||||
width="380"
|
||||
height="160"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect3" />
|
||||
<text
|
||||
x="80"
|
||||
y="205"
|
||||
class="h2"
|
||||
id="text4">Utilisateur (lecteur/éditeur)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="230"
|
||||
class="txt"
|
||||
id="text5">• lit une page</text>
|
||||
<text
|
||||
x="80"
|
||||
y="252"
|
||||
class="txt"
|
||||
id="text6"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• sur un paragraphe : Citer / Proposer / Marque-page</text>
|
||||
<text
|
||||
x="80"
|
||||
y="274"
|
||||
class="txt"
|
||||
id="text7">• Proposer visible uniquement si “editors”</text>
|
||||
<text
|
||||
x="80"
|
||||
y="300"
|
||||
class="small"
|
||||
id="text8">(le gate est runtime via whoami)</text>
|
||||
<!-- Astro page + EditionLayout -->
|
||||
<rect
|
||||
x="470"
|
||||
y="175"
|
||||
width="560"
|
||||
height="330"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect8" />
|
||||
<text
|
||||
x="490"
|
||||
y="205"
|
||||
class="h2"
|
||||
id="text9">Site Astro statique — EditionLayout</text>
|
||||
<text
|
||||
x="490"
|
||||
y="230"
|
||||
class="mono"
|
||||
id="text10">src/layouts/EditionLayout.astro</text>
|
||||
<text
|
||||
x="490"
|
||||
y="260"
|
||||
class="h3"
|
||||
id="text11">Variables publiques injectées</text>
|
||||
<text
|
||||
x="490"
|
||||
y="282"
|
||||
class="txt"
|
||||
id="text13">• <tspan
|
||||
class="mono"
|
||||
id="tspan11">PUBLIC_GITEA_BASE</tspan>, <tspan
|
||||
class="mono"
|
||||
id="tspan12">PUBLIC_GITEA_OWNER</tspan>, <tspan
|
||||
class="mono"
|
||||
id="tspan13">PUBLIC_GITEA_REPO</tspan></text>
|
||||
<text
|
||||
x="490"
|
||||
y="304"
|
||||
class="txt"
|
||||
id="text14">• si une manque : giteaReady=false → Proposer désactivé</text>
|
||||
<text
|
||||
x="490"
|
||||
y="338"
|
||||
class="h3"
|
||||
id="text15">Outils paragraphe</text>
|
||||
<text
|
||||
x="490"
|
||||
y="362"
|
||||
class="txt"
|
||||
id="text17"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• Citer : copie une citation structurée (titre + URL#ancre)</text>
|
||||
<text
|
||||
x="490"
|
||||
y="384"
|
||||
class="txt"
|
||||
id="text18"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• Proposer : modal 2 étapes → ouvre <tspan
|
||||
class="mono"
|
||||
id="tspan17"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">/issues/new?...</tspan></text>
|
||||
<text
|
||||
x="490"
|
||||
y="418"
|
||||
class="h3"
|
||||
id="text19"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:14px;line-height:normal;font-family:sans-serif">Gate “editors” (whoami)</text>
|
||||
<text
|
||||
x="490"
|
||||
y="440"
|
||||
class="txt"
|
||||
id="text20"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• <tspan
|
||||
class="mono"
|
||||
id="tspan19"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">WHOAMI_PATH="/_auth/whoami"</tspan> + fetch same-origin</text>
|
||||
<text
|
||||
x="490"
|
||||
y="462"
|
||||
class="txt"
|
||||
id="text21"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• lit header <tspan
|
||||
class="mono"
|
||||
id="tspan20"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">Remote-Groups</tspan> → affiche/retire Proposer du DOM</text>
|
||||
<!-- Edge/Auth -->
|
||||
<rect
|
||||
x="1060"
|
||||
y="175"
|
||||
width="250"
|
||||
height="160"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect21" />
|
||||
<text
|
||||
x="1080"
|
||||
y="205"
|
||||
class="h2"
|
||||
id="text22">Traefik edge</text>
|
||||
<text
|
||||
x="1080"
|
||||
y="230"
|
||||
class="txt"
|
||||
id="text23">• Host(archicratie…)</text>
|
||||
<text
|
||||
x="1080"
|
||||
y="252"
|
||||
class="txt"
|
||||
id="text24">• middleware : chain-auth</text>
|
||||
<text
|
||||
x="1080"
|
||||
y="274"
|
||||
class="txt"
|
||||
id="text25">• route <tspan
|
||||
class="mono"
|
||||
id="tspan24">/_auth/whoami</tspan></text>
|
||||
<text
|
||||
x="1080"
|
||||
y="300"
|
||||
class="small"
|
||||
id="text26">forward-auth vers Authelia</text>
|
||||
<rect
|
||||
x="1060"
|
||||
y="350"
|
||||
width="250"
|
||||
height="155"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect26" />
|
||||
<text
|
||||
x="1080"
|
||||
y="380"
|
||||
class="h2"
|
||||
id="text27">Authelia + LLDAP</text>
|
||||
<text
|
||||
x="1080"
|
||||
y="405"
|
||||
class="txt"
|
||||
id="text28">• forward-auth : <tspan
|
||||
class="mono"
|
||||
id="tspan27">:9091</tspan></text>
|
||||
<text
|
||||
x="1080"
|
||||
y="427"
|
||||
class="txt"
|
||||
id="text29">• groupes via LDAP</text>
|
||||
<text
|
||||
x="1080"
|
||||
y="449"
|
||||
class="txt"
|
||||
id="text30">• injecte headers Remote-*</text>
|
||||
<text
|
||||
x="1080"
|
||||
y="471"
|
||||
class="small"
|
||||
id="text31">non auth ⇒ 302 vers auth.*</text>
|
||||
<!-- Gitea issue -->
|
||||
<rect
|
||||
x="1330"
|
||||
y="175"
|
||||
width="235"
|
||||
height="330"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect31" />
|
||||
<text
|
||||
x="1350"
|
||||
y="205"
|
||||
class="h2"
|
||||
id="text32">Gitea (UI)</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="230"
|
||||
class="txt"
|
||||
id="text33">Issue préremplie :</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="255"
|
||||
class="mono"
|
||||
id="text34">BASE/OWNER/REPO/issues/new</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="287"
|
||||
class="txt"
|
||||
id="text35">Contenu typique :</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="309"
|
||||
class="txt"
|
||||
id="text36">• URL page + <tspan
|
||||
class="mono"
|
||||
id="tspan35">#p-…</tspan></text>
|
||||
<text
|
||||
x="1350"
|
||||
y="331"
|
||||
class="txt"
|
||||
id="text37">• Type / State / Category</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="353"
|
||||
class="txt"
|
||||
id="text38">• proposition / commentaire</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="385"
|
||||
class="txt"
|
||||
id="text39">Résultat :</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="407"
|
||||
class="txt"
|
||||
id="text40">• issue = backlog éditorial</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="429"
|
||||
class="txt"
|
||||
id="text41">• labels (CI/bot) pour tri</text>
|
||||
<!-- Runtime connections -->
|
||||
<path
|
||||
d="M 440 260 L 470 260"
|
||||
class="line"
|
||||
id="path41" />
|
||||
<path
|
||||
d="M 1030 470 L 1060 470"
|
||||
class="dash"
|
||||
id="path42" />
|
||||
<path
|
||||
d="M 1310 320 L 1330 320"
|
||||
class="line"
|
||||
id="path43" />
|
||||
<path
|
||||
d="M 1030 270 L 1060 270"
|
||||
class="dash"
|
||||
id="path44" />
|
||||
<rect
|
||||
x="60"
|
||||
y="355"
|
||||
width="380"
|
||||
height="150"
|
||||
rx="12"
|
||||
class="note"
|
||||
id="rect44" />
|
||||
<text
|
||||
x="80"
|
||||
y="385"
|
||||
class="h2"
|
||||
id="text44">Contrat runtime (robuste)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="410"
|
||||
class="txt"
|
||||
id="text45">• Citer marche sans droits (copie + lien)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="432"
|
||||
class="txt"
|
||||
id="text46">• Proposer n’existe pas si non “editors”</text>
|
||||
<text
|
||||
x="80"
|
||||
y="454"
|
||||
class="txt"
|
||||
id="text47">• whoami renvoie 302 login si non auth</text>
|
||||
<text
|
||||
x="80"
|
||||
y="476"
|
||||
class="txt"
|
||||
id="text48">• si PUBLIC_GITEA_* faux → 404/login loop</text>
|
||||
<!-- ZONE B: CI / labels -->
|
||||
<rect
|
||||
x="35"
|
||||
y="545"
|
||||
width="1530"
|
||||
height="210"
|
||||
rx="18"
|
||||
class="zone"
|
||||
id="rect48" />
|
||||
<text
|
||||
x="60"
|
||||
y="580"
|
||||
class="h2"
|
||||
id="text49">B — Automatisation : issue → labels + checks qualité</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="610"
|
||||
width="520"
|
||||
height="120"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect49" />
|
||||
<text
|
||||
x="80"
|
||||
y="640"
|
||||
class="h2"
|
||||
id="text50">Gitea Actions (workflows)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="665"
|
||||
class="txt"
|
||||
id="text51">• triggers : issues opened / edited (labels)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="687"
|
||||
class="txt"
|
||||
id="text52">• checks build : anchors / aliases / inline-js / dist audit</text>
|
||||
<text
|
||||
x="80"
|
||||
y="709"
|
||||
class="small"
|
||||
id="text53">token API requis côté job (ex : FORGE_TOKEN) pour écrire labels</text>
|
||||
<rect
|
||||
x="610"
|
||||
y="610"
|
||||
width="430"
|
||||
height="120"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect53" />
|
||||
<text
|
||||
x="630"
|
||||
y="640"
|
||||
class="h2"
|
||||
id="text54">Runner</text>
|
||||
<text
|
||||
x="630"
|
||||
y="665"
|
||||
class="txt"
|
||||
id="text55">• conteneur : <tspan
|
||||
class="mono"
|
||||
id="tspan54">gitea-act-runner (gitea/act_runner)</tspan></text>
|
||||
<text
|
||||
x="630"
|
||||
y="687"
|
||||
class="txt"
|
||||
id="text56">• exécute jobs (souvent en conteneur)</text>
|
||||
<text
|
||||
x="630"
|
||||
y="709"
|
||||
class="txt"
|
||||
id="text57">• appelle API Gitea pour labels</text>
|
||||
<rect
|
||||
x="1070"
|
||||
y="610"
|
||||
width="465"
|
||||
height="120"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect57" />
|
||||
<text
|
||||
x="1090"
|
||||
y="640"
|
||||
class="h2"
|
||||
id="text58">Gitea (API) + labels</text>
|
||||
<text
|
||||
x="1090"
|
||||
y="665"
|
||||
class="txt"
|
||||
id="text59">• labels = tri natif (type/state/cat)</text>
|
||||
<text
|
||||
x="1090"
|
||||
y="687"
|
||||
class="txt"
|
||||
id="text60">• backlog propre, opérable</text>
|
||||
<text
|
||||
x="1090"
|
||||
y="709"
|
||||
class="small"
|
||||
id="text61">si 401 : token manquant/mauvais droits</text>
|
||||
<path
|
||||
d="M 580 670 L 610 670"
|
||||
class="line"
|
||||
id="path61" />
|
||||
<path
|
||||
d="M 1040 670 L 1070 670"
|
||||
class="line"
|
||||
id="path62" />
|
||||
<!-- ZONE C: Re-integration + anchors -->
|
||||
<rect
|
||||
x="35"
|
||||
y="780"
|
||||
width="1530"
|
||||
height="210"
|
||||
rx="18"
|
||||
class="zone"
|
||||
id="rect62" />
|
||||
<text
|
||||
x="400"
|
||||
y="815"
|
||||
class="h2"
|
||||
id="text62"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:16px;line-height:normal;font-family:sans-serif">C — Réintégration : correction → contenu web + stabilité des ancres (aliases build-time)</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="850"
|
||||
width="520"
|
||||
height="115"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect63" />
|
||||
<text
|
||||
x="80"
|
||||
y="880"
|
||||
class="h2"
|
||||
id="text63">Apply-ticket</text>
|
||||
<text
|
||||
x="80"
|
||||
y="905"
|
||||
class="mono"
|
||||
id="text64">scripts/apply-ticket.mjs <issue_number> --alias</text>
|
||||
<text
|
||||
x="80"
|
||||
y="929"
|
||||
class="txt"
|
||||
id="text65">• applique patch dans src/content/…</text>
|
||||
<text
|
||||
x="80"
|
||||
y="951"
|
||||
class="txt"
|
||||
id="text66">• écrit alias old→new dans <tspan
|
||||
class="mono"
|
||||
id="tspan65">src/anchors/anchor-aliases.json</tspan></text>
|
||||
<rect
|
||||
x="610.74738"
|
||||
y="848.78973"
|
||||
width="591.40692"
|
||||
height="117.42059"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect66" />
|
||||
<text
|
||||
x="630"
|
||||
y="880"
|
||||
class="h2"
|
||||
id="text67">Aliases canon + injection</text>
|
||||
<text
|
||||
x="630"
|
||||
y="905"
|
||||
class="mono"
|
||||
id="text68">src/anchors/anchor-aliases.json</text>
|
||||
<text
|
||||
x="630"
|
||||
y="929"
|
||||
class="txt"
|
||||
id="text69">postbuild : <tspan
|
||||
class="mono"
|
||||
id="tspan68">node scripts/inject-anchor-aliases.mjs</tspan></text>
|
||||
<text
|
||||
x="630"
|
||||
y="951"
|
||||
class="txt"
|
||||
id="text70">• injecte <tspan
|
||||
class="mono"
|
||||
id="tspan69"><span id="oldId" class="para-alias"></tspan> avant newId dans dist/**/index.html</text>
|
||||
<rect
|
||||
x="1227.5703"
|
||||
y="850"
|
||||
width="331.42966"
|
||||
height="115"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect70" />
|
||||
<text
|
||||
x="1240"
|
||||
y="880"
|
||||
class="h2"
|
||||
id="text71"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:16px;line-height:normal;font-family:sans-serif">Preuves (tests)</text>
|
||||
<text
|
||||
x="1240"
|
||||
y="905"
|
||||
class="txt"
|
||||
id="text72"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• <tspan
|
||||
class="mono"
|
||||
id="tspan71"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">scripts/check-anchor-aliases.mjs</tspan></text>
|
||||
<text
|
||||
x="1240"
|
||||
y="929"
|
||||
class="txt"
|
||||
id="text73"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• <tspan
|
||||
class="mono"
|
||||
id="tspan72"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">scripts/verify-anchor-aliases-in-dist.mjs</tspan></text>
|
||||
<text
|
||||
x="1240"
|
||||
y="951"
|
||||
class="txt"
|
||||
id="text74"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• <tspan
|
||||
class="mono"
|
||||
id="tspan73"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:ui-monospace, SFMono-Regular, Menlo, monospace">scripts/check-anchors.mjs</tspan></text>
|
||||
<path
|
||||
d="M 1495 545 L 1495 505"
|
||||
class="dash"
|
||||
id="path74" />
|
||||
<path
|
||||
d="M 320 730 L 320 850"
|
||||
class="line"
|
||||
id="path75" />
|
||||
<path
|
||||
d="M 580 908 L 610 908"
|
||||
class="line"
|
||||
id="path76" />
|
||||
<path
|
||||
d="M 1202.0514,908 H 1226"
|
||||
class="line"
|
||||
id="path77"
|
||||
sodipodi:nodetypes="cc" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 16 KiB |
631
docs/diagrams/archicratie-web-edition-machine-editoriale.svg
Normal file
@@ -0,0 +1,631 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1600"
|
||||
height="1020"
|
||||
viewBox="0 0 1600 1020"
|
||||
version="1.1"
|
||||
id="svg77"
|
||||
sodipodi:docname="archicratie-web-edition-machine-editoriale.svg"
|
||||
inkscape:version="1.3-alpha (95f74fb, 2023-03-31)"
|
||||
inkscape:export-filename="out/archicratie-web-edition-machine-editoriale.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview77"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.82625"
|
||||
inkscape:cx="409.07716"
|
||||
inkscape:cy="573.0711"
|
||||
inkscape:window-width="1472"
|
||||
inkscape:window-height="1022"
|
||||
inkscape:window-x="234"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg77" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<marker
|
||||
id="arrow"
|
||||
viewBox="0 0 10 10"
|
||||
refX="9.5"
|
||||
refY="5"
|
||||
markerWidth="8"
|
||||
markerHeight="8"
|
||||
orient="auto-start-reverse">
|
||||
<path
|
||||
d="M 0 0 L 10 5 L 0 10 z"
|
||||
fill="#222"
|
||||
id="path1" />
|
||||
</marker>
|
||||
<style
|
||||
id="style1">
|
||||
.title { font: 700 22px sans-serif; fill:#111; }
|
||||
.small { font: 12px sans-serif; fill:#111; }
|
||||
.h2 { font: 700 16px sans-serif; fill:#111; }
|
||||
.h3 { font: 700 14px sans-serif; fill:#111; }
|
||||
.txt { font: 13px sans-serif; fill:#111; }
|
||||
.mono { font: 12px ui-monospace, SFMono-Regular, Menlo, monospace; fill:#111; }
|
||||
.zone { fill:#f3f3f3; stroke:#111; stroke-width:2; }
|
||||
.box { fill:#fafafa; stroke:#222; stroke-width:1.5; }
|
||||
.note { fill:#fff; stroke:#666; stroke-width:1.2; }
|
||||
.line { stroke:#222; stroke-width:2; fill:none; marker-end:url(#arrow); }
|
||||
.dash { stroke:#222; stroke-width:2; fill:none; stroke-dasharray:7 6; marker-end:url(#arrow); }
|
||||
</style>
|
||||
</defs>
|
||||
<!-- Header -->
|
||||
<text
|
||||
x="40"
|
||||
y="45"
|
||||
class="title"
|
||||
id="text1">Archicratie – Web Edition : Machine éditoriale VERBATIM (Proposer / Citer / /_auth/whoami / aliases / apply-ticket)</text>
|
||||
<text
|
||||
x="40"
|
||||
y="75"
|
||||
class="small"
|
||||
id="text2">Sources “vraies” : src/layouts/EditionLayout.astro (WHOAMI_PATH="/_auth/whoami", GITEA_* via import.meta.env.PUBLIC_*), src/anchors/anchor-aliases.json, scripts/inject-anchor-aliases.mjs, scripts/apply-ticket.mjs --alias.</text>
|
||||
<!-- ZONE A: Runtime -->
|
||||
<rect
|
||||
x="35"
|
||||
y="110"
|
||||
width="1530"
|
||||
height="420"
|
||||
rx="18"
|
||||
class="zone"
|
||||
id="rect2" />
|
||||
<text
|
||||
x="60"
|
||||
y="145"
|
||||
class="h2"
|
||||
id="text3">A — Runtime (navigateur) : paragraphe → outils (¶ / Citer / Proposer) → issue Gitea</text>
|
||||
<!-- Reader -->
|
||||
<rect
|
||||
x="60"
|
||||
y="175"
|
||||
width="380"
|
||||
height="160"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect3" />
|
||||
<text
|
||||
x="80"
|
||||
y="205"
|
||||
class="h2"
|
||||
id="text4">Utilisateur (lecteur/éditeur)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="230"
|
||||
class="txt"
|
||||
id="text5">• lit une page</text>
|
||||
<text
|
||||
x="80"
|
||||
y="252"
|
||||
class="txt"
|
||||
id="text6">• sur un paragraphe : ¶ / Citer / Proposer</text>
|
||||
<text
|
||||
x="80"
|
||||
y="274"
|
||||
class="txt"
|
||||
id="text7">• Proposer visible uniquement si “editors”</text>
|
||||
<text
|
||||
x="80"
|
||||
y="300"
|
||||
class="small"
|
||||
id="text8">(le gate est runtime via whoami)</text>
|
||||
<!-- Astro page + EditionLayout -->
|
||||
<rect
|
||||
x="470"
|
||||
y="175"
|
||||
width="560"
|
||||
height="330"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect8" />
|
||||
<text
|
||||
x="490"
|
||||
y="205"
|
||||
class="h2"
|
||||
id="text9">Site Astro statique — EditionLayout</text>
|
||||
<text
|
||||
x="490"
|
||||
y="230"
|
||||
class="mono"
|
||||
id="text10">src/layouts/EditionLayout.astro</text>
|
||||
<text
|
||||
x="490"
|
||||
y="260"
|
||||
class="h3"
|
||||
id="text11">Variables publiques injectées</text>
|
||||
<text
|
||||
x="490"
|
||||
y="282"
|
||||
class="txt"
|
||||
id="text13">• <tspan
|
||||
class="mono"
|
||||
id="tspan11">PUBLIC_GITEA_BASE</tspan>, <tspan
|
||||
class="mono"
|
||||
id="tspan12">PUBLIC_GITEA_OWNER</tspan>, <tspan
|
||||
class="mono"
|
||||
id="tspan13">PUBLIC_GITEA_REPO</tspan></text>
|
||||
<text
|
||||
x="490"
|
||||
y="304"
|
||||
class="txt"
|
||||
id="text14">• si une manque : giteaReady=false → Proposer désactivé</text>
|
||||
<text
|
||||
x="490"
|
||||
y="338"
|
||||
class="h3"
|
||||
id="text15">Outils paragraphe</text>
|
||||
<text
|
||||
x="490"
|
||||
y="360"
|
||||
class="txt"
|
||||
id="text16">• ¶ : lien d’ancre vers <tspan
|
||||
class="mono"
|
||||
id="tspan15">#p-…</tspan></text>
|
||||
<text
|
||||
x="490"
|
||||
y="382"
|
||||
class="txt"
|
||||
id="text17">• Citer : copie une citation structurée (titre + URL#ancre)</text>
|
||||
<text
|
||||
x="490"
|
||||
y="404"
|
||||
class="txt"
|
||||
id="text18">• Proposer : modal 2 étapes → ouvre <tspan
|
||||
class="mono"
|
||||
id="tspan17">/issues/new?...</tspan></text>
|
||||
<text
|
||||
x="490"
|
||||
y="438"
|
||||
class="h3"
|
||||
id="text19">Gate “editors” (whoami)</text>
|
||||
<text
|
||||
x="490"
|
||||
y="460"
|
||||
class="txt"
|
||||
id="text20">• <tspan
|
||||
class="mono"
|
||||
id="tspan19">WHOAMI_PATH="/_auth/whoami"</tspan> + fetch same-origin</text>
|
||||
<text
|
||||
x="490"
|
||||
y="482"
|
||||
class="txt"
|
||||
id="text21">• lit header <tspan
|
||||
class="mono"
|
||||
id="tspan20">Remote-Groups</tspan> → affiche/retire Proposer du DOM</text>
|
||||
<!-- Edge/Auth -->
|
||||
<rect
|
||||
x="1060"
|
||||
y="175"
|
||||
width="250"
|
||||
height="160"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect21" />
|
||||
<text
|
||||
x="1080"
|
||||
y="205"
|
||||
class="h2"
|
||||
id="text22">Traefik edge</text>
|
||||
<text
|
||||
x="1080"
|
||||
y="230"
|
||||
class="txt"
|
||||
id="text23">• Host(archicratie…)</text>
|
||||
<text
|
||||
x="1080"
|
||||
y="252"
|
||||
class="txt"
|
||||
id="text24">• middleware : chain-auth</text>
|
||||
<text
|
||||
x="1080"
|
||||
y="274"
|
||||
class="txt"
|
||||
id="text25">• route <tspan
|
||||
class="mono"
|
||||
id="tspan24">/_auth/whoami</tspan></text>
|
||||
<text
|
||||
x="1080"
|
||||
y="300"
|
||||
class="small"
|
||||
id="text26">forward-auth vers Authelia</text>
|
||||
<rect
|
||||
x="1060"
|
||||
y="350"
|
||||
width="250"
|
||||
height="155"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect26" />
|
||||
<text
|
||||
x="1080"
|
||||
y="380"
|
||||
class="h2"
|
||||
id="text27">Authelia + LLDAP</text>
|
||||
<text
|
||||
x="1080"
|
||||
y="405"
|
||||
class="txt"
|
||||
id="text28">• forward-auth : <tspan
|
||||
class="mono"
|
||||
id="tspan27">:9091</tspan></text>
|
||||
<text
|
||||
x="1080"
|
||||
y="427"
|
||||
class="txt"
|
||||
id="text29">• groupes via LDAP</text>
|
||||
<text
|
||||
x="1080"
|
||||
y="449"
|
||||
class="txt"
|
||||
id="text30">• injecte headers Remote-*</text>
|
||||
<text
|
||||
x="1080"
|
||||
y="471"
|
||||
class="small"
|
||||
id="text31">non auth ⇒ 302 vers auth.*</text>
|
||||
<!-- Gitea issue -->
|
||||
<rect
|
||||
x="1330"
|
||||
y="175"
|
||||
width="220.47655"
|
||||
height="328.7897"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect31" />
|
||||
<text
|
||||
x="1350"
|
||||
y="205"
|
||||
class="h2"
|
||||
id="text32">Gitea (UI)</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="230"
|
||||
class="txt"
|
||||
id="text33">Issue préremplie :</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="255"
|
||||
class="mono"
|
||||
id="text34">BASE/OWNER/REPO/issues/new</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="287"
|
||||
class="txt"
|
||||
id="text35">Contenu typique :</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="309"
|
||||
class="txt"
|
||||
id="text36">• URL page + <tspan
|
||||
class="mono"
|
||||
id="tspan35">#p-…</tspan></text>
|
||||
<text
|
||||
x="1350"
|
||||
y="331"
|
||||
class="txt"
|
||||
id="text37">• Type / State / Category</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="353"
|
||||
class="txt"
|
||||
id="text38">• proposition / commentaire</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="385"
|
||||
class="txt"
|
||||
id="text39">Résultat :</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="407"
|
||||
class="txt"
|
||||
id="text40">• issue = backlog éditorial</text>
|
||||
<text
|
||||
x="1350"
|
||||
y="429"
|
||||
class="txt"
|
||||
id="text41">• labels (CI/bot) pour tri</text>
|
||||
<!-- Runtime connections -->
|
||||
<path
|
||||
d="M 440 260 L 470 260"
|
||||
class="line"
|
||||
id="path41" />
|
||||
<path
|
||||
d="M 1030 470 L 1060 470"
|
||||
class="dash"
|
||||
id="path42" />
|
||||
<path
|
||||
d="M 1310 320 L 1330 320"
|
||||
class="line"
|
||||
id="path43" />
|
||||
<path
|
||||
d="M 1030 270 L 1060 270"
|
||||
class="dash"
|
||||
id="path44" />
|
||||
<rect
|
||||
x="60"
|
||||
y="355"
|
||||
width="380"
|
||||
height="150"
|
||||
rx="12"
|
||||
class="note"
|
||||
id="rect44" />
|
||||
<text
|
||||
x="80"
|
||||
y="385"
|
||||
class="h2"
|
||||
id="text44">Contrat runtime (robuste)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="410"
|
||||
class="txt"
|
||||
id="text45">• Citer marche sans droits (copie + lien)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="432"
|
||||
class="txt"
|
||||
id="text46">• Proposer n’existe pas si non “editors”</text>
|
||||
<text
|
||||
x="80"
|
||||
y="454"
|
||||
class="txt"
|
||||
id="text47">• whoami renvoie 302 login si non auth</text>
|
||||
<text
|
||||
x="80"
|
||||
y="476"
|
||||
class="txt"
|
||||
id="text48">• si PUBLIC_GITEA_* faux → 404/login loop</text>
|
||||
<!-- ZONE B: CI / labels -->
|
||||
<rect
|
||||
x="35"
|
||||
y="545"
|
||||
width="1530"
|
||||
height="210"
|
||||
rx="18"
|
||||
class="zone"
|
||||
id="rect48" />
|
||||
<text
|
||||
x="60"
|
||||
y="580"
|
||||
class="h2"
|
||||
id="text49">B — Automatisation : issue → labels + checks qualité</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="610"
|
||||
width="520"
|
||||
height="120"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect49" />
|
||||
<text
|
||||
x="80"
|
||||
y="640"
|
||||
class="h2"
|
||||
id="text50">Gitea Actions (workflows)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="665"
|
||||
class="txt"
|
||||
id="text51">• triggers : issues opened / edited (labels)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="687"
|
||||
class="txt"
|
||||
id="text52">• checks build : anchors / aliases / inline-js / dist audit</text>
|
||||
<text
|
||||
x="80"
|
||||
y="709"
|
||||
class="small"
|
||||
id="text53">token API requis côté job (ex : FORGE_TOKEN) pour écrire labels</text>
|
||||
<rect
|
||||
x="610"
|
||||
y="610"
|
||||
width="430"
|
||||
height="120"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect53" />
|
||||
<text
|
||||
x="630"
|
||||
y="640"
|
||||
class="h2"
|
||||
id="text54">Runner</text>
|
||||
<text
|
||||
x="630"
|
||||
y="665"
|
||||
class="txt"
|
||||
id="text55">• conteneur : <tspan
|
||||
class="mono"
|
||||
id="tspan54">gitea-act-runner (gitea/act_runner)</tspan></text>
|
||||
<text
|
||||
x="630"
|
||||
y="687"
|
||||
class="txt"
|
||||
id="text56">• exécute jobs (souvent en conteneur)</text>
|
||||
<text
|
||||
x="630"
|
||||
y="709"
|
||||
class="txt"
|
||||
id="text57">• appelle API Gitea pour labels</text>
|
||||
<rect
|
||||
x="1070"
|
||||
y="610"
|
||||
width="465"
|
||||
height="120"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect57" />
|
||||
<text
|
||||
x="1090"
|
||||
y="640"
|
||||
class="h2"
|
||||
id="text58">Gitea (API) + labels</text>
|
||||
<text
|
||||
x="1090"
|
||||
y="665"
|
||||
class="txt"
|
||||
id="text59">• labels = tri natif (type/state/cat)</text>
|
||||
<text
|
||||
x="1090"
|
||||
y="687"
|
||||
class="txt"
|
||||
id="text60">• backlog propre, opérable</text>
|
||||
<text
|
||||
x="1090"
|
||||
y="709"
|
||||
class="small"
|
||||
id="text61">si 401 : token manquant/mauvais droits</text>
|
||||
<path
|
||||
d="M 580 670 L 610 670"
|
||||
class="line"
|
||||
id="path61" />
|
||||
<path
|
||||
d="M 1040 670 L 1070 670"
|
||||
class="line"
|
||||
id="path62" />
|
||||
<!-- ZONE C: Re-integration + anchors -->
|
||||
<rect
|
||||
x="35"
|
||||
y="780"
|
||||
width="1530"
|
||||
height="210"
|
||||
rx="18"
|
||||
class="zone"
|
||||
id="rect62" />
|
||||
<text
|
||||
x="300"
|
||||
y="815"
|
||||
class="h2"
|
||||
id="text62"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:16px;line-height:normal;font-family:sans-serif">C — Réintégration : correction → contenu web + stabilité des ancres (aliases build-time)</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="850"
|
||||
width="520"
|
||||
height="115"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect63" />
|
||||
<text
|
||||
x="80"
|
||||
y="880"
|
||||
class="h2"
|
||||
id="text63">Apply-ticket</text>
|
||||
<text
|
||||
x="80"
|
||||
y="905"
|
||||
class="mono"
|
||||
id="text64">scripts/apply-ticket.mjs <issue_number> --alias</text>
|
||||
<text
|
||||
x="80"
|
||||
y="929"
|
||||
class="txt"
|
||||
id="text65">• applique patch dans src/content/…</text>
|
||||
<text
|
||||
x="80"
|
||||
y="951"
|
||||
class="txt"
|
||||
id="text66">• écrit alias old→new dans <tspan
|
||||
class="mono"
|
||||
id="tspan65">src/anchors/anchor-aliases.json</tspan></text>
|
||||
<rect
|
||||
x="610"
|
||||
y="850"
|
||||
width="518.78973"
|
||||
height="130.73373"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect66" />
|
||||
<text
|
||||
x="630"
|
||||
y="880"
|
||||
class="h2"
|
||||
id="text67">Aliases canon + injection</text>
|
||||
<text
|
||||
x="630"
|
||||
y="905"
|
||||
class="mono"
|
||||
id="text68">src/anchors/anchor-aliases.json</text>
|
||||
<text
|
||||
x="630"
|
||||
y="929"
|
||||
class="txt"
|
||||
id="text69">postbuild : <tspan
|
||||
class="mono"
|
||||
id="tspan68">node scripts/inject-anchor-aliases.mjs</tspan></text>
|
||||
<text
|
||||
x="630"
|
||||
y="951"
|
||||
class="txt"
|
||||
id="text70"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan77"
|
||||
x="630"
|
||||
y="951">• injecte</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan78"
|
||||
x="630"
|
||||
y="967.25"><span id="oldId" class="para-alias"> avant newId dans dist/**/index.html</tspan></text>
|
||||
<rect
|
||||
x="1160"
|
||||
y="850"
|
||||
width="375"
|
||||
height="115"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect70" />
|
||||
<text
|
||||
x="1180"
|
||||
y="880"
|
||||
class="h2"
|
||||
id="text71">Preuves (tests)</text>
|
||||
<text
|
||||
x="1180"
|
||||
y="905"
|
||||
class="txt"
|
||||
id="text72">• <tspan
|
||||
class="mono"
|
||||
id="tspan71">scripts/check-anchor-aliases.mjs</tspan></text>
|
||||
<text
|
||||
x="1180"
|
||||
y="929"
|
||||
class="txt"
|
||||
id="text73">• <tspan
|
||||
class="mono"
|
||||
id="tspan72">scripts/verify-anchor-aliases-in-dist.mjs</tspan></text>
|
||||
<text
|
||||
x="1180"
|
||||
y="951"
|
||||
class="txt"
|
||||
id="text74">• <tspan
|
||||
class="mono"
|
||||
id="tspan73">scripts/check-anchors.mjs</tspan></text>
|
||||
<path
|
||||
d="M 1495 545 L 1495 505"
|
||||
class="dash"
|
||||
id="path74" />
|
||||
<path
|
||||
d="M 220,730 V 850"
|
||||
class="line"
|
||||
id="path75" />
|
||||
<path
|
||||
d="M 580 908 L 610 908"
|
||||
class="line"
|
||||
id="path76" />
|
||||
<path
|
||||
d="M 1130 908 L 1160 908"
|
||||
class="line"
|
||||
id="path77" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
618
docs/diagrams/diagram.svg
Normal file
@@ -0,0 +1,618 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1600"
|
||||
height="980"
|
||||
viewBox="0 0 1600 980"
|
||||
version="1.1"
|
||||
id="svg66"
|
||||
sodipodi:docname="diagram.svg"
|
||||
inkscape:version="1.3-alpha (95f74fb, 2023-03-31)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview66"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="0.82625"
|
||||
inkscape:cx="1002.118"
|
||||
inkscape:cy="617.85174"
|
||||
inkscape:window-width="1472"
|
||||
inkscape:window-height="1022"
|
||||
inkscape:window-x="234"
|
||||
inkscape:window-y="30"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg66" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<marker
|
||||
id="arrow"
|
||||
viewBox="0 0 10 10"
|
||||
refX="9.5"
|
||||
refY="5"
|
||||
markerWidth="8"
|
||||
markerHeight="8"
|
||||
orient="auto-start-reverse">
|
||||
<path
|
||||
d="M 0 0 L 10 5 L 0 10 z"
|
||||
fill="#222"
|
||||
id="path1" />
|
||||
</marker>
|
||||
<style
|
||||
id="style1">
|
||||
.title { font: 700 22px sans-serif; fill:#111; }
|
||||
.h2 { font: 700 16px sans-serif; fill:#111; }
|
||||
.txt { font: 13px sans-serif; fill:#111; }
|
||||
.small { font: 12px sans-serif; fill:#111; }
|
||||
.box { fill:#fafafa; stroke:#222; stroke-width:1.5; }
|
||||
.zone { fill:#f3f3f3; stroke:#111; stroke-width:2; }
|
||||
.note { fill:#fff; stroke:#666; stroke-width:1.2; }
|
||||
.line { stroke:#222; stroke-width:2; fill:none; marker-end:url(#arrow); }
|
||||
.dash { stroke:#222; stroke-width:2; fill:none; stroke-dasharray:7 6; marker-end:url(#arrow); }
|
||||
</style>
|
||||
</defs>
|
||||
<!-- Header -->
|
||||
<text
|
||||
x="40"
|
||||
y="45"
|
||||
class="title"
|
||||
id="text1">Archicratie – Web Edition : schéma global (Local Mac Studio vs NAS Synology DS220+)</text>
|
||||
<text
|
||||
x="40"
|
||||
y="75"
|
||||
class="small"
|
||||
id="text2">Lecture : (1) utilisateur → DSM → Traefik/Authelia → site ; (2) dev → package → slot green/blue → switch Traefik (provider file) ; (3) proposer → issues → runner → labels.</text>
|
||||
<!-- LOCAL ZONE -->
|
||||
<rect
|
||||
x="35"
|
||||
y="110"
|
||||
width="520"
|
||||
height="820"
|
||||
rx="18"
|
||||
class="zone"
|
||||
id="rect2" />
|
||||
<text
|
||||
x="60"
|
||||
y="145"
|
||||
class="h2"
|
||||
id="text3">LOCAL — Mac Studio (atelier de dev)</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="175"
|
||||
width="470"
|
||||
height="95"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect3" />
|
||||
<text
|
||||
x="80"
|
||||
y="205"
|
||||
class="h2"
|
||||
id="text4">Repo Astro (édition)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="230"
|
||||
class="txt"
|
||||
id="text5">• src/content/ (contenu web)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="250"
|
||||
class="txt"
|
||||
id="text6">• scripts tooling (anchors, import docx, apply-ticket)</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="295"
|
||||
width="470"
|
||||
height="80"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect6" />
|
||||
<text
|
||||
x="80"
|
||||
y="325"
|
||||
class="h2"
|
||||
id="text7">Build statique</text>
|
||||
<text
|
||||
x="80"
|
||||
y="350"
|
||||
class="txt"
|
||||
id="text8">npm run build → dist/ (site statique)</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="400"
|
||||
width="470"
|
||||
height="95"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect8" />
|
||||
<text
|
||||
x="80"
|
||||
y="430"
|
||||
class="h2"
|
||||
id="text9">Release pack</text>
|
||||
<text
|
||||
x="80"
|
||||
y="455"
|
||||
class="txt"
|
||||
id="text10">archive .tar.gz + .sha256</text>
|
||||
<text
|
||||
x="80"
|
||||
y="475"
|
||||
class="txt"
|
||||
id="text11">destination NAS : /volume2/docker/archicratie-web/incoming/</text>
|
||||
<rect
|
||||
x="60"
|
||||
y="520"
|
||||
width="470"
|
||||
height="120"
|
||||
rx="12"
|
||||
class="note"
|
||||
id="rect11" />
|
||||
<text
|
||||
x="80"
|
||||
y="550"
|
||||
class="h2"
|
||||
id="text12">Centre de vérité</text>
|
||||
<text
|
||||
x="80"
|
||||
y="575"
|
||||
class="txt"
|
||||
id="text13">Tu commits/push vers Gitea (NAS) :</text>
|
||||
<text
|
||||
x="80"
|
||||
y="598"
|
||||
class="txt"
|
||||
id="text14">• code + docs + diagrammes (SVG)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="621"
|
||||
class="txt"
|
||||
id="text15">• issues = backlog éditorial</text>
|
||||
<!-- NAS ZONE -->
|
||||
<rect
|
||||
x="590"
|
||||
y="110"
|
||||
width="975"
|
||||
height="820"
|
||||
rx="18"
|
||||
class="zone"
|
||||
id="rect15" />
|
||||
<text
|
||||
x="615"
|
||||
y="145"
|
||||
class="h2"
|
||||
id="text16">DISTANT — NAS Synology DS220+ (DSM + Container Manager)</text>
|
||||
<!-- USERS -->
|
||||
<rect
|
||||
x="615"
|
||||
y="175"
|
||||
width="275"
|
||||
height="90"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect16" />
|
||||
<text
|
||||
x="635"
|
||||
y="205"
|
||||
class="h2"
|
||||
id="text17">Utilisateurs (web)</text>
|
||||
<text
|
||||
x="635"
|
||||
y="230"
|
||||
class="txt"
|
||||
id="text18">• visiteurs</text>
|
||||
<text
|
||||
x="635"
|
||||
y="250"
|
||||
class="txt"
|
||||
id="text19">• éditeurs (accès protégé)</text>
|
||||
<!-- DSM Reverse Proxy -->
|
||||
<rect
|
||||
x="920"
|
||||
y="175"
|
||||
width="615"
|
||||
height="90"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect19" />
|
||||
<text
|
||||
x="945"
|
||||
y="205"
|
||||
class="h2"
|
||||
id="text20">DSM Reverse Proxy (HTTPS public → Traefik)</text>
|
||||
<text
|
||||
x="945"
|
||||
y="230"
|
||||
class="txt"
|
||||
id="text21">• pointe vers 127.0.0.1:18080 (Traefik edge)</text>
|
||||
<text
|
||||
x="945"
|
||||
y="252"
|
||||
class="txt"
|
||||
id="text22">• bascule/rollback = switch Traefik (reload) ; DSM reste stable</text>
|
||||
<!-- Edge Traefik -->
|
||||
<rect
|
||||
x="920"
|
||||
y="295"
|
||||
width="615"
|
||||
height="110"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect22" />
|
||||
<text
|
||||
x="945"
|
||||
y="325"
|
||||
class="h2"
|
||||
id="text23">Traefik (edge) — écoute 127.0.0.1:18080</text>
|
||||
<text
|
||||
x="945"
|
||||
y="350"
|
||||
class="txt"
|
||||
id="text24">• entrée unique derrière DSM</text>
|
||||
<text
|
||||
x="945"
|
||||
y="372"
|
||||
class="txt"
|
||||
id="text25">• middlewares : sanitize-remote + forward-auth Authelia</text>
|
||||
<text
|
||||
x="945"
|
||||
y="394"
|
||||
class="txt"
|
||||
id="text26">• un seul backend site actif (blue OU green) via 20-archicratie-backend.yml</text>
|
||||
<!-- Auth Stack -->
|
||||
<rect
|
||||
x="615"
|
||||
y="310"
|
||||
width="275"
|
||||
height="250"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect26" />
|
||||
<text
|
||||
x="635"
|
||||
y="340"
|
||||
class="h2"
|
||||
id="text27">Auth stack</text>
|
||||
<text
|
||||
x="635"
|
||||
y="365"
|
||||
class="txt"
|
||||
id="text28">Authelia</text>
|
||||
<text
|
||||
x="635"
|
||||
y="387"
|
||||
class="small"
|
||||
id="text29">• forward-auth : /api/authz/forward-auth</text>
|
||||
<text
|
||||
x="635"
|
||||
y="415"
|
||||
class="txt"
|
||||
id="text30">LLDAP</text>
|
||||
<text
|
||||
x="635"
|
||||
y="438"
|
||||
class="small"
|
||||
id="text31">• annuaire LDAP “source of truth”</text>
|
||||
<text
|
||||
x="635"
|
||||
y="466"
|
||||
class="txt"
|
||||
id="text32">Redis</text>
|
||||
<text
|
||||
x="635"
|
||||
y="489"
|
||||
class="small"
|
||||
id="text33">• sessions / cache (selon config)</text>
|
||||
<text
|
||||
x="635"
|
||||
y="525"
|
||||
class="small"
|
||||
id="text34"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan68"
|
||||
x="635"
|
||||
y="525">Objectif : SSO/MFA + anti lock-out</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan69"
|
||||
x="635"
|
||||
y="540">déploiement progressif)</tspan></text>
|
||||
<!-- Web Blue/Green -->
|
||||
<rect
|
||||
x="920"
|
||||
y="435"
|
||||
width="300"
|
||||
height="135"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect34" />
|
||||
<text
|
||||
x="945"
|
||||
y="465"
|
||||
class="h2"
|
||||
id="text35">web_blue (slot A)</text>
|
||||
<text
|
||||
x="945"
|
||||
y="490"
|
||||
class="txt"
|
||||
id="text36">127.0.0.1:8081 → container:80</text>
|
||||
<text
|
||||
x="945"
|
||||
y="515"
|
||||
class="txt"
|
||||
id="text37">sert dist/ (Nginx/HTTP)</text>
|
||||
<text
|
||||
x="945"
|
||||
y="540"
|
||||
class="small"
|
||||
id="text38">ne jamais modifier si LIVE</text>
|
||||
<rect
|
||||
x="1235"
|
||||
y="435"
|
||||
width="300"
|
||||
height="135"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect38" />
|
||||
<text
|
||||
x="1260"
|
||||
y="465"
|
||||
class="h2"
|
||||
id="text39">web_green (slot B)</text>
|
||||
<text
|
||||
x="1260"
|
||||
y="490"
|
||||
class="txt"
|
||||
id="text40">127.0.0.1:8082 → container:80</text>
|
||||
<text
|
||||
x="1260"
|
||||
y="515"
|
||||
class="txt"
|
||||
id="text41">sert dist/ (Nginx/HTTP)</text>
|
||||
<text
|
||||
x="1260"
|
||||
y="540"
|
||||
class="small"
|
||||
id="text42">slot “next” (staging)</text>
|
||||
<!-- Switch script -->
|
||||
<rect
|
||||
x="847.41852"
|
||||
y="587.45636"
|
||||
width="691.17664"
|
||||
height="69.928497"
|
||||
rx="13.486373"
|
||||
class="note"
|
||||
id="rect42" />
|
||||
<text
|
||||
x="932.38275"
|
||||
y="617.42059"
|
||||
class="txt"
|
||||
id="text43"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan67"
|
||||
x="932.38275"
|
||||
y="617.42059">switch-archicratie.sh : bascule blue/green en réécrivant 20-archicratie-backend.yml</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="932.38275"
|
||||
y="633.67059"
|
||||
id="tspan3">puis reload Traefik (provider file)</tspan></text>
|
||||
<!-- Gitea -->
|
||||
<rect
|
||||
x="615"
|
||||
y="690"
|
||||
width="520"
|
||||
height="160"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect43" />
|
||||
<text
|
||||
x="635"
|
||||
y="720"
|
||||
class="h2"
|
||||
id="text44"
|
||||
style="font-style:normal;font-variant:normal;font-weight:700;font-stretch:normal;font-size:16px;line-height:normal;font-family:sans-serif">Gitea (forge web + API)</text>
|
||||
<text
|
||||
x="635"
|
||||
y="745"
|
||||
class="txt"
|
||||
id="text45"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• repo = centre de vérité</text>
|
||||
<text
|
||||
x="635"
|
||||
y="768"
|
||||
class="txt"
|
||||
id="text46"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• issues = backlog</text>
|
||||
<text
|
||||
x="635"
|
||||
y="791"
|
||||
class="txt"
|
||||
id="text47"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif">• labels = tri natif (type/state/cat)</text>
|
||||
<text
|
||||
x="635"
|
||||
y="814"
|
||||
class="small"
|
||||
id="text48"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif">Note : parfois laissé sans forward-auth (runner/accès API) selon réglage</text>
|
||||
<!-- Runner -->
|
||||
<rect
|
||||
x="1160"
|
||||
y="690"
|
||||
width="375"
|
||||
height="170"
|
||||
rx="12"
|
||||
class="box"
|
||||
id="rect48" />
|
||||
<text
|
||||
x="1185"
|
||||
y="720"
|
||||
class="h2"
|
||||
id="text49">Gitea Actions Runner (act_runner)</text>
|
||||
<text
|
||||
x="1185"
|
||||
y="745"
|
||||
class="txt"
|
||||
id="text50">• exécute les workflows</text>
|
||||
<text
|
||||
x="1185"
|
||||
y="768"
|
||||
class="txt"
|
||||
id="text51">• doit monter /var/run/docker.sock</text>
|
||||
<text
|
||||
x="1185"
|
||||
y="791"
|
||||
class="txt"
|
||||
id="text52">• jobs en conteneur (ex : python:3.12-slim)</text>
|
||||
<text
|
||||
x="1185"
|
||||
y="814"
|
||||
class="small"
|
||||
id="text53"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan78"
|
||||
x="1185"
|
||||
y="814">• applique labels via API avec PAT (FORGE_TOKEN)</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan79"
|
||||
x="1185"
|
||||
y="829">— sinon 401</tspan></text>
|
||||
<!-- Connections -->
|
||||
<!-- User -> DSM -->
|
||||
<path
|
||||
d="M 890 220 L 920 220"
|
||||
class="line"
|
||||
id="path53" />
|
||||
<!-- DSM -> Traefik -->
|
||||
<path
|
||||
d="M 1225 265 L 1225 295"
|
||||
class="line"
|
||||
id="path54" />
|
||||
<!-- Traefik -> Web (one active) -->
|
||||
<path
|
||||
d="M 1100 405 L 1070 435"
|
||||
class="dash"
|
||||
id="path55" />
|
||||
<path
|
||||
d="M 1355 405 L 1385 435"
|
||||
class="dash"
|
||||
id="path56" />
|
||||
<!-- Traefik -> Auth -->
|
||||
<path
|
||||
d="M 920 350 L 890 350"
|
||||
class="line"
|
||||
id="path57" />
|
||||
<!-- DSM -> Gitea (via router / host rules) -->
|
||||
<path
|
||||
d="M 917.44325,255.3177 883.05597,688.03328"
|
||||
class="dash"
|
||||
id="path58"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<!-- Gitea -> Runner -->
|
||||
<path
|
||||
d="M 1135 710 L 1160 750"
|
||||
class="line"
|
||||
id="path59" />
|
||||
<!-- Runner -> Gitea API -->
|
||||
<path
|
||||
d="M 1160 805 L 1135 740"
|
||||
class="dash"
|
||||
id="path60" />
|
||||
<!-- Local -> NAS incoming -->
|
||||
<path
|
||||
d="M 530 448 L 615 448"
|
||||
class="line"
|
||||
id="path61" />
|
||||
<!-- Legend -->
|
||||
<rect
|
||||
x="60"
|
||||
y="670"
|
||||
width="470"
|
||||
height="245"
|
||||
rx="12"
|
||||
class="note"
|
||||
id="rect61" />
|
||||
<text
|
||||
x="80"
|
||||
y="700"
|
||||
class="h2"
|
||||
id="text61">Légende / invariants (ce qui casse “pour de vrai”)</text>
|
||||
<text
|
||||
x="80"
|
||||
y="725"
|
||||
class="txt"
|
||||
id="text62"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan70"
|
||||
x="80"
|
||||
y="725">• Prod safe : on ne touche jamais au slot LIVE ;</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan71"
|
||||
x="80"
|
||||
y="741.25">build/test sur l’autre ; switch Traefik ; DSM ne change pas.</tspan></text>
|
||||
<text
|
||||
x="80"
|
||||
y="768"
|
||||
class="txt"
|
||||
id="text63"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan76"
|
||||
x="80"
|
||||
y="768">• Runner : sans docker.sock → aucun job ;</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan77"
|
||||
x="80"
|
||||
y="784.40051">sans FORGE_TOKEN → 401 (labels).</tspan></text>
|
||||
<text
|
||||
x="80"
|
||||
y="811"
|
||||
class="txt"
|
||||
id="text64"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan74"
|
||||
x="80"
|
||||
y="811">• Edge : Traefik :18080 derrière DSM ; sanitize-remote</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan75"
|
||||
x="80"
|
||||
y="827.25">+ forward-auth Authelia.</tspan></text>
|
||||
<text
|
||||
x="80"
|
||||
y="854"
|
||||
class="txt"
|
||||
id="text65"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1"
|
||||
x="80"
|
||||
y="854">• Blue/green : 8081/8082 ; Traefik décide le LIVE</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2"
|
||||
x="80"
|
||||
y="870.25">(DSM pointe toujours sur :18080).</tspan></text>
|
||||
<text
|
||||
x="80"
|
||||
y="891"
|
||||
class="small"
|
||||
id="text66"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:normal;font-family:sans-serif"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan72"
|
||||
x="80"
|
||||
y="891">Astuce : exporte en PNG/PDF pour lecture “grand public”,</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan73"
|
||||
x="80"
|
||||
y="906">garde SVG comme source éditable.</tspan></text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 15 KiB |
67
docs/gitea-pr-main-protege.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Workflow Git/Gitea — main protégé (PR only)
|
||||
|
||||
## Objectif
|
||||
Éviter toute casse de `main` : on travaille **toujours** via branche + Pull Request.
|
||||
|
||||
## 1) Démarrer propre (local)
|
||||
en bash :
|
||||
|
||||
git fetch origin --prune
|
||||
git checkout main
|
||||
git reset --hard origin/main
|
||||
git clean -fd
|
||||
|
||||
## 2) Créer une branche
|
||||
|
||||
git checkout -b fix/ma-modif
|
||||
|
||||
## 3) Modifier, tester, commit
|
||||
|
||||
npm test
|
||||
git add -A
|
||||
git commit -m "Mon changement"
|
||||
|
||||
## 4) Push (création branche distante)
|
||||
|
||||
git push -u origin fix/ma-modif
|
||||
|
||||
## 5) Créer la Pull Request (UI Gitea)
|
||||
|
||||
Gitea → repository → Pull Requests → New Pull Request
|
||||
|
||||
base : main
|
||||
compare : fix/ma-modif
|
||||
|
||||
Si “je ne vois pas de PR”
|
||||
|
||||
Vérifie d’abord qu’il y a un diff réel :
|
||||
|
||||
git log --oneline origin/main..HEAD
|
||||
|
||||
Si la commande ne sort rien : ta branche ne contient aucun commit différent → PR inutile/invisible.
|
||||
|
||||
## 6) Conflits
|
||||
|
||||
Ne merge pas en local vers main (push refusé si main protégé).
|
||||
On met à jour la branche de PR :
|
||||
|
||||
Option A (simple) : merge main dans la branche
|
||||
|
||||
git fetch origin
|
||||
git merge origin/main
|
||||
# résoudre conflits
|
||||
npm test
|
||||
git push
|
||||
|
||||
Option B (plus propre) : rebase
|
||||
|
||||
git fetch origin
|
||||
git rebase origin/main
|
||||
# résoudre conflits, puis:
|
||||
npm test
|
||||
git push --force-with-lease
|
||||
|
||||
## 7) Merge
|
||||
|
||||
Toujours depuis l’UI de la Pull Request (ou via un mainteneur).
|
||||
|
||||
69
docs/proposer-whoami-gate.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# “Proposer” protégé par groupe (whoami / editors)
|
||||
|
||||
## But
|
||||
Le bouton **Proposer** (création d’issue Gitea pré-remplie) doit être :
|
||||
- visible **uniquement** pour les membres du groupe `editors`,
|
||||
- **absent** pour les autres utilisateurs,
|
||||
- robuste (fail-closed), mais **non-collant** (pas de “bloqué” après un échec transitoire).
|
||||
|
||||
## Pré-requis (build-time)
|
||||
Les variables publiques Astro doivent être injectées au build :
|
||||
- `PUBLIC_GITEA_BASE`
|
||||
- `PUBLIC_GITEA_OWNER`
|
||||
- `PUBLIC_GITEA_REPO`
|
||||
|
||||
Si une seule manque → `giteaReady=false` → Proposer est désactivé.
|
||||
|
||||
### Vérification NAS (slots blue/green)
|
||||
Exemple :
|
||||
- blue : http://127.0.0.1:8081/...
|
||||
- green : http://127.0.0.1:8082/...
|
||||
|
||||
Commande (ex) :
|
||||
`curl -sS http://127.0.0.1:8081/archicratie/archicrat-ia/chapitre-4/ | grep -n "const GITEA_" | head`
|
||||
|
||||
## Signal d’auth (runtime) : `/_auth/whoami`
|
||||
Le site appelle `/_auth/whoami` (same-origin) pour récupérer :
|
||||
- `Remote-User`
|
||||
- `Remote-Groups`
|
||||
Ces headers sont injectés par la chaîne edge (Traefik → Authelia forward-auth).
|
||||
|
||||
### Appel robuste
|
||||
- cache-bust : `?_=${Date.now()}`
|
||||
- `cache: "no-store"`
|
||||
- `credentials: "include"`
|
||||
|
||||
### Critère
|
||||
`groups.includes("editors")`
|
||||
|
||||
## Comportement attendu (UX)
|
||||
- utilisateur editors : le bouton “Proposer” est visible, ouvre la modal, puis ouvre Gitea.
|
||||
- utilisateur non editors : le bouton “Proposer” n’existe pas (retiré du DOM).
|
||||
|
||||
## Pièges connus
|
||||
1) Tester en direct 8081/8082 ne reflète pas toujours la chaîne Traefik+Authelia.
|
||||
2) Un gate “collant” peut rester OFF si l’échec est mis en cache trop agressivement.
|
||||
3) Si “Proposer” est caché via `style.display="none"`, il faut le réafficher via `style.display=""` (pas via `hidden=false`).
|
||||
|
||||
## Debug rapide (console navigateur)
|
||||
en js :
|
||||
|
||||
(async () => {
|
||||
const r = await fetch("/_auth/whoami?_=" + Date.now(), {
|
||||
credentials: "include",
|
||||
cache: "no-store",
|
||||
redirect: "follow",
|
||||
});
|
||||
const t = await r.text();
|
||||
const groups = (t.match(/^Remote-Groups:\s*(.*)$/mi)?.[1] || "")
|
||||
.split(",").map(s => s.trim()).filter(Boolean);
|
||||
console.log({ ok: r.ok, status: r.status, groups, raw: t.slice(0, 220) + "..." });
|
||||
})();
|
||||
|
||||
## Définition “done”
|
||||
|
||||
Archicratia (editors) voit Proposer et peut ouvrir un ticket.
|
||||
|
||||
s-FunX (non editors) ne voit pas Proposer.
|
||||
|
||||
Les deux slots blue/green injectent les constantes Gitea dans le HTML.
|
||||
82
docs/runbook-deploiement-web-blue-green.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Runbook — Déploiement Archicratie Web Édition (Blue/Green)
|
||||
|
||||
## Arborescence NAS (repère)
|
||||
- `/volume2/docker/archicratie-web/current/` : état courant (Dockerfile, docker-compose.yml, dist buildé en image)
|
||||
- `/volume2/docker/archicratie-web/releases/` : historiques éventuels
|
||||
- `/volume2/docker/edge/` : Traefik + config dynamique
|
||||
|
||||
> Important : les commandes `docker compose -f ...` doivent viser le **docker-compose.yml présent dans `current/`**.
|
||||
|
||||
---
|
||||
|
||||
## Pré-requis Synology
|
||||
Sur NAS, les commandes ont été exécutées avec :
|
||||
en bash
|
||||
sudo env DOCKER_API_VERSION=1.43 docker ...
|
||||
|
||||
(contexte DSM / compat API)
|
||||
|
||||
### 1) Variables de build (Gitea)
|
||||
|
||||
Dans /volume2/docker/archicratie-web/current créer/maintenir :
|
||||
|
||||
cat > .env <<'EOF'
|
||||
PUBLIC_GITEA_BASE=https://gitea.archicratie.trans-hands.synology.me
|
||||
PUBLIC_GITEA_OWNER=Archicratia
|
||||
PUBLIC_GITEA_REPO=archicratie-edition
|
||||
EOF
|
||||
|
||||
### 2) Build images (blue + green) — méthode robuste
|
||||
|
||||
cd /volume2/docker/archicratie-web/current
|
||||
|
||||
sudo env DOCKER_API_VERSION=1.43 docker compose -f docker-compose.yml build --no-cache web_blue web_green
|
||||
|
||||
Puis recréer les conteneurs sans rebuild :
|
||||
|
||||
sudo env DOCKER_API_VERSION=1.43 docker compose -f docker-compose.yml up -d --force-recreate --no-build web_blue web_green
|
||||
|
||||
### 3) Vérifier que les deux slots sont OK
|
||||
|
||||
curl -sS -D- http://127.0.0.1:8081/ | head -n 12
|
||||
curl -sS -D- http://127.0.0.1:8082/ | head -n 12
|
||||
|
||||
Attendu :
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
|
||||
Server: nginx/...
|
||||
|
||||
### 4) Traefik : s’assurer qu’un seul backend est actif
|
||||
|
||||
Fichier :
|
||||
/volume2/docker/edge/config/dynamic/20-archicratie-backend.yml
|
||||
|
||||
Attendu : une seule URL (8081 OU 8082)
|
||||
|
||||
http:
|
||||
services:
|
||||
archicratie_web:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://127.0.0.1:8081"
|
||||
|
||||
### 5) Smoke via Traefik (entrée réelle)
|
||||
|
||||
curl -sS -H 'Host: archicratie.trans-hands.synology.me' http://127.0.0.1:18080/ | head -n 20
|
||||
|
||||
Attendu :
|
||||
|
||||
si non loggé : 302 vers Authelia
|
||||
|
||||
si loggé : HTML du site
|
||||
|
||||
### 6) Piège classique : conflit de nom de conteneur
|
||||
|
||||
Si :
|
||||
Conflict. The container name "/archicratie-web-blue" is already in use...
|
||||
|
||||
Faire :
|
||||
|
||||
sudo docker rm -f archicratie-web-blue
|
||||
sudo env DOCKER_API_VERSION=1.43 docker compose -f docker-compose.yml up -d --force-recreate --no-build web_blue
|
||||
71
docs/runbook-gitea-branches-pr.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Runbook — Gitea : Branches, PR, Merge (sans se faire piéger)
|
||||
|
||||
## Règle n°1 (hyper importante)
|
||||
Une PR n’apparaît dans Gitea que si la branche contient **au moins 1 commit différent de `main`**.
|
||||
|
||||
Symptôme typique :
|
||||
- `git push -u origin fix/xxx`
|
||||
- et tu vois : `Total 0 ...`
|
||||
→ ça veut dire : **aucun nouveau commit** → la branche est identique à main → pas de vraie PR à proposer.
|
||||
|
||||
---
|
||||
|
||||
## Workflow “propre” (pas à pas)
|
||||
### 1) Remettre `main` propre
|
||||
en bash
|
||||
|
||||
git checkout main
|
||||
git pull --ff-only
|
||||
|
||||
### 2) Créer une branche de travail
|
||||
|
||||
git checkout -b fix/mon-fix
|
||||
|
||||
### 3) Faire un changement réel
|
||||
|
||||
Modifier le fichier (ex : src/layouts/EditionLayout.astro)
|
||||
|
||||
Vérifier :
|
||||
|
||||
git status -sb
|
||||
|
||||
→ doit montrer un fichier modifié.
|
||||
|
||||
### 4) Tester
|
||||
|
||||
npm test
|
||||
|
||||
### 5) Commit
|
||||
|
||||
git add src/layouts/EditionLayout.astro
|
||||
git commit -m "Fix: ..."
|
||||
|
||||
### 6) Push
|
||||
|
||||
git push -u origin fix/mon-fix
|
||||
|
||||
### 7) Créer la PR dans l’UI Gitea
|
||||
|
||||
# Aller dans Pull Requests
|
||||
|
||||
# New Pull Request
|
||||
|
||||
Base : main
|
||||
|
||||
Compare : fix/mon-fix
|
||||
|
||||
Branch protection (si “Not allowed to push to protected branch main”)
|
||||
|
||||
# C’est normal si main est protégé :
|
||||
|
||||
On ne pousse jamais directement sur main.
|
||||
|
||||
On merge via PR (UI), avec un compte autorisé.
|
||||
|
||||
Si Gitea refuse de merger automatiquement :
|
||||
|
||||
soit tu actives le réglage côté Gitea “manual merge detection” (admin),
|
||||
|
||||
soit tu fais le merge localement MAIS tu ne pourras pas pousser sur main si la protection l’interdit.
|
||||
|
||||
Conclusion : la voie “pro” = PR + merge UI.
|
||||
67
docs/runbook-proposer-gitea.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Runbook — Bouton “Proposer” (site → Gitea issue) + Gate Authelia
|
||||
|
||||
## Objectif
|
||||
Permettre une proposition de correction éditoriale depuis un paragraphe du site, en créant une *issue* Gitea pré-remplie, uniquement pour les membres du groupe `editors`.
|
||||
|
||||
---
|
||||
|
||||
## Pré-requis
|
||||
- Traefik (edge) en front
|
||||
- Authelia (forwardAuth) opérationnel
|
||||
- Router `/_auth/whoami` exposé (whoami)
|
||||
- Variables `PUBLIC_GITEA_*` injectées au build du site
|
||||
|
||||
---
|
||||
|
||||
## Vérification rapide (navigateur)
|
||||
### 1) Qui suis-je ? (groupes)
|
||||
Dans la console :
|
||||
en js :
|
||||
await fetch("/_auth/whoami?_=" + Date.now(), {
|
||||
credentials: "include",
|
||||
cache: "no-store",
|
||||
}).then(r => r.text());
|
||||
|
||||
Attendu (extraits) :
|
||||
|
||||
Remote-User: <login>
|
||||
|
||||
Remote-Groups: ...,editors,... pour un éditeur
|
||||
|
||||
### 2) Le bouton existe ?
|
||||
document.querySelectorAll(".para-propose").length
|
||||
|
||||
> 0 si editors
|
||||
|
||||
0 si non-editor
|
||||
|
||||
## Vérification côté NAS (build vars)
|
||||
### 1) Blue et Green contiennent les constantes ?
|
||||
|
||||
P="/archicratie/archicrat-ia/chapitre-4/"
|
||||
|
||||
curl -sS "http://127.0.0.1:8081$P" | grep -n "const GITEA_BASE" | head -n 2
|
||||
curl -sS "http://127.0.0.1:8082$P" | grep -n "const GITEA_BASE" | head -n 2
|
||||
|
||||
### 2) Si une des deux est vide → rebuild propre
|
||||
|
||||
Dans /volume2/docker/archicratie-web/current :
|
||||
|
||||
cat > .env <<'EOF'
|
||||
PUBLIC_GITEA_BASE=https://gitea.archicratie.trans-hands.synology.me
|
||||
PUBLIC_GITEA_OWNER=Archicratia
|
||||
PUBLIC_GITEA_REPO=archicratie-edition
|
||||
EOF
|
||||
|
||||
sudo env DOCKER_API_VERSION=1.43 docker compose -f docker-compose.yml build --no-cache web_blue web_green
|
||||
sudo env DOCKER_API_VERSION=1.43 docker compose -f docker-compose.yml up -d --force-recreate --no-build web_blue web_green
|
||||
|
||||
## Dépannage (si Proposer “disparaît”)
|
||||
|
||||
Vérifier groupes via /_auth/whoami
|
||||
|
||||
Vérifier const GITEA_BASE via curl sur le slot actif
|
||||
|
||||
Vérifier que Traefik sert bien le slot actif (grep via curl -H Host: ... http://127.0.0.1:18080/...)
|
||||
|
||||
Ouvrir la console : vérifier qu’aucune erreur JS n’empêche l’injection des outils paragraphe
|
||||
@@ -12,7 +12,7 @@
|
||||
"build": "astro build",
|
||||
"build:clean": "npm run clean && npm run build",
|
||||
|
||||
"postbuild": "node scripts/inject-anchor-aliases.mjs && npx pagefind --site dist",
|
||||
"postbuild": "node scripts/inject-anchor-aliases.mjs && node scripts/dedupe-ids-dist.mjs && npx pagefind --site dist",
|
||||
|
||||
"import": "node scripts/import-docx.mjs",
|
||||
"apply:ticket": "node scripts/apply-ticket.mjs",
|
||||
|
||||
148
scripts/build-para-index.mjs
Normal file
@@ -0,0 +1,148 @@
|
||||
// scripts/build-para-index.mjs
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
function parseArgs(argv) {
|
||||
const out = { inDir: "dist", outFile: "dist/para-index.json" };
|
||||
|
||||
for (let i = 0; i < argv.length; i++) {
|
||||
const a = argv[i];
|
||||
|
||||
if (a === "--in" && argv[i + 1]) {
|
||||
out.inDir = argv[++i];
|
||||
continue;
|
||||
}
|
||||
if (a.startsWith("--in=")) {
|
||||
out.inDir = a.slice("--in=".length);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (a === "--out" && argv[i + 1]) {
|
||||
out.outFile = argv[++i];
|
||||
continue;
|
||||
}
|
||||
if (a.startsWith("--out=")) {
|
||||
out.outFile = a.slice("--out=".length);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
async function exists(p) {
|
||||
try {
|
||||
await fs.access(p);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function walk(dir) {
|
||||
const out = [];
|
||||
const ents = await fs.readdir(dir, { withFileTypes: true });
|
||||
for (const e of ents) {
|
||||
const p = path.join(dir, e.name);
|
||||
if (e.isDirectory()) out.push(...(await walk(p)));
|
||||
else out.push(p);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function stripTags(html) {
|
||||
return String(html || "")
|
||||
.replace(/<script\b[\s\S]*?<\/script>/gi, " ")
|
||||
.replace(/<style\b[\s\S]*?<\/style>/gi, " ")
|
||||
.replace(/<[^>]+>/g, " ");
|
||||
}
|
||||
|
||||
function decodeEntities(s) {
|
||||
// minimal, volontairement (évite dépendances)
|
||||
return String(s || "")
|
||||
.replace(/ /g, " ")
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
|
||||
function normalizeSpaces(s) {
|
||||
return decodeEntities(s).replace(/\s+/g, " ").trim();
|
||||
}
|
||||
|
||||
function relPageFromIndexHtml(inDirAbs, fileAbs) {
|
||||
const rel = path.relative(inDirAbs, fileAbs).replace(/\\/g, "/");
|
||||
if (!/index\.html$/i.test(rel)) return null;
|
||||
|
||||
// dist/<page>/index.html -> "/<page>/"
|
||||
const page = "/" + rel.replace(/index\.html$/i, "");
|
||||
return page;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const { inDir, outFile } = parseArgs(process.argv.slice(2));
|
||||
const CWD = process.cwd();
|
||||
|
||||
const inDirAbs = path.isAbsolute(inDir) ? inDir : path.join(CWD, inDir);
|
||||
const outAbs = path.isAbsolute(outFile) ? outFile : path.join(CWD, outFile);
|
||||
|
||||
// ✅ antifragile: si dist/ (ou inDir) absent -> on SKIP proprement
|
||||
if (!(await exists(inDirAbs))) {
|
||||
console.log(`ℹ️ para-index: skip (input missing): ${inDir}`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const files = (await walk(inDirAbs)).filter((p) => /index\.html$/i.test(p));
|
||||
|
||||
if (!files.length) {
|
||||
console.log(`ℹ️ para-index: skip (no index.html found in): ${inDir}`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const items = [];
|
||||
const byId = Object.create(null);
|
||||
|
||||
// <p ... id="p-...">...</p>
|
||||
// (regex volontairement stricte sur l'id pour éviter faux positifs)
|
||||
const reP = /<p\b([^>]*\bid\s*=\s*["'](p-\d+-[^"']+)["'][^>]*)>([\s\S]*?)<\/p>/gi;
|
||||
|
||||
for (const f of files) {
|
||||
const page = relPageFromIndexHtml(inDirAbs, f);
|
||||
if (!page) continue;
|
||||
|
||||
const html = await fs.readFile(f, "utf8");
|
||||
|
||||
let m;
|
||||
while ((m = reP.exec(html))) {
|
||||
const id = m[2];
|
||||
const inner = m[3];
|
||||
|
||||
if (byId[id] != null) continue; // protège si jamais doublons
|
||||
|
||||
const text = normalizeSpaces(stripTags(inner));
|
||||
if (!text) continue;
|
||||
|
||||
byId[id] = items.length;
|
||||
items.push({ id, page, text });
|
||||
}
|
||||
}
|
||||
|
||||
const out = {
|
||||
schema: 1,
|
||||
generatedAt: new Date().toISOString(),
|
||||
items,
|
||||
byId,
|
||||
};
|
||||
|
||||
await fs.mkdir(path.dirname(outAbs), { recursive: true });
|
||||
await fs.writeFile(outAbs, JSON.stringify(out), "utf8");
|
||||
|
||||
console.log(`✅ para-index: items=${items.length} -> ${path.relative(CWD, outAbs)}`);
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error("FAIL: build-para-index crashed:", e);
|
||||
process.exit(1);
|
||||
});
|
||||
173
scripts/check-annotations.mjs
Normal file
@@ -0,0 +1,173 @@
|
||||
// scripts/check-annotations.mjs
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import YAML from "yaml";
|
||||
|
||||
const CWD = process.cwd();
|
||||
const ANNO_DIR = path.join(CWD, "src", "annotations");
|
||||
const DIST_DIR = path.join(CWD, "dist");
|
||||
const ALIASES_PATH = path.join(CWD, "src", "anchors", "anchor-aliases.json");
|
||||
|
||||
async function exists(p) {
|
||||
try { await fs.access(p); return true; } catch { return false; }
|
||||
}
|
||||
|
||||
async function walk(dir) {
|
||||
const out = [];
|
||||
const ents = await fs.readdir(dir, { withFileTypes: true });
|
||||
for (const e of ents) {
|
||||
const p = path.join(dir, e.name);
|
||||
if (e.isDirectory()) out.push(...(await walk(p)));
|
||||
else out.push(p);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function escRe(s) {
|
||||
return String(s).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
}
|
||||
|
||||
function inferPageKeyFromFile(fileAbs) {
|
||||
const rel = path.relative(ANNO_DIR, fileAbs).replace(/\\/g, "/");
|
||||
return rel.replace(/\.(ya?ml|json)$/i, "");
|
||||
}
|
||||
|
||||
function normalizePageKey(s) {
|
||||
return String(s || "").replace(/^\/+/, "").replace(/\/+$/, "");
|
||||
}
|
||||
|
||||
function isPlainObject(x) {
|
||||
return !!x && typeof x === "object" && !Array.isArray(x);
|
||||
}
|
||||
|
||||
async function loadAliases() {
|
||||
if (!(await exists(ALIASES_PATH))) return {};
|
||||
try {
|
||||
const raw = await fs.readFile(ALIASES_PATH, "utf8");
|
||||
const json = JSON.parse(raw);
|
||||
return isPlainObject(json) ? json : {};
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function parseDoc(raw, fileAbs) {
|
||||
if (/\.json$/i.test(fileAbs)) return JSON.parse(raw);
|
||||
return YAML.parse(raw);
|
||||
}
|
||||
|
||||
function getAlias(aliases, pageKey, oldId) {
|
||||
// supporte:
|
||||
// 1) { "<pageKey>": { "<old>": "<new>" } }
|
||||
// 2) { "<old>": "<new>" }
|
||||
const a1 = aliases?.[pageKey]?.[oldId];
|
||||
if (a1) return a1;
|
||||
const a2 = aliases?.[oldId];
|
||||
if (a2) return a2;
|
||||
return "";
|
||||
}
|
||||
|
||||
async function main() {
|
||||
if (!(await exists(ANNO_DIR))) {
|
||||
console.log("✅ annotations: aucun dossier src/annotations — rien à vérifier.");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!(await exists(DIST_DIR))) {
|
||||
console.error("FAIL: dist/ absent. Lance d’abord `npm run build` (ou `npm test`).");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const aliases = await loadAliases();
|
||||
const files = (await walk(ANNO_DIR)).filter((p) => /\.(ya?ml|json)$/i.test(p));
|
||||
|
||||
let pages = 0;
|
||||
let checked = 0;
|
||||
let failures = 0;
|
||||
const notes = [];
|
||||
|
||||
for (const f of files) {
|
||||
const rel = path.relative(CWD, f).replace(/\\/g, "/");
|
||||
const raw = await fs.readFile(f, "utf8");
|
||||
|
||||
let doc;
|
||||
try {
|
||||
doc = parseDoc(raw, f);
|
||||
} catch (e) {
|
||||
failures++;
|
||||
notes.push(`- PARSE FAIL: ${rel} (${String(e?.message ?? e)})`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isPlainObject(doc) || doc.schema !== 1) {
|
||||
failures++;
|
||||
notes.push(`- INVALID: ${rel} (schema must be 1)`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const pageKey = normalizePageKey(inferPageKeyFromFile(f));
|
||||
|
||||
if (doc.page != null && normalizePageKey(doc.page) !== pageKey) {
|
||||
failures++;
|
||||
notes.push(`- PAGE MISMATCH: ${rel} (page="${doc.page}" != path="${pageKey}")`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isPlainObject(doc.paras)) {
|
||||
failures++;
|
||||
notes.push(`- INVALID: ${rel} (missing object key "paras")`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const distFile = path.join(DIST_DIR, pageKey, "index.html");
|
||||
if (!(await exists(distFile))) {
|
||||
failures++;
|
||||
notes.push(`- MISSING PAGE: dist/${pageKey}/index.html (from ${rel})`);
|
||||
continue;
|
||||
}
|
||||
|
||||
pages++;
|
||||
const html = await fs.readFile(distFile, "utf8");
|
||||
|
||||
for (const paraId of Object.keys(doc.paras)) {
|
||||
checked++;
|
||||
|
||||
if (!/^p-\d+-/i.test(paraId)) {
|
||||
failures++;
|
||||
notes.push(`- INVALID ID: ${rel} (${paraId})`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const re = new RegExp(`\\bid=["']${escRe(paraId)}["']`, "g");
|
||||
if (re.test(html)) continue;
|
||||
|
||||
const alias = getAlias(aliases, pageKey, paraId);
|
||||
if (alias) {
|
||||
const re2 = new RegExp(`\\bid=["']${escRe(alias)}["']`, "g");
|
||||
if (re2.test(html)) {
|
||||
notes.push(`- WARN alias used: ${pageKey} ${paraId} -> ${alias}`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
failures++;
|
||||
notes.push(`- MISSING ID: ${pageKey} (#${paraId})`);
|
||||
}
|
||||
}
|
||||
|
||||
const warns = notes.filter((x) => x.startsWith("- WARN"));
|
||||
|
||||
if (failures > 0) {
|
||||
console.error(`FAIL: annotations invalid (pages=${pages} checked=${checked} failures=${failures})`);
|
||||
for (const n of notes) console.error(n);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
for (const w of warns) console.log(w);
|
||||
console.log(`✅ annotations OK: pages=${pages} checked=${checked} warnings=${warns.length}`);
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error("FAIL: annotations check crashed:", e);
|
||||
process.exit(1);
|
||||
});
|
||||
134
scripts/dedupe-ids-dist.mjs
Normal file
@@ -0,0 +1,134 @@
|
||||
import { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
const DIST_DIR = path.resolve("dist");
|
||||
|
||||
/** @param {string} dir */
|
||||
async function walkHtml(dir) {
|
||||
/** @type {string[]} */
|
||||
const out = [];
|
||||
const entries = await fs.readdir(dir, { withFileTypes: true });
|
||||
for (const e of entries) {
|
||||
const p = path.join(dir, e.name);
|
||||
if (e.isDirectory()) out.push(...(await walkHtml(p)));
|
||||
else if (e.isFile() && p.endsWith(".html")) out.push(p);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** @param {string} attrs */
|
||||
function getClass(attrs) {
|
||||
const m = attrs.match(/\bclass="([^"]*)"/i);
|
||||
return m ? m[1] : "";
|
||||
}
|
||||
|
||||
/** @param {{tag:string,id:string,cls:string}} occ */
|
||||
function score(occ) {
|
||||
// plus petit = mieux (on garde)
|
||||
if (occ.tag === "span" && /\bdetails-anchor\b/.test(occ.cls)) return 0;
|
||||
if (/^h[1-6]$/.test(occ.tag)) return 1;
|
||||
if (occ.tag === "p" && occ.id.startsWith("p-")) return 2;
|
||||
return 10; // tout le reste (toc, nav, etc.)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
let changedFiles = 0;
|
||||
let removed = 0;
|
||||
|
||||
const files = await walkHtml(DIST_DIR);
|
||||
|
||||
for (const file of files) {
|
||||
let html = await fs.readFile(file, "utf8");
|
||||
|
||||
// capture: <tag ... id="X" ...>
|
||||
const re = /<([A-Za-z][\w:-]*)([^>]*?)\s+id="([^"]+)"([^>]*?)>/g;
|
||||
|
||||
/** @type {Array<{id:string,tag:string,pre:string,post:string,start:number,end:number,cls:string,idx:number}>} */
|
||||
const occs = [];
|
||||
let m;
|
||||
let idx = 0;
|
||||
|
||||
while ((m = re.exec(html)) !== null) {
|
||||
const tag = m[1].toLowerCase();
|
||||
const pre = m[2] || "";
|
||||
const id = m[3] || "";
|
||||
const post = m[4] || "";
|
||||
const fullAttrs = `${pre}${post}`;
|
||||
const cls = getClass(fullAttrs);
|
||||
|
||||
occs.push({
|
||||
id,
|
||||
tag,
|
||||
pre,
|
||||
post,
|
||||
start: m.index,
|
||||
end: m.index + m[0].length,
|
||||
cls,
|
||||
idx: idx++,
|
||||
});
|
||||
}
|
||||
|
||||
if (occs.length === 0) continue;
|
||||
|
||||
/** @type {Map<string, Array<typeof occs[number]>>} */
|
||||
const byId = new Map();
|
||||
for (const o of occs) {
|
||||
if (!o.id) continue;
|
||||
const arr = byId.get(o.id) || [];
|
||||
arr.push(o);
|
||||
byId.set(o.id, arr);
|
||||
}
|
||||
|
||||
/** @type {Array<{start:number,end:number,repl:string}>} */
|
||||
const edits = [];
|
||||
|
||||
for (const [id, arr] of byId.entries()) {
|
||||
if (arr.length <= 1) continue;
|
||||
|
||||
// choisir le “meilleur” porteur d’id : details-anchor > h2/h3... > p-... > reste
|
||||
const sorted = [...arr].sort((a, b) => {
|
||||
const sa = score(a);
|
||||
const sb = score(b);
|
||||
if (sa !== sb) return sa - sb;
|
||||
return a.idx - b.idx; // stable: premier
|
||||
});
|
||||
|
||||
const keep = sorted[0];
|
||||
|
||||
for (const o of sorted.slice(1)) {
|
||||
// remplacer l’ouverture de tag en supprimant l’attribut id
|
||||
// <tag{pre} id="X"{post}> ==> <tag{pre}{post}>
|
||||
const repl = `<${o.tag}${o.pre}${o.post}>`;
|
||||
edits.push({ start: o.start, end: o.end, repl });
|
||||
removed++;
|
||||
}
|
||||
|
||||
// sécurité: on “force” l'id sur le keep (au cas où il aurait été modifié plus haut)
|
||||
// (on ne touche pas au keep ici, juste on ne le retire pas)
|
||||
void keep;
|
||||
void id;
|
||||
}
|
||||
|
||||
if (edits.length === 0) continue;
|
||||
|
||||
// appliquer de la fin vers le début
|
||||
edits.sort((a, b) => b.start - a.start);
|
||||
for (const e of edits) {
|
||||
html = html.slice(0, e.start) + e.repl + html.slice(e.end);
|
||||
}
|
||||
|
||||
await fs.writeFile(file, html, "utf8");
|
||||
changedFiles++;
|
||||
}
|
||||
|
||||
if (changedFiles > 0) {
|
||||
console.log(`✅ dedupe-ids-dist: files_changed=${changedFiles} ids_removed=${removed}`);
|
||||
} else {
|
||||
console.log("ℹ️ dedupe-ids-dist: no duplicates found");
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error("❌ dedupe-ids-dist failed:", err);
|
||||
process.exit(1);
|
||||
});
|
||||
101
scripts/seed-gitea-labels.mjs
Normal file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* seed-gitea-labels — crée les labels attendus (idempotent)
|
||||
*
|
||||
* Usage:
|
||||
* FORGE_TOKEN=... FORGE_API=http://192.168.1.20:3000 node scripts/seed-gitea-labels.mjs
|
||||
* (ou FORGE_BASE=https://gitea... si pas de FORGE_API)
|
||||
*
|
||||
* Optionnel:
|
||||
* GITEA_OWNER / GITEA_REPO (sinon auto-détecté via git remote origin)
|
||||
*/
|
||||
|
||||
import { spawnSync } from "node:child_process";
|
||||
|
||||
function getEnv(name, fallback = "") {
|
||||
return (process.env[name] ?? fallback).trim();
|
||||
}
|
||||
|
||||
function inferOwnerRepoFromGit() {
|
||||
const r = spawnSync("git", ["remote", "get-url", "origin"], { encoding: "utf-8" });
|
||||
if (r.status !== 0) return null;
|
||||
const u = (r.stdout || "").trim();
|
||||
const m = u.match(/[:/](?<owner>[^/]+)\/(?<repo>[^/]+?)(?:\.git)?$/);
|
||||
if (!m?.groups) return null;
|
||||
return { owner: m.groups.owner, repo: m.groups.repo };
|
||||
}
|
||||
|
||||
async function apiReq(base, token, method, path, payload = null) {
|
||||
const url = `${base.replace(/\/+$/, "")}/api/v1${path}`;
|
||||
const headers = {
|
||||
Authorization: `token ${token}`,
|
||||
Accept: "application/json",
|
||||
"User-Agent": "archicratie-seed-labels/1.0",
|
||||
};
|
||||
const init = { method, headers };
|
||||
|
||||
if (payload != null) {
|
||||
init.headers["Content-Type"] = "application/json";
|
||||
init.body = JSON.stringify(payload);
|
||||
}
|
||||
|
||||
const res = await fetch(url, init);
|
||||
const text = await res.text().catch(() => "");
|
||||
let json = null;
|
||||
try { json = text ? JSON.parse(text) : null; } catch {}
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status} ${method} ${url}\n${text}`);
|
||||
return json;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const token = getEnv("FORGE_TOKEN");
|
||||
if (!token) throw new Error("FORGE_TOKEN manquant");
|
||||
|
||||
const inferred = inferOwnerRepoFromGit() || {};
|
||||
const owner = getEnv("GITEA_OWNER", inferred.owner || "");
|
||||
const repo = getEnv("GITEA_REPO", inferred.repo || "");
|
||||
if (!owner || !repo) throw new Error("Impossible de déterminer owner/repo (GITEA_OWNER/GITEA_REPO ou git remote)");
|
||||
|
||||
const base = getEnv("FORGE_API") || getEnv("FORGE_BASE");
|
||||
if (!base) throw new Error("FORGE_API ou FORGE_BASE manquant");
|
||||
|
||||
const wanted = [
|
||||
// type/*
|
||||
{ name: "type/comment", color: "1d76db", description: "Commentaire éditorial (site)" },
|
||||
{ name: "type/media", color: "1d76db", description: "Media à intégrer (image/audio/video)" },
|
||||
{ name: "type/correction", color: "1d76db", description: "Correction proposée" },
|
||||
{ name: "type/fact-check", color: "1d76db", description: "Vérification / sourçage" },
|
||||
|
||||
// state/*
|
||||
{ name: "state/a-trier", color: "0e8a16", description: "À trier" },
|
||||
{ name: "state/recevable", color: "0e8a16", description: "Recevable" },
|
||||
{ name: "state/a-sourcer", color: "0e8a16", description: "À sourcer" },
|
||||
|
||||
// scope/*
|
||||
{ name: "scope/readers", color: "5319e7", description: "Signalé par lecteur" },
|
||||
{ name: "scope/editors", color: "5319e7", description: "Signalé par éditeur" },
|
||||
];
|
||||
|
||||
const labels = (await apiReq(base, token, "GET", `/repos/${owner}/${repo}/labels?limit=1000`)) || [];
|
||||
const existing = new Set(labels.map((x) => x?.name).filter(Boolean));
|
||||
|
||||
let created = 0;
|
||||
for (const L of wanted) {
|
||||
if (existing.has(L.name)) continue;
|
||||
await apiReq(base, token, "POST", `/repos/${owner}/${repo}/labels`, {
|
||||
name: L.name,
|
||||
color: L.color,
|
||||
description: L.description,
|
||||
});
|
||||
created++;
|
||||
console.log("✅ created:", L.name);
|
||||
}
|
||||
|
||||
if (created === 0) console.log("ℹ️ seed: nothing to do (all labels already exist)");
|
||||
else console.log(`✅ seed done: created=${created}`);
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error("💥 seed-gitea-labels:", e?.message || e);
|
||||
process.exit(1);
|
||||
});
|
||||
59
src/annotations/archicrat-ia/prologue.yml
Normal file
@@ -0,0 +1,59 @@
|
||||
schema: 1
|
||||
|
||||
# optionnel (si présent, doit matcher le chemin du fichier)
|
||||
page: archicrat-ia/prologue
|
||||
|
||||
paras:
|
||||
p-0-d7974f88:
|
||||
refs:
|
||||
- label: "Happycratie — (Cabanas & Illouz) via Cairn"
|
||||
url: "https://shs.cairn.info/revue-ethnologie-francaise-2019-4-page-813?lang=fr"
|
||||
kind: "article"
|
||||
- label: "Techno-féodalisme — Variations (OpenEdition)"
|
||||
url: "https://journals.openedition.org/variations/2290"
|
||||
kind: "article"
|
||||
|
||||
authors:
|
||||
- "Eva Illouz"
|
||||
- "Yanis Varoufakis"
|
||||
|
||||
quotes:
|
||||
- text: "Dans Happycratie, Edgar Cabanas et Eva Illouz..."
|
||||
source: "Happycratie, p.1"
|
||||
- text: "En eux-mêmes, les actifs ne sont ni féodaux ni capitalistes..."
|
||||
source: "Entretien Morozov/Varoufakis — techno-féodalisme"
|
||||
|
||||
media:
|
||||
- type: "image"
|
||||
src: "/public/media/archicrat-ia/prologue/p-0-d7974f88/schema-1.svg"
|
||||
caption: "Tableau explicatif"
|
||||
credit: "ChatGPT"
|
||||
- type: "image"
|
||||
src: "/public/media/archicrat-ia/prologue/p-0-d7974f88/schema-2.svg"
|
||||
caption: "Diagramme d’évolution"
|
||||
credit: "Yanis Varoufakis"
|
||||
|
||||
comments_editorial:
|
||||
- text: "TODO: nuancer / préciser — commentaire éditorial versionné (pas public)."
|
||||
status: "draft"
|
||||
|
||||
p-1-2ef25f29:
|
||||
refs:
|
||||
- label: "Kafka et le pouvoir — Bernard Lahire (Cairn)"
|
||||
url: "https://shs.cairn.info/franz-kafka--9782707159410-page-475?lang=fr"
|
||||
kind: "book"
|
||||
|
||||
authors:
|
||||
- "Bernard Lahire"
|
||||
|
||||
quotes:
|
||||
- text: "Si l’on voulait chercher quelque chose comme une vision du monde chez Kafka..."
|
||||
source: "Bernard Lahire, Franz Kafka, p.475+"
|
||||
|
||||
media:
|
||||
- type: "video"
|
||||
src: "/public/media/archicrat-ia/prologue/p-1-2ef25f29/bien_commun.mp4"
|
||||
caption: "Entretien avec Bernard Lahire"
|
||||
credit: "Cairn.info"
|
||||
|
||||
comments_editorial: []
|
||||
@@ -7,7 +7,10 @@ const entries = (await getCollection("archicratie"))
|
||||
.filter((e) => e.slug.startsWith("archicrat-ia/"))
|
||||
.sort((a, b) => (a.data.order ?? 0) - (b.data.order ?? 0));
|
||||
|
||||
const href = (slug) => `/archicratie/${slug}/`;
|
||||
// ✅ On route l’Essai-thèse sur /archicrat-ia/<slug-sans-prefix>/
|
||||
// (Astro trailingSlash = always → on garde le "/" final)
|
||||
const strip = (s) => String(s || "").replace(/^archicrat-ia\//, "");
|
||||
const href = (slug) => `/archicrat-ia/${strip(slug)}/`;
|
||||
---
|
||||
|
||||
<nav class="toc-global" aria-label="Table des matières — ArchiCraT-IA">
|
||||
@@ -66,7 +69,6 @@ const href = (slug) => `/archicratie/${slug}/`;
|
||||
opacity: .88;
|
||||
}
|
||||
|
||||
/* On garde <ol> mais on neutralise tout marker/numéro */
|
||||
.toc-global__list{
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
@@ -148,7 +150,6 @@ const href = (slug) => `/archicratie/${slug}/`;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
|
||||
@media (prefers-color-scheme: dark){
|
||||
.toc-global{ background: rgba(255,255,255,0.04); }
|
||||
.toc-link:hover{ background: rgba(255,255,255,0.06); }
|
||||
|
||||
@@ -1,35 +1,128 @@
|
||||
---
|
||||
// src/components/LevelToggle.astro
|
||||
const { initialLevel = 1 } = Astro.props;
|
||||
---
|
||||
<div class="level-toggle" role="group" aria-label="Niveau de lecture">
|
||||
<button type="button" class="lvl-btn" data-level="1" aria-pressed="true">Niveau 1</button>
|
||||
<button type="button" class="lvl-btn" data-level="2" aria-pressed="false">Niveau 2</button>
|
||||
<button type="button" class="lvl-btn" data-level="3" aria-pressed="false">Niveau 3</button>
|
||||
|
||||
<div class="level-toggle" role="group" aria-label="Mode d’édition">
|
||||
<button type="button" class="level-btn" data-level="1">Propos</button>
|
||||
<button type="button" class="level-btn" data-level="2">Références</button>
|
||||
<button type="button" class="level-btn" data-level="3">Illustrations</button>
|
||||
<button type="button" class="level-btn" data-level="4">Commentaires</button>
|
||||
</div>
|
||||
|
||||
<script is:inline>
|
||||
<script is:inline define:vars={{ initialLevel }}>
|
||||
(() => {
|
||||
const KEY = "archicratie.readingLevel";
|
||||
const buttons = Array.from(document.querySelectorAll(".lvl-btn"));
|
||||
const BODY = document.body;
|
||||
|
||||
function apply(level) {
|
||||
document.body.setAttribute("data-reading-level", String(level));
|
||||
buttons.forEach((b) => b.setAttribute("aria-pressed", b.dataset.level === String(level) ? "true" : "false"));
|
||||
const wrap = document.querySelector(".level-toggle");
|
||||
if (!wrap) return;
|
||||
|
||||
const buttons = Array.from(wrap.querySelectorAll("button[data-level]"));
|
||||
if (!buttons.length) return;
|
||||
|
||||
const KEY = "archicratie:readingLevel";
|
||||
|
||||
function clampLevel(n) {
|
||||
const x = Number.parseInt(String(n), 10);
|
||||
if (!Number.isFinite(x)) return 1;
|
||||
return Math.min(4, Math.max(1, x));
|
||||
}
|
||||
|
||||
// Valeur par défaut : si rien n'est stocké, on met 1 (citoyen).
|
||||
// Si JS est absent/casse, le site reste lisible (tout s'affiche).
|
||||
const stored = Number(localStorage.getItem(KEY));
|
||||
const level = (stored === 1 || stored === 2 || stored === 3) ? stored : 1;
|
||||
function setActiveUI(lvl) {
|
||||
for (const b of buttons) {
|
||||
const on = String(b.dataset.level) === String(lvl);
|
||||
b.classList.toggle("is-active", on);
|
||||
b.setAttribute("aria-pressed", on ? "true" : "false");
|
||||
}
|
||||
}
|
||||
|
||||
apply(level);
|
||||
function captureBeforeLevelSwitch() {
|
||||
const paraId =
|
||||
window.__archiCurrentParaId ||
|
||||
window.__archiLastParaId ||
|
||||
String(location.hash || "").replace(/^#/, "") ||
|
||||
"";
|
||||
|
||||
buttons.forEach((b) => {
|
||||
b.addEventListener("click", () => {
|
||||
const lvl = Number(b.dataset.level);
|
||||
localStorage.setItem(KEY, String(lvl));
|
||||
apply(lvl);
|
||||
});
|
||||
window.__archiLevelSwitchCtx = {
|
||||
paraId,
|
||||
hash: location.hash || "",
|
||||
scrollY: window.scrollY || 0,
|
||||
t: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
function applyLevel(lvl, { persist = true } = {}) {
|
||||
const v = clampLevel(lvl);
|
||||
|
||||
if (BODY) BODY.dataset.readingLevel = String(v);
|
||||
setActiveUI(v);
|
||||
|
||||
if (persist) {
|
||||
try { localStorage.setItem(KEY, String(v)); } catch {}
|
||||
}
|
||||
|
||||
try {
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("archicratie:readingLevel", { detail: { level: v } })
|
||||
);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// init : storage > initialLevel
|
||||
let start = clampLevel(initialLevel);
|
||||
try {
|
||||
const stored = localStorage.getItem(KEY);
|
||||
if (stored) start = clampLevel(stored);
|
||||
} catch {}
|
||||
|
||||
applyLevel(start, { persist: false });
|
||||
|
||||
// clicks
|
||||
wrap.addEventListener("click", (ev) => {
|
||||
const btn = ev.target?.closest?.("button[data-level]");
|
||||
if (!btn) return;
|
||||
ev.preventDefault();
|
||||
|
||||
// ✅ crucial : on capture la position AVANT le reflow lié au changement de niveau
|
||||
captureBeforeLevelSwitch();
|
||||
applyLevel(btn.dataset.level);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.level-toggle{
|
||||
display: inline-flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.level-btn{
|
||||
border: 1px solid rgba(127,127,127,0.40);
|
||||
background: rgba(127,127,127,0.08);
|
||||
border-radius: 999px;
|
||||
padding: 6px 10px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: filter .12s ease, transform .12s ease, background .12s ease, border-color .12s ease;
|
||||
}
|
||||
|
||||
.level-btn:hover{
|
||||
filter: brightness(1.08);
|
||||
}
|
||||
|
||||
.level-btn.is-active{
|
||||
border-color: rgba(160,160,255,0.95);
|
||||
background: rgba(140,140,255,0.18);
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.level-btn.is-active:hover{
|
||||
filter: brightness(1.12);
|
||||
}
|
||||
|
||||
.level-btn:active{
|
||||
transform: translateY(1px);
|
||||
}
|
||||
</style>
|
||||
|
||||
1064
src/components/SidePanel.astro
Normal file
@@ -3,7 +3,7 @@
|
||||
<a href="/editions/">Carte des œuvres</a><span aria-hidden="true"> · </span>
|
||||
<a href="/methode/">Méthode</a><span aria-hidden="true"> · </span>
|
||||
<a href="/recherche/">Recherche</a><span aria-hidden="true"> · </span>
|
||||
<a href="/archicratie/">Essai-thèse</a><span aria-hidden="true"> · </span>
|
||||
<a href="/archicrat-ia/">Essai-thèse</a><span aria-hidden="true"> · </span>
|
||||
<a href="/traite/">Traité</a><span aria-hidden="true"> · </span>
|
||||
<a href="/ia/">Cas IA</a><span aria-hidden="true"> · </span>
|
||||
<a href="/glossaire/">Glossaire</a><span aria-hidden="true"> · </span>
|
||||
|
||||
38
src/pages/archicrat-ia/[...slug].astro
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
import EditionLayout from "../../layouts/EditionLayout.astro";
|
||||
import { getCollection } from "astro:content";
|
||||
import EditionToc from "../../components/EditionToc.astro";
|
||||
import LocalToc from "../../components/LocalToc.astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const entries = (await getCollection("archicratie"))
|
||||
.filter((e) => e.slug.startsWith("archicrat-ia/"));
|
||||
|
||||
return entries.map((entry) => ({
|
||||
// ✅ inline : jamais de helper externe (évite "stripPrefix is not defined")
|
||||
params: { slug: entry.slug.replace(/^archicrat-ia\//, "") },
|
||||
props: { entry },
|
||||
}));
|
||||
}
|
||||
|
||||
const { entry } = Astro.props;
|
||||
const { Content, headings } = await entry.render();
|
||||
---
|
||||
|
||||
<EditionLayout
|
||||
title={entry.data.title}
|
||||
editionLabel="Essai-thèse"
|
||||
editionKey="archicrat-ia"
|
||||
statusLabel="essai-thèse"
|
||||
statusKey="essai_these"
|
||||
level={entry.data.level}
|
||||
version={entry.data.version}
|
||||
>
|
||||
<Fragment slot="aside">
|
||||
<EditionToc currentSlug={entry.slug} />
|
||||
<LocalToc headings={headings} />
|
||||
</Fragment>
|
||||
|
||||
<h1>{entry.data.title}</h1>
|
||||
<Content />
|
||||
</EditionLayout>
|
||||
22
src/pages/archicrat-ia/index.astro
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
import SiteLayout from "../../layouts/SiteLayout.astro";
|
||||
import { getCollection } from "astro:content";
|
||||
|
||||
const entries = (await getCollection("archicratie"))
|
||||
.filter((e) => e.slug.startsWith("archicrat-ia/"));
|
||||
|
||||
entries.sort((a, b) => (a.data.order ?? 9999) - (b.data.order ?? 9999));
|
||||
|
||||
const strip = (slug) => slug.replace(/^archicrat-ia\//, "");
|
||||
const href = (slug) => `/archicrat-ia/${strip(slug)}/`;
|
||||
---
|
||||
|
||||
<SiteLayout title="Essai-thèse — ArchiCraT-IA">
|
||||
<h1>Essai-thèse — ArchiCraT-IA</h1>
|
||||
|
||||
<ul>
|
||||
{entries.map((e) => (
|
||||
<li><a href={href(e.slug)}>{e.data.title}</a></li>
|
||||
))}
|
||||
</ul>
|
||||
</SiteLayout>
|
||||
@@ -5,7 +5,8 @@ import EditionToc from "../../components/EditionToc.astro";
|
||||
import LocalToc from "../../components/LocalToc.astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const entries = await getCollection("archicratie");
|
||||
const entries = (await getCollection("archicratie"))
|
||||
.filter((e) => !e.slug.startsWith("archicrat-ia/"));
|
||||
return entries.map((entry) => ({
|
||||
params: { slug: entry.slug },
|
||||
props: { entry },
|
||||
|
||||
@@ -80,6 +80,12 @@ main { padding: 0; }
|
||||
border-top: 1px dashed rgba(127,127,127,0.35);
|
||||
font-size: 14px;
|
||||
}
|
||||
/* Edition-bar: cacher des badges (non destructif) */
|
||||
.edition-bar [data-badge="edition"],
|
||||
.edition-bar [data-badge="status"],
|
||||
.edition-bar [data-badge="version"]{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.badge {
|
||||
padding: 2px 8px;
|
||||
@@ -95,7 +101,34 @@ main { padding: 0; }
|
||||
padding: 5px 12px;
|
||||
}
|
||||
|
||||
/* Toggle niveaux */
|
||||
/* Jump by paragraph id */
|
||||
.jump-form{
|
||||
display: inline-flex;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
}
|
||||
.jump-input{
|
||||
border: 1px solid rgba(127,127,127,0.55);
|
||||
background: transparent;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
font-size: 13px;
|
||||
width: 320px;
|
||||
}
|
||||
.jump-input.is-error{
|
||||
outline: 2px solid rgba(127,127,127,0.55);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.jump-btn{
|
||||
border: 1px solid rgba(127,127,127,0.55);
|
||||
background: transparent;
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Toggle niveaux (legacy, non bloquant) */
|
||||
.level-toggle { display: inline-flex; gap: 6px; }
|
||||
.lvl-btn {
|
||||
border: 1px solid rgba(127,127,127,0.55);
|
||||
@@ -112,14 +145,22 @@ main { padding: 0; }
|
||||
|
||||
/* Règles niveaux */
|
||||
body[data-reading-level="1"] .level-2,
|
||||
body[data-reading-level="1"] .level-3 { display: none; }
|
||||
body[data-reading-level="2"] .level-3 { display: none; }
|
||||
body[data-reading-level="1"] .level-3,
|
||||
body[data-reading-level="1"] .level-4 { display: none; }
|
||||
|
||||
body[data-reading-level="2"] .level-3,
|
||||
body[data-reading-level="2"] .level-4 { display: none; }
|
||||
|
||||
body[data-reading-level="3"] .level-2,
|
||||
body[data-reading-level="3"] .level-4 { display: none; }
|
||||
|
||||
body[data-reading-level="4"] .level-2,
|
||||
body[data-reading-level="4"] .level-3 { display: none; }
|
||||
|
||||
/* ==========================
|
||||
Scroll offset (anchors / headings / paras)
|
||||
========================== */
|
||||
|
||||
/* Paragraph tools + bookmark */
|
||||
.reading p[id]{
|
||||
position: relative;
|
||||
padding-right: 14rem;
|
||||
@@ -183,6 +224,14 @@ body[data-reading-level="2"] .level-3 { display: none; }
|
||||
}
|
||||
.para-bookmark:hover{ text-decoration: underline; }
|
||||
|
||||
/* Highlight (jump / resume / arrivée hash) */
|
||||
.para-highlight{
|
||||
background: rgba(127,127,127,0.10);
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 0 2px rgba(127,127,127,0.35);
|
||||
transition: box-shadow 160ms ease;
|
||||
}
|
||||
|
||||
.build-stamp {
|
||||
margin-top: 28px;
|
||||
padding-top: 14px;
|
||||
@@ -196,15 +245,51 @@ body[data-reading-level="2"] .level-3 { display: none; }
|
||||
border-radius: 16px;
|
||||
padding: 10px 12px;
|
||||
margin: 14px 0;
|
||||
position: relative;
|
||||
}
|
||||
.details-summary {
|
||||
cursor: pointer;
|
||||
font-weight: 650;
|
||||
|
||||
/* ✅ Handle minimal pour sections fermées : pas de titre visible, mais ouvrable */
|
||||
.details-summary{
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
border: 1px dashed rgba(127,127,127,.25);
|
||||
border-radius: 999px;
|
||||
padding: 6px 10px;
|
||||
margin: 10px 0;
|
||||
|
||||
background: rgba(127,127,127,0.06);
|
||||
position: relative;
|
||||
|
||||
/* cache le texte réel (souvent le titre), sans casser l’accessibilité */
|
||||
color: transparent;
|
||||
}
|
||||
.details-summary::-webkit-details-marker { display: none; }
|
||||
.details-summary a { text-decoration: none; }
|
||||
.details-summary a:hover { text-decoration: underline; }
|
||||
|
||||
.details-summary::before{
|
||||
content: "▸ Ouvrir la section";
|
||||
color: rgba(127,127,127,0.85);
|
||||
font-size: 12px;
|
||||
font-weight: 850;
|
||||
}
|
||||
@media (prefers-color-scheme: dark){
|
||||
.details-summary::before{ color: rgba(220,220,220,0.82); }
|
||||
}
|
||||
|
||||
details[open] > .details-summary{
|
||||
/* une fois ouvert, on le rend “SR-only” pour éviter le doublon visuel */
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.details-body { margin-top: 10px; }
|
||||
|
||||
/* Smooth scroll */
|
||||
@@ -224,7 +309,6 @@ html{ scroll-behavior: smooth; }
|
||||
width: var(--reading-width);
|
||||
right: auto;
|
||||
|
||||
/* colle au header */
|
||||
top: var(--sticky-header-h);
|
||||
|
||||
z-index: 60;
|
||||
@@ -247,7 +331,7 @@ html{ scroll-behavior: smooth; }
|
||||
box-sizing: border-box;
|
||||
|
||||
padding: 8px 12px;
|
||||
padding-right: 84px; /* réserve pour les boutons */
|
||||
padding-right: 84px;
|
||||
|
||||
border: 1px solid rgba(127,127,127,.20);
|
||||
border-top: 0;
|
||||
@@ -259,7 +343,7 @@ html{ scroll-behavior: smooth; }
|
||||
|
||||
box-shadow: 0 10px 22px rgba(0,0,0,.06);
|
||||
|
||||
position: relative; /* pour rf-actions */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark){
|
||||
@@ -278,7 +362,6 @@ html{ scroll-behavior: smooth; }
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.rf-line[hidden]{ display: none !important; }
|
||||
|
||||
.rf-h1{
|
||||
@@ -298,7 +381,6 @@ html{ scroll-behavior: smooth; }
|
||||
font-weight: var(--rf-h3-fw);
|
||||
opacity: .92;
|
||||
}
|
||||
|
||||
.rf-line:hover{ text-decoration: underline; }
|
||||
|
||||
/* Actions */
|
||||
@@ -327,3 +409,14 @@ html{ scroll-behavior: smooth; }
|
||||
background: rgba(127,127,127,0.16);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/* ==========================
|
||||
PATCH CRUCIAL : éviter les “rectangles vides”
|
||||
(details fermés + summary handle minimal)
|
||||
========================== */
|
||||
|
||||
.reading details.details-section:not([open]){
|
||||
border: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||