Palette (promo/, les 4 pages) — ajoute --rose:#ff6fc4 (frange magenta) et
--vert:#5cff9d (vert fluo), uniquement dans les DÉGRADÉS FONCÉS : fond fixe du
corps, nappe .aurora dérivante, filets .rule. Opacités de 5,5 % à 8,5 %, une
teinte et non un motif. Le vert entre par la gauche et le rose sort par la
droite, comme une vraie aurore. --aurora (texte et boutons) est inchangé :
l'identité de marque ne bouge pas. Appliqué identiquement aux quatre fichiers,
0 conflit CSS après coup.
Thème Forgejo (alliance.css, 29 → 118 lignes) — la feuille étant injectée par
templates/custom/header.tmpl sur toutes les pages, le wiki est couvert sans
feuille distincte. Réorganisée en deux sections de risque explicite :
§1 Variables — couleurs officielles + ciel nocturne. Sûr, résiste aux
mises à jour. ÉPROUVÉ sur forge-01 (CHANGELOG 2026-07-03).
§2 Décor — fond aurore, filet sous les titres, citations, tableaux et code
en ligne de .markup. Fragile (classes internes). JAMAIS RENDU.
Supprimer §2 ramène au thème sobre. Le ciel nocturne ne s'applique qu'aux
thèmes sombres, pour ne pas casser le thème clair.
docs/theme-forgejo-hors-flotte.md — pose manuelle sur une instance Forgejo non
gérée par Set-OPS (la forge historique qui héberge ce dépôt et son wiki).
Forgejo n'ayant aucun réglage web pour le CSS, il faut déposer la feuille sur
le serveur. La procédure ne duplique aucun fichier : elle pointe vers ceux du
rôle. Inclut la détection du répertoire custom, un garde-fou pour ne pas
écraser un header.tmpl existant (ajout de ligne), la vérification curl et la
marche arrière.
Corrige deux affirmations fausses de ma part :
- « thème jamais rendu par un Forgejo réel » était faux pour §1, éprouvée.
Le statut est désormais donné section par section.
- Contradiction consignée sur forge-01 : le plan la dit `etat: planifie`, le
CHANGELOG 2026-07-03 dit le branding « prouvé sur forge-01 ». Les deux ne
peuvent pas être vrais ; l'écart est écrit dans le README du rôle, à trancher.
Validé : équilibre accolades/parenthèses du CSS, 0 conflit CSS entre les quatre
pages, lien de doc résolu, ansible-lint 0 échec sur 485 fichiers,
prouver.py --verifier → CONFORME 16/16.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
686 lines
45 KiB
HTML
686 lines
45 KiB
HTML
<!doctype html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Set-OPS — Capacités du moteur · Chezlepro</title>
|
|
<meta name="description" content="Set-OPS : moteur Ansible d'écosystèmes numériques souverains — identité, PKI, DNS, données, courriel, edge TLS, observabilité, forge, sauvegardes, pare-feu. Sur votre propre grappe Proxmox, sans SaaS, prouvé.">
|
|
<meta name="color-scheme" content="dark">
|
|
</head>
|
|
<body>
|
|
<style>
|
|
:root{
|
|
--night:#05060f; --night-2:#0a0d24; --night-3:#0e1640;
|
|
--ink:#e9ecff; --dim:#99a1c9; --dim-2:#727aa6;
|
|
--line:rgba(255,255,255,.10); --line-2:rgba(255,255,255,.06);
|
|
--panel:rgba(255,255,255,.045); --panel-2:rgba(255,255,255,.03);
|
|
--teal:#4fe3c1; --cyan:#56c2ff; --violet:#a98bff; --amber:#ffc46b;
|
|
--rose:#ff6fc4; --vert:#5cff9d; /* frange magenta + vert fluo de l'aurore */
|
|
--aurora:linear-gradient(100deg,var(--teal) 0%,var(--cyan) 46%,var(--violet) 100%);
|
|
--sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Noto Sans","Helvetica Neue",Arial,sans-serif;
|
|
--mono:ui-monospace,"SF Mono","JetBrains Mono",Menlo,Consolas,"Liberation Mono",monospace;
|
|
--wrap:1140px;
|
|
}
|
|
*{box-sizing:border-box}
|
|
html{scroll-behavior:smooth}
|
|
body{
|
|
margin:0; font-family:var(--sans); color:var(--ink); line-height:1.6;
|
|
background:
|
|
radial-gradient(1200px 760px at 82% -8%,#141c4c 0%,transparent 58%),
|
|
radial-gradient(900px 620px at 8% -2%,#0e1640 0%,transparent 55%),
|
|
radial-gradient(780px 540px at 97% 38%,rgba(255,111,196,.085) 0%,transparent 62%),
|
|
radial-gradient(840px 580px at 3% 72%,rgba(92,255,157,.065) 0%,transparent 62%),
|
|
radial-gradient(700px 500px at 50% 112%,rgba(169,139,255,.07) 0%,transparent 60%),
|
|
linear-gradient(180deg,var(--night-2) 0%,var(--night) 62%) fixed;
|
|
-webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
|
|
overflow-x:hidden;
|
|
}
|
|
/* ---- fond animé : ciel + aurore + constellation ---- */
|
|
#sky{position:fixed;inset:0;z-index:-2;pointer-events:none}
|
|
#sky canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
|
|
.aurora{
|
|
position:fixed;left:-10%;right:-10%;top:-22%;height:74vh;z-index:-1;pointer-events:none;
|
|
filter:blur(64px) saturate(140%);opacity:.42;
|
|
background:
|
|
radial-gradient(34% 52% at 6% 52%,var(--vert) 0%,transparent 66%),
|
|
radial-gradient(40% 60% at 20% 30%,var(--teal) 0%,transparent 70%),
|
|
radial-gradient(45% 70% at 55% 20%,var(--cyan) 0%,transparent 70%),
|
|
radial-gradient(40% 65% at 82% 35%,var(--violet) 0%,transparent 70%),
|
|
radial-gradient(32% 48% at 95% 62%,var(--rose) 0%,transparent 66%);
|
|
animation:drift 24s ease-in-out infinite alternate;
|
|
}
|
|
@keyframes drift{from{transform:translate(-3%,0) scale(1)}to{transform:translate(3%,2%) scale(1.08)}}
|
|
.wrap{max-width:var(--wrap);margin-inline:auto;padding-inline:24px}
|
|
/* ---- nav ---- */
|
|
header.nav{position:sticky;top:0;z-index:20;backdrop-filter:blur(12px);
|
|
background:linear-gradient(180deg,rgba(5,6,15,.72),rgba(5,6,15,.28));
|
|
border-bottom:1px solid var(--line-2)}
|
|
.nav .wrap{display:flex;align-items:center;gap:20px;height:64px}
|
|
.brand{display:flex;align-items:center;gap:11px;font-weight:650;letter-spacing:.2px;text-decoration:none;color:var(--ink)}
|
|
.brand svg{width:30px;height:30px;flex:none}
|
|
.brand b{font-weight:750}
|
|
.nav nav{margin-left:auto;display:flex;gap:24px;align-items:center}
|
|
.nav nav a{color:var(--dim);text-decoration:none;font-size:.94rem;font-weight:500}
|
|
.nav nav a:hover{color:var(--ink)}
|
|
.nav nav a[aria-current="page"]{color:var(--ink);font-weight:640}
|
|
.nav nav a[aria-current="page"]::after{content:"";display:block;height:2px;border-radius:2px;background:var(--aurora);margin-top:3px}
|
|
.nav .cta-mini{padding:8px 16px;border-radius:999px;background:var(--aurora);color:#04121a;font-weight:700;font-size:.9rem}
|
|
.nav .cta-mini:hover{color:#04121a;filter:brightness(1.08)}
|
|
@media(max-width:760px){.nav nav a:not(.cta-mini){display:none}}
|
|
/* ---- typographie ---- */
|
|
.eyebrow{font-family:var(--mono);font-size:.76rem;letter-spacing:.28em;text-transform:uppercase;color:var(--cyan);font-weight:600}
|
|
h1,h2,h3{text-wrap:balance;line-height:1.08;margin:0}
|
|
.grad{background:var(--aurora);-webkit-background-clip:text;background-clip:text;color:transparent}
|
|
p{margin:0}
|
|
.lede{color:var(--dim);font-size:1.12rem;max-width:60ch}
|
|
/* ---- hero ---- */
|
|
.hero{position:relative;padding:82px 0 60px}
|
|
.hero .eyebrow{display:block;margin-bottom:22px}
|
|
.hero h1{font-size:clamp(2.3rem,6vw,4.6rem);font-weight:800;letter-spacing:-.02em;max-width:17ch}
|
|
.hero .lede{margin-top:26px;font-size:clamp(1.05rem,1.9vw,1.26rem);max-width:64ch}
|
|
.cta-row{display:flex;flex-wrap:wrap;gap:14px;margin-top:36px}
|
|
.btn{display:inline-flex;align-items:center;gap:9px;padding:14px 24px;border-radius:999px;font-weight:700;text-decoration:none;font-size:1rem;border:1px solid transparent;transition:transform .15s ease,filter .15s ease,border-color .15s ease}
|
|
.btn-primary{background:var(--aurora);color:#04121a}
|
|
.btn-primary:hover{transform:translateY(-2px);filter:brightness(1.08)}
|
|
.btn-ghost{color:var(--ink);border-color:var(--line);background:var(--panel)}
|
|
.btn-ghost:hover{border-color:var(--cyan);transform:translateY(-2px)}
|
|
.flow{margin-top:40px;font-family:var(--mono);font-size:.92rem;color:var(--dim);display:flex;flex-wrap:wrap;gap:10px 14px;align-items:center}
|
|
.flow code{color:var(--teal);background:var(--panel);border:1px solid var(--line-2);padding:4px 10px;border-radius:7px;white-space:nowrap}
|
|
.flow .arw{color:var(--dim-2)}
|
|
/* ---- bandeaux de section ---- */
|
|
section{padding:72px 0;position:relative}
|
|
.sec-head{max-width:68ch;margin-bottom:42px}
|
|
.sec-head h2{font-size:clamp(1.75rem,3.4vw,2.6rem);font-weight:750;letter-spacing:-.015em;margin-top:14px}
|
|
.sec-head p{margin-top:16px;color:var(--dim);font-size:1.07rem}
|
|
.rule{height:1px;border:0;margin:0;background:linear-gradient(90deg,rgba(92,255,157,.28),rgba(86,194,255,.22) 34%,rgba(255,111,196,.24) 68%,transparent)}
|
|
/* ---- méthode : 4 temps ---- */
|
|
.beats{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:18px}
|
|
.beat{background:var(--panel-2);border:1px solid var(--line-2);border-radius:15px;padding:22px}
|
|
.beat .n{font-family:var(--mono);font-size:.8rem;color:var(--cyan);letter-spacing:.1em}
|
|
.beat h3{font-size:1.06rem;font-weight:680;margin:12px 0 8px}
|
|
.beat p{color:var(--dim);font-size:.94rem}
|
|
/* ---- piliers (capacités) ---- */
|
|
.pillars{display:grid;grid-template-columns:repeat(2,1fr);gap:20px}
|
|
@media(max-width:820px){.pillars{grid-template-columns:1fr}}
|
|
.card{position:relative;background:var(--panel);border:1px solid var(--line);border-radius:18px;padding:26px;overflow:hidden;transition:transform .2s ease,border-color .2s ease,box-shadow .2s ease}
|
|
.card:hover{transform:translateY(-3px);border-color:rgba(86,194,255,.42);box-shadow:0 18px 50px -24px rgba(86,194,255,.45)}
|
|
.card::before{content:"";position:absolute;inset:0 0 auto 0;height:2px;background:var(--aurora);opacity:.75}
|
|
.card .kick{display:flex;align-items:center;gap:12px;margin-bottom:14px}
|
|
.card .dot{width:34px;height:34px;border-radius:10px;flex:none;display:grid;place-items:center;background:rgba(86,194,255,.12);border:1px solid rgba(86,194,255,.28)}
|
|
.card .dot svg{width:19px;height:19px}
|
|
.card h3{font-size:1.2rem;font-weight:720;margin-bottom:10px}
|
|
.card .sub{color:var(--dim);font-size:.96rem;margin-top:8px}
|
|
.chips{display:flex;flex-wrap:wrap;gap:7px;margin:16px 0 4px}
|
|
.chip{font-family:var(--mono);font-size:.76rem;color:var(--ink);background:rgba(255,255,255,.05);border:1px solid var(--line);padding:4px 9px;border-radius:7px}
|
|
ul.does{list-style:none;padding:0;margin:16px 0 0;display:grid;gap:9px}
|
|
ul.does li{position:relative;padding-left:22px;color:var(--dim);font-size:.94rem}
|
|
ul.does li::before{content:"";position:absolute;left:2px;top:.62em;width:7px;height:7px;border-radius:2px;background:var(--aurora);transform:rotate(45deg)}
|
|
ul.does b{color:var(--ink);font-weight:640}
|
|
.card .kick .st{margin-left:auto}
|
|
/* ---- console opérateur ---- */
|
|
.console{background:linear-gradient(180deg,rgba(10,13,36,.9),rgba(5,6,15,.9));border:1px solid var(--line);border-radius:16px;overflow:hidden;box-shadow:0 24px 70px -30px rgba(0,0,0,.8)}
|
|
.console .bar{display:flex;align-items:center;gap:8px;padding:12px 16px;border-bottom:1px solid var(--line-2);background:rgba(255,255,255,.02)}
|
|
.console .bar i{width:11px;height:11px;border-radius:50%;display:block}
|
|
.console .bar i:nth-child(1){background:#ff5f57}
|
|
.console .bar i:nth-child(2){background:#febc2e}
|
|
.console .bar i:nth-child(3){background:#28c840}
|
|
.console .bar span{margin-left:8px;font-family:var(--mono);font-size:.82rem;color:var(--dim)}
|
|
.console pre{margin:0;padding:22px 20px;font-family:var(--mono);font-size:.86rem;line-height:1.85;overflow-x:auto}
|
|
.console .c{color:var(--dim-2)}
|
|
/* commentaire */
|
|
.console .p{color:var(--teal)}
|
|
/* prompt/cmd */
|
|
.console .o{color:var(--ink)}
|
|
/* sortie */
|
|
.console .g{color:var(--cyan)}
|
|
/* mise en avant */
|
|
|
|
.split{display:grid;grid-template-columns:1.05fr .95fr;gap:40px;align-items:center}
|
|
@media(max-width:860px){.split{grid-template-columns:1fr;gap:28px}}
|
|
/* ---- cycle de vie ---- */
|
|
.life{display:grid;grid-template-columns:repeat(4,1fr);gap:0}
|
|
.life .step{padding:24px 22px;border:1px solid var(--line-2);border-right:0;background:var(--panel-2);position:relative}
|
|
.life .step:first-child{border-radius:15px 0 0 15px}
|
|
.life .step:last-child{border-right:1px solid var(--line-2);border-radius:0 15px 15px 0}
|
|
.life .step .k{font-family:var(--mono);font-size:.78rem;color:var(--cyan)}
|
|
.life .step h3{font-size:1.02rem;margin:10px 0 7px;font-weight:680}
|
|
.life .step p{color:var(--dim);font-size:.9rem}
|
|
@media(max-width:820px){.life{grid-template-columns:1fr}.life .step{border-right:1px solid var(--line-2);border-bottom:0}.life .step:first-child{border-radius:15px 15px 0 0}.life .step:last-child{border-radius:0 0 15px 15px}}
|
|
/* ---- preuve : traits ---- */
|
|
.proof{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
|
|
@media(max-width:820px){.proof{grid-template-columns:1fr}}
|
|
.pf{background:var(--panel);border:1px solid var(--line);border-radius:16px;padding:24px}
|
|
.pf h3{font-size:1.1rem;font-weight:700;margin-bottom:10px;display:flex;align-items:center;gap:10px}
|
|
.pf h3 svg{width:20px;height:20px}
|
|
.pf p{color:var(--dim);font-size:.95rem}
|
|
.pf code{font-family:var(--mono);color:var(--teal);font-size:.85em}
|
|
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:16px;margin-bottom:34px}
|
|
.stat{background:var(--panel-2);border:1px solid var(--line-2);border-radius:15px;padding:22px}
|
|
.stat b{display:block;font-size:1.9rem;font-weight:800;font-variant-numeric:tabular-nums}
|
|
.stat b .grad{font-weight:800}
|
|
.stat span{color:var(--dim);font-size:.86rem}
|
|
/* ---- feuille de route ---- */
|
|
.roadmap{display:flex;flex-wrap:wrap;gap:14px}
|
|
.rm{flex:1 1 260px;border:1px dashed rgba(169,139,255,.4);border-radius:14px;padding:20px 22px;background:rgba(169,139,255,.05)}
|
|
.rm .k{font-family:var(--mono);font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;color:var(--violet)}
|
|
.rm h3{font-size:1.05rem;margin:9px 0 6px;font-weight:680}
|
|
.rm p{color:var(--dim);font-size:.9rem}
|
|
/* ---- clôture ---- */
|
|
.st{display:inline-flex;align-items:center;gap:6px;font-family:var(--mono);font-size:.7rem;letter-spacing:.07em;text-transform:uppercase;padding:4px 10px;border-radius:999px;white-space:nowrap;margin-left:auto;flex:none}
|
|
.st.ok{color:#7ff0d0;background:rgba(79,227,193,.12);border:1px solid rgba(79,227,193,.32)}
|
|
.st.wip{color:#ffd79a;background:rgba(255,196,107,.1);border:1px solid rgba(255,196,107,.3)}
|
|
.st.road{color:#c3b2ff;background:rgba(169,139,255,.1);border:1px solid rgba(169,139,255,.3)}
|
|
.honest{background:var(--panel-2);border:1px solid var(--line);border-left:3px solid var(--amber);border-radius:14px;padding:24px 26px}
|
|
.honest h3{font-size:1.04rem;font-weight:700;margin-bottom:12px;color:var(--amber)}
|
|
.honest ul{margin:0;padding-left:20px;display:grid;gap:10px}
|
|
.honest li{color:var(--dim);font-size:.95rem}
|
|
.honest b{color:var(--ink);font-weight:640}
|
|
.close{text-align:center;padding:88px 0 96px}
|
|
.close h2{font-size:clamp(1.9rem,4.6vw,3.1rem);font-weight:800;letter-spacing:-.02em;max-width:20ch;margin-inline:auto}
|
|
.close p{margin:20px auto 0;color:var(--dim);max-width:56ch;font-size:1.06rem}
|
|
.close .cta-row{justify-content:center}
|
|
.closing{text-align:center;padding:96px 0 40px}
|
|
.closing h2{font-size:clamp(2rem,4.4vw,3.2rem);font-weight:800;letter-spacing:-.02em;max-width:18ch;margin-inline:auto}
|
|
.closing p{margin:20px auto 0;color:var(--dim);max-width:52ch;font-size:1.08rem}
|
|
footer{border-top:1px solid var(--line-2);padding:40px 0;color:var(--dim-2);font-size:.9rem}
|
|
footer .wrap{display:flex;flex-wrap:wrap;gap:16px 28px;align-items:center;justify-content:space-between}
|
|
footer .brand{opacity:.95}
|
|
footer .meta{margin-left:auto;display:flex;flex-wrap:wrap;gap:6px 22px;font-size:.86rem}
|
|
footer .meta span b{color:var(--ink);font-weight:600}
|
|
footer a{color:var(--dim);text-decoration:none}
|
|
/* ---- révélations au scroll ---- */
|
|
.reveal{opacity:0;transform:translateY(16px);transition:opacity .6s ease,transform .6s ease}
|
|
.reveal.in{opacity:1;transform:none}
|
|
:focus-visible{outline:2px solid var(--cyan);outline-offset:3px;border-radius:6px}
|
|
@media(prefers-reduced-motion:reduce){
|
|
.aurora{animation:none}
|
|
.reveal{opacity:1;transform:none;transition:none}
|
|
html{scroll-behavior:auto}
|
|
}
|
|
</style>
|
|
|
|
<div id="sky" aria-hidden="true"><canvas></canvas></div>
|
|
<div class="aurora" aria-hidden="true"></div>
|
|
|
|
<!-- =================== NAV =================== -->
|
|
<header class="nav">
|
|
<div class="wrap">
|
|
<a class="brand" href="#top" aria-label="Set-OPS — Chezlepro">
|
|
<svg viewBox="0 0 32 32" role="img" aria-hidden="true"><defs>
|
|
<radialGradient id="sky1" cx="50%" cy="36%" r="75%"><stop offset="0%" stop-color="#10184a"/><stop offset="100%" stop-color="#05060f"/></radialGradient>
|
|
<linearGradient id="au1" x1="0" y1="1" x2="1" y2="0"><stop offset="0%" stop-color="#2ec18f"/><stop offset="45%" stop-color="#56c2ff"/><stop offset="100%" stop-color="#a98bff"/></linearGradient>
|
|
<radialGradient id="gl1" cx="50%" cy="50%" r="50%"><stop offset="0%" stop-color="#bfe9ff"/><stop offset="100%" stop-color="#bfe9ff" stop-opacity="0"/></radialGradient>
|
|
<radialGradient id="st1" cx="50%" cy="45%" r="60%"><stop offset="0%" stop-color="#fff"/><stop offset="100%" stop-color="#d6ecff"/></radialGradient>
|
|
</defs>
|
|
<circle cx="16" cy="16" r="16" fill="url(#sky1)"/>
|
|
<path d="M3 21 C 9 16, 13 23, 18 18 C 22 14, 26 17, 30 13" fill="none" stroke="url(#au1)" stroke-width="2.6" stroke-linecap="round" opacity=".85"/>
|
|
<circle cx="7" cy="9" r=".9" fill="#cfe6ff"/><circle cx="24" cy="8" r="1.1" fill="#fff"/><circle cx="26" cy="22" r=".8" fill="#bfe9ff"/><circle cx="9" cy="25" r=".7" fill="#cfe6ff"/>
|
|
<circle cx="16" cy="15" r="9" fill="url(#gl1)" opacity=".55"/>
|
|
<path d="M16 5 C 16.9 12.4, 17.6 13.1, 25 14 C 17.6 14.9, 16.9 15.6, 16 23 C 15.1 15.6, 14.4 14.9, 7 14 C 14.4 13.1, 15.1 12.4, 16 5 Z" fill="url(#st1)"/>
|
|
</svg>
|
|
<span>Set‑OPS <b>·</b> <span style="color:var(--dim);font-weight:500">Chezlepro</span></span>
|
|
</a>
|
|
<nav>
|
|
<a href="index.html" aria-current="page">Capacités</a>
|
|
<a href="offres.html">Offres</a>
|
|
<a href="tarifs.html">Tarifs</a>
|
|
<a href="valeur.html">Valeur</a>
|
|
<a class="cta-mini" href="https://chezlepro.ca/contact">Nous parler</a>
|
|
</nav>
|
|
</div>
|
|
</header>
|
|
|
|
<a id="top"></a>
|
|
<!-- =================== HÉROS =================== -->
|
|
<div class="hero">
|
|
<div class="wrap">
|
|
<span class="eyebrow">Alliance Boréale · moteur d'écosystèmes souverains</span>
|
|
<h1>Votre écosystème numérique, <span class="grad">souverain</span> — et prouvé.</h1>
|
|
<p class="lede">Set‑OPS est un moteur Ansible qui <b style="color:var(--ink)">construit et exploite tout un écosystème interne</b> — identité, confiance, DNS, données, courriel, observabilité, forge — sur <b style="color:var(--ink)">votre propre grappe Proxmox</b>. À partir d'un plan déclaratif. Sans SaaS. Sans conteneur propriétaire. Et exploitable <b style="color:var(--ink)">sans aucune IA</b>.</p>
|
|
<div class="cta-row">
|
|
<a class="btn btn-primary" href="#capacites">Voir tout ce qu'il sait faire →</a>
|
|
<a class="btn btn-ghost" href="#demarrer">De zéro à votre écosystème</a>
|
|
</div>
|
|
<div class="flow" aria-label="flux de travail">
|
|
<code>édite le plan</code><span class="arw">→</span>
|
|
<code>make instancier</code><span class="arw">→</span>
|
|
<code>make deployer</code><span class="arw">→</span>
|
|
<code>make prouver</code>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- =================== MÉTHODE =================== -->
|
|
<section id="methode">
|
|
<div class="wrap">
|
|
<div class="sec-head reveal">
|
|
<span class="eyebrow">La méthode</span>
|
|
<h2>Vous décrivez. Le moteur génère. Ansible déploie. <span class="grad">La preuve suit.</span></h2>
|
|
<p>Set‑OPS se pilote par un <b style="color:var(--ink)">plan</b>, pas par l'édition de l'inventaire. Les registres sont la source unique de vérité ; l'inventaire Ansible en est dérivé. Vous ne touchez jamais <code style="font-family:var(--mono);color:var(--teal)">hosts.yml</code> à la main.</p>
|
|
</div>
|
|
<div class="beats">
|
|
<div class="beat reveal"><div class="n">01 · décrire</div><h3>Un plan déclaratif</h3><p>Serveurs, applications, bases, domaines, nomenclature — des registres lisibles par la machine, votre seule source de vérité.</p></div>
|
|
<div class="beat reveal"><div class="n">02 · générer</div><h3>Un inventaire dérivé</h3><p>VMID, IP, VLAN et passerelle sont <b style="color:var(--ink)">dérivés</b> de la fonction. <code style="font-family:var(--mono);color:var(--teal)">make instancier</code> montre le diff avant d'appliquer.</p></div>
|
|
<div class="beat reveal"><div class="n">03 · déployer</div><h3>Par groupes, en couches</h3><p>Chaque groupe a son playbook homonyme. L'orchestrateur déploie socle → PKI → services → apps → agents, dans l'ordre.</p></div>
|
|
<div class="beat reveal"><div class="n">04 · prouver</div><h3>Une preuve rejouable</h3><p><code style="font-family:var(--mono);color:var(--teal)">make prouver</code> rejoue les vérifications et produit un rapport horodaté. Le dépôt n'affirme jamais plus qu'il ne prouve.</p></div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<hr class="rule">
|
|
|
|
<!-- =================== CAPACITÉS =================== -->
|
|
<section id="capacites">
|
|
<div class="wrap">
|
|
<div class="sec-head reveal">
|
|
<span class="eyebrow">Tout ce qu'il sait faire</span>
|
|
<h2>Sept piliers. Un écosystème complet, <span class="grad">natif, chiffré, relié.</span></h2>
|
|
<p>Tout ce qu'un hébergeur met en ligne, Set‑OPS le tient en interne — en logiciel libre, sur systemd et paquets, sans dépendance à un géant. Voici, pilier par pilier, ce qu'il déploie et exploite. <b style="color:var(--ink)">Le badge <span class="st ok" style="margin:0">Éprouvé</span> marque ce qui tourne sur des VM réelles</b> ; <span class="st road" style="margin:0">Feuille de route</span> ce qui est planifié.</p>
|
|
</div>
|
|
|
|
<div class="pillars">
|
|
|
|
<!-- Identité -->
|
|
<article class="card reveal">
|
|
<div class="kick">
|
|
<span class="dot"><svg viewBox="0 0 24 24" fill="none" stroke="#56c2ff" stroke-width="1.8"><circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 4-6 8-6s8 2 8 6"/></svg></span>
|
|
<h3>Identité & accès</h3>
|
|
<span class="st ok">Éprouvé</span>
|
|
</div>
|
|
<p class="sub">Une identité, un mot de passe, pour tout le parc.</p>
|
|
<div class="chips"><span class="chip">OpenLDAP</span><span class="chip">Keycloak</span><span class="chip">oauth2-proxy</span><span class="chip">OIDC · RBAC</span></div>
|
|
<ul class="does">
|
|
<li><b>Un annuaire central</b> (OpenLDAP) source unique des identités.</li>
|
|
<li><b>SSO web</b> via Keycloak, qui fédère l'annuaire — « se connecter avec votre organisation ».</li>
|
|
<li><b>Mets n'importe quelle app derrière le SSO</b> avec oauth2-proxy, même sans OIDC natif.</li>
|
|
<li><b>RBAC</b> : des rôles de realm pilotent les niveaux d'accès (ex. Grafana Admin/Editor/Viewer).</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<!-- PKI -->
|
|
<article class="card reveal">
|
|
<div class="kick">
|
|
<span class="dot"><svg viewBox="0 0 24 24" fill="none" stroke="#56c2ff" stroke-width="1.8"><path d="M12 2l7 3v6c0 5-3 8-7 9-4-1-7-4-7-9V5z"/><path d="M9 12l2 2 4-4"/></svg></span>
|
|
<h3>Confiance & PKI</h3>
|
|
<span class="st ok">Éprouvé</span>
|
|
</div>
|
|
<p class="sub">Votre propre autorité de certification. Tout le trafic interne, chiffré et vérifié.</p>
|
|
<div class="chips"><span class="chip">step-ca</span><span class="chip">ACME</span><span class="chip">client_pki</span><span class="chip">mTLS</span></div>
|
|
<ul class="does">
|
|
<li><b>Une AC interne</b> (step-ca) qui émet les certificats par ACME.</li>
|
|
<li><b>Certificats d'hôte auto-renouvelés</b>, avec rechargement des vrais consommateurs.</li>
|
|
<li><b>Zéro-confiance est-ouest</b> : PostgreSQL en <code>verify-full</code>, LDAPS, métriques & logs en HTTPS, LMTP vérifié.</li>
|
|
<li><b>Aucune dépendance</b> à une AC publique pour la confiance interne.</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<!-- DNS & réseau -->
|
|
<article class="card reveal">
|
|
<div class="kick">
|
|
<span class="dot"><svg viewBox="0 0 24 24" fill="none" stroke="#56c2ff" stroke-width="1.8"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18"/></svg></span>
|
|
<h3>Nommage & réseau</h3>
|
|
<span class="st ok">Éprouvé</span>
|
|
</div>
|
|
<p class="sub">Un DNS interne cohérent, et un réseau convergé multi-tenant.</p>
|
|
<div class="chips"><span class="chip">PowerDNS</span><span class="chip">Unbound</span><span class="chip">VLAN dérivé</span><span class="chip">make devis-reseau</span></div>
|
|
<ul class="does">
|
|
<li><b>DNS autoritatif interne</b> (PowerDNS) : les enregistrements d'exposition se dérivent du plan.</li>
|
|
<li><b>Résolveur local</b> (Unbound) + plancher <code>/etc/hosts</code>, sans casser Internet.</li>
|
|
<li><b>Réseau convergé 10/8</b>, VLAN dérivé par tenant, isolation inter-tenant.</li>
|
|
<li><b>Config du switch générée</b> (VLANs, passerelles, ACLs) depuis les nomenclatures.</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<!-- Données -->
|
|
<article class="card reveal">
|
|
<div class="kick">
|
|
<span class="dot"><svg viewBox="0 0 24 24" fill="none" stroke="#56c2ff" stroke-width="1.8"><ellipse cx="12" cy="5" rx="8" ry="3"/><path d="M4 5v14c0 1.7 3.6 3 8 3s8-1.3 8-3V5"/><path d="M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3"/></svg></span>
|
|
<h3>Données</h3>
|
|
<span class="st ok">Éprouvé</span>
|
|
</div>
|
|
<p class="sub">Bases relationnelles et cache, provisionnés depuis le registre.</p>
|
|
<div class="chips"><span class="chip">PostgreSQL</span><span class="chip">Redis</span><span class="chip">TLS verify-full</span><span class="chip">binding app→base</span></div>
|
|
<ul class="does">
|
|
<li><b>PostgreSQL</b> provisionne ses bases & rôles depuis le registre — le secret ne quitte jamais le rôle.</li>
|
|
<li><b>Chiffrement obligatoire</b> : la base refuse toute connexion non-TLS du réseau.</li>
|
|
<li><b>Cache réseau Redis</b> authentifié (accès sans mot de passe refusé).</li>
|
|
<li><b>Liens déclaratifs</b> : une app se relie à sa base sans group_vars codés en dur.</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<!-- Courriel -->
|
|
<article class="card reveal">
|
|
<div class="kick">
|
|
<span class="dot"><svg viewBox="0 0 24 24" fill="none" stroke="#56c2ff" stroke-width="1.8"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 7l9 6 9-6"/></svg></span>
|
|
<h3>Courriel souverain</h3>
|
|
<span class="st ok">Éprouvé</span>
|
|
</div>
|
|
<p class="sub">Recevoir <i>et</i> envoyer, de bout en bout, sur votre infrastructure.</p>
|
|
<div class="chips"><span class="chip">Postfix</span><span class="chip">Dovecot</span><span class="chip">rspamd</span><span class="chip">DKIM · SASL</span></div>
|
|
<ul class="does">
|
|
<li><b>MTA Postfix</b> + soumission <code>:587</code> authentifiée (SASL déléguée à Dovecot).</li>
|
|
<li><b>Boîtes Dovecot</b> (IMAP, Maildir), utilisateurs résolus sur l'annuaire LDAP.</li>
|
|
<li><b>Antispam & signature</b> : rspamd + DKIM. Flux prouvé SMTP→LDAP→LMTP→IMAP.</li>
|
|
<li><b>Interne de bout en bout</b> — aucune fuite vers un tiers.</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<!-- Edge / TLS -->
|
|
<article class="card reveal">
|
|
<div class="kick">
|
|
<span class="dot"><svg viewBox="0 0 24 24" fill="none" stroke="#56c2ff" stroke-width="1.8"><path d="M4 12h16M4 12a8 8 0 0116 0M4 12a8 8 0 0016 0"/><rect x="9" y="9" width="6" height="6" rx="1" fill="#56c2ff" stroke="none" opacity=".5"/></svg></span>
|
|
<h3>Reverse-proxy & TLS</h3>
|
|
<span class="st ok">Éprouvé</span>
|
|
</div>
|
|
<p class="sub">Déclare une exposition — tout le reste se dérive.</p>
|
|
<div class="chips"><span class="chip">nginx edge</span><span class="chip">TLS step-ca</span><span class="chip">X-Forwarded</span><span class="chip">WAF</span></div>
|
|
<ul class="does">
|
|
<li>Un champ <code>expose</code> produit <b>vhost + SAN de cert + enregistrement DNS + alias plancher</b>, auto-dérivés.</li>
|
|
<li><b>Terminaison TLS</b> avec le cert step-ca (chaîne validée, plus de snakeoil).</li>
|
|
<li><b>Un seul edge</b> route tout le trafic HTTP(S) externe vers les services internes.</li>
|
|
<li>Prêt pour une <b>frontière publique OPNsense</b> en bordure.</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<!-- Observabilité -->
|
|
<article class="card reveal">
|
|
<div class="kick">
|
|
<span class="dot"><svg viewBox="0 0 24 24" fill="none" stroke="#56c2ff" stroke-width="1.8"><path d="M3 17l5-6 4 4 5-8 4 6"/><path d="M3 21h18"/></svg></span>
|
|
<h3>Observabilité & supervision</h3>
|
|
<span class="st ok">Éprouvé</span>
|
|
</div>
|
|
<p class="sub">Voir toute la flotte : métriques, journaux, tableaux de bord, impact.</p>
|
|
<div class="chips"><span class="chip">Prometheus</span><span class="chip">Loki</span><span class="chip">Grafana</span><span class="chip">Icinga2 · BPM</span></div>
|
|
<ul class="does">
|
|
<li><b>Métriques</b> (Prometheus scrape la flotte en HTTPS) & <b>journaux</b> centralisés (Loki).</li>
|
|
<li><b>Tableaux de bord Grafana</b>, accès par le SSO, dashboards provisionnés.</li>
|
|
<li><b>Supervision active</b> Icinga2 + IcingaDB + Icinga Web 2, sous SSO.</li>
|
|
<li><b>Impact métier (BPM)</b> : agrège des services en processus métier — irremplaçable par un graphe.</li>
|
|
</ul>
|
|
</article>
|
|
|
|
<!-- Applicatif -->
|
|
<article class="card reveal">
|
|
<div class="kick">
|
|
<span class="dot"><svg viewBox="0 0 24 24" fill="none" stroke="#56c2ff" stroke-width="1.8"><path d="M8 18l-5-6 5-6M16 6l5 6-5 6M13 4l-2 16"/></svg></span>
|
|
<h3>Applicatif & forge</h3>
|
|
<span class="st ok">Éprouvé</span>
|
|
</div>
|
|
<p class="sub">Vos services internes, adossés à l'identité commune.</p>
|
|
<div class="chips"><span class="chip">Forgejo</span><span class="chip">SSO OIDC</span><span class="chip">branding</span></div>
|
|
<ul class="does">
|
|
<li><b>Forge Git Forgejo</b> : dépôts, CI, wiki — <b>branchée au SSO</b>, comptes auto-créés depuis l'annuaire.</li>
|
|
<li><b>Adossée à PostgreSQL</b> (base provisionnée depuis le registre) et exposée par l'edge.</li>
|
|
<li><b>Identité visuelle</b> par le mécanisme officiel (pas de fork), résistante aux mises à jour.</li>
|
|
<li>La couche <b>collaboration & web applicative</b> arrive — voir la feuille de route.</li>
|
|
</ul>
|
|
</article>
|
|
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<hr class="rule">
|
|
|
|
<!-- =================== SOCLE & MÉTHODE TRANSVERSE =================== -->
|
|
<section>
|
|
<div class="wrap">
|
|
<div class="sec-head reveal">
|
|
<span class="eyebrow">Le socle & la méthode</span>
|
|
<h2>Ce qui traverse <span class="grad">toutes les VM.</span></h2>
|
|
<p>Sous les piliers, un socle commun tient l'ensemble : durcissement, pare-feu, sauvegardes, et l'outillage qui rend le tout reproductible.</p>
|
|
</div>
|
|
<div class="pillars">
|
|
<article class="card reveal">
|
|
<div class="kick"><span class="dot"><svg viewBox="0 0 24 24" fill="none" stroke="#56c2ff" stroke-width="1.8"><path d="M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z"/></svg></span><h3>Durcissement par défaut</h3></div>
|
|
<p class="sub">Chaque VM naît sécurisée.</p>
|
|
<div class="chips"><span class="chip">SSH clé-only</span><span class="chip">AppArmor</span><span class="chip">auditd</span><span class="chip">fail2ban</span><span class="chip">unattended-upgrades</span></div>
|
|
<ul class="does">
|
|
<li><b>Accès SSH par clé dès le départ</b> (mot de passe désactivé, <code>AuthenticationMethods publickey</code>).</li>
|
|
<li><b>AppArmor, auditd, fail2ban, sysctl, journald</b> — appliqués par le groupe socle.</li>
|
|
<li><b>nftables préparé</b> dans le template, activé au bon moment sur les clones.</li>
|
|
</ul>
|
|
</article>
|
|
<article class="card reveal">
|
|
<div class="kick"><span class="dot"><svg viewBox="0 0 24 24" fill="none" stroke="#56c2ff" stroke-width="1.8"><path d="M4 6h16M4 12h16M4 18h16"/><circle cx="8" cy="6" r="2" fill="#05060f"/><circle cx="16" cy="12" r="2" fill="#05060f"/><circle cx="9" cy="18" r="2" fill="#05060f"/></svg></span><h3>Pare-feu est-ouest</h3></div>
|
|
<p class="sub">Moindre privilège, dérivé du registre des flux.</p>
|
|
<div class="chips"><span class="chip">nftables</span><span class="chip">registre des flux</span><span class="chip">policy drop</span></div>
|
|
<ul class="does">
|
|
<li><b>Qui-parle-à-qui</b> déclaré dans un registre de flux (port, sens, pair, chiffrement, raison).</li>
|
|
<li><b>Règles par hôte générées</b> : <code>ip saddr</code> = moindre privilège, reste refusé.</li>
|
|
<li>Le même registre alimente <b>nftables interne et OPNsense</b> en bordure.</li>
|
|
</ul>
|
|
</article>
|
|
<article class="card reveal">
|
|
<div class="kick"><span class="dot"><svg viewBox="0 0 24 24" fill="none" stroke="#56c2ff" stroke-width="1.8"><path d="M21 12a9 9 0 11-3-6.7M21 4v5h-5"/></svg></span><h3>Sauvegardes 3-2-1</h3></div>
|
|
<p class="sub">L'état, pas les VM — car l'infra se reconstruit par le code.</p>
|
|
<div class="chips"><span class="chip">restic</span><span class="chip">chiffré</span><span class="chip">jobs déclaratifs</span><span class="chip">Tier 0</span></div>
|
|
<ul class="does">
|
|
<li><b>Sauvegardes restic hors-nœud, chiffrées</b>, avec rétention automatique.</li>
|
|
<li><b>Jobs déclaratifs</b> par nœud (dumps PG, LDIF, Maildir, dépôts Git, clés d'AC).</li>
|
|
<li><b>Restauration prouvée</b>, jusqu'au Tier 0 (les clés de l'autorité de certification).</li>
|
|
</ul>
|
|
</article>
|
|
<article class="card reveal">
|
|
<div class="kick"><span class="dot"><svg viewBox="0 0 24 24" fill="none" stroke="#56c2ff" stroke-width="1.8"><rect x="3" y="4" width="18" height="14" rx="2"/><path d="M8 21h8M12 18v3M7 9l2 2-2 2M12 13h4"/></svg></span><h3>Le plan & le GUI</h3></div>
|
|
<p class="sub">Une source unique, éditable en ligne de commande ou à l'écran.</p>
|
|
<div class="chips"><span class="chip">registres</span><span class="chip">GUI local</span><span class="chip">bindings</span><span class="chip">orchestrateur</span></div>
|
|
<ul class="does">
|
|
<li><b>Interface locale</b> (<code>make inventaire-ui</code>) : vues Serveurs, Applications, Domaines, Réseau, Flux, Couches.</li>
|
|
<li><b>Bindings déclaratifs</b> : les relations service→service vivent dans le plan.</li>
|
|
<li><b>Orchestrateur en couches</b> : un point d'entrée ordonné, déterministe, généré.</li>
|
|
</ul>
|
|
</article>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<hr class="rule">
|
|
|
|
<!-- =================== CONSOLE OPÉRATEUR =================== -->
|
|
<section id="demarrer">
|
|
<div class="wrap split">
|
|
<div class="reveal">
|
|
<span class="eyebrow">La console de l'opérateur</span>
|
|
<h2 style="font-size:clamp(1.75rem,3.2vw,2.5rem);font-weight:750;letter-spacing:-.015em;margin-top:14px">De la grappe nue à <span class="grad">l'écosystème vivant.</span></h2>
|
|
<p class="lede" style="margin-top:16px">Tout passe par <code style="font-family:var(--mono);color:var(--teal)">make</code> et un plan. Un modèle générique <code style="font-family:var(--mono);color:var(--teal)">socle</code> — DNS, AC/PKI, edge TLS, courriel — est prêt à copier, renseigner, déployer. Puis vous vivez dans le plan.</p>
|
|
<ul class="does" style="margin-top:20px">
|
|
<li><b>Golden template</b> Debian 13 construit une fois, cloné pour chaque VM.</li>
|
|
<li><b>Clone Proxmox + cloud-init</b> pour l'identité initiale, puis conformité par groupes.</li>
|
|
<li><b>Reconstruction from-zero en une commande</b> — crée les VM manquantes puis déploie tout.</li>
|
|
<li><b>Multi-tenant portable</b> : une instance par écosystème, prouvée par reconstruction.</li>
|
|
</ul>
|
|
</div>
|
|
<div class="console reveal" role="img" aria-label="Exemple de session make de Set-OPS">
|
|
<div class="bar"><i></i><i></i><i></i><span>opérateur@pilote — set-ops</span></div>
|
|
<pre><span class="c"># 1 · copier un modèle, le renseigner, générer l'inventaire</span>
|
|
<span class="p">$ cp -r exemples/modeles/socle ../mon-instance && ln -s ../mon-instance instance</span>
|
|
<span class="p">$ make instancier-appliquer</span> <span class="c">FORCE=1</span>
|
|
<span class="o">production/hosts.yml généré depuis le plan.</span>
|
|
|
|
<span class="c"># 2 · construire le template, créer les VM, déployer la flotte</span>
|
|
<span class="p">$ make preparer-modele</span> <span class="c"># socle + durcissement + cloud-init</span>
|
|
<span class="p">$ make reconstruire</span> <span class="c">CONFIRMER=true</span> <span class="c"># crée les VM PUIS déploie tout</span>
|
|
<span class="o">13 hôtes déployés · 0 échec</span>
|
|
|
|
<span class="c"># 3 · valider et PROUVER</span>
|
|
<span class="p">$ make valider</span> <span class="c"># recette fonctionnelle</span>
|
|
<span class="o">Prometheus 6/6 UP · 6 vhosts HTTPS · courriel bout-en-bout · 6 dépôts restaurés</span>
|
|
<span class="p">$ make prouver</span>
|
|
<span class="g">CONFORME : 16 OK, 0 échec, 0 sauté → docs/audit/preuve-AAAA-MM-JJ.md</span>
|
|
</pre>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<hr class="rule">
|
|
|
|
<!-- =================== CYCLE DE VIE =================== -->
|
|
<section>
|
|
<div class="wrap">
|
|
<div class="sec-head reveal">
|
|
<span class="eyebrow">Cycle de vie</span>
|
|
<h2>Du template nu à la flotte, <span class="grad">et retour à zéro.</span></h2>
|
|
</div>
|
|
<div class="life reveal">
|
|
<div class="step"><div class="k">socle</div><h3>Goldeniser</h3><p>Une VM Debian 13 minimale devient le golden template : socle, durcissement, cloud-init, qemu-guest-agent.</p></div>
|
|
<div class="step"><div class="k">clone</div><h3>Cloner & identifier</h3><p>Clone via l'API Proxmox ; cloud-init donne hostname, clé, IP, DNS. VMID/IP/VLAN lus dans le plan.</p></div>
|
|
<div class="step"><div class="k">conformité</div><h3>Converger</h3><p>Les playbooks de groupes appliquent l'état voulu, relançables sans effet de bord. La flotte converge.</p></div>
|
|
<div class="step"><div class="k">from-zero</div><h3>Reconstruire</h3><p>Tout supprimer, puis <code>make myDay</code> : l'écosystème renaît du code — la preuve de portabilité sans réserve.</p></div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<hr class="rule">
|
|
|
|
<!-- =================== PREUVE & SOUVERAINETÉ =================== -->
|
|
<section id="preuve">
|
|
<div class="wrap">
|
|
<div class="sec-head reveal">
|
|
<span class="eyebrow">Preuve & souveraineté</span>
|
|
<h2>Il ne fait pas que le dire. <span class="grad">Il le prouve.</span></h2>
|
|
<p>Un outil d'exploitation réelle, pas une démonstration. Chaque affirmation publique est tracée vers une commande de preuve rejouable — ou corrigée.</p>
|
|
</div>
|
|
<div class="proof">
|
|
<div class="pf reveal"><h3><svg viewBox="0 0 24 24" fill="none" stroke="#4fe3c1" stroke-width="1.9"><path d="M20 6L9 17l-5-5"/></svg>Vérifier</h3><p><code>make verifier</code> enchaîne lint, tests, cohérence, syntaxe <b style="color:var(--ink)">et les preuves</b>. Un dépôt qui se tient droit.</p></div>
|
|
<div class="pf reveal"><h3><svg viewBox="0 0 24 24" fill="none" stroke="#4fe3c1" stroke-width="1.9"><path d="M9 12l2 2 4-4"/><circle cx="12" cy="12" r="9"/></svg>Prouver</h3><p><code>make prouver</code> produit un rapport <b style="color:var(--ink)">horodaté et rejouable</b> — 16 preuves reliées au registre des affirmations. Une pièce justificative.</p></div>
|
|
<div class="pf reveal"><h3><svg viewBox="0 0 24 24" fill="none" stroke="#4fe3c1" stroke-width="1.9"><path d="M3 12h4l3 8 4-16 3 8h4"/></svg>Valider</h3><p><code>make valider</code> : recette fonctionnelle sur la flotte vivante — cibles UP, vhosts HTTPS, courriel livré, sauvegardes restaurées.</p></div>
|
|
</div>
|
|
<div class="stats reveal">
|
|
<div class="stat"><b class="grad">100 %</b><span>logiciel libre (AGPLv3) — rien n'est verrouillé</span></div>
|
|
<div class="stat"><b><span class="grad">0</span></b><span>dépendance SaaS · zéro conteneur propriétaire</span></div>
|
|
<div class="stat"><b><span class="grad">0</span></b><span>IA requise — la doc, <code style="font-family:var(--mono);font-size:.7em;color:var(--teal)">make</code> et le GUI suffisent</span></div>
|
|
<div class="stat"><b class="grad">natif</b><span>systemd + paquets — pas de PaaS, pas de magie</span></div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<hr class="rule">
|
|
|
|
<!-- =================== FEUILLE DE ROUTE =================== -->
|
|
<section>
|
|
<div class="wrap">
|
|
<div class="sec-head reveal">
|
|
<span class="eyebrow">Feuille de route</span>
|
|
<h2>Ce qui arrive — <span class="grad">annoncé, pas surestimé.</span></h2>
|
|
<p>Fidèle au principe : on ne présente jamais comme prêt ce qui ne l'est pas. Ces capacités sont conçues et attendues, en rôles natifs comme les autres.</p>
|
|
</div>
|
|
<div class="roadmap reveal">
|
|
<div class="rm"><div class="k">Collaboration</div><h3>Nextcloud & Collabora</h3><p>Fichiers, agenda, édition en ligne — sous la même identité SSO. Build prioritaire, offre « maison-OBNL ».</p></div>
|
|
<div class="rm"><div class="k">Couche web</div><h3>Frontal & dorsal applicatifs</h3><p>Présentation (UI, assets) et application (API), servis derrière l'edge — pour mettre vos propres applications web en ligne.</p></div>
|
|
<div class="rm"><div class="k">Certification</div><h3>Label Souverain · Résilient · Exemplaire</h3><p>Trois niveaux accumulatifs pour attester la qualité d'un écosystème — garde-fou social inclus.</p></div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- =================== RÉSERVES =================== -->
|
|
<section id="reserves">
|
|
<div class="wrap">
|
|
<div class="sec-head reveal">
|
|
<span class="eyebrow">Honnêteté</span>
|
|
<h2>Ce que nous ne prétendons pas.</h2>
|
|
<p>La règle du projet est écrite dans son dépôt : <i>ne jamais affirmer plus que ce qu'on prouve.</i> Elle s'applique aussi à cette page.</p>
|
|
</div>
|
|
<div class="honest reveal">
|
|
<h3>Nos réserves, en clair</h3>
|
|
<ul>
|
|
<li><b>« Éprouvé » et « feuille de route » ne se mélangent pas.</b> Les capacités marquées éprouvées ont été déployées et vérifiées sur des machines réelles ; les autres sont annoncées comme des intentions, jamais comme des livrables.</li>
|
|
<li><b>Il faut quelqu'un.</b> Set‑OPS réduit énormément le travail d'exploitation ; il ne le supprime pas. Une personne responsable reste nécessaire, à l'interne ou sous contrat.</li>
|
|
<li><b>Le projet repose encore sur un seul mainteneur.</b> C'est le risque principal, et nous le nommons. La documentation, les procédures et le registre de preuves existent précisément pour que le savoir ne vive pas dans une seule tête.</li>
|
|
<li><b>Une épreuve est en cours.</b> Un administrateur système indépendant doit installer l'ensemble à partir de la seule documentation, sans aide et sans IA. Le protocole est public, le résultat sera publié — <i>y compris s'il échoue.</i></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- =================== CLÔTURE =================== -->
|
|
<div class="close">
|
|
<div class="wrap reveal">
|
|
<h2>Reprenez le contrôle de votre <span class="grad">infra numérique</span>.</h2>
|
|
<p>Un plan, votre grappe Proxmox, et tout un écosystème numérique — libre, chiffré, prouvé. Sous le ciel de l'Alliance Boréale.</p>
|
|
<div class="cta-row">
|
|
<a class="btn btn-primary" href="offres.html">Voir les offres →</a>
|
|
<a class="btn btn-ghost" href="valeur.html#calcul">Simuler le coût</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<footer>
|
|
<div class="wrap">
|
|
<div style="display:flex;align-items:center;gap:10px">
|
|
<svg viewBox="0 0 32 32" width="26" height="26" aria-hidden="true">
|
|
<circle cx="16" cy="16" r="16" fill="#0a0d24"/>
|
|
<path d="M3 21 C 9 16, 13 23, 18 18 C 22 14, 26 17, 30 13" fill="none" stroke="#56c2ff" stroke-width="2.4" stroke-linecap="round" opacity=".8"/>
|
|
<path d="M16 6 C 16.8 12.6, 17.4 13.2, 24 14 C 17.4 14.8, 16.8 15.4, 16 22 C 15.2 15.4, 14.6 14.8, 8 14 C 14.6 13.2, 15.2 12.6, 16 6 Z" fill="#e9ecff"/></svg>
|
|
<span>Chezlepro inc. · Saint-Bruno-de-Montarville, Québec</span>
|
|
</div>
|
|
<div><a href="index.html">Capacités</a> · <a href="offres.html">Offres</a> · <a href="tarifs.html">Tarifs</a> · <a href="valeur.html">Valeur</a></div>
|
|
<div>Set‑OPS — moteur libre, licence AGPLv3 · <a href="https://chezlepro.ca">chezlepro.ca</a></div>
|
|
</div>
|
|
</footer>
|
|
|
|
<script>
|
|
(function(){
|
|
var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
|
|
/* ---------- constellation ---------- */
|
|
var sky = document.querySelector('#sky canvas');
|
|
if(sky){
|
|
var ctx = sky.getContext('2d'), W, H, DPR, stars=[], raf;
|
|
function size(){
|
|
DPR = Math.min(window.devicePixelRatio||1, 2);
|
|
W = sky.clientWidth; H = sky.clientHeight;
|
|
sky.width = W*DPR; sky.height = H*DPR; ctx.setTransform(DPR,0,0,DPR,0,0);
|
|
var count = Math.min(120, Math.round(W*H/14000));
|
|
stars = [];
|
|
for(var i=0;i<count;i++){
|
|
stars.push({x:Math.random()*W, y:Math.random()*H,
|
|
r:Math.random()*1.3+0.3, vx:(Math.random()-.5)*0.12, vy:(Math.random()-.5)*0.12,
|
|
tw:Math.random()*Math.PI*2, ts:Math.random()*0.02+0.006});
|
|
}
|
|
}
|
|
function frame(){
|
|
ctx.clearRect(0,0,W,H);
|
|
for(var i=0;i<stars.length;i++){
|
|
var s=stars[i];
|
|
if(!reduce){ s.x+=s.vx; s.y+=s.vy; s.tw+=s.ts;
|
|
if(s.x<0)s.x+=W; if(s.x>W)s.x-=W; if(s.y<0)s.y+=H; if(s.y>H)s.y-=H; }
|
|
var a = 0.5 + Math.sin(s.tw)*0.4;
|
|
ctx.beginPath(); ctx.arc(s.x,s.y,s.r,0,6.2832);
|
|
ctx.fillStyle='rgba(207,230,255,'+a.toFixed(3)+')'; ctx.fill();
|
|
}
|
|
/* liens de constellation */
|
|
for(var i=0;i<stars.length;i++){
|
|
for(var j=i+1;j<stars.length;j++){
|
|
var dx=stars[i].x-stars[j].x, dy=stars[i].y-stars[j].y, d=dx*dx+dy*dy;
|
|
if(d<10000){
|
|
var o=(1-d/10000)*0.22;
|
|
ctx.strokeStyle='rgba(86,194,255,'+o.toFixed(3)+')'; ctx.lineWidth=0.6;
|
|
ctx.beginPath(); ctx.moveTo(stars[i].x,stars[i].y); ctx.lineTo(stars[j].x,stars[j].y); ctx.stroke();
|
|
}
|
|
}
|
|
}
|
|
if(!reduce) raf=requestAnimationFrame(frame);
|
|
}
|
|
size(); frame();
|
|
if(reduce){ /* dessin unique déjà fait */ }
|
|
var to; window.addEventListener('resize',function(){ clearTimeout(to); to=setTimeout(function(){ cancelAnimationFrame(raf); size(); frame(); },180); });
|
|
document.addEventListener('visibilitychange',function(){
|
|
if(document.hidden){ cancelAnimationFrame(raf); } else if(!reduce){ raf=requestAnimationFrame(frame); }
|
|
});
|
|
}
|
|
|
|
/* ---------- révélations au scroll ---------- */
|
|
var els = document.querySelectorAll('.reveal');
|
|
if(reduce || !('IntersectionObserver' in window)){
|
|
els.forEach(function(e){ e.classList.add('in'); });
|
|
} else {
|
|
var io = new IntersectionObserver(function(entries){
|
|
entries.forEach(function(en){ if(en.isIntersecting){ en.target.classList.add('in'); io.unobserve(en.target); } });
|
|
}, {rootMargin:'0px 0px -8% 0px', threshold:0.08});
|
|
els.forEach(function(e){ io.observe(e); });
|
|
}
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|