diff --git a/frontend/package.json b/frontend/package.json
index 7151c84..efcaf1c 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -7,6 +7,7 @@
"license": "MIT",
"scripts": {
"dev": "vite dev",
+ "prebuild": "node scripts/gen-sitemap.mjs",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
diff --git a/frontend/scripts/gen-sitemap.mjs b/frontend/scripts/gen-sitemap.mjs
new file mode 100644
index 0000000..af46f96
--- /dev/null
+++ b/frontend/scripts/gen-sitemap.mjs
@@ -0,0 +1,47 @@
+// Génère static/sitemap.xml au build (script `prebuild`) — remplace le
+// sitemap qu'apportait @astrojs/sitemap à l'ère Astro. Zéro dépendance :
+// les slugs sont relus depuis les frontmatters de content/outils/.
+import { readdirSync, readFileSync, writeFileSync } from 'node:fs'
+import path from 'node:path'
+import { fileURLToPath } from 'node:url'
+
+const SITE_URL = 'https://chatcontrol.o-k-i.net'
+const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
+const OUTILS = path.resolve(ROOT, '..', 'content', 'outils')
+
+// les valeurs du frontmatter sont encodées en JSON (cf. tools.server.ts)
+function slugOf(file) {
+ const raw = readFileSync(path.join(OUTILS, file), 'utf8')
+ const m = raw.match(/^slug:\s*("(?:[^"\\]|\\.)*")/m)
+ return m ? JSON.parse(m[1]) : file.replace(/\.md$/, '')
+}
+
+const slugs = readdirSync(OUTILS)
+ .filter((f) => f.endsWith('.md'))
+ .map(slugOf)
+ .sort((a, b) => a.localeCompare(b, 'fr'))
+
+const lastmod = new Date().toISOString().slice(0, 10)
+
+const entry = (loc, priority) => `
+ ${SITE_URL}${loc}
+ ${lastmod}
+ ${priority}
+ `
+
+const urls = [
+ entry('/', '1.0'),
+ entry('/outils/', '0.8'),
+ ...slugs.map((slug) => entry(`/outils/${slug}/`, '0.6')),
+ entry('/quiz/', '0.5'),
+ entry('/contribuer/', '0.5')
+]
+
+const xml = `
+
+${urls.join('\n')}
+
+`
+
+writeFileSync(path.join(ROOT, 'static', 'sitemap.xml'), xml)
+console.log(`sitemap.xml : ${urls.length} URLs (lastmod ${lastmod})`)
diff --git a/frontend/src/lib/components/Seo.svelte b/frontend/src/lib/components/Seo.svelte
new file mode 100644
index 0000000..4a634b2
--- /dev/null
+++ b/frontend/src/lib/components/Seo.svelte
@@ -0,0 +1,43 @@
+
+
+
+ {fullTitle}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/lib/site.ts b/frontend/src/lib/site.ts
index cbe04db..a267afa 100644
--- a/frontend/src/lib/site.ts
+++ b/frontend/src/lib/site.ts
@@ -1,5 +1,8 @@
/** Constantes du site — un seul endroit à changer si la forge bouge. */
export const REPO_URL = 'https://labola.o-k-i.net/cyber-mawonaj/lage-chat-control'
+
+/** Origine de production — base des URL absolues SEO (canonical, OG, sitemap). */
+export const SITE_URL = 'https://chatcontrol.o-k-i.net'
export const NEW_TOOL_ISSUE_URL = `${REPO_URL}/issues/new?template=.gitea/ISSUE_TEMPLATE/nouvo-zouti.yaml`
/**
diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte
index b54742a..69463c1 100644
--- a/frontend/src/routes/+page.svelte
+++ b/frontend/src/routes/+page.svelte
@@ -1,5 +1,6 @@
-
- {t('site.name')} — {t('site.tagline')}
-
-
+
diff --git a/frontend/src/routes/contribuer/+page.svelte b/frontend/src/routes/contribuer/+page.svelte
index 6719337..c0d7c76 100644
--- a/frontend/src/routes/contribuer/+page.svelte
+++ b/frontend/src/routes/contribuer/+page.svelte
@@ -1,4 +1,5 @@
-
- {t('contrib.title')} — {t('site.name')}
-
-
+
{t('contrib.title')}
diff --git a/frontend/src/routes/outils/+page.svelte b/frontend/src/routes/outils/+page.svelte
index 467b883..3e8cc8b 100644
--- a/frontend/src/routes/outils/+page.svelte
+++ b/frontend/src/routes/outils/+page.svelte
@@ -7,6 +7,7 @@
import ToolCard from '$lib/components/ToolCard.svelte'
import EndMarker from '$lib/components/EndMarker.svelte'
import DifficultyBadge from '$lib/components/DifficultyBadge.svelte'
+ import Seo from '$lib/components/Seo.svelte'
import { t } from '$lib/i18n/index.svelte'
let { data } = $props()
@@ -43,10 +44,7 @@
}
-
- {t('directory.title')} — {t('site.name')}
-
-
+
{t('directory.title')}
diff --git a/frontend/src/routes/outils/[slug]/+page.svelte b/frontend/src/routes/outils/[slug]/+page.svelte
index 89293a3..4b3d454 100644
--- a/frontend/src/routes/outils/[slug]/+page.svelte
+++ b/frontend/src/routes/outils/[slug]/+page.svelte
@@ -2,6 +2,7 @@
import { base } from '$app/paths'
import AdoptButton from '$lib/components/AdoptButton.svelte'
import DifficultyBadge from '$lib/components/DifficultyBadge.svelte'
+ import Seo from '$lib/components/Seo.svelte'
import { getLocale, t } from '$lib/i18n/index.svelte'
let { data } = $props()
@@ -34,15 +35,12 @@
- {tool.name} — {t('site.name')}
-
-
-
-
{@html jsonLd}
+
+
diff --git a/frontend/src/routes/quiz/+page.svelte b/frontend/src/routes/quiz/+page.svelte
index 37f664e..59586c8 100644
--- a/frontend/src/routes/quiz/+page.svelte
+++ b/frontend/src/routes/quiz/+page.svelte
@@ -1,5 +1,6 @@
-
- {t('quiz.title')} — {t('site.name')}
-
-
+
{t('quiz.eyebrow')}
diff --git a/frontend/static/robots.txt b/frontend/static/robots.txt
index c2a49f4..a024b78 100644
--- a/frontend/static/robots.txt
+++ b/frontend/static/robots.txt
@@ -1,2 +1,4 @@
User-agent: *
Allow: /
+
+Sitemap: https://chatcontrol.o-k-i.net/sitemap.xml
diff --git a/frontend/static/sitemap.xml b/frontend/static/sitemap.xml
new file mode 100644
index 0000000..678c760
--- /dev/null
+++ b/frontend/static/sitemap.xml
@@ -0,0 +1,298 @@
+
+
+
+ https://chatcontrol.o-k-i.net/
+ 2026-07-21
+ 1.0
+
+
+ https://chatcontrol.o-k-i.net/outils/
+ 2026-07-21
+ 0.8
+
+
+ https://chatcontrol.o-k-i.net/outils/aegis/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/alias/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/backups/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/bitchat/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/bitcoin/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/bitwarden/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/brave/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/briar/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/cloudai/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/cloudflare/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/cryptomator/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/databrokers/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/element/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/fediverse/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/firefox/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/grapheneos/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/ivpn/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/keepassxc/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/linux/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/localai/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/mailbox/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/maps/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/mastodon/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/molly/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/monero/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/mullvad/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/mullvadbrowser/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/mullvaddns/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/nc-storage/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/nextcloud/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/nostr/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/notes/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/photos/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/pihole/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/pocketpal/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/protondrive/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/protonmail/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/protonpass/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/protonvpn/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/quad9/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/qubes/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/search/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/session/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/signal/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/simplex/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/synapse/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/tails/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/tailscale/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/tor/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/tuta/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/ublock/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/visio/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/website/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/yubikey/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/outils/yunohost/
+ 2026-07-21
+ 0.6
+
+
+ https://chatcontrol.o-k-i.net/quiz/
+ 2026-07-21
+ 0.5
+
+
+ https://chatcontrol.o-k-i.net/contribuer/
+ 2026-07-21
+ 0.5
+
+