SPB Git forge

spb/groupe-ka

Public

Groupe KA — site du holding + KA ID (compte unique & SSO des 7 plateformes). Next.js 16, SQLite, Google & Apple login.

81commits 1branches 0releases
89.2 MBsize
maindefault branch
22 days agolast push
TypeScript 70.4% HTML 18.4% JavaScript 4% Python 3.8% CSS 3.4%

SEO : canonical, JSON-LD Organization+WebSite, robots.txt, sitemap.xml, template de titres

- layout : alternates.canonical ./ (par route), og:url harmonisé, html lang fr-CA,
  title template %s | Groupe KA, données structurées schema.org (holding + 13 plateformes,
  WebSite inLanguage fr-CA)
- src/app/robots.ts : allow / ; disallow /api/, /compte, /sso ; lien sitemap
- src/app/sitemap.ts : accueil + 9 pages publiques
- pages : suffixe — Groupe KA retiré des titres (géré par le template)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Simon-Pierre Boucher committed 1 mo ago (Aug 22, 2026) parent d06a1a7

17 changed files +133 −17

modified src/app/avis/page.tsx +1 −1
@@ -2,7 +2,7 @@
2 2 import type { Metadata } from "next";
3 3
4 4 export const metadata: Metadata = {
5 − title: "Avis : notre rôle d'agrégateur — Groupe KA",
5 + title: "Avis : notre rôle d'agrégateur",
6 6 description:
7 7 "Groupe KA est un agrégateur de contenu : nous ne vendons rien, ne louons rien et ne sommes partie à aucune transaction. Aucun contrat ne se forme entre vous et Groupe KA du fait de la consultation de nos plateformes.",
8 8 };
modified src/app/bots/page.tsx +1 −1
@@ -2,7 +2,7 @@
2 2 import type { Metadata } from "next";
3 3
4 4 export const metadata: Metadata = {
5 − title: "Déclaration de transparence — Robots d'indexation — Groupe KA",
5 + title: "Déclaration de transparence — Robots d'indexation",
6 6 description:
7 7 "Fonctionnement des robots d'indexation du Groupe KA (ka·2, ka·4, ka·6) : données publiques uniquement, respect de robots.txt, charge minimale, retrait sur demande — zéro boîte noire.",
8 8 };
modified src/app/compte/carte/page.tsx +1 −1
@@ -12,7 +12,7 @@ import { roleCard } from "@/lib/roles";
12 12 import PrintButton from "./PrintButton";
13 13
14 14 export const metadata: Metadata = {
15 − title: "Carte imprimable | Groupe KA",
15 + title: "Carte imprimable",
16 16 robots: { index: false },
17 17 };
18 18
modified src/app/compte/page.tsx +1 −1
@@ -24,7 +24,7 @@ import ProfileForm from "./ProfileForm";
24 24 import CopyText from "./CopyText";
25 25
26 26 export const metadata: Metadata = {
27 − title: "Mon KA ID | Groupe KA",
27 + title: "Mon KA ID",
28 28 description: "Votre compte unique pour les plateformes du Groupe KA.",
29 29 };
30 30
modified src/app/conditions/page.tsx +1 −1
@@ -2,7 +2,7 @@
2 2 import type { Metadata } from "next";
3 3
4 4 export const metadata: Metadata = {
5 − title: "Conditions d’utilisation — Groupe KA",
5 + title: "Conditions d’utilisation",
6 6 description:
7 7 "Conditions d’utilisation du site groupe-ka.com et principes communs aux plateformes du Groupe KA.",
8 8 };
modified src/app/confidentialite/page.tsx +1 −1
@@ -2,7 +2,7 @@
2 2 import type { Metadata } from "next";
3 3
4 4 export const metadata: Metadata = {
5 − title: "Politique de confidentialité — Groupe KA",
5 + title: "Politique de confidentialité",
6 6 description:
7 7 "Politique de confidentialité du site groupe-ka.com — Loi 25, aucun traceur publicitaire, aucun témoin tiers.",
8 8 };
modified src/app/connexion/page.tsx +1 −1
@@ -6,7 +6,7 @@ import { SSO_CLIENTS } from "@/lib/sso";
6 6 import AuthForm from "./AuthForm";
7 7
8 8 export const metadata: Metadata = {
9 − title: "KA ID — connexion | Groupe KA",
9 + title: "KA ID — connexion",
10 10 description:
11 11 "Un seul compte pour toutes les plateformes du Groupe KA : créez votre KA ID ou continuez avec Google.",
12 12 };
modified src/app/layout.tsx +69 −3
@@ -17,14 +17,20 @@ const jetbrains = JetBrains_Mono({
17 17
18 18 export const metadata: Metadata = {
19 19 metadataBase: new URL("https://www.groupe-ka.com"),
20 − title: "Groupe KA — holding d’agrégateurs automatisés, sans boîte noire",
20 + title: {
21 + default: "Groupe KA — holding d’agrégateurs automatisés, sans boîte noire",
22 + template: "%s | Groupe KA",
23 + },
24 + alternates: {
25 + canonical: "./",
26 + },
21 27 description:
22 28 "Groupe KA est un holding québécois d’agrégateurs de produits et services entièrement automatisés : Trouve·Ka (moteur de recherche du web québécois), Lou·Ka (location), Immo·Ka (propriétés à vendre), Vrai-Prix (valeur résidentielle), ValoPlex (plex), Auto·Ka (voitures usagées), Fabri·Ka (produits québécois), Food·Ka (épicerie), Resto·Ka (restaurants, menus et prix), Sorti·Ka (sorties et événements) Créa·Ka (créateurs d’ici) et Job·Ka (emplois). Zéro saisie manuelle.",
23 29 openGraph: {
24 30 title: "Groupe KA — holding d’agrégateurs automatisés, sans boîte noire",
25 31 description:
26 32 "Ka, c’est l’agrégation : des centaines de connecteurs, dix plateformes — Lou·Ka, Immo·Ka, Vrai-Prix, ValoPlex, Auto·Ka, Fabri·Ka, Food·Ka, Resto·Ka, Sorti·Ka, Créa·Ka et Job·Ka.",
27 − url: "https://www.groupe-ka.com",
33 + url: "./",
28 34 siteName: "Groupe KA",
29 35 locale: "fr_CA",
30 36 type: "website",
@@ -49,6 +55,62 @@ export const viewport: Viewport = {
49 55 viewportFit: "cover",
50 56 };
51 57
58 +// Données structurées schema.org (SEO) : le holding + ses plateformes,
59 +// alignées sur la liste réellement affichée dans le pied de page.
60 +const SITE_URL = "https://www.groupe-ka.com/";
61 +const PLATEFORMES: [string, string][] = [
62 + ["Trouve·Ka", "https://www.trouve-ka.com"],
63 + ["Lou·Ka", "https://www.lou-ka.com"],
64 + ["Immo·Ka", "https://www.immo-ka.com"],
65 + ["Vrai-Prix", "https://www.vrai-prix.com"],
66 + ["ValoPlex", "https://www.valoplex.com"],
67 + ["Auto·Ka", "https://www.auto-ka.com"],
68 + ["Fabri·Ka", "https://www.fabri-ka.com"],
69 + ["Food·Ka", "https://www.food-ka.com"],
70 + ["Resto·Ka", "https://www.resto-ka.com"],
71 + ["Sorti·Ka", "https://www.sorti-ka.com"],
72 + ["Créa·Ka", "https://www.crea-ka.com"],
73 + ["API·Ka", "https://www.api-ka.com"],
74 + ["Job·Ka", "https://www.job-ka.com"],
75 +];
76 +const JSON_LD = {
77 + "@context": "https://schema.org",
78 + "@graph": [
79 + {
80 + "@type": "Organization",
81 + "@id": `${SITE_URL}#organization`,
82 + name: "Groupe KA",
83 + url: SITE_URL,
84 + logo: `${SITE_URL}og.png`,
85 + description:
86 + "Holding québécois d’agrégateurs de produits et services entièrement automatisés — zéro saisie manuelle, zéro boîte noire.",
87 + email: "contact@groupe-ka.com",
88 + areaServed: {
89 + "@type": "AdministrativeArea",
90 + name: "Québec, Canada",
91 + },
92 + brand: PLATEFORMES.map(([name, url]) => ({
93 + "@type": "Brand",
94 + name,
95 + url,
96 + })),
97 + subOrganization: PLATEFORMES.map(([name, url]) => ({
98 + "@type": "Organization",
99 + name,
100 + url,
101 + })),
102 + },
103 + {
104 + "@type": "WebSite",
105 + "@id": `${SITE_URL}#website`,
106 + name: "Groupe KA",
107 + url: SITE_URL,
108 + inLanguage: "fr-CA",
109 + publisher: { "@id": `${SITE_URL}#organization` },
110 + },
111 + ],
112 +};
113 +
52 114 const NAV_ITEMS = [
53 115 { href: "/#trouve-ka", label: "Moteur" },
54 116 { href: "/#flux", label: "L’agrégation" },
@@ -113,10 +175,14 @@ export default async function RootLayout({
113 175 }: Readonly<{ children: React.ReactNode }>) {
114 176 const ticker = tickerItems(await getLiveMetrics());
115 177 return (
116 − <html lang="fr">
178 + <html lang="fr-CA">
117 179 <body
118 180 className={`${spaceGrotesk.variable} ${inter.variable} ${jetbrains.variable} bg-paper text-ink`}
119 181 >
182 + <script
183 + type="application/ld+json"
184 + dangerouslySetInnerHTML={{ __html: JSON.stringify(JSON_LD) }}
185 + />
120 186 <header className="sticky top-0 z-[var(--z-header)] border-b-2 border-ink bg-paper md:bg-[rgba(245,243,238,0.88)] md:backdrop-blur-xl">
121 187 <div className="mx-auto flex h-16 max-w-6xl items-center justify-between px-4 sm:px-6">
122 188 <a href="#" className="group" aria-label="Groupe KA — accueil">
modified src/app/loi-25/page.tsx +1 −1
@@ -2,7 +2,7 @@
2 2 import type { Metadata } from "next";
3 3
4 4 export const metadata: Metadata = {
5 − title: "Protection des renseignements personnels (Loi 25) — Groupe KA",
5 + title: "Protection des renseignements personnels (Loi 25)",
6 6 description:
7 7 "Comment Groupe KA recueille, utilise, conserve et protège les renseignements personnels, conformément à la Loi 25 du Québec — agrégateur de contenu public, demandes d'accès, de rectification et de retrait.",
8 8 };
modified src/app/m/[kaId]/page.tsx +1 −1
@@ -7,7 +7,7 @@ import { db } from "@/lib/db";
7 7 import { roleLabel } from "@/lib/roles";
8 8
9 9 export const metadata: Metadata = {
10 − title: "Identification de membre | Groupe KA",
10 + title: "Identification de membre",
11 11 description: "Identification d'un membre du Groupe KA par son KA-ID.",
12 12 robots: { index: false },
13 13 };
modified src/app/retrait/page.tsx +1 −1
@@ -2,7 +2,7 @@
2 2 import type { Metadata } from "next";
3 3
4 4 export const metadata: Metadata = {
5 − title: "Politique de retrait et de révision — Groupe KA",
5 + title: "Politique de retrait et de révision",
6 6 description:
7 7 "Comment demander le retrait d'une annonce indexée sur les plateformes du Groupe KA, la révision d'une estimation ou l'arrêt de la couverture d'une propriété sur Vrai-Prix et ValoPlex. Sans frais, traité en 48 à 72 heures ouvrables.",
8 8 };
added src/app/robots.ts +17 −0
@@ -0,0 +1,17 @@
1 +// Auteur : Simon-Pierre Boucher — contact@spboucher.ai
2 +// robots.txt généré par Next (Metadata API) — SEO 2026-08-22.
3 +import type { MetadataRoute } from "next";
4 +
5 +export default function robots(): MetadataRoute.Robots {
6 + return {
7 + rules: [
8 + {
9 + userAgent: "*",
10 + allow: "/",
11 + // Routes techniques ou de compte : rien à indexer.
12 + disallow: ["/api/", "/compte", "/sso"],
13 + },
14 + ],
15 + sitemap: "https://www.groupe-ka.com/sitemap.xml",
16 + };
17 +}
added src/app/sitemap.ts +33 −0
@@ -0,0 +1,33 @@
1 +// Auteur : Simon-Pierre Boucher — contact@spboucher.ai
2 +// sitemap.xml généré par Next (Metadata API) — SEO 2026-08-22.
3 +// Pages publiques statiques seulement (les fiches /m et /u sont des pages
4 +// de membre, /compte et /connexion des pages de session : exclues).
5 +import type { MetadataRoute } from "next";
6 +
7 +const BASE = "https://www.groupe-ka.com";
8 +
9 +export default function sitemap(): MetadataRoute.Sitemap {
10 + const lastModified = new Date();
11 + const pages: {
12 + path: string;
13 + changeFrequency: MetadataRoute.Sitemap[number]["changeFrequency"];
14 + priority: number;
15 + }[] = [
16 + { path: "/", changeFrequency: "daily", priority: 1 },
17 + { path: "/stats", changeFrequency: "daily", priority: 0.8 },
18 + { path: "/status", changeFrequency: "daily", priority: 0.6 },
19 + { path: "/telecharger", changeFrequency: "weekly", priority: 0.7 },
20 + { path: "/avis", changeFrequency: "monthly", priority: 0.5 },
21 + { path: "/bots", changeFrequency: "monthly", priority: 0.5 },
22 + { path: "/retrait", changeFrequency: "monthly", priority: 0.4 },
23 + { path: "/conditions", changeFrequency: "yearly", priority: 0.3 },
24 + { path: "/confidentialite", changeFrequency: "yearly", priority: 0.3 },
25 + { path: "/loi-25", changeFrequency: "yearly", priority: 0.3 },
26 + ];
27 + return pages.map(({ path, changeFrequency, priority }) => ({
28 + url: `${BASE}${path}`,
29 + lastModified,
30 + changeFrequency,
31 + priority,
32 + }));
33 +}
modified src/app/stats/page.tsx +1 −1
@@ -20,7 +20,7 @@ import {
20 20 import EcoStatsClient from "./eco-client";
21 21
22 22 export const metadata: Metadata = {
23 − title: "Statistiques de l'écosystème — Groupe KA",
23 + title: "Statistiques de l'écosystème",
24 24 description:
25 25 "Tableau de bord maître du Groupe KA : indicateurs consolidés en direct des plateformes de l'écosystème ·Ka, classement par volume, croissance comparée, résumé par plateforme et rapports écosystème PDF.",
26 26 };
modified src/app/status/page.tsx +1 −1
@@ -16,7 +16,7 @@ import {
16 16 export const dynamic = "force-dynamic";
17 17
18 18 export const metadata: Metadata = {
19 − title: "Statut des services — Groupe KA",
19 + title: "Statut des services",
20 20 description:
21 21 "État en direct et historique de disponibilité des plateformes de l'écosystème Groupe KA : vérifications aux 5 minutes, barres 24 h et 90 jours, latences.",
22 22 };
modified src/app/telecharger/page.tsx +1 −1
@@ -5,7 +5,7 @@
5 5 import type { Metadata } from "next";
6 6
7 7 export const metadata: Metadata = {
8 − title: "Télécharger l'app KA — Groupe KA",
8 + title: "Télécharger l'app KA",
9 9 description:
10 10 "KA, la super-app de l'écosystème Groupe KA : 12 univers, recherche universelle, carte 2D/3D, favoris, KA Agent. iPhone (TestFlight), Android (APK direct) et macOS (DMG notarié).",
11 11 };
modified src/app/u/[kaId]/page.tsx +1 −1
@@ -12,7 +12,7 @@ import {
12 12 import { roleCard } from "@/lib/roles";
13 13
14 14 export const metadata: Metadata = {
15 − title: "Profil de membre | Groupe KA",
15 + title: "Profil de membre",
16 16 description: "Profil public d'un membre du Groupe KA.",
17 17 };
18 18
19 19