cv-web-liabeuf/infrastructure.html
LIABEUF, Stephane (External) 773cc71613 securisation d'acces à la page
2026-06-24 07:06:24 +02:00

992 lines
No EOL
25 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Mon Code · Mon Infrastructure · Ma Maîtrise</title>
<link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="shortcut icon" href="favicon.svg">
<style>
:root {
--bg: #02060d;
--panel: rgba(4, 10, 18, .88);
--text: #f5fbff;
--muted: #a9b6c7;
--blue: #00a8ff;
--purple: #b457ff;
--green: #20ef67;
--cyan: #56ffe3;
--orange: #ff9c13;
--line: rgba(255, 255, 255, .12);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
color: var(--text);
background:
radial-gradient(circle at 18% 28%, rgba(0, 168, 255, .22), transparent 28%),
radial-gradient(circle at 52% 18%, rgba(180, 87, 255, .17), transparent 24%),
radial-gradient(circle at 72% 45%, rgba(32, 239, 103, .18), transparent 28%),
radial-gradient(circle at 86% 18%, rgba(255, 156, 19, .12), transparent 24%),
linear-gradient(180deg, #03070d, #010309 65%, #000);
overflow-x: hidden;
}
body::before {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
background-image:
linear-gradient(rgba(255, 255, 255, .035) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, .035) 1px, transparent 1px);
background-size: 48px 48px;
mask-image: radial-gradient(circle at center, #000 0 45%, transparent 72%);
}
.page {
width: min(1880px, 100%);
margin: 0 auto;
padding: 10px 12px 14px;
transform: scale(.82);
transform-origin: top center;
height: 122vh;
}
.pipeline {
display: grid;
grid-template-columns: repeat(5, minmax(250px, 1fr));
gap: 14px;
align-items: stretch;
}
.card {
position: relative;
min-height: 620px;
border: 1px solid var(--accent);
border-radius: 18px;
padding: 16px 16px 14px;
background: linear-gradient(180deg, rgba(255, 255, 255, .045), rgba(255, 255, 255, .012)), var(--panel);
box-shadow: 0 0 30px rgba(var(--rgb), .20), inset 0 0 24px rgba(var(--rgb), .08);
overflow: hidden;
}
.card::after {
content: "";
position: absolute;
inset: -40%;
background: radial-gradient(circle, rgba(var(--rgb), .16), transparent 42%);
opacity: .9;
z-index: -1;
}
.blue {
--accent: var(--blue);
--rgb: 0, 168, 255;
}
.purple {
--accent: var(--purple);
--rgb: 180, 87, 255;
}
.green {
--accent: var(--green);
--rgb: 32, 239, 103;
}
.orange {
--accent: var(--orange);
--rgb: 255, 156, 19;
}
.step-head {
display: grid;
grid-template-columns: 44px minmax(0, 1fr);
gap: 14px;
align-items: center;
margin-bottom: 18px;
}
.badge {
width: 44px;
height: 44px;
display: grid;
place-items: center;
border-radius: 50%;
color: #001018;
font-weight: 900;
font-size: 25px;
background: var(--accent);
box-shadow: 0 0 24px rgba(var(--rgb), .78);
}
h1,
h2,
h3,
p {
margin: 0;
}
h2 {
color: var(--accent);
font-size: clamp(18px, 1.35vw, 28px);
letter-spacing: .03em;
line-height: 1.05;
text-transform: uppercase;
word-break: break-word;
overflow-wrap: break-word;
}
.subtitle {
margin-top: 7px;
color: #fff;
font-weight: 600;
font-size: 15px;
}
.icons-row {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 18px;
margin: 22px 0 24px;
text-align: center;
}
.tool-icon,
.big-icon {
width: 58px;
height: 58px;
margin: 0 auto 8px;
display: grid;
place-items: center;
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, .2);
background: rgba(255, 255, 255, .05);
font-size: 35px;
filter: drop-shadow(0 0 10px rgba(var(--rgb), .4));
}
.mini-label {
color: #fff;
font-size: 14px;
}
.code-window,
.browser-window,
.box {
border: 1px solid rgba(var(--rgb), .75);
border-radius: 12px;
background: rgba(0, 0, 0, .46);
box-shadow: inset 0 0 22px rgba(var(--rgb), .08), 0 0 22px rgba(var(--rgb), .12);
overflow: hidden;
}
.window-top {
height: 33px;
display: flex;
align-items: center;
gap: 7px;
padding: 0 12px;
border-bottom: 1px solid rgba(255, 255, 255, .1);
background: rgba(255, 255, 255, .04);
font-size: 11px;
color: var(--muted);
}
.dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: #ff5f56;
}
.dot:nth-child(2) {
background: #ffbd2e;
}
.dot:nth-child(3) {
background: #27c93f;
}
pre {
margin: 0;
padding: 14px 16px 20px;
color: #8df5ff;
font: 13px/1.6 "SFMono-Regular", Consolas, monospace;
white-space: pre-wrap;
}
.note,
.feature-list,
.status-card {
margin-top: 18px;
padding: 18px;
border: 1px solid rgba(var(--rgb), .58);
border-radius: 12px;
background: rgba(var(--rgb), .055);
color: #fff;
line-height: 1.45;
}
.note strong {
color: var(--accent);
}
.forgejo {
text-align: center;
margin: 16px 0 20px;
}
.brand {
display: inline-flex;
align-items: center;
gap: 12px;
font-size: 34px;
font-weight: 800;
}
.repo {
margin: 20px auto;
width: 78%;
padding: 12px 18px;
border: 1px solid var(--accent);
border-radius: 10px;
color: var(--accent);
background: rgba(var(--rgb), .1);
font-weight: 800;
}
.server-illustration {
width: 180px;
height: 150px;
margin: 18px auto;
border-radius: 50%;
border: 2px solid var(--accent);
background:
radial-gradient(circle at 50% 32%, var(--accent), transparent 8%),
repeating-radial-gradient(circle, rgba(var(--rgb), .24) 0 2px, transparent 3px 22px),
linear-gradient(180deg, rgba(var(--rgb), .35), rgba(0, 0, 0, .15));
box-shadow: 0 0 35px rgba(var(--rgb), .5);
}
.feature-list ul {
list-style: none;
padding: 0;
margin: 0;
}
.feature-list li {
margin: 8px 0;
color: #e7f1ff;
}
.feature-list li::before {
content: "✓";
color: var(--accent);
margin-right: 10px;
}
.radar {
position: relative;
width: 245px;
height: 245px;
margin: 18px auto 24px;
border-radius: 50%;
border: 1px solid rgba(32, 239, 103, .75);
background: repeating-radial-gradient(circle, rgba(32, 239, 103, .23) 0 1px, transparent 2px 24px), linear-gradient(90deg, transparent 49.5%, rgba(32, 239, 103, .55) 50%, transparent 50.5%), linear-gradient(0deg, transparent 49.5%, rgba(32, 239, 103, .55) 50%, transparent 50.5%);
box-shadow: 0 0 45px rgba(32, 239, 103, .35), inset 0 0 30px rgba(32, 239, 103, .15);
overflow: hidden;
}
.radar::before {
content: "";
position: absolute;
inset: 0;
background: conic-gradient(from 0deg, rgba(32, 239, 103, .75), rgba(32, 239, 103, .25) 18deg, transparent 65deg);
animation: scan 3s linear infinite;
}
.radar::after {
content: "C";
position: absolute;
inset: 0;
display: grid;
place-items: center;
font-size: 70px;
font-weight: 900;
color: #8fffe0;
text-shadow: 0 0 22px #20ef67;
}
@keyframes scan {
to {
transform: rotate(360deg);
}
}
.process-box {
display: grid;
grid-template-columns: 56px 1fr;
gap: 14px;
align-items: center;
margin: 12px 0;
padding: 13px 15px;
border: 1px solid rgba(32, 239, 103, .65);
border-radius: 10px;
background: rgba(32, 239, 103, .07);
}
.process-box .icon {
font-size: 34px;
}
.process-box h3 {
font-size: 15px;
margin-bottom: 4px;
}
.process-box p {
color: var(--muted);
font-size: 13px;
}
.url-box {
display: grid;
grid-template-columns: 54px 1fr;
align-items: center;
gap: 14px;
padding: 16px;
margin: 18px 0;
color: #fff;
}
.url-box .globe {
color: var(--orange);
font-size: 42px;
}
.url-box strong {
color: #20ef67;
display: block;
margin-top: 6px;
}
.server-box {
display: grid;
grid-template-columns: 58px 1fr;
gap: 15px;
padding: 20px;
margin: 20px 0;
align-items: center;
}
.server-box .nginx {
width: 56px;
height: 56px;
display: grid;
place-items: center;
background: #099642;
clip-path: polygon(50% 0, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
font-weight: 900;
font-size: 28px;
}
.dynamic h3 {
color: var(--orange);
text-align: center;
margin-bottom: 12px;
}
.dynamic p {
margin: 7px 0;
color: #fff;
}
.dynamic p::before {
content: ">>";
color: var(--orange);
margin-right: 10px;
}
.browser-window {
margin-top: 18px;
}
.browser-content {
padding: 16px;
overflow: hidden;
}
.profile {
display: grid;
grid-template-columns: 70px minmax(0, 1fr);
gap: 12px;
align-items: center;
}
.avatar {
width: 68px;
height: 68px;
border-radius: 50%;
border: 2px solid rgba(255, 255, 255, .4);
background: radial-gradient(circle at 50% 35%, #ffc29b, #1d4f72 46%, #06101d 70%);
box-shadow: 0 0 22px rgba(86, 255, 227, .35);
}
.profile h3 {
font-size: 17px;
line-height: 1.15;
overflow-wrap: anywhere;
}
.profile p {
color: #d8e1ed;
margin-top: 3px;
font-size: 12px;
line-height: 1.25;
}
.btn {
display: inline-block;
margin-top: 8px;
padding: 7px 10px;
border-radius: 6px;
background: var(--green);
color: #00220c;
font-weight: 900;
font-size: 10px;
white-space: nowrap;
}
.menu {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 7px;
margin-top: 16px;
max-width: 100%;
}
.menu div {
min-width: 0;
padding: 8px 3px;
border: 1px solid rgba(255, 255, 255, .14);
border-radius: 8px;
text-align: center;
font-size: 9px;
line-height: 1.15;
overflow: hidden;
word-break: break-word;
overflow-wrap: anywhere;
}
.menu span {
display: block;
font-size: 16px;
line-height: 1;
margin-bottom: 3px;
}
.status-card {
display: grid;
grid-template-columns: 52px 1fr;
align-items: center;
gap: 16px;
font-size: 18px;
}
.status-card .status-icon {
font-size: 38px;
color: var(--green);
}
.flow {
margin: 12px 0 10px;
border: 1px solid rgba(255, 255, 255, .16);
border-radius: 14px;
padding: 10px 14px 12px;
background: rgba(255, 255, 255, .035);
}
.flow h3 {
text-align: center;
letter-spacing: .05em;
margin-bottom: 14px;
}
.flow-row {
display: flex;
flex-wrap: nowrap;
gap: 10px;
justify-content: space-between;
align-items: center;
overflow-x: auto;
padding-bottom: 4px;
}
.flow-item {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
flex-shrink: 0;
}
.flow-ico {
font-size: 38px;
filter: drop-shadow(0 0 10px rgba(32, 239, 103, .55));
}
.arrow {
color: var(--accent, var(--green));
font-size: 24px;
text-shadow: 0 0 10px currentColor;
flex-shrink: 0;
}
.flow-item p {
font-size: 12px;
color: #f4f8ff;
line-height: 1.3;
white-space: nowrap;
}
.benefits {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 0;
border: 1px solid rgba(255, 255, 255, .18);
border-radius: 14px;
overflow: hidden;
background: rgba(255, 255, 255, .035);
}
.benefit {
display: grid;
grid-template-columns: 62px 1fr;
gap: 14px;
padding: 12px 14px;
border-right: 1px solid rgba(255, 255, 255, .12);
align-items: center;
}
.benefit:last-child {
border-right: 0;
}
.benefit .bico {
width: 48px;
height: 48px;
display: grid;
place-items: center;
border-radius: 50%;
border: 1px solid var(--green);
font-size: 26px;
color: var(--green);
box-shadow: 0 0 18px rgba(32, 239, 103, .18);
}
.benefit:nth-child(5) .bico {
color: var(--orange);
border-color: var(--orange);
}
.benefit h4 {
margin: 0 0 3px;
letter-spacing: .06em;
font-size: 13px;
text-transform: uppercase;
}
.benefit p {
color: var(--muted);
font-size: 13px;
line-height: 1.35;
}
.tagline {
width: min(1200px, 100%);
margin: 22px auto 0;
padding: 11px 32px;
text-align: center;
border: 1px solid var(--purple);
border-radius: 11px;
background: rgba(180, 87, 255, .08);
box-shadow: 0 0 22px rgba(180, 87, 255, .18);
}
.tagline h1 {
font-size: 24px;
letter-spacing: .28em;
}
.tagline .blue-text {
color: var(--blue);
}
.tagline .green-text {
color: var(--green);
}
.tagline .orange-text {
color: var(--orange);
}
.tagline p {
color: #dce6f2;
letter-spacing: .08em;
margin-top: 5px;
}
@media (max-width: 1400px) {
.pipeline {
grid-template-columns: repeat(2, 1fr);
}
.card {
min-height: auto;
}
.flow-row,
.benefits {
grid-template-columns: 1fr;
}
.arrow {
transform: rotate(90deg);
text-align: center;
}
.benefit {
border-right: 0;
border-bottom: 1px solid rgba(255, 255, 255, .12);
}
}
@media (max-width: 1400px) {
.page {
transform: scale(.72);
height: auto;
}
}
@media (max-width: 740px) {
.page {
padding: 14px;
}
.pipeline {
grid-template-columns: 1fr;
gap: 16px;
}
.card {
padding: 18px;
}
.icons-row,
.menu {
grid-template-columns: 1fr;
}
.profile {
grid-template-columns: 1fr;
text-align: center;
}
.avatar {
margin: 0 auto;
}
.tagline h1 {
font-size: 18px;
letter-spacing: .08em;
}
}
</style>
</head>
<body>
<main class="page">
<section class="tagline" style="margin: 0 auto 18px;">
<div style="text-align:left;margin-bottom:10px"><a id="backBtn" href="index.html" style="color:var(--muted);font-size:12px;text-decoration:none;letter-spacing:.08em;text-transform:uppercase;">← Retour au CV</a></div>
<h1><span class="blue-text">MON CODE.</span> <span class="green-text">MON INFRASTRUCTURE.</span> <span
class="orange-text">MA MAÎTRISE.</span></h1>
<p>Liberté, performance et sécurité au service de mon identité professionnelle.</p>
</section>
<section class="pipeline">
<article class="card blue">
<div class="step-head">
<div class="badge">1</div>
<div>
<h2>Edition</h2>
<p class="subtitle">Code en local</p>
</div>
</div>
<div class="icons-row">
<div>
<div class="tool-icon"></div>
<p class="mini-label">Antigravity</p>
</div>
<div>
<div class="tool-icon"></div>
<p class="mini-label">Claude Code</p>
</div>
<div>
<div class="tool-icon"></div>
<p class="mini-label">Git</p>
</div>
</div>
<p style="text-align:center; margin-bottom:18px;">Je développe mon projet CV en local.</p>
<div class="code-window">
<div class="window-top"><span class="dot"></span><span class="dot"></span><span class="dot"></span><span
style="margin-left:8px">index.html</span><span style="margin-left:auto;color:#20ef67">● sauvegardé</span>
</div>
<pre>&lt;!DOCTYPE html&gt;
&lt;html lang="fr"&gt;
&lt;head&gt;
&lt;title&gt;Stéphane Liabeuf - CV&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;header&gt;
&lt;h1&gt;Stéphane Liabeuf&lt;/h1&gt;
&lt;p&gt;25 ans d'expérience en SI&lt;/p&gt;
&lt;/header&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
</div>
<div class="note"><strong>Jutilise Antigravity, Claude Code et Git</strong> pour développer et versionner mon
projet CV.</div>
</article>
<article class="card purple">
<div class="step-head">
<div class="badge">2</div>
<div>
<h2>Dépôt</h2>
<p class="subtitle">Forgejo Personnel</p>
</div>
</div>
<div class="forgejo">
<div class="brand"><span style="color:#55ff45">◖/&gt;</span> Forgejo</div>
<div class="repo">stephaneliabeuf / cv</div>
<div class="server-illustration"></div>
</div>
<p style="text-align:center; line-height:1.6;">En transférant mon projet vers Forgejo, je centralise mon code
sur mon propre serveur.<br><br>Forgejo agit comme la <strong>source de vérité</strong> qui conserve tout
lhistorique de mes versions.</p>
<div class="feature-list">
<ul>
<li>Dépôt privé</li>
<li>Historique complet des commits</li>
<li>Branches & Tags</li>
<li>Permissions & sécurité</li>
</ul>
</div>
</article>
<article class="card green">
<div class="step-head">
<div class="badge">3</div>
<div>
<h2>Orchestrateur</h2>
<p class="subtitle">Coolify</p>
</div>
</div>
<div class="brand" style="justify-content:center; margin-top:8px;"><span style="color:#56ffe3">C</span> Coolify
</div>
<div class="radar"></div>
<div class="process-box">
<div class="icon">👁</div>
<div>
<h3>Surveillance du dépôt Forgejo</h3>
<p>Détection dun nouveau push</p>
</div>
</div>
<div class="process-box">
<div class="icon">⚙️</div>
<div>
<h3>Lancement automatique du déploiement</h3>
<p>Récupération du code · Build · Préparation</p>
</div>
</div>
<div class="process-box">
<div class="icon">🚀</div>
<div>
<h3>Déploiement & mise à jour de linstance</h3>
<p>Rolling update sans interruption</p>
</div>
</div>
<div class="feature-list"><strong style="color:var(--green)">Mon serveur Coolify auto-hébergé</strong>
<ul>
<li>Connexion Forgejo via PAT</li>
<li>Déploiements automatisés</li>
<li>Environnements & variables</li>
<li>Logs & monitoring</li>
</ul>
</div>
</article>
<article class="card orange">
<div class="step-head">
<div class="badge">4</div>
<div>
<h2>Diffusion</h2>
<p class="subtitle">Web Server</p>
</div>
</div>
<div class="box url-box">
<div class="globe"></div>
<div>https://cv.stephaneliabeuf.fr<strong>🔒 HTTPS (SSL/TLS)</strong></div>
</div>
<div style="text-align:center; color:var(--orange); font-size:36px;"></div>
<div class="box server-box">
<div class="nginx">N</div>
<div>
<h3>Conteneur Nginx</h3>
<p style="color:#dbe5f0;margin-top:8px;">Fichiers du CV<br>(HTML, CSS, JS, JSON)</p>
</div>
</div>
<p style="text-align:center; line-height:1.55; margin:20px 0;">Coolify déploie une instance via un conteneur
Nginx qui rend mon CV accessible sur <strong>cv.stephaneliabeuf.fr</strong>.<br><br>Il gère aussi le
certificat SSL pour que mon site soit sécurisé.</p>
<div class="note dynamic">
<h3>Configuration dynamique<br>Source JSON paramétrable</h3>
<p>Pointer sur différents fichiers JSON</p>
<p>Contenu du CV externe et modulaire</p>
<p>Mise à jour sans rebuild</p>
</div>
</article>
<article class="card green">
<div class="step-head">
<div class="badge">5</div>
<div>
<h2>En ligne !</h2>
<p class="subtitle">Mon CV est accessible</p>
</div>
</div>
<div class="browser-window">
<div class="window-top"><span class="dot"></span><span class="dot"></span><span class="dot"></span><span
style="margin-left:8px;color:#20ef67">🔒 https://cv.stephaneliabeuf.fr</span></div>
<div class="browser-content">
<div class="profile">
<div class="avatar"></div>
<div>
<h3>Stéphane Liabeuf</h3>
<p>25 ans dexpérience en SI</p>
<p>DSI / UX / Digital</p><span class="btn">Télécharger mon CV</span>
</div>
</div>
<div class="menu">
<div><span></span>Expérience</div>
<div><span></span>Compétences</div>
<div><span></span>Missions</div>
<div><span></span>Contact</div>
</div>
</div>
</div>
<div class="status-card">
<div class="status-icon"></div>
<div><strong>Source JSON sélectionnée</strong><br><span
style="font-size:14px;color:#dbe5f0">cv-data-limagrain.json</span></div>
</div>
<div class="status-card">
<div class="status-icon">🔒</div>
<div><strong>Sécurisé</strong><br>HTTPS / SSL</div>
</div>
<div class="status-card">
<div class="status-icon"></div>
<div>Mon CV est en ligne,<br>sécurisé en HTTPS.</div>
</div>
</article>
</section>
<section class="flow">
<h3>LE FLUX EN ACTION</h3>
<div class="flow-row">
<div class="flow-item"><span class="flow-ico">💻</span>
<p>Je code en local<br>Antigravity, Claude Code, Git</p>
</div>
<div class="arrow"></div>
<div class="flow-item"><span class="flow-ico"></span>
<p>Je pousse<br>sur Forgejo</p>
</div>
<div class="arrow"></div>
<div class="flow-item"><span class="flow-ico">◖/&gt;</span>
<p>Forgejo détecte<br>le push webhook</p>
</div>
<div class="arrow"></div>
<div class="flow-item"><span class="flow-ico">C</span>
<p>Coolify lance<br>le déploiement</p>
</div>
<div class="arrow"></div>
<div class="flow-item"><span class="flow-ico"></span>
<p>Nginx sert<br>mon CV</p>
</div>
<div class="arrow"></div>
<div class="flow-item"><span class="flow-ico">🛡</span>
<p>Site sécurisé<br>et accessible</p>
</div>
</div>
</section>
<section class="benefits">
<div class="benefit">
<div class="bico">🛡</div>
<div>
<h4>100% indépendant</h4>
<p>Hébergé sur mes propres serveurs</p>
</div>
</div>
<div class="benefit">
<div class="bico"></div>
<div>
<h4>Zéro dépendance</h4>
<p>Aucun service tiers pour lhébergement</p>
</div>
</div>
<div class="benefit">
<div class="bico"></div>
<div>
<h4>Déploiement automatisé</h4>
<p>Chaque push met le site à jour</p>
</div>
</div>
<div class="benefit">
<div class="bico">🔒</div>
<div>
<h4>Sécurisé</h4>
<p>HTTPS natif, sauvegardes et contrôles daccès</p>
</div>
</div>
<div class="benefit">
<div class="bico"></div>
<div>
<h4>Maîtrisé & évolutif</h4>
<p>Scalable, monitoré et entièrement sous contrôle</p>
</div>
</div>
</section>
</main>
<script>
const cv = new URLSearchParams(window.location.search).get('cv');
const validCodes = ['f3b9c7a8d5e4b2d1c0a9b8d7', 'e2d1c0b9a8f7e6d5c4b3a2f1', 'a1b2c3d4e5f6a7b8c9d0e1f2'];
if (!cv || !validCodes.includes(cv)) {
window.location.href = 'index.html';
} else {
document.getElementById('backBtn').href = `index.html?cv=${cv}`;
}
</script>
</body>
</html>